diff --git a/nasher.cfg b/nasher.cfg index 6ddc716..faa916d 100644 --- a/nasher.cfg +++ b/nasher.cfg @@ -1,28 +1,26 @@ [package] name = "Realms of Trinity II [PRC8]" -description = "Realms of Trinity II with PRC8& other enhancements" -version = "2.01" +description = "Realms of Trinity II with PRC8 & other enhancements" +version = "2.02prc8" url = "https://discord.gg/gZtMe894eh" author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>" author = "Tab" -[Sources] -include = "src/mod/**/*.{nss,json,sq3}" + [package.sources] + include = "src/module/**/*.{nss.json}" + include = "src/include/**/*.{nss}" -[Rules] -"*.ndb" = "debugSymbols" -"*" = "unknown" + [package.rules] + "*" = "src/module/$ext" [Target] name = "default" file = "Realms of Trinity II [PRC8].mod" -description = "Realms of Trinity II with PRC8& other enhancements" +description = "Realms of Trinity II with PRC8 & other enhancements" [target.sources] - include = "src/mod/**/*" - include = "src/prc8/include/**/*" - filter = "nui_i_library.nss" - filter = "util_i_library.nss" + include = "src/module/**/*" + include = "src/include/**/*" filter = "bnd_inc_bndfunc.nss" filter = "bnd_vestig_const.nss" filter = "inc_2dacache.nss" @@ -230,4 +228,20 @@ description = "Realms of Trinity II with PRC8& other enhancements" filter = "x2_inc_cutscenep.nss" filter = "x2_inc_spellhook.nss" filter = "x3_inc_horse.nss" - filter = "xchst_inc.nss" \ No newline at end of file + filter = "prc_inc_string.nss" + filter = "prc_nui_sc_inc.nss" + filter = "prc_nui_scd_inc.nss" + filter = "prc_nui_consts.nss" + filter = "nw_inc_nui" + filter = "xchst_inc.nss" + filter = "nui_i_library.nss" + +[target] +name = "pepshak" +file = "peps_prc8.hak" +description = "PEPS hakpak for PRC8 version of Realms of Trinity II." + [target.sources] + include = "src/hakpak/peps_prc8/**/*" + + [target.rules] + "*" = "src/hakpak/peps_prc8/$ext" \ No newline at end of file diff --git a/pack_haks.cmd b/pack_haks.cmd new file mode 100644 index 0000000..f07456c --- /dev/null +++ b/pack_haks.cmd @@ -0,0 +1 @@ +nasher pack pepshak --verbose \ No newline at end of file diff --git a/pack_module.cmd b/pack_module.cmd new file mode 100644 index 0000000..2308124 --- /dev/null +++ b/pack_module.cmd @@ -0,0 +1 @@ +nasher pack default --verbose \ No newline at end of file diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index a8feacf..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Ignore packed files -*.erf -*.hak -*.mod -*.tlk - -# Ignore the nasher directory -.nasher/ diff --git a/src/_removed/nw_c2_default1.ncs b/src/_removed/nw_c2_default1.ncs new file mode 100644 index 0000000..4f5b1f9 Binary files /dev/null and b/src/_removed/nw_c2_default1.ncs differ diff --git a/src/mod/nss/nw_c2_default1.nss b/src/_removed/nw_c2_default1.nss similarity index 100% rename from src/mod/nss/nw_c2_default1.nss rename to src/_removed/nw_c2_default1.nss diff --git a/src/_removed/nw_c2_default2.ncs b/src/_removed/nw_c2_default2.ncs new file mode 100644 index 0000000..c3a4f7e Binary files /dev/null and b/src/_removed/nw_c2_default2.ncs differ diff --git a/src/mod/nss/nw_c2_default2.nss b/src/_removed/nw_c2_default2.nss similarity index 100% rename from src/mod/nss/nw_c2_default2.nss rename to src/_removed/nw_c2_default2.nss diff --git a/src/_removed/nw_c2_default3.ncs b/src/_removed/nw_c2_default3.ncs new file mode 100644 index 0000000..c54384c Binary files /dev/null and b/src/_removed/nw_c2_default3.ncs differ diff --git a/src/mod/nss/nw_c2_default3.nss b/src/_removed/nw_c2_default3.nss similarity index 100% rename from src/mod/nss/nw_c2_default3.nss rename to src/_removed/nw_c2_default3.nss diff --git a/src/_removed/nw_c2_default4.ncs b/src/_removed/nw_c2_default4.ncs new file mode 100644 index 0000000..b8652e3 Binary files /dev/null and b/src/_removed/nw_c2_default4.ncs differ diff --git a/src/mod/nss/nw_c2_default4.nss b/src/_removed/nw_c2_default4.nss similarity index 100% rename from src/mod/nss/nw_c2_default4.nss rename to src/_removed/nw_c2_default4.nss diff --git a/src/_removed/nw_c2_default5.ncs b/src/_removed/nw_c2_default5.ncs new file mode 100644 index 0000000..1502fbc Binary files /dev/null and b/src/_removed/nw_c2_default5.ncs differ diff --git a/src/mod/nss/nw_c2_default5.nss b/src/_removed/nw_c2_default5.nss similarity index 100% rename from src/mod/nss/nw_c2_default5.nss rename to src/_removed/nw_c2_default5.nss diff --git a/src/_removed/nw_c2_default6.ncs b/src/_removed/nw_c2_default6.ncs new file mode 100644 index 0000000..1727698 Binary files /dev/null and b/src/_removed/nw_c2_default6.ncs differ diff --git a/src/mod/nss/nw_c2_default6.nss b/src/_removed/nw_c2_default6.nss similarity index 100% rename from src/mod/nss/nw_c2_default6.nss rename to src/_removed/nw_c2_default6.nss diff --git a/src/_removed/nw_c2_default8.ncs b/src/_removed/nw_c2_default8.ncs new file mode 100644 index 0000000..2df2091 Binary files /dev/null and b/src/_removed/nw_c2_default8.ncs differ diff --git a/src/mod/nss/nw_c2_default8.nss b/src/_removed/nw_c2_default8.nss similarity index 100% rename from src/mod/nss/nw_c2_default8.nss rename to src/_removed/nw_c2_default8.nss diff --git a/src/_removed/nw_c2_defaulta.ncs b/src/_removed/nw_c2_defaulta.ncs new file mode 100644 index 0000000..bb9b17a Binary files /dev/null and b/src/_removed/nw_c2_defaulta.ncs differ diff --git a/src/mod/nss/nw_c2_defaulta.nss b/src/_removed/nw_c2_defaulta.nss similarity index 100% rename from src/mod/nss/nw_c2_defaulta.nss rename to src/_removed/nw_c2_defaulta.nss diff --git a/src/_removed/nw_c2_defaultb.ncs b/src/_removed/nw_c2_defaultb.ncs new file mode 100644 index 0000000..146034f Binary files /dev/null and b/src/_removed/nw_c2_defaultb.ncs differ diff --git a/src/mod/nss/nw_c2_defaultb.nss b/src/_removed/nw_c2_defaultb.nss similarity index 100% rename from src/mod/nss/nw_c2_defaultb.nss rename to src/_removed/nw_c2_defaultb.nss diff --git a/src/_removed/nw_c2_defaulte.ncs b/src/_removed/nw_c2_defaulte.ncs new file mode 100644 index 0000000..1eb9873 Binary files /dev/null and b/src/_removed/nw_c2_defaulte.ncs differ diff --git a/src/mod/nss/nw_c2_defaulte.nss b/src/_removed/nw_c2_defaulte.nss similarity index 100% rename from src/mod/nss/nw_c2_defaulte.nss rename to src/_removed/nw_c2_defaulte.nss diff --git a/src/hakpak/peps_prc8/2da/ai_messages.2da b/src/hakpak/peps_prc8/2da/ai_messages.2da new file mode 100644 index 0000000..cc5d0c9 --- /dev/null +++ b/src/hakpak/peps_prc8/2da/ai_messages.2da @@ -0,0 +1,49 @@ +2DA V2.0 + + Message_Type Text +0 AI_Message "Picking up too much junk? Adjust the loot filter." +1 AI_Message "Try the AI on your player for a different experience!" +2 AI_Message "Does your associates talk to much? Reduce their speech." +3 AI_Message "Modes will keep your character engaged in that task." +4 AI_Message "Give Thieves picks to your rogues, they will use them." +5 AI_Message "Want your associates using more magic? Up their magic level." +6 AI_Message "Using up spells too fast? Control what they can cast!" +7 AI_Message "You can adjust when associates heal in and out of combat." +8 AI_Message "Don't want to be a team player? Turn party healing off." +9 AI_Message "Need help picking up all that loot? Turn Auto looting on." +10 Widget_Message "Place your widgets then lock'em into place!" +11 Widget_Message "Like an associates settings? Copy them to other associates." +12 Widget_Message "Use action button to control your associates actions." +13 Widget_Message "'All' commands are good for getting control of the party." +14 Widget_Message "Normal mode clears any specific commands." +15 Widget_Message "Follow command makes them stop fighting and follow!" +16 Widget_Message "Have traps? You can make a skilled associate use them." +17 Widget_Message "Put the camera focus on an associate to get better control." +18 Widget_Message "Don't like your associates familiar? Change it!" +19 Widget_Message "Don't like your associates animal companion? Change it!" +20 General_Message "Right click on the widget portrait to open the AI menu." +21 General_Message "Give your associates magic items, they can use more now!" +22 General_Message "Use the boxes to the right to add commands to your widgets." +23 General_Message "Use the mouse wheel to change a button's [values]." +24 General_Message "Use the mouse wheel to change a button's [values]." +25 General_Message "Use the mouse wheel to change a button's [values]." +26 General_Message "Want a module supported? Ask on Discord or the Vault." +27 Rule_Message "Allow more henchman into your party, upto 12 can join!" +28 Rule_Message "Too many widgets? You can turn your associate widgets off!" +29 Rule_Message "Party too big and can't get down the hall? Use Ghost mode!" +30 Rule_Message "Is the game too easy? Goto Main Options and change the RULES!" +31 Rule_Message "Increase the difficulty, make monster attack weaker targets." +32 Rule_Message "Monsters too powerful? Turn on moral checks." +33 Rule_Message "Allow casters to prebuff for stronger opponents." +34 Rule_Message "Allow casters to presummon for more enemy support." +35 Rule_Message "Change up your opponents tactics. Turn on monster tactics." +36 Rule_Message "Allow enemies to have their familiars and animal companions." +37 Rule_Message "Make summons more powerful, stop unsummons on master's death!" +38 Rule_Message "Want a pile on? Increase the distance monsters can respond!" +39 Rule_Message "Monster's perception can be changed up or down!" +40 Rule_Message "Want to see a massacre! Set the enemy corpses to remain." +41 Rule_Message "Looking for variety? Turn on wandering to get a surprise!" +42 Rule_Message "Not hard enough? Up the number of monsters you fight!" +43 Rule_Message "Monsters just falling over? Increase their health!" +44 Widget_Message "Change your associates memorized spells to what you need!" +45 Widget_message "Control the spells your party uses by turning on the Quick use widget!" diff --git a/src/hakpak/peps_prc8/2da/ai_spells.2da b/src/hakpak/peps_prc8/2da/ai_spells.2da new file mode 100644 index 0000000..14db4b5 --- /dev/null +++ b/src/hakpak/peps_prc8/2da/ai_spells.2da @@ -0,0 +1,19400 @@ +2DA V2.0 + + Label ImmunityType SaveType SpellResist Category HostileSetting Buff_Duration Buff_Target Buff_Group +0 Acid_Fog Acid **** 1 I 1 **** **** **** +1 Aid **** **** **** E 0 2 9 **** +2 Animate_Dead **** **** **** S 0 **** **** **** +3 Barkskin **** **** **** P 0 3 7 **** +4 Bestow_Curse **** Will 1 T 1 **** **** **** +5 Blade_Barrier **** Reflex 1 I 1 **** **** **** +6 Bless **** **** **** E 0 2 0 **** +7 Bless_Weapon[NOT_USED] **** **** **** **** **** **** **** **** +8 Blindness_and_Deafness Blindness Fortitude 1 R 1 **** **** **** +9 Bulls_Strength **** **** **** E 0 3 1 **** +10 Burning_Hands Fire Reflex 1 I 1 **** **** **** +11 Call_Lightning Electricity Reflex 1 D 1 **** **** **** +12 Calm_Emotions[NOT_USED] **** **** **** **** **** **** **** **** +13 Cats_Grace **** **** **** E 0 3 2 **** +14 Chain_Lightning Electricity Reflex 1 D 1 **** **** **** +15 Charm_Monster Mind_Affecting Will 1 R 1 **** **** **** +16 Charm_Person Mind_Affecting Will 1 R 1 **** **** **** +17 Charm_Person_or_Animal Mind_Affecting Will 1 R 1 **** **** **** +18 Circle_of_Death Death Fortitude 1 D 1 **** **** **** +19 Circle_of_Doom Negative Fortitude 1 D 1 **** **** **** +20 Clairaudience_and_Clairvoyance **** **** **** C 0 2 5 **** +21 Clarity **** **** **** C 0 2 13 **** +22 Cloak_of_Chaos[NOT_USED] **** **** **** **** **** **** **** **** +23 Cloudkill Poison Fortitude 0 I 1 **** **** **** +24 Color_Spray Blindness Will 1 I 1 **** **** **** +25 Cone_of_Cold Cold Reflex 1 I 1 **** **** **** +26 Confusion Confusion Will 1 D 1 **** **** **** +27 Contagion Disease Fortitude 1 T 1 **** **** **** +28 Control_Undead NoImmunity Will 1 R 1 **** **** **** +29 Create_Greater_Undead **** **** **** S 0 3 0 -2 +30 Create_Undead **** **** **** S 0 3 0 -2 +31 Cure_Critical_Wounds **** **** **** H 0 **** **** **** +32 Cure_Light_Wounds **** **** **** H 0 **** **** **** +33 Cure_Minor_Wounds **** **** **** H 0 **** **** **** +34 Cure_Moderate_Wounds **** **** **** H 0 **** **** **** +35 Cure_Serious_Wounds **** **** **** H 0 **** **** **** +36 Darkness **** **** **** I 0 **** **** **** +37 Daze Dazed Will 1 R 1 **** **** **** +38 Death_Ward **** **** **** E 0 3 11 **** +39 Delayed_Blast_Fireball Fire Reflex 1 I 1 **** **** **** +40 Dismissal **** **** 1 I 1 **** **** **** +41 Dispel_Magic **** **** **** R 0 **** **** **** +42 Divine_Power **** **** **** E 0 2 0 **** +43 Dominate_Animal Domination Will 1 R 1 **** **** **** +44 Dominate_Monster Domination Will 1 R 1 **** **** **** +45 Dominate_Person Domination Will 1 R 1 **** **** **** +46 Doom Fear Will 1 R 1 **** **** **** +47 Elemental_Shield **** **** **** P 0 2 7 **** +48 Elemental_Swarm **** **** **** S 0 3 0 -2 +49 Endurance **** **** **** E 0 3 3 **** +50 Endure_Elements **** **** **** P 0 3 10 -1 +51 Energy_Drain Level_Drain **** 1 R 1 **** **** **** +52 Enervation Level_Drain **** 1 R 1 **** **** **** +53 Entangle **** Reflex 0 I 1 **** **** **** +54 Fear Fear Will 1 D 1 **** **** **** +55 Feeblemind Mind_Affecting Will 1 R 1 **** **** **** +56 Finger_of_Death Death Fortitude 1 R 1 **** **** **** +57 Fire_Storm Fire Reflex 1 D 1 **** **** **** +58 Fireball Fire Reflex 1 I 1 **** **** **** +59 Flame_Arrow Fire Reflex 1 R 1 **** **** **** +60 Flame_Lash Fire Reflex 1 R 1 **** **** **** +61 Flame_Strike Fire Reflex 1 I 1 **** **** **** +62 Freedom_of_Movement **** **** **** E 0 2 9 **** +63 Gate **** **** **** S 0 3 0 -2 +64 Ghoul_Touch Poison Fortitude 1 T 1 **** **** **** +65 Globe_of_Invulnerability **** **** **** P 0 2 0 -7 +66 Grease **** Reflex 0 I 1 **** **** **** +67 Greater_Dispelling **** **** **** R 0 **** **** **** +68 Greater_Magic_Weapon[NOT_USED] **** **** **** **** **** **** **** **** +69 Greater_Planar_Binding **** **** **** S 0 3 0 -2 +70 Greater_Restoration **** **** **** C 0 **** **** **** +71 Greater_Shadow_Conjuration **** **** **** **** 1 **** **** **** +72 Greater_Spell_Breach **** **** 0 R 1 **** **** **** +73 Greater_Spell_Mantle **** **** **** P 0 2 0 -9 +74 Greater_Stoneskin **** **** **** P 0 3 0 -8 +75 Gust_of_Wind **** Fortitude 0 I 1 **** **** **** +76 Hammer_of_the_Gods Divine Will 1 D 1 **** **** **** +77 Harm Negative Will 1 T 1 **** **** **** +78 Haste **** **** **** E 0 2 9 -16 +79 Heal **** **** **** H 0 **** **** **** +80 Healing_Circle **** **** **** H 0 **** **** **** +81 Hold_Animal Paralysis Will 1 R 1 **** **** **** +82 Hold_Monster Paralysis Will 1 R 1 **** **** **** +83 Hold_Person Paralysis Will 1 R 1 **** **** **** +84 Holy_Aura[NOT_USED] **** **** **** **** **** **** **** **** +85 Holy_Sword[NOT_USED] **** **** **** **** **** **** **** **** +86 Identify **** **** **** **** 0 **** **** **** +87 Implosion Death Fortitude 1 I 1 **** **** **** +88 Improved_Invisibility **** **** **** E 0 2 7 -5 +89 Incendiary_Cloud Fire Reflex 0 I 1 **** **** **** +90 Invisibility **** **** **** E 0 2 7 -5 +91 Invisibility_Purge **** **** **** E 0 2 0 **** +92 Invisibility_Sphere **** **** **** E 0 2 0 -5 +93 Knock **** **** **** **** 0 **** **** **** +94 Lesser_Dispel **** **** **** R 0 **** **** **** +95 Lesser_Mind_Blank **** **** **** E 0 2 13 **** +96 Lesser_Planar_Binding **** **** **** S 0 3 0 -2 +97 Lesser_Restoration **** **** **** C 0 **** **** **** +98 Lesser_Spell_Breach **** **** 0 R 1 **** **** **** +99 Lesser_Spell_Mantle **** **** **** P 0 2 0 -9 +100 Light **** **** **** **** 0 3 0 -15 +101 Lightning_Bolt Electricity Reflex 1 I 1 **** **** **** +102 Mage_Armor **** **** **** P 0 3 7 -102 +103 Magic_Circle_against_Chaos **** **** **** P 0 3 14 -10 +104 Magic_Circle_against_Evil **** **** **** P 0 3 14 -11 +105 Magic_Circle_against_Good **** **** **** P 0 3 14 -12 +106 Magic_Circle_against_Law **** **** **** P 0 3 14 -13 +107 Magic_Missile **** **** 1 R 1 **** **** **** +108 Magic_Vestment[NOT_USED] **** **** **** **** **** **** **** **** +109 Magic_Weapon[NOT_USED] **** **** **** **** **** **** **** **** +110 Mass_Blindness_and_Deafness Blindness Will 1 D 1 **** **** **** +111 Mass_Charm Charm Will 1 D 1 **** **** **** +112 Mass_Domination Domination Will 1 D 1 **** **** **** +113 Mass_Haste **** **** **** E 0 2 0 -16 +114 Mass_Heal **** **** **** H 0 **** **** **** +115 Melfs_Acid_Arrow Acid **** 0 R 1 **** **** **** +116 Meteor_Swarm Fire Reflex 1 D 1 **** **** **** +117 Mind_Blank **** **** **** E 0 2 0 **** +118 Mind_Fog Mind_Affecting Will 1 I 1 **** **** **** +119 Minor_Globe_of_Invulnerability **** **** **** P 0 2 0 -7 +120 Ghostly_Visage **** **** **** P 0 2 0 -8 +121 Ethereal_Visage **** **** **** E 0 2 0 -8 +122 Mordenkainens_Disjunction **** **** **** I 0 **** **** **** +123 Mordenkainens_Sword **** **** **** S 0 2 0 -2 +124 Natures_Balance Postive Will 0 D 0 **** **** **** +125 Negative_Energy_Protection **** **** **** P 0 2 10 **** +126 Neutralize_Poison **** **** **** C 0 **** **** **** +127 Phantasmal_Killer Fear Will 1 R 1 **** **** **** +128 Planar_Binding **** **** **** S 0 3 0 -2 +129 Poison Poison Fortitude 1 R 1 **** **** **** +130 Polymorph_Self **** **** **** **** 0 2 0 -17 +131 Power_Word_Kill **** **** 1 R 1 **** **** **** +132 Power_Word_Stun **** **** 1 I 1 **** **** **** +133 Prayer **** **** **** E 0 2 0 **** +134 Premonition **** **** **** P 0 3 0 -8 +135 Prismatic_Spray Mind_Affecing Will 1 I 1 **** **** **** +136 Protection__from_Chaos[NOT_USED] **** **** **** **** **** **** **** **** +137 Protection_from_Elements **** **** **** P 0 3 10 -1 +138 Protection_from_Evil **** **** **** **** **** **** **** **** +139 Protection_from_Good **** **** **** **** **** **** **** **** +140 Protection_from_Law **** **** **** **** **** **** **** **** +141 Protection_from_Spells **** **** **** P 0 3 0 **** +142 Raise_Dead **** **** **** **** 0 **** **** **** +143 Ray_of_Enfeeblement **** **** 1 R 1 **** **** **** +144 Ray_of_Frost Cold **** 1 R 1 **** **** **** +145 Remove_Blindness_and_Deafness **** **** **** C 0 **** **** **** +146 Remove_Curse **** **** **** C 0 **** **** **** +147 Remove_Disease **** **** **** C 0 **** **** **** +148 Remove_Fear **** **** **** C 0 3 13 **** +149 Remove_Paralysis **** **** **** C 0 **** **** **** +150 Resist_Elements **** **** **** P 0 2 10 -1 +151 Resistance **** **** **** P 0 2 14 **** +152 Restoration **** **** **** C 0 **** **** **** +153 Resurrection **** **** **** **** 0 **** **** **** +154 Sanctuary **** **** **** E 0 2 8 -5 +155 Scare Fear Will 1 R 1 **** **** **** +156 Searing_Light Divine **** 1 R 1 **** **** **** +157 See_Invisibility **** **** **** E 0 2 9 **** +158 Shades **** **** **** **** 1 **** **** **** +159 Shadow_Conjuration **** **** **** **** 1 **** **** **** +160 Shadow_Shield **** **** **** P 0 2 0 **** +161 Shapechange **** **** **** **** 0 2 0 -17 +162 Shield_of_Law[NOT_USED] **** **** **** **** **** **** **** **** +163 Silence **** **** **** I 1 **** **** **** +164 Slay_Living Negative Fortitude 1 R 1 **** **** **** +165 Sleep Sleep Will 1 I 1 **** **** **** +166 Slow **** **** **** D 1 **** **** **** +167 Sound_Burst Sonic Fortitude 1 I 1 **** **** **** +168 Spell_Resistance **** **** **** P 0 2 14 **** +169 Spell_Mantle **** **** **** P 0 2 0 -9 +170 Sphere_of_Chaos **** **** **** E 1 **** **** **** +171 Stinking_Cloud Poison Fortitude 1 I 1 **** **** **** +172 Stoneskin **** **** **** P 0 3 7 -8 +173 Storm_of_Vengeance Electricity Reflex 1 D 1 **** **** **** +174 Summon_Creature_I **** **** **** S 0 3 0 -2 +175 Summon_Creature_II **** **** **** S 0 3 0 -2 +176 Summon_Creature_III **** **** **** S 0 3 0 -2 +177 Summon_Creature_IV **** **** **** S 0 3 0 -2 +178 Summon_Creature_IX **** **** **** S 0 3 0 -2 +179 Summon_Creature_V **** **** **** S 0 3 0 -2 +180 Summon_Creature_VI **** **** **** S 0 3 0 -2 +181 Summon_Creature_VII **** **** **** S 0 3 0 -2 +182 Summon_Creature_VIII **** **** **** S 0 3 0 -2 +183 Sunbeam Divine Reflex 1 D 1 **** **** **** +184 Tensers_Transformation **** **** **** E 0 **** **** **** +185 Time_Stop **** **** **** D 0 **** **** **** +186 True_Seeing **** **** **** E 0 2 9 **** +187 Unholy_Aura[NOT_USED] **** **** **** **** **** **** **** **** +188 Vampiric_Touch Negative **** 1 T 1 **** **** **** +189 Virtue **** **** **** E 0 2 10 **** +190 Wail_of_the_Banshee Death Fortitude 1 D 1 **** **** **** +191 Wall_of_Fire Fire Reflex 1 I 1 **** **** **** +192 Web **** Reflex 1 I 1 **** **** **** +193 Weird Fear Will 1 D 1 **** **** **** +194 Word_of_Faith Divine **** 1 D 1 **** **** **** +195 AURA_BLINDING Mind_Affecting Will 0 A 1 **** **** **** +196 Aura_Cold **** **** **** A 1 **** **** **** +197 Aura_Electricity **** **** **** A 1 **** **** **** +198 Aura_Fear **** **** **** A 1 **** **** **** +199 Aura_Fire **** **** **** A 1 **** **** **** +200 Aura_Menace **** **** **** A 1 **** **** **** +201 Aura_Protection **** **** **** A 0 **** **** **** +202 Aura_Stun **** **** **** A 1 **** **** **** +203 Aura_Unearthly_Visage **** **** **** A 1 **** **** **** +204 Aura_Unnatural **** **** **** A 1 **** **** **** +205 Bolt_Ability_Drain_Charisma **** **** 0 R 1 **** **** **** +206 Bolt_Ability_Drain_Constitution **** **** 0 R 1 **** **** **** +207 Bolt_Ability_Drain_Dexterity **** **** 0 R 1 **** **** **** +208 Bolt_Ability_Drain_Intelligence **** **** 0 R 1 **** **** **** +209 Bolt_Ability_Drain_Strength **** **** 0 R 1 **** **** **** +210 Bolt_Ability_Drain_Wisdom **** **** 0 R 1 **** **** **** +211 Bolt_Acid Acid **** 0 R 1 **** **** **** +212 Bolt_Charm **** **** 0 R 1 **** **** **** +213 Bolt_Cold Cold **** 0 R 1 **** **** **** +214 Bolt_Confuse **** **** 0 R 1 **** **** **** +215 Bolt_Daze **** **** 0 R 1 **** **** **** +216 Bolt_Death **** **** 0 R 1 **** **** **** +217 Bolt_Disease **** **** 0 R 1 **** **** **** +218 Bolt_Dominate **** **** 0 R 1 **** **** **** +219 Bolt_Fire Fire **** 0 R 1 **** **** **** +220 Bolt_Knockdown **** **** 0 R 1 **** **** **** +221 Bolt_Level_Drain **** **** 0 R 1 **** **** **** +222 Bolt_Lightning Electricity **** 0 R 1 **** **** **** +223 Bolt_Paralyze **** **** 0 R 1 **** **** **** +224 Bolt_Poison **** **** 0 R 1 **** **** **** +225 Bolt_Shards **** **** 0 R 1 **** **** **** +226 Bolt_Slow **** **** 0 R 1 **** **** **** +227 Bolt_Stun **** **** 0 R 1 **** **** **** +228 Bolt_Web **** **** 0 R 1 **** **** **** +229 Cone_Acid Acid Reflex 0 I 1 **** **** **** +230 Cone_Cold Cold Reflex 0 I 1 **** **** **** +231 Cone_Disease Disease Fortitude 0 I 1 **** **** **** +232 Cone_Fire Fire Reflex 0 I 1 **** **** **** +233 Cone_Lightning Electricity Reflex 0 I 1 **** **** **** +234 Cone_Poison Poison Fortitude 0 I 1 **** **** **** +235 Cone_Sonic Sonic Reflex 0 I 1 **** **** **** +236 Dragon_Breath_Acid Acid Reflex 0 **** 1 **** **** **** +237 Dragon_Breath_Cold Cold Reflex 0 **** 1 **** **** **** +238 Dragon_Breath_Fear Fear Will 0 **** 1 **** **** **** +239 Dragon_Breath_Fire Fire Reflex 0 **** 1 **** **** **** +240 Dragon_Breath_Gas Acid Reflex 0 **** 1 **** **** **** +241 Dragon_Breath_Lightning Electricity Reflex 0 **** 1 **** **** **** +242 Dragon_Breath_Paralyze Paralyze Fortitude 0 **** 1 **** **** **** +243 Dragon_Breath_Sleep Sleep Will 0 **** 1 **** **** **** +244 Dragon_Breath_Slow **** Reflex 0 **** 1 **** **** **** +245 Dragon_Breath_Weaken Negative Reflex 0 **** 1 **** **** **** +246 Dragon_Wing_Buffet **** **** **** **** 1 **** **** **** +247 Ferocity_1 **** **** **** **** 0 **** **** **** +248 Ferocity_2 **** **** **** **** 0 **** **** **** +249 Ferocity_3 **** **** **** **** 0 **** **** **** +250 Gaze_Charm Charm Will 0 I 1 **** **** **** +251 Gaze_Confusion Confusion Will 0 I 1 **** **** **** +252 Gaze_Daze Daze Will 0 I 1 **** **** **** +253 Gaze_Death Death Will 0 I 1 **** **** **** +254 Gaze_Destroy_Chaos Death Will 0 I 1 **** **** **** +255 Gaze_Destroy_Evil Death Will 0 I 1 **** **** **** +256 Gaze_Destroy_Good Death Will 0 I 1 **** **** **** +257 Gaze_Destroy_Law Death Will 0 I 1 **** **** **** +258 Gaze_Dominate Domination Will 0 I 1 **** **** **** +259 Gaze_Doom **** Will 0 I 1 **** **** **** +260 Gaze_Fear Fear Will 0 I 1 **** **** **** +261 Gaze_Paralysis **** Will 0 I 1 **** **** **** +262 Gaze_Stunned Mind_Affecting Will 0 I 1 **** **** **** +263 Golem_Breath_Gas Poison Fortitude 0 I 1 **** **** **** +264 Hell_Hound_Firebreath Fire **** 0 I 1 **** **** **** +265 Howl_Confuse Confusion Will 0 I 1 **** **** **** +266 Howl_Daze Daze Will 0 I 1 **** **** **** +267 Howl_Death Death Will 0 I 1 **** **** **** +268 Howl_Doom **** Will 0 I 1 **** **** **** +269 Howl_Fear Fear Will 0 I 1 **** **** **** +270 Howl_Paralysis **** Will 0 I 1 **** **** **** +271 Howl_Sonic Sonic Fortitude 0 I 1 **** **** **** +272 Howl_Stun Mind_Affecting Will 0 I 1 **** **** **** +273 Intensity_1 **** **** **** **** 0 **** **** **** +274 Intensity_2 **** **** **** **** 0 **** **** **** +275 Intensity_3 **** **** **** **** 0 **** **** **** +276 Krenshar_Scare Fear Will 0 D 1 **** **** **** +277 Lesser_Body_Adjustment **** **** **** H 0 **** **** **** +278 Mephit_Salt_Breath Acid Reflex 0 I 1 **** **** **** +279 Mephit_Steam_Breath Fire Reflex 0 I 1 **** **** **** +280 Mummy_Bolster_Undead **** **** **** E 1 **** **** **** +281 Pulse_Drown **** Reflex 0 D 1 **** **** **** +282 Pulse_Spores Disease Fortitude 0 D 1 **** **** **** +283 Pulse_Whirlwind **** Reflex 0 D 1 **** **** **** +284 Pulse_Fire Fire Reflex 0 I 1 **** **** **** +285 Pulse_Lightning Electricity Reflex 0 I 1 **** **** **** +286 Pulse_Cold Cold Reflex 0 I 1 **** **** **** +287 Pulse_Negative Negative Reflex 0 I 1 **** **** **** +288 Pulse_Holy Divine Reflex 0 I 1 **** **** **** +289 Pulse_Death Death Fortitude 0 I 1 **** **** **** +290 Pulse_Level_Drain Level_Drain Fortitude 0 I 1 **** **** **** +291 Pulse_Ability_Drain_Intelligence Ability_Drain Fortitude 0 D 1 **** **** **** +292 Pulse_Ability_Drain_Charisma Ability_Drain Fortitude 0 D 1 **** **** **** +293 Pulse_Ability_Drain_Constitution Ability_Drain Fortitude 0 D 1 **** **** **** +294 Pulse_Ability_Drain_Dexterity Ability_Drain Fortitude 0 D 1 **** **** **** +295 Pulse_Ability_Drain_Strength Ability_Drain Fortitude 0 D 1 **** **** **** +296 Pulse_Ability_Drain_Wisdom Ability_Drain Fortitude 0 D 1 **** **** **** +297 Pulse_Poison Poison Fortitude 0 D 1 **** **** **** +298 Pulse_Disease Disease Fortitude 0 D 1 **** **** **** +299 Rage_3 **** **** **** *** 0 **** **** **** +300 Rage_4 **** **** **** *** 0 **** **** **** +301 Rage_5 **** **** **** **** 0 **** **** **** +302 Smoke_Claw **** Fortitude 0 T 1 **** **** **** +303 Summon_Slaad **** **** **** S 1 **** **** **** +304 Summon_Tanarri **** **** **** S 1 **** **** **** +305 Trumpet_Blast **** Will 0 D 1 **** **** **** +306 Tyrant_Fog_Mist **** **** **** A 1 **** **** **** +307 BARBARIAN_RAGE **** **** **** **** 0 **** **** **** +308 Turn_Undead Divine **** **** D 1 **** **** **** +309 Wholeness_of_Body **** **** **** H 0 **** **** **** +310 Quivering_Palm **** **** **** **** 1 **** **** **** +311 Empty_Body **** **** **** E 0 **** **** **** +312 Detect_Evil **** **** **** **** 0 **** **** **** +313 Lay_On_Hands **** **** **** H 0 **** **** **** +314 Aura_Of_Courage **** **** **** **** 0 **** **** **** +315 Smite_Evil **** **** **** T 1 **** **** **** +316 Remove_Disease **** **** **** C 0 **** **** **** +317 Summon_Animal_Companion **** **** **** **** 0 **** **** **** +318 Summon_Familiar **** **** **** **** 0 **** **** **** +319 Elemental_Shape **** **** **** **** 0 **** **** **** +320 Wild_Shape **** **** **** **** 0 **** **** **** +321 PROTECTION_FROM_ALIGNMENT **** **** **** **** 0 **** **** **** +322 Magic_Circle_against_Alignment **** **** **** **** 0 **** **** **** +323 Aura_versus_Alignment **** **** **** **** 0 **** **** **** +324 SHADES_Summon_Shadow **** **** **** D 0 **** **** **** +325 DELETED_PRO_Cold **** **** **** **** 0 **** **** **** +326 DELETED_PRO_Fire **** **** **** **** 0 **** **** **** +327 DELETED_PRO_Acid **** **** **** **** 0 **** **** **** +328 DELETED_PRO_Sonic **** **** **** **** 0 **** **** **** +329 DELETED_PRO_Elec **** **** **** **** 0 **** **** **** +330 DELETED_END_Cold **** **** **** **** 0 **** **** **** +331 DELETED_END_Fire **** **** **** **** 0 **** **** **** +332 DELETED_END_Acid **** **** **** **** 0 **** **** **** +333 DELETED_END_Sonic **** **** **** **** 0 **** **** **** +334 DELETED_END_Elec **** **** **** **** 0 **** **** **** +335 DELETED_RES_Cold **** **** **** **** 0 **** **** **** +336 DELETED_RES_Fire **** **** **** **** 0 **** **** **** +337 DELETED_RES_Acid **** **** **** **** 0 **** **** **** +338 DELETED_RES_Sonic **** **** **** **** 0 **** **** **** +339 DELETED_RES_Elec **** **** **** **** 0 **** **** **** +340 SHADES_Cone_of_Cold Cold Reflex 1 I 1 **** **** **** +341 SHADES_Fireball Fire Reflex 1 I 1 **** **** **** +342 SHADES_Stoneskin **** **** **** P 0 **** **** **** +343 SHADES_Wall_of_Fire Fire Reflex 1 I 1 **** **** **** +344 SHADOW_CON_Summon_Shadow **** **** **** D 0 **** **** **** +345 SHADOW_CON_Darkness **** **** **** I 0 **** **** **** +346 SHADOW_CON_Inivsibility **** **** **** E 0 **** **** **** +347 SHADOW_CON_Mage_Armor **** **** **** P 0 **** **** **** +348 SHADOW_CON_Magic_Missile **** **** 1 R 1 **** **** **** +349 GR_SHADOW_CON_Summon_Shadow **** **** **** D 0 **** **** **** +350 GR_SHADOW_CON_Acid_Arrow Acid **** 1 R 1 **** **** **** +351 GR_SHADOW_CON_Ghostly_Visage **** **** **** P 0 **** **** **** +352 GR_SHADOW_CON_Web **** Reflex 0 I 1 **** **** **** +353 GR_SHADOW_CON_Minor_Globe **** **** **** P 0 **** **** **** +354 Eagle_Splendor **** **** **** E 0 3 6 **** +355 Owls_Wisdom **** **** **** E 0 3 5 **** +356 Foxs_Cunning **** **** **** E 0 3 4 **** +357 Greater_Eagle_Splendor[NOT_USED] **** **** **** **** **** **** **** **** +358 Greater_Owls_Wisdom[NOT_USED] **** **** **** **** **** **** **** **** +359 Greater_Foxs_Cunning[NOT_USED] **** **** **** **** **** **** **** **** +360 Greater_Bulls_Strength[NOT_USED] **** **** **** **** **** **** **** **** +361 Greater_Cats_Grace[NOT_USED] **** **** **** **** *** **** **** **** +362 Greater_Endurance[NOT_USED] **** **** **** **** **** **** **** **** +363 Awaken **** **** **** E 0 **** **** **** +364 Creeping_Doom **** **** 0 D 1 **** **** **** +365 Ultravision **** **** **** E 0 3 9 **** +366 Destruction Death Fortitude 1 R 1 **** **** **** +367 Horrid_Wilting **** Fortitude 1 D 1 **** **** **** +368 Ice_Storm Cold **** 1 I 1 **** **** **** +369 Energy_Buffer **** **** **** P 0 2 0 -1 +370 Negative_Energy_Burst Negative Will 1 D 1 **** **** **** +371 Negative_Energy_Ray Negative Will 1 R 1 **** **** **** +372 Aura_of_Vitality **** **** **** E 0 2 0 **** +373 War_Cry **** **** **** D 0 **** **** **** +374 Regenerate **** **** **** E 0 2 10 -6 +375 Evards_Black_Tentacles **** Fortitude 0 D 1 **** **** **** +376 Legend_Lore **** **** **** **** 0 **** **** **** +377 Find_Traps **** **** **** **** 0 **** **** **** +378 Summon_Mephit **** **** **** S 0 **** **** **** +379 Summon_Celestial **** **** **** S 0 **** **** **** +380 Battle_Mastery_Spell **** **** **** E 0 **** **** **** +381 Divine_Strength **** **** **** E 0 **** **** **** +382 Divine_Protection **** **** **** E 0 **** **** **** +383 Negative_Plane_Avatar **** **** **** E 0 **** **** **** +384 Divine_Trickery **** **** **** E 0 **** **** **** +385 Rogues_Cunning **** **** **** E 0 **** **** **** +386 ACTIVATE_ITEM **** **** **** **** 0 **** **** **** +387 Polymorph_GIANT_SPIDER **** **** **** **** 0 **** **** **** +388 Polymorph_TROLL **** **** **** **** 0 **** **** **** +389 Polymorph_UMBER_HULK **** **** **** **** 0 **** **** **** +390 Polymorph_PIXIE **** **** **** **** 0 **** **** **** +391 Polymorph_ZOMBIE **** **** **** **** 0 **** **** **** +392 Shapechange_RED_DRAGON **** **** **** **** 0 **** **** **** +393 Shapechange_FIRE_GIANT **** **** **** **** 0 **** **** **** +394 Shapechange_BALOR **** **** **** **** 0 **** **** **** +395 Shapechange_DEATH_SLAAD **** **** **** **** 0 **** **** **** +396 Shapechange_IRON_GOLEM **** **** **** **** 0 **** **** **** +397 Elemental_Shape_FIRE **** **** **** **** 0 **** **** **** +398 Elemental_Shape_WATER **** **** **** **** 0 **** **** **** +399 Elemental_Shape_EARTH **** **** **** **** 0 **** **** **** +400 Elemental_Shape_AIR **** **** **** **** 0 **** **** **** +401 Wild_Shape_BROWN_BEAR **** **** **** **** 0 **** **** **** +402 Wild_Shape_PANTHER **** **** **** **** 0 **** **** **** +403 Wild_Shape_WOLF **** **** **** **** 0 **** **** **** +404 Wild_Shape_BOAR **** **** **** **** 0 **** **** **** +405 Wild_Shape_BADGER **** **** **** **** 0 **** **** **** +406 Special_Alcohol_Beer **** **** **** **** 0 **** **** **** +407 Special_Alcohol_Wine **** **** **** **** 0 **** **** **** +408 Special_Alcohol_Spirits **** **** **** **** 0 **** **** **** +409 Special_Herb_Belladonna **** **** **** **** 0 **** **** **** +410 Special_Herb_Garlic **** **** **** **** 0 **** **** **** +411 Bards_Song **** **** **** **** 0 **** **** **** +412 Aura_Fear_Dragon **** **** **** A 1 **** **** **** +413 ACTIVATE_ITEM_SELF **** **** **** **** 0 **** **** **** +414 Divine_Favor **** **** **** E 0 2 0 **** +415 True_Strike **** **** **** E 0 **** **** **** +416 Flare **** Fortitude 1 R 1 **** **** **** +417 Shield **** **** **** P 0 2 7 **** +418 Entropic_Shield **** **** **** P 0 2 0 **** +419 Continual_Flame **** **** **** **** 0 3 0 -15 +420 One_With_The_Land **** **** **** **** 0 3 0 **** +421 Camoflage **** **** **** **** 0 3 0 **** +422 Blood_Frenzy **** **** **** **** 0 2 0 **** +423 Bombardment **** Reflex 1 I 1 **** **** **** +424 Acid_Splash Acid **** 0 R 1 **** **** **** +425 Quillfire Poison Fortitude 0 R 1 **** **** **** +426 Earthquake **** Fortitude 0 I 1 **** **** **** +427 Sunburst Divine Reflex 1 D 1 **** **** **** +428 ACTIVATE_ITEM_SELF2 **** **** **** **** 0 **** **** **** +429 AuraOfGlory Mind_Affecting **** **** E 0 2 0 **** +430 Banishment **** Will 1 I 1 **** **** **** +431 Inflict_Minor_Wounds Negative Will 1 T 1 **** **** **** +432 Inflict_Light_Wounds Negative Will 1 T 1 **** **** **** +433 Inflict_Moderate_Wounds Negative Will 1 T 1 **** **** **** +434 Inflict_Serious_Wounds Negative Will 1 T 1 **** **** **** +435 Inflict_Critical_Wounds Negative Will 1 T 1 **** **** **** +436 BalagarnsIronHorn **** **** 1 D 1 **** **** **** +437 Drown **** Fortitude 1 R 1 **** **** **** +438 Owls_Insight **** **** **** E 0 3 5 **** +439 Electric_Jolt Electricity **** 0 R 1 **** **** **** +440 Firebrand Fire Reflex 1 R 1 **** **** **** +441 Wounding_Whispers Sonic **** 0 P 0 2 0 **** +442 Amplify **** **** **** E 0 2 5 **** +443 Etherealness **** **** **** E 0 2 0 -5 +444 Undeaths_Eternal_Foe **** **** **** E 0 2 10 **** +445 Dirge **** Fortitude 0 I 1 **** **** **** +446 Inferno Fire **** 1 R 1 **** **** **** +447 Isaacs_Lesser_Missile_Storm **** **** 1 R 1 **** **** **** +448 Isaacs_Greater_Missile_Storm **** **** 1 R 1 **** **** **** +449 Bane Fear Will 1 E 1 **** **** **** +450 Shield_of_Faith **** **** **** P 0 2 7 -3 +451 Planar_Ally **** **** **** S 0 3 0 -2 +452 Magic_Fang **** **** **** P 0 **** **** **** +453 Greater_Magic_Fang **** **** **** P 0 **** **** **** +454 Spike_Growth **** Reflex 1 I 1 **** **** **** +455 Mass_Camoflage **** **** **** E 0 2 0 **** +456 Expeditious_Retreat **** **** **** E 0 2 7 **** +457 Tashas_Hideous_Laughter Mind_Affecting Will 1 R 1 **** **** **** +458 Displacement **** **** **** E 0 2 7 -8 +459 Bigbys_Interposing_Hand **** **** **** R 0 **** **** **** +460 Bigbys_Forceful_Hand **** **** 1 R 1 **** **** **** +461 Bigbys_Grasping_Hand **** **** 1 R 1 **** **** **** +462 Bigbys_Clenched_Fist **** **** 1 R 1 **** **** **** +463 Bigbys_Crushing_Hand **** **** 1 R 1 **** **** **** +464 Grenade_Fire Fire **** 0 I 1 **** **** **** +465 Grenade_Tangle **** Reflex 0 I 1 **** **** **** +466 Grenade_Holy Divine **** 0 I 1 **** **** **** +467 Grenade_Choking **** **** 0 I 1 **** **** **** +468 Grenade_Thunderstone **** Fortitude 0 I 1 **** **** **** +469 Grenade_Acid Acid **** 0 I 1 **** **** **** +470 Grenade_Chicken **** **** 0 R 1 **** **** **** +471 Grenade_Caltrops **** **** 0 I 1 **** **** **** +472 ACTIVATE_ITEM_PORTAL **** **** **** **** 0 **** **** **** +473 Divine_Might **** **** **** **** 0 **** **** **** +474 Divine_Shield **** **** **** **** 0 **** **** **** +475 SHADOW_DAZE Daze Will 1 R 1 **** **** **** +476 SUMMON_SHADOW **** **** **** R 1 **** **** **** +477 SHADOW_EVADE **** **** **** E 0 **** **** **** +478 TYMORAS_SMILE **** **** **** E 0 **** **** **** +479 CRAFT_HARPER_ITEM **** **** **** **** 0 **** **** **** +480 Sleep Sleep Will 1 D 1 **** **** **** +481 Cats_Grace **** **** **** E 0 **** **** **** +482 Eagle_Splendor **** **** **** E 0 **** **** **** +483 Invisibility **** **** **** E 0 **** **** **** +484 **** **** **** **** **** **** **** **** **** +485 Flesh_to_stone **** Fortitude 1 R 1 **** **** **** +486 Stone_to_flesh **** **** **** E 0 **** **** **** +487 Trap_Arrow **** **** **** **** 1 **** **** **** +488 Trap_Bolt **** **** **** **** 1 **** **** **** +489 PADDING **** **** **** **** **** **** **** **** +490 PADDING **** **** **** **** **** **** **** **** +491 PADDING **** **** **** **** **** **** **** **** +492 PADDING **** **** **** **** **** **** **** **** +493 Trap_Dart **** **** **** **** 1 **** **** **** +494 Trap_Shuriken **** **** **** **** 1 **** **** **** +495 Breath_Petrify Petrification Fortitude 0 R 1 **** **** **** +496 Touch_Petrify Petrification Fortitude 0 R 1 **** **** **** +497 Gaze_Petrify Petrification Fortitude 0 R 1 **** **** **** +498 Manticore_Spikes **** **** **** R 1 **** **** **** +499 RodOfWonder **** **** **** **** 1 **** **** **** +500 DeckOfManyThings **** **** **** **** 0 **** **** **** +501 PADDING **** **** **** **** **** **** **** **** +502 ElementalSummoningItem **** **** **** **** 0 3 0 -2 +503 DeckAvatar **** **** **** **** 0 **** **** **** +504 Gem_Spray **** **** **** **** 1 **** **** **** +505 Butterfly_Spray **** **** **** **** 1 **** **** **** +506 HealingKit **** **** **** E **** **** **** **** +507 PowerStone **** **** **** **** 0 **** **** **** +508 Spellstaff **** **** **** **** 0 **** **** **** +509 Charger **** **** **** **** 0 **** **** **** +510 Decharger **** **** **** **** 0 **** **** **** +511 Kobold_Jump **** **** **** **** **** **** **** **** +512 Crumble Sonic **** 0 R 1 **** **** **** +513 Infestation_of_Maggots Disease Fortitude 1 T 1 **** **** **** +514 Healing_Sting Negative Fortitude 1 T 1 **** **** **** +515 Great_Thunderclap Sonic **** 0 I 1 **** **** **** +516 Ball_Lightning Electricity **** 1 I 1 **** **** **** +517 Battletide **** **** 1 D 1 **** **** **** +518 Combust Fire Reflex 1 T 1 **** **** **** +519 Death_Armor **** **** **** P 0 2 0 **** +520 Gedlees_Electric_Loop Electricity Reflex 1 D 1 **** **** **** +521 Horizikauls_Boom Sonic Will 1 R 1 **** **** **** +522 Ironguts **** **** **** E 0 3 11 **** +523 Mestils_Acid_Breath Acid Reflex 1 I 1 **** **** **** +524 Mestils_Acid_Sheath Acid **** **** P 0 2 9 **** +525 Monstrous_Regeneration **** **** **** H 0 2 10 -6 +526 Scintillating_Sphere Electricity Reflex 1 I 1 **** **** **** +527 Stone_Bones **** **** **** P 0 3 7 **** +528 Undeath_to_Death **** Will 1 D 1 **** **** **** +529 Vine_Mine **** **** 0 **** 1 **** **** **** +530 Vine_Mine_Entangle **** **** 0 I 1 **** **** **** +531 Vine_Mine_Hamper_Movement **** **** 0 I 1 **** **** **** +532 Vine_Mine_Camouflage **** **** **** P 0 **** **** **** +533 Black_Blade_of_Disaster **** **** **** S 0 **** **** **** +534 Shelgarns_Persistent_Blade **** **** **** S 0 2 0 -2 +535 Blade_Thirst **** **** **** E 0 2 15 -14 +536 Deafening_Clang **** **** **** E 0 2 15 -14 +537 Bless_Weapon **** **** **** E 0 2 15 **** +538 Holy_Sword **** **** **** E 0 2 15 **** +539 Keen_Edge **** **** **** E 0 3 15 **** +540 **** **** **** **** **** **** **** **** **** +541 Blackstaff **** **** **** E 0 2 15 **** +542 Flame_Weapon **** **** **** E 0 3 15 **** +543 Ice_Dagger Cold Reflex 1 R 1 **** **** **** +544 Magic_Weapon **** **** **** E 0 3 15 -14 +545 Greater_Magic_Weapon **** **** **** E 0 3 15 -14 +546 Magic_Vestment **** **** **** E 0 3 15 -4 +547 Stonehold Paralysis Will 1 I 1 **** **** **** +548 Darkfire **** **** **** E 0 3 15 **** +549 Glyph_of_Warding Sonic Reflex 1 I 1 **** **** **** +550 **** **** **** **** **** **** **** **** **** +551 MONSTER_MindBlast **** **** **** I 1 **** **** **** +552 MONSTER_CharmMonster **** **** **** R 1 **** **** **** +553 Goblin_Ballista_Fireball Fire **** **** **** 1 **** **** **** +554 Ioun_Stone_Dusty_Rose **** **** **** **** 0 **** **** **** +555 Ioun_Stone_Pale_Blue **** **** **** **** 0 **** **** **** +556 Ioun_Stone_Scarlet_Blue **** **** **** **** 0 **** **** **** +557 Ioun_Stone_Blue **** **** **** **** 0 **** **** **** +558 Ioun_Stone_Deep_Red **** **** **** **** 0 **** **** **** +559 Ioun_Stone_Pink **** **** **** **** 0 **** **** **** +560 Ioun_Stone_Pink_Green **** **** **** **** 0 **** **** **** +561 Whirlwind **** **** **** **** 0 **** **** **** +562 AuraOfGlory_X2 Mind_Affecting **** **** E 0 **** **** **** +563 Haste_Slow_X2 **** **** **** E 0 **** **** **** +564 Summon_Shadow_X2 **** **** **** S 0 **** **** **** +565 Tide_of_Battle **** **** **** D 0 **** **** **** +566 Evil_Blight **** **** **** T 0 **** **** **** +567 Cure_Critical_Wounds_Others **** **** **** H 0 **** **** **** +568 Restoration_Others **** **** **** C 0 **** **** **** +569 Cloud_of_Bewilderment Poison Fortitude 1 I 1 **** **** **** +570 PADDING **** **** **** **** **** **** **** **** +571 PADDING **** **** **** **** **** **** **** **** +572 PADDING **** **** **** **** **** **** **** **** +573 PADDING **** **** **** **** **** **** **** **** +574 PADDING **** **** **** **** **** **** **** **** +575 PADDING **** **** **** **** **** **** **** **** +576 PADDING **** **** **** **** **** **** **** **** +577 PADDING **** **** **** **** **** **** **** **** +578 PADDING **** **** **** **** **** **** **** **** +579 PADDING **** **** **** **** **** **** **** **** +580 PADDING **** **** **** **** **** **** **** **** +581 PADDING **** **** **** **** **** **** **** **** +582 PADDING **** **** **** **** **** **** **** **** +583 PADDING **** **** **** **** **** **** **** **** +584 PADDING **** **** **** **** **** **** **** **** +585 PADDING **** **** **** **** **** **** **** **** +586 PADDING **** **** **** **** **** **** **** **** +587 PADDING **** **** **** **** **** **** **** **** +588 PADDING **** **** **** **** **** **** **** **** +589 PADDING **** **** **** **** **** **** **** **** +590 PADDING **** **** **** **** **** **** **** **** +591 PADDING **** **** **** **** **** **** **** **** +592 PADDING **** **** **** **** **** **** **** **** +593 PADDING **** **** **** **** **** **** **** **** +594 PADDING **** **** **** **** **** **** **** **** +595 PADDING **** **** **** **** **** **** **** **** +596 PADDING **** **** **** **** **** **** **** **** +597 PADDING **** **** **** **** **** **** **** **** +598 PADDING **** **** **** **** **** **** **** **** +599 PADDING **** **** **** **** **** **** **** **** +600 ARImbueArrow **** **** **** **** 1 **** **** **** +601 ARSeekerArrow **** **** **** **** 1 **** **** **** +602 ARSeekerArrow2 **** **** **** **** 1 **** **** **** +603 ARHailOfArrows **** **** **** I 1 **** **** **** +604 ARArrowOfDeath **** **** **** **** 1 **** **** **** +605 ASGhostlyVisage **** **** **** P 0 **** **** **** +606 ASDarkness **** **** **** **** 0 **** **** **** +607 ASInvisibility **** **** **** E 0 **** **** **** +608 ASImprovedInvisibility **** **** **** E 0 **** **** **** +609 BGCreateDead **** **** **** S 1 **** **** **** +610 BGFiendish Negative **** **** T 1 **** **** **** +611 BGInflictSerious Negative **** **** T 1 **** **** **** +612 BGInflictCritical Negative **** **** T 1 **** **** **** +613 BK_Contagion Disease **** **** T 1 **** **** **** +614 BK_BullsStrength **** **** **** E 0 **** **** **** +615 Twinfists **** **** **** **** 0 **** **** **** +616 LichLyrics **** **** **** **** 0 **** **** **** +617 Iceberry **** **** **** **** 0 **** **** **** +618 Flameberry **** **** **** **** 0 **** **** **** +619 PrayerBox **** **** **** **** 0 **** **** **** +620 Flying_Debris **** **** **** **** **** **** **** **** +621 PADDING **** **** **** **** **** **** **** **** +622 DC_Divine_Wrath **** **** **** E 0 **** **** **** +623 PM_Animate_Dead **** **** **** S 0 **** **** **** +624 PM_Summon_Undead **** **** **** S 0 **** **** **** +625 PM_Undead_Graft1 Mind_Affecting **** **** T 1 **** **** **** +626 PM_Undead_Graft2 Mind_Affecting **** **** T 1 **** **** **** +627 PM_Summon_Greater_Undead **** **** **** S 0 **** **** **** +628 PM_Deathless_Master_Touch Death **** **** T 1 **** **** **** +629 PADDING **** **** **** **** **** **** **** **** +630 PADDING **** **** **** **** **** **** **** **** +631 PADDING **** **** **** **** **** **** **** **** +632 PADDING **** **** **** **** **** **** **** **** +633 PADDING **** **** **** **** **** **** **** **** +634 PADDING **** **** **** **** **** **** **** **** +635 PADDING **** **** **** **** **** **** **** **** +636 Hellball **** Reflex 0 I 1 **** **** **** +637 Mummy_Dust **** **** **** S 0 **** **** **** +638 Dragon_Knight **** **** **** S 0 **** **** **** +639 Epic_Mage_Armor **** **** **** P 0 **** **** **** +640 Ruin Positive Fortitude 0 R 1 **** **** **** +641 DWDEF_Defensive_Stance **** **** **** A 0 **** **** **** +642 Mighty_Rage **** **** **** A 0 **** **** **** +643 PlanarTurning **** **** **** D 1 **** **** **** +644 Curse_Song **** **** **** E 0 **** **** **** +645 Improved_Whirlwind **** **** **** **** 0 **** **** **** +646 Greater_Wild_Shape_1 **** **** **** **** 0 **** **** **** +647 Epic_Blinding_speed **** **** **** E 0 **** **** **** +648 Dye_Armor_cloth1 **** **** **** **** 0 **** **** **** +649 Dye_Armor_Cloth2 **** **** **** **** 0 **** **** **** +650 Dye_Armor_Leather1 **** **** **** **** 0 **** **** **** +651 Dye_Armor_Leather2 **** **** **** **** 0 **** **** **** +652 Dye_Armor_Metal1 **** **** **** **** 0 **** **** **** +653 Dye_Armor_Metal2 **** **** **** **** 0 **** **** **** +654 Add_Item_Property **** **** **** **** 0 **** **** **** +655 Poison_Weapon **** **** **** **** 0 **** **** **** +656 Craft_Weapon **** **** **** **** 0 **** **** **** +657 Craft_Armor **** **** **** **** 0 **** **** **** +658 Greater_Wild_Shape_Wyrmling_Red **** **** **** **** 0 **** **** **** +659 Greater_Wild_Shape_Wyrmling_Blue **** **** **** **** 0 **** **** **** +660 Greater_Wild_Shape_Wyrmling_Black **** **** **** **** 0 **** **** **** +661 Greater_Wild_Shape_Wyrmling_White **** **** **** **** 0 **** **** **** +662 Greater_Wild_Shape_Wyrmling_Green **** **** **** **** 0 **** **** **** +663 WyrmlingPCBreathCold Cold Reflex 0 I 1 **** **** **** +664 WyrmlingPCBreathAcid Acid Reflex 0 I 1 **** **** **** +665 WyrmlingPCBreathFire Fire Reflex 0 I 1 **** **** **** +666 WyrmlingPCBreathGas Acid Reflex 0 I 1 **** **** **** +667 WyrmlingPCBreathLightning Electricity Reflex 0 I 1 **** **** **** +668 ITEM_Teleport **** **** **** **** **** **** **** **** +669 ITEM_Chaos_Shield **** **** **** **** **** **** **** **** +670 Greater_Wild_Shape_Basilisk **** **** **** **** 0 **** **** **** +671 Greater_Wild_Shape_Beholder **** **** **** **** 0 **** **** **** +672 Greater_Wild_Shape_Harpy **** **** **** **** 0 **** **** **** +673 Greater_Wild_Shape_Drider **** **** **** **** 0 **** **** **** +674 Greater_Wild_Shape_Manticore **** **** **** **** 0 **** **** **** +675 Greater_Wild_Shape_2 **** **** **** **** 0 **** **** **** +676 Greater_Wild_Shape_3 **** **** **** **** 0 **** **** **** +677 Greater_Wild_Shape_4 **** **** **** **** 0 **** **** **** +678 Greater_Wild_Shape_Gargoyle **** **** **** **** 0 **** **** **** +679 Greater_Wild_Shape_Medusa **** **** **** **** 0 **** **** **** +680 Greater_Wild_Shape_Minotaur **** **** **** **** 0 **** **** **** +681 Humanoid_Shape **** **** **** **** 0 **** **** **** +682 Humanoid_Shape_Drow **** **** **** **** 0 **** **** **** +683 Humanoid_Shape_Lizardfolk **** **** **** **** 0 **** **** **** +684 Humanoid_Shape_KoboldAssa **** **** **** **** 0 **** **** **** +685 Undead_shape **** **** **** **** 0 **** **** **** +686 Harpysong Mind_Affecting Will 0 I 1 **** **** **** +687 GWildShape_Stonegaze Petrification Fortitude 0 R 1 **** **** **** +688 GWildShape_DriderDarkness **** **** **** **** 0 **** **** **** +689 SlayRakshasa **** **** **** **** **** **** **** **** +690 RedDragonDiscipleBreath Fire Relfex 0 I 1 **** **** **** +691 Greater_Wild_Shape_Mindflayer **** **** **** **** 0 **** **** **** +692 Greater_Wild_Shape_Spikes **** **** **** R 1 **** **** **** +693 GWildShape_Mindblast **** **** **** I 1 **** **** **** +694 Greater_Wild_Shape_DireTiger **** **** **** **** 0 **** **** **** +695 Epic_Warding **** **** **** P 1 **** **** **** +696 OnHitFireDamage Fire **** **** **** 1 **** **** **** +697 ACTIVATE_ITEM_L **** **** **** **** 0 **** **** **** +698 Dragon_Breath_Negative Negative Reflex 0 I 1 **** **** **** +699 **** **** **** **** P 0 **** **** **** +700 ACTIVATE_ITEM_ONHITSPELLCAST **** **** **** **** 0 **** **** **** +701 Summon_Baatezu **** **** **** S 1 **** **** **** +702 OnHitPlanarRift Cold **** **** R 1 **** **** **** +703 OnHitDarkfire Cold **** **** R 1 **** **** **** +704 Undead_Shape_risen_lord **** **** **** **** 0 **** **** **** +705 Undead_Shape_Vampire **** **** **** **** 0 **** **** **** +706 Undead_Shape_Spectre **** **** **** **** 0 **** **** **** +707 Greater_Wild_Shape_Red_dragon **** **** **** **** 0 **** **** **** +708 Greater_Wild_Shape_Blue_dragon **** **** **** **** 0 **** **** **** +709 Greater_Wild_Shape_Green_dragon **** **** **** **** 0 **** **** **** +710 EyeballRay0 Cold Fortitude 0 R 1 **** **** **** +711 EyeballRay1 Negative Fortitude 0 R 1 **** **** **** +712 EyeballRay2 Fire Fortitude 0 R 1 **** **** **** +713 Mindflayer_Mindblast_10 Mind_Affecting Will 0 I 1 **** **** **** +714 Mindflayer_Paragon_Mindblast **** **** **** P 1 **** **** **** +715 Golem_Ranged_Slam **** Reflex 0 R 1 **** **** **** +716 SuckBrain **** **** **** P 0 **** **** **** +717 ACTIVATE_ITEM_SEQUENCER_1 **** **** **** **** 0 **** **** **** +718 ACTIVATE_ITEM_SEQUENCER_2 **** **** **** **** 0 **** **** **** +719 ACTIVATE_ITEM_SEQUENCER_3 **** **** **** **** 0 **** **** **** +720 CLEAR_SEQUENCER **** **** **** **** 0 **** **** **** +721 OnHitFlamingSkin **** **** **** **** 0 **** **** **** +722 Mimic_Eat **** **** **** R **** **** **** **** +723 Mimic_Gem_Thrower **** **** **** R **** **** **** **** +724 Etherealness **** **** **** **** 0 **** **** **** +725 Dragon_Shape **** **** **** **** 0 **** **** **** +726 Mimic_Eat_Enemy **** **** **** R **** **** **** **** +727 Beholder_Anti_Magic_Cone **** **** **** I **** **** **** **** +728 **** **** **** **** **** 1 **** **** **** +729 Mimic_Steal_armor **** **** **** R **** **** **** **** +730 **** **** **** **** **** 0 **** **** **** +731 Bebelith_Web **** Reflex 0 R 1 **** **** **** +732 Outsider_Shape **** **** **** **** 0 **** **** **** +733 Outsider_Shape_Azer **** **** **** **** 0 **** **** **** +734 Outsider_Shape_Rakshasa **** **** **** **** 0 **** **** **** +735 Outsider_Shape_DeathSlaad **** **** **** **** 0 **** **** **** +736 Beholder_Special_Spell_AI **** **** **** I 1 **** **** **** +737 Construct_Shape **** **** **** **** 0 **** **** **** +738 Construct_Shape_StoneGolem **** **** **** **** 0 **** **** **** +739 Construct_Shape_DemonFleshGolem **** **** **** **** 0 **** **** **** +740 Construct_Shape_IronGolem **** **** **** **** 0 **** **** **** +741 Psionic_Inertial_Barrier **** **** **** P 0 **** **** **** +742 Craft_Weapon_Component **** **** **** **** 0 **** **** **** +743 Craft_Armor_Component **** **** **** **** 0 **** **** **** +744 Grenade_FireBomb Fire **** 0 R 1 **** **** **** +745 Grenade_AcidBomb Acid **** 0 R 1 **** **** **** +746 Hell_Catapult_Male **** **** **** R **** **** **** **** +747 Hell_Catapult_Female **** **** **** R **** **** **** **** +748 Hell_Br_Catapult_Male **** **** **** R **** **** **** **** +749 Hell_Brazier_Male **** **** **** R **** **** **** **** +750 Hell_Fence_Male **** **** **** R **** **** **** **** +751 Hell_Boulder_Male **** **** **** R **** **** **** **** +752 Hell_Tree_Male **** **** **** R **** **** **** **** +753 Hell_KNOWER_EFFECT1 **** **** **** R **** **** **** **** +754 Hell_KNOWER_EFFECT2 **** **** **** R **** **** **** **** +755 Hell_KNOWER_EFFECT3 **** **** **** R **** **** **** **** +756 OnHitBebilithAttack **** **** **** **** 1 **** **** **** +757 ShadowBlend **** **** **** **** 0 **** **** **** +758 OnHitDemilichTouch **** **** **** **** 1 **** **** **** +759 UndeadSelfHarm Positive **** **** H 0 **** **** **** +760 OnHitDracolichTouch **** **** **** **** 1 **** **** **** +761 Aura_of_Hellfire Fire **** **** D 1 **** **** **** +762 Hell_Inferno Fire **** **** R 1 **** **** **** +763 Psionic_Mass_Concussion **** **** **** D 1 **** **** **** +764 GlyphOfWardingDefault **** **** **** I 1 **** **** **** +765 Hell_KNOWER_EFFECT4 **** **** **** R **** **** **** **** +766 Hell_KNOWER_EFFECT5 **** **** **** R **** **** **** **** +767 Intelligent_Weapon_Talk **** **** **** **** 0 **** **** **** +768 Intelligent_Weapon_OnHit **** **** **** **** 1 **** **** **** +769 Shadow_Attack **** **** **** T 1 **** **** **** +770 Slaad_Chaos_Spittle Acid **** **** R 1 **** **** **** +771 Dragon_Breath_Prismatic Mind_Affecting Reflex 0 I 1 **** **** **** +772 Spiral_Fireball Fire **** **** I 1 **** **** **** +773 Battle_Boulder_Toss **** **** **** R **** **** **** **** +774 Deflecting_Force **** **** **** P 0 **** **** **** +775 Giant_hurl_rock **** **** 0 R 1 **** **** **** +776 Beholder_Node_1 Death Fortitude 0 I 1 **** **** **** +777 Beholder_Node_2 **** Will 0 I 1 **** **** **** +778 Beholder_Node_3 Petrification Fortitude 0 I 1 **** **** **** +779 Beholder_Node_4 Charm Will 0 I 1 **** **** **** +780 Beholder_Node_5 **** Will 0 I 1 **** **** **** +781 Bridge_VFX **** **** **** R **** **** **** **** +782 Sphere_Spell **** **** **** R **** **** **** **** +783 Beholder_Node_6 **** Fortitude 0 I 1 **** **** **** +784 Beholder_Node_7 Fear Will 0 I 1 **** **** **** +785 Beholder_Node_8 **** **** 0 I 1 **** **** **** +786 Beholder_Node_9 **** **** 0 I 1 **** **** **** +787 Beholder_Node_10 **** **** 0 I 1 **** **** **** +788 OnHitParalyze **** **** **** **** 1 **** **** **** +789 Illithid_Mindblast **** Will 0 I 1 **** **** **** +790 OnHitDeafenClang **** **** **** **** 1 **** **** **** +791 OnHitKnockDown **** **** **** **** 0 **** **** **** +792 OnHitFreeze **** **** **** **** 0 **** **** **** +793 Demonic_Grappling_Hand **** **** **** R **** **** **** **** +794 Ballista_Bolt **** **** **** I 1 **** **** **** +795 ACTIVATE_ITEM_T **** **** **** **** 0 **** **** **** +796 Dragon_Breath_Lightning Electricity Reflex 0 I 1 **** **** **** +797 Dragon_Breath_Fire Fire Reflex 0 I 1 **** **** **** +798 Dragon_Breath_Gas Acid Reflex 0 I 1 **** **** **** +799 Vampire_Invisibility **** **** **** E 0 **** **** **** +800 Vampire_DominationGaze Domination Will 0 I 1 **** **** **** +801 Azer_Fire_Blast Fire Reflex 0 R 1 **** **** **** +802 Shifter_Spectre_Attack Drain Fortitude 0 T 1 **** **** **** +803 SeaHag_EvilEye Drain Fortitude 0 I 1 **** **** **** +804 Aura_HorrificAppearance **** Fortitude 0 A 1 **** **** **** +805 Troglodyte_Stench **** **** **** A 1 **** **** **** +806 PDK_RallyingCry **** **** **** E 0 **** **** **** +807 PDK_Shield **** **** **** E 0 **** **** **** +808 PDK_Fear Fear Will 1 D 1 **** **** **** +809 PDK_OathOfWrath **** **** **** R 0 **** **** **** +810 PDK_FinalStand **** **** **** E 0 **** **** **** +811 PDK_InspireCourage **** **** **** E 0 **** **** **** +812 Horse_Menu **** **** **** **** 0 **** **** **** +813 Horse_Mount **** **** **** **** 0 **** **** **** +814 Horse_Dismount **** **** **** **** 0 **** **** **** +815 Horse_Party_Mount **** **** **** **** 0 **** **** **** +816 Horse_Party_Dismount **** **** **** **** 0 **** **** **** +817 Horse_Assign_Mount **** **** **** **** 0 **** **** **** +818 Paladin_Summon_Mount **** **** **** **** 0 **** **** **** +819 Nightmare_Smoke **** **** **** A 1 **** **** **** +820 DM_TOOL_01 **** **** **** **** 0 **** **** **** +821 DM_TOOL_02 **** **** **** **** 0 **** **** **** +822 DM_TOOL_03 **** **** **** **** 0 **** **** **** +823 DM_TOOL_04 **** **** **** **** 0 **** **** **** +824 DM_TOOL_05 **** **** **** **** 0 **** **** **** +825 DM_TOOL_06 **** **** **** **** 0 **** **** **** +826 DM_TOOL_07 **** **** **** **** 0 **** **** **** +827 DM_TOOL_08 **** **** **** **** 0 **** **** **** +828 DM_TOOL_09 **** **** **** **** 0 **** **** **** +829 DM_TOOL_10 **** **** **** **** 0 **** **** **** +830 PLAYER_TOOL_01 **** **** **** **** 0 **** **** **** +831 PLAYER_TOOL_02 **** **** **** **** 0 **** **** **** +832 PLAYER_TOOL_03 **** **** **** **** 0 **** **** **** +833 PLAYER_TOOL_04 **** **** **** **** 0 **** **** **** +834 PLAYER_TOOL_05 **** **** **** **** 0 **** **** **** +835 PLAYER_TOOL_06 **** **** **** **** 0 **** **** **** +836 PLAYER_TOOL_07 **** **** **** **** 0 **** **** **** +837 PLAYER_TOOL_08 **** **** **** **** 0 **** **** **** +838 PLAYER_TOOL_09 **** **** **** **** 0 **** **** **** +839 PLAYER_TOOL_10 **** **** **** **** 0 **** **** **** +840 **** **** **** **** **** **** **** **** **** +841 **** **** **** **** **** **** **** **** **** +842 **** **** **** **** **** **** **** **** **** +843 **** **** **** **** **** **** **** **** **** +844 **** **** **** **** **** **** **** **** **** +845 **** **** **** **** **** **** **** **** **** +846 **** **** **** **** **** **** **** **** **** +847 **** **** **** **** **** **** **** **** **** +848 **** **** **** **** **** **** **** **** **** +849 **** **** **** **** **** **** **** **** **** +850 **** **** **** **** **** **** **** **** **** +851 **** **** **** **** **** **** **** **** **** +852 **** **** **** **** **** **** **** **** **** +853 **** **** **** **** **** **** **** **** **** +854 **** **** **** **** **** **** **** **** **** +855 **** **** **** **** **** **** **** **** **** +856 **** **** **** **** **** **** **** **** **** +857 **** **** **** **** **** **** **** **** **** +858 **** **** **** **** **** **** **** **** **** +859 **** **** **** **** **** **** **** **** **** +860 **** **** **** **** **** **** **** **** **** +861 **** **** **** **** **** **** **** **** **** +862 **** **** **** **** **** **** **** **** **** +863 **** **** **** **** **** **** **** **** **** +864 **** **** **** **** **** **** **** **** **** +865 **** **** **** **** **** **** **** **** **** +866 **** **** **** **** **** **** **** **** **** +867 **** **** **** **** **** **** **** **** **** +868 **** **** **** **** **** **** **** **** **** +869 **** **** **** **** **** **** **** **** **** +870 **** **** **** **** **** **** **** **** **** +871 **** **** **** **** **** **** **** **** **** +872 **** **** **** **** **** **** **** **** **** +873 **** **** **** **** **** **** **** **** **** +874 **** **** **** **** **** **** **** **** **** +875 **** **** **** **** **** **** **** **** **** +876 **** **** **** **** **** **** **** **** **** +877 **** **** **** **** **** **** **** **** **** +878 **** **** **** **** **** **** **** **** **** +879 **** **** **** **** **** **** **** **** **** +880 **** **** **** **** **** **** **** **** **** +881 **** **** **** **** **** **** **** **** **** +882 **** **** **** **** **** **** **** **** **** +883 **** **** **** **** **** **** **** **** **** +884 **** **** **** **** **** **** **** **** **** +885 **** **** **** **** **** **** **** **** **** +886 **** **** **** **** **** **** **** **** **** +887 **** **** **** **** **** **** **** **** **** +888 **** **** **** **** **** **** **** **** **** +889 **** **** **** **** **** **** **** **** **** +890 **** **** **** **** **** **** **** **** **** +891 **** **** **** **** **** **** **** **** **** +892 **** **** **** **** **** **** **** **** **** +893 **** **** **** **** **** **** **** **** **** +894 **** **** **** **** **** **** **** **** **** +895 **** **** **** **** **** **** **** **** **** +896 **** **** **** **** **** **** **** **** **** +897 **** **** **** **** **** **** **** **** **** +898 **** **** **** **** **** **** **** **** **** +899 **** **** **** **** **** **** **** **** **** +900 **** **** **** **** **** **** **** **** **** +901 **** **** **** **** **** **** **** **** **** +902 **** **** **** **** **** **** **** **** **** +903 **** **** **** **** **** **** **** **** **** +904 **** **** **** **** **** **** **** **** **** +905 **** **** **** **** **** **** **** **** **** +906 **** **** **** **** **** **** **** **** **** +907 **** **** **** **** **** **** **** **** **** +908 **** **** **** **** **** **** **** **** **** +909 **** **** **** **** **** **** **** **** **** +910 **** **** **** **** **** **** **** **** **** +911 **** **** **** **** **** **** **** **** **** +912 **** **** **** **** **** **** **** **** **** +913 **** **** **** **** **** **** **** **** **** +914 **** **** **** **** **** **** **** **** **** +915 **** **** **** **** **** **** **** **** **** +916 **** **** **** **** **** **** **** **** **** +917 **** **** **** **** **** **** **** **** **** +918 **** **** **** **** **** **** **** **** **** +919 **** **** **** **** **** **** **** **** **** +920 **** **** **** **** **** **** **** **** **** +921 **** **** **** **** **** **** **** **** **** +922 **** **** **** **** **** **** **** **** **** +923 **** **** **** **** **** **** **** **** **** +924 **** **** **** **** **** **** **** **** **** +925 **** **** **** **** **** **** **** **** **** +926 **** **** **** **** **** **** **** **** **** +927 **** **** **** **** **** **** **** **** **** +928 **** **** **** **** **** **** **** **** **** +929 **** **** **** **** **** **** **** **** **** +930 **** **** **** **** **** **** **** **** **** +931 **** **** **** **** **** **** **** **** **** +932 **** **** **** **** **** **** **** **** **** +933 **** **** **** **** **** **** **** **** **** +934 **** **** **** **** **** **** **** **** **** +935 **** **** **** **** **** **** **** **** **** +936 **** **** **** **** **** **** **** **** **** +937 **** **** **** **** **** **** **** **** **** +938 **** **** **** **** **** **** **** **** **** +939 **** **** **** **** **** **** **** **** **** +940 **** **** **** **** **** **** **** **** **** +941 **** **** **** **** **** **** **** **** **** +942 **** **** **** **** **** **** **** **** **** +943 **** **** **** **** **** **** **** **** **** +944 **** **** **** **** **** **** **** **** **** +945 **** **** **** **** **** **** **** **** **** +946 **** **** **** **** **** **** **** **** **** +947 **** **** **** **** **** **** **** **** **** +948 **** **** **** **** **** **** **** **** **** +949 **** **** **** **** **** **** **** **** **** +950 **** **** **** **** **** **** **** **** **** +951 **** **** **** **** **** **** **** **** **** +952 **** **** **** **** **** **** **** **** **** +953 **** **** **** **** **** **** **** **** **** +954 **** **** **** **** **** **** **** **** **** +955 **** **** **** **** **** **** **** **** **** +956 **** **** **** **** **** **** **** **** **** +957 **** **** **** **** **** **** **** **** **** +958 **** **** **** **** **** **** **** **** **** +959 **** **** **** **** **** **** **** **** **** +960 **** **** **** **** **** **** **** **** **** +961 **** **** **** **** **** **** **** **** **** +962 **** **** **** **** **** **** **** **** **** +963 **** **** **** **** **** **** **** **** **** +964 **** **** **** **** **** **** **** **** **** +965 **** **** **** **** **** **** **** **** **** +966 **** **** **** **** **** **** **** **** **** +967 **** **** **** **** **** **** **** **** **** +968 **** **** **** **** **** **** **** **** **** +969 **** **** **** **** **** **** **** **** **** +970 **** **** **** **** **** **** **** **** **** +971 **** **** **** **** **** **** **** **** **** +972 **** **** **** **** **** **** **** **** **** +973 **** **** **** **** **** **** **** **** **** +974 **** **** **** **** **** **** **** **** **** +975 **** **** **** **** **** **** **** **** **** +976 **** **** **** **** **** **** **** **** **** +977 **** **** **** **** **** **** **** **** **** +978 **** **** **** **** **** **** **** **** **** +979 **** **** **** **** **** **** **** **** **** +980 **** **** **** **** **** **** **** **** **** +981 **** **** **** **** **** **** **** **** **** +982 **** **** **** **** **** **** **** **** **** +983 **** **** **** **** **** **** **** **** **** +984 **** **** **** **** **** **** **** **** **** +985 **** **** **** **** **** **** **** **** **** +986 **** **** **** **** **** **** **** **** **** +987 **** **** **** **** **** **** **** **** **** +988 **** **** **** **** **** **** **** **** **** +989 **** **** **** **** **** **** **** **** **** +990 **** **** **** **** **** **** **** **** **** +991 **** **** **** **** **** **** **** **** **** +992 **** **** **** **** **** **** **** **** **** +993 **** **** **** **** **** **** **** **** **** +994 **** **** **** **** **** **** **** **** **** +995 **** **** **** **** **** **** **** **** **** +996 **** **** **** **** **** **** **** **** **** +997 **** **** **** **** **** **** **** **** **** +998 **** **** **** **** **** **** **** **** **** +999 **** **** **** **** **** **** **** **** **** +1000 **** **** **** **** **** **** **** **** **** +1001 **** **** **** **** **** **** **** **** **** +1002 **** **** **** **** **** **** **** **** **** +1003 **** **** **** **** **** **** **** **** **** +1004 **** **** **** **** **** **** **** **** **** +1005 **** **** **** **** **** **** **** **** **** +1006 **** **** **** **** **** **** **** **** **** +1007 **** **** **** **** **** **** **** **** **** +1008 **** **** **** **** **** **** **** **** **** +1009 **** **** **** **** **** **** **** **** **** +1010 **** **** **** **** **** **** **** **** **** +1011 **** **** **** **** **** **** **** **** **** +1012 **** **** **** **** **** **** **** **** **** +1013 **** **** **** **** **** **** **** **** **** +1014 **** **** **** **** **** **** **** **** **** +1015 **** **** **** **** **** **** **** **** **** +1016 **** **** **** **** **** **** **** **** **** +1017 **** **** **** **** **** **** **** **** **** +1018 **** **** **** **** **** **** **** **** **** +1019 **** **** **** **** **** **** **** **** **** +1020 **** **** **** **** **** **** **** **** **** +1021 **** **** **** **** **** **** **** **** **** +1022 **** **** **** **** **** **** **** **** **** +1023 **** **** **** **** **** **** **** **** **** +1024 **** **** **** **** **** **** **** **** **** +1025 **** **** **** **** **** **** **** **** **** +1026 **** **** **** **** **** **** **** **** **** +1027 **** **** **** **** **** **** **** **** **** +1028 **** **** **** **** **** **** **** **** **** +1029 **** **** **** **** **** **** **** **** **** +1030 **** **** **** **** **** **** **** **** **** +1031 **** **** **** **** **** **** **** **** **** +1032 **** **** **** **** **** **** **** **** **** +1033 **** **** **** **** **** **** **** **** **** +1034 **** **** **** **** **** **** **** **** **** +1035 **** **** **** **** **** **** **** **** **** +1036 **** **** **** **** **** **** **** **** **** +1037 **** **** **** **** **** **** **** **** **** +1038 **** **** **** **** **** **** **** **** **** +1039 **** **** **** **** **** **** **** **** **** +1040 **** **** **** **** **** **** **** **** **** +1041 **** **** **** **** **** **** **** **** **** +1042 **** **** **** **** **** **** **** **** **** +1043 **** **** **** **** **** **** **** **** **** +1044 **** **** **** **** **** **** **** **** **** +1045 **** **** **** **** **** **** **** **** **** +1046 **** **** **** **** **** **** **** **** **** +1047 **** **** **** **** **** **** **** **** **** +1048 **** **** **** **** **** **** **** **** **** +1049 **** **** **** **** **** **** **** **** **** +1050 **** **** **** **** **** **** **** **** **** +1051 **** **** **** **** **** **** **** **** **** +1052 **** **** **** **** **** **** **** **** **** +1053 **** **** **** **** **** **** **** **** **** +1054 **** **** **** **** **** **** **** **** **** +1055 **** **** **** **** **** **** **** **** **** +1056 **** **** **** **** **** **** **** **** **** +1057 **** **** **** **** **** **** **** **** **** +1058 **** **** **** **** **** **** **** **** **** +1059 **** **** **** **** **** **** **** **** **** +1060 **** **** **** **** **** **** **** **** **** +1061 **** **** **** **** **** **** **** **** **** +1062 **** **** **** **** **** **** **** **** **** +1063 **** **** **** **** **** **** **** **** **** +1064 **** **** **** **** **** **** **** **** **** +1065 **** **** **** **** **** **** **** **** **** +1066 **** **** **** **** **** **** **** **** **** +1067 **** **** **** **** **** **** **** **** **** +1068 **** **** **** **** **** **** **** **** **** +1069 **** **** **** **** **** **** **** **** **** +1070 **** **** **** **** **** **** **** **** **** +1071 **** **** **** **** **** **** **** **** **** +1072 **** **** **** **** **** **** **** **** **** +1073 **** **** **** **** **** **** **** **** **** +1074 **** **** **** **** **** **** **** **** **** +1075 **** **** **** **** **** **** **** **** **** +1076 **** **** **** **** **** **** **** **** **** +1077 **** **** **** **** **** **** **** **** **** +1078 **** **** **** **** **** **** **** **** **** +1079 **** **** **** **** **** **** **** **** **** +1080 **** **** **** **** **** **** **** **** **** +1081 **** **** **** **** **** **** **** **** **** +1082 **** **** **** **** **** **** **** **** **** +1083 **** **** **** **** **** **** **** **** **** +1084 **** **** **** **** **** **** **** **** **** +1085 **** **** **** **** **** **** **** **** **** +1086 **** **** **** **** **** **** **** **** **** +1087 **** **** **** **** **** **** **** **** **** +1088 **** **** **** **** **** **** **** **** **** +1089 **** **** **** **** **** **** **** **** **** +1090 **** **** **** **** **** **** **** **** **** +1091 **** **** **** **** **** **** **** **** **** +1092 **** **** **** **** **** **** **** **** **** +1093 **** **** **** **** **** **** **** **** **** +1094 **** **** **** **** **** **** **** **** **** +1095 **** **** **** **** **** **** **** **** **** +1096 **** **** **** **** **** **** **** **** **** +1097 **** **** **** **** **** **** **** **** **** +1098 **** **** **** **** **** **** **** **** **** +1099 **** **** **** **** **** **** **** **** **** +1100 **** **** **** **** **** **** **** **** **** +1101 **** **** **** **** **** **** **** **** **** +1102 **** **** **** **** **** **** **** **** **** +1103 **** **** **** **** **** **** **** **** **** +1104 **** **** **** **** **** **** **** **** **** +1105 **** **** **** **** **** **** **** **** **** +1106 **** **** **** **** **** **** **** **** **** +1107 **** **** **** **** **** **** **** **** **** +1108 **** **** **** **** **** **** **** **** **** +1109 **** **** **** **** **** **** **** **** **** +1110 **** **** **** **** **** **** **** **** **** +1111 **** **** **** **** **** **** **** **** **** +1112 **** **** **** **** **** **** **** **** **** +1113 **** **** **** **** **** **** **** **** **** +1114 **** **** **** **** **** **** **** **** **** +1115 **** **** **** **** **** **** **** **** **** +1116 **** **** **** **** **** **** **** **** **** +1117 **** **** **** **** **** **** **** **** **** +1118 **** **** **** **** **** **** **** **** **** +1119 **** **** **** **** **** **** **** **** **** +1120 **** **** **** **** **** **** **** **** **** +1121 **** **** **** **** **** **** **** **** **** +1122 **** **** **** **** **** **** **** **** **** +1123 **** **** **** **** **** **** **** **** **** +1124 **** **** **** **** **** **** **** **** **** +1125 **** **** **** **** **** **** **** **** **** +1126 **** **** **** **** **** **** **** **** **** +1127 **** **** **** **** **** **** **** **** **** +1128 **** **** **** **** **** **** **** **** **** +1129 **** **** **** **** **** **** **** **** **** +1130 **** **** **** **** **** **** **** **** **** +1131 **** **** **** **** **** **** **** **** **** +1132 **** **** **** **** **** **** **** **** **** +1133 **** **** **** **** **** **** **** **** **** +1134 **** **** **** **** **** **** **** **** **** +1135 **** **** **** **** **** **** **** **** **** +1136 **** **** **** **** **** **** **** **** **** +1137 **** **** **** **** **** **** **** **** **** +1138 **** **** **** **** **** **** **** **** **** +1139 **** **** **** **** **** **** **** **** **** +1140 **** **** **** **** **** **** **** **** **** +1141 **** **** **** **** **** **** **** **** **** +1142 **** **** **** **** **** **** **** **** **** +1143 **** **** **** **** **** **** **** **** **** +1144 **** **** **** **** **** **** **** **** **** +1145 **** **** **** **** **** **** **** **** **** +1146 **** **** **** **** **** **** **** **** **** +1147 **** **** **** **** **** **** **** **** **** +1148 **** **** **** **** **** **** **** **** **** +1149 **** **** **** **** **** **** **** **** **** +1150 **** **** **** **** **** **** **** **** **** +1151 **** **** **** **** **** **** **** **** **** +1152 **** **** **** **** **** **** **** **** **** +1153 **** **** **** **** **** **** **** **** **** +1154 **** **** **** **** **** **** **** **** **** +1155 **** **** **** **** **** **** **** **** **** +1156 **** **** **** **** **** **** **** **** **** +1157 **** **** **** **** **** **** **** **** **** +1158 **** **** **** **** **** **** **** **** **** +1159 **** **** **** **** **** **** **** **** **** +1160 **** **** **** **** **** **** **** **** **** +1161 **** **** **** **** **** **** **** **** **** +1162 **** **** **** **** **** **** **** **** **** +1163 **** **** **** **** **** **** **** **** **** +1164 **** **** **** **** **** **** **** **** **** +1165 **** **** **** **** **** **** **** **** **** +1166 **** **** **** **** **** **** **** **** **** +1167 **** **** **** **** **** **** **** **** **** +1168 **** **** **** **** **** **** **** **** **** +1169 **** **** **** **** **** **** **** **** **** +1170 **** **** **** **** **** **** **** **** **** +1171 **** **** **** **** **** **** **** **** **** +1172 **** **** **** **** **** **** **** **** **** +1173 **** **** **** **** **** **** **** **** **** +1174 **** **** **** **** **** **** **** **** **** +1175 **** **** **** **** **** **** **** **** **** +1176 **** **** **** **** **** **** **** **** **** +1177 **** **** **** **** **** **** **** **** **** +1178 **** **** **** **** **** **** **** **** **** +1179 **** **** **** **** **** **** **** **** **** +1180 **** **** **** **** **** **** **** **** **** +1181 **** **** **** **** **** **** **** **** **** +1182 **** **** **** **** **** **** **** **** **** +1183 **** **** **** **** **** **** **** **** **** +1184 **** **** **** **** **** **** **** **** **** +1185 **** **** **** **** **** **** **** **** **** +1186 **** **** **** **** **** **** **** **** **** +1187 **** **** **** **** **** **** **** **** **** +1188 **** **** **** **** **** **** **** **** **** +1189 **** **** **** **** **** **** **** **** **** +1190 **** **** **** **** **** **** **** **** **** +1191 **** **** **** **** **** **** **** **** **** +1192 **** **** **** **** **** **** **** **** **** +1193 **** **** **** **** **** **** **** **** **** +1194 **** **** **** **** **** **** **** **** **** +1195 **** **** **** **** **** **** **** **** **** +1196 **** **** **** **** **** **** **** **** **** +1197 **** **** **** **** **** **** **** **** **** +1198 **** **** **** **** **** **** **** **** **** +1199 **** **** **** **** **** **** **** **** **** +1200 **** **** **** **** **** **** **** **** **** +1201 **** **** **** **** **** **** **** **** **** +1202 **** **** **** **** **** **** **** **** **** +1203 **** **** **** **** **** **** **** **** **** +1204 **** **** **** **** **** **** **** **** **** +1205 **** **** **** **** **** **** **** **** **** +1206 **** **** **** **** **** **** **** **** **** +1207 **** **** **** **** **** **** **** **** **** +1208 **** **** **** **** **** **** **** **** **** +1209 **** **** **** **** **** **** **** **** **** +1210 **** **** **** **** **** **** **** **** **** +1211 **** **** **** **** **** **** **** **** **** +1212 **** **** **** **** **** **** **** **** **** +1213 **** **** **** **** **** **** **** **** **** +1214 **** **** **** **** **** **** **** **** **** +1215 **** **** **** **** **** **** **** **** **** +1216 **** **** **** **** **** **** **** **** **** +1217 **** **** **** **** **** **** **** **** **** +1218 **** **** **** **** **** **** **** **** **** +1219 **** **** **** **** **** **** **** **** **** +1220 **** **** **** **** **** **** **** **** **** +1221 **** **** **** **** **** **** **** **** **** +1222 **** **** **** **** **** **** **** **** **** +1223 **** **** **** **** **** **** **** **** **** +1224 **** **** **** **** **** **** **** **** **** +1225 **** **** **** **** **** **** **** **** **** +1226 **** **** **** **** **** **** **** **** **** +1227 **** **** **** **** **** **** **** **** **** +1228 **** **** **** **** **** **** **** **** **** +1229 **** **** **** **** **** **** **** **** **** +1230 **** **** **** **** **** **** **** **** **** +1231 **** **** **** **** **** **** **** **** **** +1232 **** **** **** **** **** **** **** **** **** +1233 **** **** **** **** **** **** **** **** **** +1234 **** **** **** **** **** **** **** **** **** +1235 **** **** **** **** **** **** **** **** **** +1236 **** **** **** **** **** **** **** **** **** +1237 **** **** **** **** **** **** **** **** **** +1238 **** **** **** **** **** **** **** **** **** +1239 **** **** **** **** **** **** **** **** **** +1240 **** **** **** **** **** **** **** **** **** +1241 **** **** **** **** **** **** **** **** **** +1242 **** **** **** **** **** **** **** **** **** +1243 **** **** **** **** **** **** **** **** **** +1244 **** **** **** **** **** **** **** **** **** +1245 **** **** **** **** **** **** **** **** **** +1246 **** **** **** **** **** **** **** **** **** +1247 **** **** **** **** **** **** **** **** **** +1248 **** **** **** **** **** **** **** **** **** +1249 **** **** **** **** **** **** **** **** **** +1250 **** **** **** **** **** **** **** **** **** +1251 **** **** **** **** **** **** **** **** **** +1252 **** **** **** **** **** **** **** **** **** +1253 **** **** **** **** **** **** **** **** **** +1254 **** **** **** **** **** **** **** **** **** +1255 **** **** **** **** **** **** **** **** **** +1256 **** **** **** **** **** **** **** **** **** +1257 **** **** **** **** **** **** **** **** **** +1258 **** **** **** **** **** **** **** **** **** +1259 **** **** **** **** **** **** **** **** **** +1260 **** **** **** **** **** **** **** **** **** +1261 **** **** **** **** **** **** **** **** **** +1262 **** **** **** **** **** **** **** **** **** +1263 **** **** **** **** **** **** **** **** **** +1264 **** **** **** **** **** **** **** **** **** +1265 **** **** **** **** **** **** **** **** **** +1266 **** **** **** **** **** **** **** **** **** +1267 **** **** **** **** **** **** **** **** **** +1268 **** **** **** **** **** **** **** **** **** +1269 **** **** **** **** **** **** **** **** **** +1270 **** **** **** **** **** **** **** **** **** +1271 **** **** **** **** **** **** **** **** **** +1272 **** **** **** **** **** **** **** **** **** +1273 **** **** **** **** **** **** **** **** **** +1274 **** **** **** **** **** **** **** **** **** +1275 **** **** **** **** **** **** **** **** **** +1276 **** **** **** **** **** **** **** **** **** +1277 **** **** **** **** **** **** **** **** **** +1278 **** **** **** **** **** **** **** **** **** +1279 **** **** **** **** **** **** **** **** **** +1280 **** **** **** **** **** **** **** **** **** +1281 **** **** **** **** **** **** **** **** **** +1282 **** **** **** **** **** **** **** **** **** +1283 **** **** **** **** **** **** **** **** **** +1284 **** **** **** **** **** **** **** **** **** +1285 **** **** **** **** **** **** **** **** **** +1286 **** **** **** **** **** **** **** **** **** +1287 **** **** **** **** **** **** **** **** **** +1288 **** **** **** **** **** **** **** **** **** +1289 **** **** **** **** **** **** **** **** **** +1290 **** **** **** **** **** **** **** **** **** +1291 **** **** **** **** **** **** **** **** **** +1292 **** **** **** **** **** **** **** **** **** +1293 **** **** **** **** **** **** **** **** **** +1294 **** **** **** **** **** **** **** **** **** +1295 **** **** **** **** **** **** **** **** **** +1296 **** **** **** **** **** **** **** **** **** +1297 **** **** **** **** **** **** **** **** **** +1298 **** **** **** **** **** **** **** **** **** +1299 **** **** **** **** **** **** **** **** **** +1300 **** **** **** **** **** **** **** **** **** +1301 **** **** **** **** **** **** **** **** **** +1302 **** **** **** **** **** **** **** **** **** +1303 **** **** **** **** **** **** **** **** **** +1304 **** **** **** **** **** **** **** **** **** +1305 **** **** **** **** **** **** **** **** **** +1306 **** **** **** **** **** **** **** **** **** +1307 **** **** **** **** **** **** **** **** **** +1308 **** **** **** **** **** **** **** **** **** +1309 **** **** **** **** **** **** **** **** **** +1310 **** **** **** **** **** **** **** **** **** +1311 **** **** **** **** **** **** **** **** **** +1312 **** **** **** **** **** **** **** **** **** +1313 **** **** **** **** **** **** **** **** **** +1314 **** **** **** **** **** **** **** **** **** +1315 **** **** **** **** **** **** **** **** **** +1316 **** **** **** **** **** **** **** **** **** +1317 **** **** **** **** **** **** **** **** **** +1318 **** **** **** **** **** **** **** **** **** +1319 **** **** **** **** **** **** **** **** **** +1320 **** **** **** **** **** **** **** **** **** +1321 **** **** **** **** **** **** **** **** **** +1322 **** **** **** **** **** **** **** **** **** +1323 **** **** **** **** **** **** **** **** **** +1324 **** **** **** **** **** **** **** **** **** +1325 **** **** **** **** **** **** **** **** **** +1326 **** **** **** **** **** **** **** **** **** +1327 **** **** **** **** **** **** **** **** **** +1328 **** **** **** **** **** **** **** **** **** +1329 **** **** **** **** **** **** **** **** **** +1330 **** **** **** **** **** **** **** **** **** +1331 **** **** **** **** **** **** **** **** **** +1332 **** **** **** **** **** **** **** **** **** +1333 **** **** **** **** **** **** **** **** **** +1334 **** **** **** **** **** **** **** **** **** +1335 **** **** **** **** **** **** **** **** **** +1336 **** **** **** **** **** **** **** **** **** +1337 **** **** **** **** **** **** **** **** **** +1338 **** **** **** **** **** **** **** **** **** +1339 **** **** **** **** **** **** **** **** **** +1340 **** **** **** **** **** **** **** **** **** +1341 **** **** **** **** **** **** **** **** **** +1342 **** **** **** **** **** **** **** **** **** +1343 **** **** **** **** **** **** **** **** **** +1344 **** **** **** **** **** **** **** **** **** +1345 **** **** **** **** **** **** **** **** **** +1346 **** **** **** **** **** **** **** **** **** +1347 **** **** **** **** **** **** **** **** **** +1348 **** **** **** **** **** **** **** **** **** +1349 **** **** **** **** **** **** **** **** **** +1350 **** **** **** **** **** **** **** **** **** +1351 **** **** **** **** **** **** **** **** **** +1352 **** **** **** **** **** **** **** **** **** +1353 **** **** **** **** **** **** **** **** **** +1354 **** **** **** **** **** **** **** **** **** +1355 **** **** **** **** **** **** **** **** **** +1356 **** **** **** **** **** **** **** **** **** +1357 **** **** **** **** **** **** **** **** **** +1358 **** **** **** **** **** **** **** **** **** +1359 **** **** **** **** **** **** **** **** **** +1360 **** **** **** **** **** **** **** **** **** +1361 **** **** **** **** **** **** **** **** **** +1362 **** **** **** **** **** **** **** **** **** +1363 **** **** **** **** **** **** **** **** **** +1364 **** **** **** **** **** **** **** **** **** +1365 **** **** **** **** **** **** **** **** **** +1366 **** **** **** **** **** **** **** **** **** +1367 **** **** **** **** **** **** **** **** **** +1368 **** **** **** **** **** **** **** **** **** +1369 **** **** **** **** **** **** **** **** **** +1370 **** **** **** **** **** **** **** **** **** +1371 **** **** **** **** **** **** **** **** **** +1372 **** **** **** **** **** **** **** **** **** +1373 **** **** **** **** **** **** **** **** **** +1374 **** **** **** **** **** **** **** **** **** +1375 **** **** **** **** **** **** **** **** **** +1376 **** **** **** **** **** **** **** **** **** +1377 **** **** **** **** **** **** **** **** **** +1378 **** **** **** **** **** **** **** **** **** +1379 **** **** **** **** **** **** **** **** **** +1380 **** **** **** **** **** **** **** **** **** +1381 **** **** **** **** **** **** **** **** **** +1382 **** **** **** **** **** **** **** **** **** +1383 **** **** **** **** **** **** **** **** **** +1384 **** **** **** **** **** **** **** **** **** +1385 **** **** **** **** **** **** **** **** **** +1386 **** **** **** **** **** **** **** **** **** +1387 **** **** **** **** **** **** **** **** **** +1388 **** **** **** **** **** **** **** **** **** +1389 **** **** **** **** **** **** **** **** **** +1390 **** **** **** **** **** **** **** **** **** +1391 **** **** **** **** **** **** **** **** **** +1392 **** **** **** **** **** **** **** **** **** +1393 **** **** **** **** **** **** **** **** **** +1394 **** **** **** **** **** **** **** **** **** +1395 **** **** **** **** **** **** **** **** **** +1396 **** **** **** **** **** **** **** **** **** +1397 **** **** **** **** **** **** **** **** **** +1398 **** **** **** **** **** **** **** **** **** +1399 **** **** **** **** **** **** **** **** **** +1400 **** **** **** **** **** **** **** **** **** +1401 **** **** **** **** **** **** **** **** **** +1402 **** **** **** **** **** **** **** **** **** +1403 **** **** **** **** **** **** **** **** **** +1404 **** **** **** **** **** **** **** **** **** +1405 **** **** **** **** **** **** **** **** **** +1406 **** **** **** **** **** **** **** **** **** +1407 **** **** **** **** **** **** **** **** **** +1408 **** **** **** **** **** **** **** **** **** +1409 **** **** **** **** **** **** **** **** **** +1410 **** **** **** **** **** **** **** **** **** +1411 **** **** **** **** **** **** **** **** **** +1412 **** **** **** **** **** **** **** **** **** +1413 **** **** **** **** **** **** **** **** **** +1414 **** **** **** **** **** **** **** **** **** +1415 **** **** **** **** **** **** **** **** **** +1416 **** **** **** **** **** **** **** **** **** +1417 **** **** **** **** **** **** **** **** **** +1418 **** **** **** **** **** **** **** **** **** +1419 **** **** **** **** **** **** **** **** **** +1420 **** **** **** **** **** **** **** **** **** +1421 **** **** **** **** **** **** **** **** **** +1422 **** **** **** **** **** **** **** **** **** +1423 **** **** **** **** **** **** **** **** **** +1424 **** **** **** **** **** **** **** **** **** +1425 **** **** **** **** **** **** **** **** **** +1426 **** **** **** **** **** **** **** **** **** +1427 **** **** **** **** **** **** **** **** **** +1428 **** **** **** **** **** **** **** **** **** +1429 **** **** **** **** **** **** **** **** **** +1430 **** **** **** **** **** **** **** **** **** +1431 **** **** **** **** **** **** **** **** **** +1432 **** **** **** **** **** **** **** **** **** +1433 **** **** **** **** **** **** **** **** **** +1434 **** **** **** **** **** **** **** **** **** +1435 **** **** **** **** **** **** **** **** **** +1436 **** **** **** **** **** **** **** **** **** +1437 **** **** **** **** **** **** **** **** **** +1438 **** **** **** **** **** **** **** **** **** +1439 **** **** **** **** **** **** **** **** **** +1440 **** **** **** **** **** **** **** **** **** +1441 **** **** **** **** **** **** **** **** **** +1442 **** **** **** **** **** **** **** **** **** +1443 **** **** **** **** **** **** **** **** **** +1444 **** **** **** **** **** **** **** **** **** +1445 **** **** **** **** **** **** **** **** **** +1446 **** **** **** **** **** **** **** **** **** +1447 **** **** **** **** **** **** **** **** **** +1448 **** **** **** **** **** **** **** **** **** +1449 **** **** **** **** **** **** **** **** **** +1450 **** **** **** **** **** **** **** **** **** +1451 **** **** **** **** **** **** **** **** **** +1452 **** **** **** **** **** **** **** **** **** +1453 **** **** **** **** **** **** **** **** **** +1454 **** **** **** **** **** **** **** **** **** +1455 **** **** **** **** **** **** **** **** **** +1456 **** **** **** **** **** **** **** **** **** +1457 **** **** **** **** **** **** **** **** **** +1458 **** **** **** **** **** **** **** **** **** +1459 **** **** **** **** **** **** **** **** **** +1460 **** **** **** **** **** **** **** **** **** +1461 **** **** **** **** **** **** **** **** **** +1462 **** **** **** **** **** **** **** **** **** +1463 **** **** **** **** **** **** **** **** **** +1464 **** **** **** **** **** **** **** **** **** +1465 **** **** **** **** **** **** **** **** **** +1466 **** **** **** **** **** **** **** **** **** +1467 **** **** **** **** **** **** **** **** **** +1468 **** **** **** **** **** **** **** **** **** +1469 **** **** **** **** **** **** **** **** **** +1470 **** **** **** **** **** **** **** **** **** +1471 **** **** **** **** **** **** **** **** **** +1472 **** **** **** **** **** **** **** **** **** +1473 **** **** **** **** **** **** **** **** **** +1474 **** **** **** **** **** **** **** **** **** +1475 **** **** **** **** **** **** **** **** **** +1476 **** **** **** **** **** **** **** **** **** +1477 **** **** **** **** **** **** **** **** **** +1478 **** **** **** **** **** **** **** **** **** +1479 **** **** **** **** **** **** **** **** **** +1480 **** **** **** **** **** **** **** **** **** +1481 **** **** **** **** **** **** **** **** **** +1482 **** **** **** **** **** **** **** **** **** +1483 **** **** **** **** **** **** **** **** **** +1484 **** **** **** **** **** **** **** **** **** +1485 Warsoul_CultPower **** **** **** **** **** **** **** **** +1486 Warsoul_SoulTyrant **** **** **** **** **** **** **** **** +1487 SPIRETOP_FOG_CLOUD_BREATH **** **** **** **** **** **** **** **** +1488 MEPHLING_BREATH_WEAPON **** **** **** **** **** **** **** **** +1489 ARANEA_ALTFORM_RADIAL **** **** **** **** **** **** **** **** +1490 ARANEA_ALT_HUMANOID **** **** **** **** **** **** **** **** +1491 ARANEA_ALT_HYBRID **** **** **** **** **** **** **** **** +1492 ARANEA_ALT_SPIDER **** **** **** **** **** **** **** **** +1493 ARANEA_WEB **** **** **** **** **** **** **** **** +1494 MUCKDWELLER_SQUIRT **** **** **** **** **** **** **** **** +1495 TN_DES_20 **** **** **** **** **** **** **** **** +1496 TN_DES_100 **** **** **** **** **** **** **** **** +1497 TN_Unsummon **** **** **** **** **** **** **** **** +1498 VAMPIRIC_DRAIN **** **** **** **** **** **** **** **** +1499 Dancing_Lights **** **** **** **** **** **** **** **** +1500 Read_Magic **** **** **** **** **** **** **** **** +1501 Sobriety **** **** **** **** **** **** **** **** +1502 Crafters_Blessing **** **** **** **** **** **** **** **** +1503 Crafters_Curse **** **** **** **** **** **** **** **** +1504 Lesser_Planar_Ally **** **** **** S 0 3 0 -2 +1505 Greater_Planar_Ally **** **** **** S 0 3 0 -2 +1506 Eternal_Charm_Monster **** **** **** **** **** **** **** **** +1507 Eternal_Charm_Person **** **** **** **** **** **** **** **** +1508 Weapon_of_Impact **** **** **** E 0 3 15 **** +1509 Shillelagh **** **** **** E 0 2 15 -14 +1510 Daze_Monster Dazed Will 1 R 1 **** **** **** +1511 Curse_Water **** **** **** **** **** **** **** **** +1512 Mislead **** **** **** P 0 2 0 **** +1513 Power_Word_Blind **** **** 1 R 1 **** **** **** +1514 BFZ_FatefulStride **** **** **** **** **** **** **** **** +1515 PA_FLETCH_1 **** **** **** **** **** **** **** **** +1516 PA_FLETCH_2 **** **** **** **** **** **** **** **** +1517 PA_FLETCH_3 **** **** **** **** **** **** **** **** +1518 PA_FLETCH_4 **** **** **** **** **** **** **** **** +1519 PA_FLETCH_5 **** **** **** **** **** **** **** **** +1520 PA_POWERSHOT **** **** **** **** **** **** **** **** +1521 PA_IMP_POWERSHOT **** **** **** **** **** **** **** **** +1522 PA_SUP_POWERSHOT **** **** **** **** **** **** **** **** +1523 Hext_StrBoost **** **** **** **** **** **** **** **** +1524 AT_RL_LOCK **** **** **** **** **** **** **** **** +1525 AT_RL_TRAP **** **** **** **** **** **** **** **** +1526 AT_ISA **** **** **** **** **** **** **** **** +1527 TN_CGUNDEAD **** **** **** **** **** **** **** **** +1528 Thousand_Faces_MEDIUM **** **** **** **** **** **** **** **** +1529 Thousand_Faces_SMALL **** **** **** **** **** **** **** **** +1530 Thousand_Faces_DWARF **** **** **** **** **** **** **** **** +1531 Thousand_Faces_ELF **** **** **** **** **** **** **** **** +1532 Thousand_Faces_HALF_ELF **** **** **** **** **** **** **** **** +1533 Thousand_Faces_HALF_ORC **** **** **** **** **** **** **** **** +1534 Thousand_Faces_HUMAN **** **** **** **** **** **** **** **** +1535 Thousand_Faces_GNOME **** **** **** **** **** **** **** **** +1536 Thousand_Faces_HALFLING **** **** **** **** **** **** **** **** +1537 Thousand_Face_OFF **** **** **** **** **** **** **** **** +1538 OcRay_ChPer **** **** **** **** **** **** **** **** +1539 OcRay_Sleep **** **** **** **** **** **** **** **** +1540 OcRay_InfW **** **** **** **** **** **** **** **** +1541 OcRay_Slow **** **** **** **** **** **** **** **** +1542 OcRay_Fear **** **** **** **** **** **** **** **** +1543 OcRay_ChMon **** **** **** **** **** **** **** **** +1544 OcRay_Tele **** **** **** **** **** **** **** **** +1545 OcRay_FlSt **** **** **** **** **** **** **** **** +1546 OcRay_Dis **** **** **** **** **** **** **** **** +1547 OcRay_Death **** **** **** **** **** **** **** **** +1548 Samu_AncestralDaisho **** **** **** **** **** **** **** **** +1549 Warpr_Rally **** **** **** **** **** **** **** **** +1550 Warpr_Inflame **** **** **** **** **** **** **** **** +1551 Warpr_ImplicableFoe **** **** **** **** **** **** **** **** +1552 Warpr_Healing_Circle **** **** **** **** **** **** **** **** +1553 TN_CLUNDEAD **** **** **** **** **** **** **** **** +1554 TN_EnergyDrain **** **** **** **** **** **** **** **** +1555 Warpr_Mass_Haste **** **** **** **** **** **** **** **** +1556 TO_Fear **** **** **** **** **** **** **** **** +1557 TO_Pallor **** **** **** **** **** **** **** **** +1558 TO_Carrion **** **** **** **** **** **** **** **** +1559 TO_DeathTouch **** **** **** **** **** **** **** **** +1560 TO_MNRUndead **** **** **** **** **** **** **** **** +1561 TO_MJRUndead **** **** **** **** **** **** **** **** +1562 TO_Nightwing **** **** **** **** **** **** **** **** +1563 Warpr_Mass_Heal **** **** **** **** **** **** **** **** +1564 SB_ShockWeap **** **** **** **** **** **** **** **** +1565 SB_HolyWeap **** **** **** **** **** **** **** **** +1566 SB_BrillWeap **** **** **** **** **** **** **** **** +1567 Spell_Turning **** **** **** P 0 3 0 -9 +1568 Death_Knell **** **** **** **** **** **** **** **** +1569 SereneGuardian_PainfulRelease **** **** **** **** **** **** **** **** +1570 SereneGuardian_DamagingRelease **** **** **** **** **** **** **** **** +1571 SereneGuardian_StaggeringRelease **** **** **** **** **** **** **** **** +1572 SereneGuardian_ConfoundingRelease **** **** **** **** **** **** **** **** +1573 SereneGuardian_SoulRelease **** **** **** **** **** **** **** **** +1574 AnimalTrance Mind_Affecting Will 1 R 1 **** **** **** +1575 Blink **** **** **** E 0 2 0 **** +1576 DetectMagic **** **** **** **** **** **** **** **** +1577 Marrusault_Howl **** **** **** **** **** **** **** **** +1578 Hybsil_Mirror_Image **** **** **** **** **** **** **** **** +1579 HYBSIL_DANCLIGHTS **** **** **** **** **** **** **** **** +1580 HYBSIL_JUMP **** **** **** **** **** **** **** **** +1581 Bariaur_Charge **** **** **** **** **** **** **** **** +1582 Wildren_fury **** **** **** **** **** **** **** **** +1583 KotMC_CombatSense **** **** **** **** **** **** **** **** +1584 InvestArmour **** **** **** **** **** **** **** **** +1585 ThayK_FinalStand **** **** **** **** **** **** **** **** +1586 ArmouredMind **** **** **** **** **** **** **** **** +1587 Diabol_Diabolism **** **** **** **** **** **** **** **** +1588 Diabol_VDiabolism **** **** **** **** **** **** **** **** +1589 MindOverBody **** **** **** **** **** **** **** **** +1590 Maester_Identification **** **** **** **** **** **** **** **** +1591 LendResolve **** **** **** **** **** **** **** **** +1592 Ollam_InspireCompetence **** **** **** **** **** **** **** **** +1593 Ollam_InspireResilience **** **** **** **** **** **** **** **** +1594 Duskblade_Channeling **** **** **** **** **** **** **** **** +1595 DivineWholeness **** **** **** **** **** **** **** **** +1596 Hexblade_Companion **** **** **** **** **** **** **** **** +1597 TribalFrenzy **** **** **** **** **** **** **** **** +1598 HexbladeCurse **** **** **** **** **** **** **** **** +1599 HexbladeAura **** **** **** **** **** **** **** **** +1600 Changestaff **** **** **** S 0 3 0 -2 +1601 Rage **** **** **** E 0 2 9 **** +1602 Arach_SpidMount **** **** **** **** **** **** **** **** +1603 Arach_DominateMale **** **** **** **** **** **** **** **** +1604 Arach_ZinCarla **** **** **** **** **** **** **** **** +1605 Arach_YochlolMaster **** **** **** **** **** **** **** **** +1606 Arach_YochlolYoch **** **** **** **** **** **** **** **** +1607 Arach_YochlolSpid **** **** **** **** **** **** **** **** +1608 Arach_YochloloGas **** **** **** **** **** **** **** **** +1609 Arach_YochlolRevert **** **** **** **** **** **** **** **** +1610 Duskblade_Quickcast **** **** **** **** **** **** **** **** +1611 WarStrike **** **** **** **** **** **** **** **** +1612 SelvetarmsWrath **** **** **** **** **** **** **** **** +1613 SpidersGrace **** **** **** **** **** **** **** **** +1614 SpiderServantMonstrous **** **** **** **** **** **** **** **** +1615 SpiderServantSword **** **** **** **** **** **** **** **** +1616 SpiderServantMyrlochar **** **** **** **** **** **** **** **** +1617 SpiderServantPhase **** **** **** **** **** **** **** **** +1618 SpiderServantMasterFeat **** **** **** **** **** **** **** **** +1619 Judgment **** **** **** **** **** **** **** **** +1620 Healer_Clean_Para **** **** **** **** **** **** **** **** +1621 InscribeRune **** **** **** **** **** **** **** **** +1622 MaximizeRune **** **** **** **** **** **** **** **** +1623 RuneChant **** **** **** **** **** **** **** **** +1624 ImprovedRunecast **** **** **** **** **** **** **** **** +1625 RuneCharges **** **** **** **** **** **** **** **** +1626 RuneUsesPerDay **** **** **** **** **** **** **** **** +1627 RuneCountOne **** **** **** **** **** **** **** **** +1628 RuneCountTen **** **** **** **** **** **** **** **** +1629 RuneClear **** **** **** **** **** **** **** **** +1630 Healer_Clean_Dis **** **** **** **** **** **** **** **** +1631 PDK_RallyingCry **** **** **** **** **** **** **** **** +1632 PDK_Fear **** **** **** **** **** **** **** **** +1633 PDK_OathOfWrath **** **** **** **** **** **** **** **** +1634 PDK_FinalStand **** **** **** **** **** **** **** **** +1635 PDK_InspireCourage **** **** **** **** **** **** **** **** +1636 Healer_Clean_Fear **** **** **** **** **** **** **** **** +1637 WidenSpell **** **** **** **** **** **** **** **** +1638 Healer_Clean_Poison **** **** **** **** **** **** **** **** +1639 Dirge_Sorrow **** **** **** **** **** **** **** **** +1640 Dirge_Bolster **** **** **** **** **** **** **** **** +1641 Dirge_Grief **** **** **** **** **** **** **** **** +1642 Dirge_Horror **** **** **** **** **** **** **** **** +1643 Dirge_Awaken **** **** **** **** **** **** **** **** +1644 Healer_Clean_Blind **** **** **** **** **** **** **** **** +1645 Suel_DispellingStrike **** **** **** **** **** **** **** **** +1646 SancMind_CleanStrike **** **** **** **** **** **** **** **** +1647 SancMind_DisruptBlow **** **** **** **** **** **** **** **** +1648 SancMind_PartitionMind **** **** **** **** **** **** **** **** +1649 Healer_Clean_Spirit **** **** **** **** **** **** **** **** +1650 ClangeddinsStrike **** **** **** **** **** **** **** **** +1651 ClangeddinsMight **** **** **** **** **** **** **** **** +1652 Rockburst **** **** **** **** **** **** **** **** +1653 Healer_Clean_Petri **** **** **** **** **** **** **** **** +1654 CheckDomainSlots **** **** **** **** **** **** **** **** +1655 CastDomainLevel1 **** **** **** **** **** **** **** **** +1656 CastDomainLevel1Slot1 **** **** **** **** **** **** **** **** +1657 CastDomainLevel1Slot2 **** **** **** **** **** **** **** **** +1658 CastDomainLevel1Slot3 **** **** **** **** **** **** **** **** +1659 CastDomainLevel1Slot4 **** **** **** **** **** **** **** **** +1660 CastDomainLevel1Slot5 **** **** **** **** **** **** **** **** +1661 CastDomainLevel2 **** **** **** **** **** **** **** **** +1662 CastDomainLevel2Slot1 **** **** **** **** **** **** **** **** +1663 CastDomainLevel2Slot2 **** **** **** **** **** **** **** **** +1664 CastDomainLevel2Slot3 **** **** **** **** **** **** **** **** +1665 CastDomainLevel2Slot4 **** **** **** **** **** **** **** **** +1666 CastDomainLevel2Slot5 **** **** **** **** **** **** **** **** +1667 CastDomainLevel3 **** **** **** **** **** **** **** **** +1668 CastDomainLevel3Slot1 **** **** **** **** **** **** **** **** +1669 CastDomainLevel3Slot2 **** **** **** **** **** **** **** **** +1670 CastDomainLevel3Slot3 **** **** **** **** **** **** **** **** +1671 CastDomainLevel3Slot4 **** **** **** **** **** **** **** **** +1672 CastDomainLevel3Slot5 **** **** **** **** **** **** **** **** +1673 CastDomainLevel4 **** **** **** **** **** **** **** **** +1674 CastDomainLevel4Slot1 **** **** **** **** **** **** **** **** +1675 CastDomainLevel4Slot2 **** **** **** **** **** **** **** **** +1676 CastDomainLevel4Slot3 **** **** **** **** **** **** **** **** +1677 CastDomainLevel4Slot4 **** **** **** **** **** **** **** **** +1678 CastDomainLevel4Slot5 **** **** **** **** **** **** **** **** +1679 CastDomainLevel5 **** **** **** **** **** **** **** **** +1680 CastDomainLevel5Slot1 **** **** **** **** **** **** **** **** +1681 CastDomainLevel5Slot2 **** **** **** **** **** **** **** **** +1682 CastDomainLevel5Slot3 **** **** **** **** **** **** **** **** +1683 CastDomainLevel5Slot4 **** **** **** **** **** **** **** **** +1684 CastDomainLevel5Slot5 **** **** **** **** **** **** **** **** +1685 CastDomainLevel6 **** **** **** **** **** **** **** **** +1686 CastDomainLevel6Slot1 **** **** **** **** **** **** **** **** +1687 CastDomainLevel6Slot2 **** **** **** **** **** **** **** **** +1688 CastDomainLevel6Slot3 **** **** **** **** **** **** **** **** +1689 CastDomainLevel6Slot4 **** **** **** **** **** **** **** **** +1690 CastDomainLevel6Slot5 **** **** **** **** **** **** **** **** +1691 CastDomainLevel7 **** **** **** **** **** **** **** **** +1692 CastDomainLevel7Slot1 **** **** **** **** **** **** **** **** +1693 CastDomainLevel7Slot2 **** **** **** **** **** **** **** **** +1694 CastDomainLevel7Slot3 **** **** **** **** **** **** **** **** +1695 CastDomainLevel7Slot4 **** **** **** **** **** **** **** **** +1696 CastDomainLevel7Slot5 **** **** **** **** **** **** **** **** +1697 Healer_New_Limb **** **** **** **** **** **** **** **** +1698 Healer_New_Life **** **** **** **** **** **** **** **** +1699 SenseMagic **** **** **** **** **** **** **** **** +1700 CHANNEL_SPELL **** **** **** **** **** **** **** **** +1701 CastDomainLevel8 **** **** **** **** **** **** **** **** +1702 CastDomainLevel8Slot1 **** **** **** **** **** **** **** **** +1703 CastDomainLevel8Slot2 **** **** **** **** **** **** **** **** +1704 CastDomainLevel8Slot3 **** **** **** **** **** **** **** **** +1705 CastDomainLevel8Slot4 **** **** **** **** **** **** **** **** +1706 CastDomainLevel8Slot5 **** **** **** **** **** **** **** **** +1707 CastDomainLevel9 **** **** **** **** **** **** **** **** +1708 CastDomainLevel9Slot1 **** **** **** **** **** **** **** **** +1709 CastDomainLevel9Slot2 **** **** **** **** **** **** **** **** +1710 CastDomainLevel9Slot3 **** **** **** **** **** **** **** **** +1711 CastDomainLevel9Slot4 **** **** **** **** **** **** **** **** +1712 CastDomainLevel9Slot5 **** **** **** **** **** **** **** **** +1713 DualBoost **** **** **** **** **** **** **** **** +1714 Charm_Domain_Power **** **** **** **** **** **** **** **** +1715 Death_Domain_Power **** **** **** **** **** **** **** **** +1716 Destruction_Domain_Power **** **** **** **** **** **** **** **** +1717 Family_Domain_Power **** **** **** **** **** **** **** **** +1718 Halfling_Domain_Power **** **** **** **** **** **** **** **** +1719 Hate_Domain_Power **** **** **** **** **** **** **** **** +1720 Nobility_Domain_Power **** **** **** **** **** **** **** **** +1721 Orc_Domain_Power **** **** **** **** **** **** **** **** +1722 Protection_Domain_Power **** **** **** **** **** **** **** **** +1723 Renewal_Domain_Power **** **** **** **** **** **** **** **** +1724 Strength_Domain_Power **** **** **** **** **** **** **** **** +1725 Travel_Domain_Power **** **** **** **** **** **** **** **** +1726 Turn_Scaleykind **** **** **** **** **** **** **** **** +1727 Turn_Slime **** **** **** **** **** **** **** **** +1728 DrowJudicator_Command_Spiders **** **** **** **** **** **** **** **** +1729 Turn_Plant **** **** **** **** **** **** **** **** +1730 Turn_Air **** **** **** **** **** **** **** **** +1731 Turn_Earth **** **** **** **** **** **** **** **** +1732 Turn_Fire **** **** **** **** **** **** **** **** +1733 Turn_Water **** **** **** **** **** **** **** **** +1734 Turn_Blightspawned **** **** **** **** **** **** **** **** +1735 AppraiseMagicValue **** **** **** **** **** **** **** **** +1736 CraftSkullTalisman **** **** **** **** **** **** **** **** +1737 Grenade_Cursed_Water **** **** **** **** **** **** **** **** +1738 Frostrager_OneTwoPunch **** **** **** **** **** **** **** **** +1739 ZealousSurge **** **** **** **** **** **** **** **** +1740 CrusaderSmite **** **** **** **** **** **** **** **** +1741 Animalistic_Power **** **** **** E 0 2 1 **** +1742 Bigbys_Striking_Fist **** Reflex 1 R 1 **** **** **** +1743 Bigbys_Tripping_Hand **** Reflex 1 R 1 **** **** **** +1744 Blade_of_Blood **** **** **** **** **** **** **** **** +1745 Blade_of_Blood_1d6 **** **** **** E 0 2 15 **** +1746 Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +1747 FEAT_FRIGHTFUL_CLEAVE **** **** **** **** **** **** **** **** +1748 FEAT_FRIGHTFUL_ATTACK **** **** **** **** **** **** **** **** +1749 FEAT_GFKILL_GHOST_STEP **** **** **** **** **** **** **** **** +1750 Acrobatic_Charge **** **** **** **** **** **** **** **** +1751 Stunning_Shout **** **** **** **** **** **** **** **** +1752 Ki_Save **** **** **** **** **** **** **** **** +1753 Ki_Skill **** **** **** **** **** **** **** **** +1754 Ki_Heal **** **** **** **** **** **** **** **** +1755 Deadly_Shout **** **** **** **** **** **** **** **** +1756 Censure_Demons **** **** **** **** **** **** **** **** +1757 Courage_Of_Heaven **** **** **** **** **** **** **** **** +1758 Consecrated_Aura **** **** **** **** **** **** **** **** +1759 Holy_Aura_Versus_Demons **** **** **** **** **** **** **** **** +1760 ChosenWeapon **** **** **** **** **** **** **** **** +1761 DexterousAttack **** **** **** **** **** **** **** **** +1762 FlurryOfSwords **** **** **** **** **** **** **** **** +1763 FalseKeeness **** **** **** **** **** **** **** **** +1764 Blur **** **** **** **** **** **** **** **** +1765 MirrorImage **** **** **** **** **** **** **** **** +1766 SuddenEmpower **** **** **** **** **** **** **** **** +1767 SuddenExtend **** **** **** **** **** **** **** **** +1768 SuddenMaximize **** **** **** **** **** **** **** **** +1769 SuddenWiden **** **** **** **** **** **** **** **** +1770 FightingChallenge **** **** **** **** **** **** **** **** +1771 TestOfMettle **** **** **** **** **** **** **** **** +1772 CallToBattle **** **** **** **** **** **** **** **** +1773 DauntingChallenge **** **** **** **** **** **** **** **** +1774 BondOfLoyalty **** **** **** **** **** **** **** **** +1775 LoyalBeyondDeath **** **** **** **** **** **** **** **** +1776 ShieldBlock **** **** **** **** **** **** **** **** +1777 BulwarkOfDefense **** **** **** **** **** **** **** **** +1778 VigilantDefender **** **** **** **** **** **** **** **** +1779 ShieldAlly **** **** **** **** **** **** **** **** +1780 ImprovedShieldAlly **** **** **** **** **** **** **** **** +1781 AttuneGem **** **** **** **** **** **** **** **** +1782 AttuneGemCraft **** **** **** **** **** **** **** **** +1783 AttuneGemCheckGem **** **** **** **** **** **** **** **** +1784 SummonUndeadI **** **** **** S 0 2 0 **** +1785 SummonUndeadII **** **** **** S 0 2 0 **** +1786 SummonUndeadIII **** **** **** S 0 2 0 **** +1787 SummonUndeadIV **** **** **** S 0 2 0 **** +1788 SummonUndeadV **** **** **** S 0 2 0 **** +1789 Scare Fear Will 1 I 1 **** **** **** +1790 Animate_Object **** **** **** **** **** **** **** **** +1791 Chill_Touch Negative Fortitude 1 T 1 **** **** **** +1792 Spellbook **** **** **** **** **** **** **** **** +1793 PnPFamiliarHide **** **** **** **** **** **** **** **** +1794 ChangeCodeSwitches **** **** **** **** **** **** **** **** +1795 FEAT_ZONE_OF_ANIMATION **** **** **** **** **** **** **** **** +1796 AugmentFamiliar **** **** **** **** **** **** **** **** +1797 Deflect **** **** **** P 0 2 0 **** +1798 EndScrying **** **** **** **** **** **** **** **** +1799 FalseLife **** **** **** P 0 3 0 **** +1800 ProtectionArrows **** **** **** P 0 2 7 **** +1801 TouchIdiocy **** **** 1 T 1 **** **** **** +1802 DeepSlumber Mind_Affecting Will 1 I 1 **** **** **** +1803 HoundDoom **** **** **** **** **** **** **** **** +1804 RepelVermin **** **** **** P 0 3 0 **** +1805 BalefulPolymorph **** Fortitude 1 R 1 **** **** **** +1806 BreakEnchantment **** **** **** **** **** **** **** **** +1807 CursedBlade **** **** **** **** **** **** **** **** +1808 SolidFog **** **** **** I 1 **** **** **** +1809 DetectScrying **** **** **** **** **** **** **** **** +1810 Channeled_Pyroburst **** **** **** **** **** **** **** **** +1811 Channeled_Pyroburst_Swift **** **** **** **** **** **** **** **** +1812 Channeled_Pyroburst_Standard **** **** **** **** **** **** **** **** +1813 Channeled_Pyroburst_Full **** **** **** **** **** **** **** **** +1814 Channeled_Pyroburst_Two **** **** **** **** **** **** **** **** +1815 Crown_Might **** **** **** E 0 3 1 **** +1816 Crown_Protection **** **** **** P 0 3 14 **** +1817 Lesser_Deflect **** **** **** P 0 2 0 **** +1818 Dimension_Hop **** **** **** **** **** **** **** **** +1819 Dispelling_Touch **** **** **** **** **** **** **** **** +1820 Doom_Scarabs **** Will 0 I 1 **** **** **** +1821 Energy_Aegis **** **** **** **** **** **** **** **** +1822 Energy_Aegis_Acid **** **** **** **** **** **** **** **** +1823 Energy_Aegis_Cold **** **** **** **** **** **** **** **** +1824 Energy_Aegis_Elec **** **** **** **** **** **** **** **** +1825 Energy_Aegis_Fire **** **** **** **** **** **** **** **** +1826 Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +1827 Energy_Surge **** **** **** **** **** **** **** **** +1828 Energy_Surge_Acid **** **** **** **** **** **** **** **** +1829 Energy_Surge_Cold **** **** **** **** **** **** **** **** +1830 Energy_Surge_Elec **** **** **** **** **** **** **** **** +1831 Energy_Surge_Fire **** **** **** **** **** **** **** **** +1832 Energy_Surge_Sonic **** **** **** **** **** **** **** **** +1833 Halt **** Will 1 R 1 **** **** **** +1834 Kelgores_Fire_Bolt Fire Reflex 0 R 1 **** **** **** +1835 Regroup **** **** **** **** **** **** **** **** +1836 Rouse **** **** **** **** **** **** **** **** +1837 Seeking_Ray Electricity **** 1 R 1 **** **** **** +1838 Slashing_Dispel **** **** **** R 1 **** **** **** +1839 Sonic_Shield **** **** **** P 0 2 0 **** +1840 Sure_Strike **** **** **** E 0 2 0 **** +1841 CoC_Bless **** **** **** **** **** **** **** **** +1842 CoC_Wrath **** **** **** **** **** **** **** **** +1843 OAAnimalCompanion **** **** **** **** **** **** **** **** +1844 Celestial_Companion **** **** **** **** **** **** **** **** +1845 Unicorn_Companion **** **** **** **** **** **** **** **** +1846 Lammasu_Companion **** **** **** **** **** **** **** **** +1847 Androsphinx_Companion **** **** **** **** **** **** **** **** +1848 SongArcanePower **** **** **** **** **** **** **** **** +1849 Close_Wounds **** **** **** H 0 **** **** **** +1850 Revivify **** **** **** **** **** **** **** **** +1851 Bless_Water **** **** **** **** **** **** **** **** +1852 Calm_Emotions **** **** **** **** **** **** **** **** +1853 Repulsion **** **** **** P 0 2 0 **** +1854 Holy_Aura **** **** **** P 0 2 0 **** +1855 True_Resurrection **** **** **** **** **** **** **** **** +1856 Foresight **** **** **** P 0 3 0 **** +1857 SongTimelessness **** **** **** **** **** **** **** **** +1858 Draconic_Arcane_Grace_Master_1_5 **** **** **** **** **** **** **** **** +1859 Draconic_Arcane_Grace_Master_6_9 **** **** **** **** **** **** **** **** +1860 Draconic_Breath_Master_1_5 **** **** **** **** **** **** **** **** +1861 Draconic_Breath_Master_6_9 **** **** **** **** **** **** **** **** +1862 Draconic_Arcane_Grace_1 **** **** **** **** **** **** **** **** +1863 Draconic_Arcane_Grace_2 **** **** **** **** **** **** **** **** +1864 Draconic_Arcane_Grace_3 **** **** **** **** **** **** **** **** +1865 Draconic_Arcane_Grace_4 **** **** **** **** **** **** **** **** +1866 Draconic_Arcane_Grace_5 **** **** **** **** **** **** **** **** +1867 Draconic_Arcane_Grace_6 **** **** **** **** **** **** **** **** +1868 Draconic_Arcane_Grace_7 **** **** **** **** **** **** **** **** +1869 Draconic_Arcane_Grace_8 **** **** **** **** **** **** **** **** +1870 Draconic_Arcane_Grace_9 **** **** **** **** **** **** **** **** +1871 Draconic_Breath_1 **** **** **** **** **** **** **** **** +1872 Draconic_Breath_2 **** **** **** **** **** **** **** **** +1873 Draconic_Breath_3 **** **** **** **** **** **** **** **** +1874 Draconic_Breath_4 **** **** **** **** **** **** **** **** +1875 Draconic_Breath_5 **** **** **** **** **** **** **** **** +1876 Draconic_Breath_6 **** **** **** **** **** **** **** **** +1877 Draconic_Breath_7 **** **** **** **** **** **** **** **** +1878 Draconic_Breath_8 **** **** **** **** **** **** **** **** +1879 Draconic_Breath_9 **** **** **** **** **** **** **** **** +1880 Breath_of_Life **** **** **** **** **** **** **** **** +1881 Swift_Wing_Wings **** **** **** **** **** **** **** **** +1882 ToT_Frightful_Presence **** **** **** **** **** **** **** **** +1883 ToT_Dominate_Dragon **** **** **** **** **** **** **** **** +1884 ToT_Breath_Weapon **** **** **** **** **** **** **** **** +1885 ToT_Cold_Cone **** **** **** **** **** **** **** **** +1886 ToT_Acid_Line **** **** **** **** **** **** **** **** +1887 ToT_Acid_Cone **** **** **** **** **** **** **** **** +1888 ToT_Elec_Line **** **** **** **** **** **** **** **** +1889 ToT_Fire_Cone **** **** **** **** **** **** **** **** +1890 Dragonfire_Strike_Toggle **** **** **** **** **** **** **** **** +1891 True_Stealth_Toggle **** **** **** **** **** **** **** **** +1892 Fire_Lash **** **** **** **** **** **** **** **** +1893 Bolt_of_Fire **** **** **** **** **** **** **** **** +1894 Nimbus **** **** **** **** **** **** **** **** +1895 Nimbus_Touch_Attack **** **** **** **** **** **** **** **** +1896 Firewalk **** **** **** **** **** **** **** **** +1897 Heat_Death **** **** **** **** **** **** **** **** +1898 Conflagration **** **** **** **** **** **** **** **** +1899 SongCosmicFire **** **** **** **** **** **** **** **** +1900 Shifter_GWShape **** **** **** **** **** **** **** **** +1901 Shifter_EGWShape **** **** **** **** **** **** **** **** +1902 Shifter_Options **** **** **** **** **** **** **** **** +1903 Shifter_TrueForm **** **** **** **** **** **** **** **** +1904 Lich_Touch **** **** **** **** **** **** **** **** +1905 Lich_Fear_Aura **** **** **** **** **** **** **** **** +1906 Lich_AlterSelf **** **** **** **** **** **** **** **** +1907 Lich_CraftWonderus **** **** **** **** **** **** **** **** +1908 Lich_Trap **** **** **** **** **** **** **** **** +1909 Assassin_DeathAttack **** **** **** **** **** **** **** **** +1910 SPELL_LASHER_THIRD_HAND **** **** **** **** **** **** **** **** +1911 SPELL_LASHER_CRACK **** **** **** **** **** **** **** **** +1912 SPELL_LASHER_STUN_SNAP **** **** **** **** **** **** **** **** +1913 SPELL_LASHER_DEATH_SPIRAL **** **** **** **** **** **** **** **** +1914 SPELL_LASHER_LASHW **** **** **** **** **** **** **** **** +1915 ForceOfPersonality **** **** **** **** **** **** **** **** +1916 InsightfulReflexes **** **** **** **** **** **** **** **** +1917 SPELL_LASHER_CRACK_DOOM **** **** **** **** **** **** **** **** +1918 Shifter_Effects_Application **** **** **** **** **** **** **** **** +1919 Shifter_QuickShiftSlots_1 **** **** **** **** **** **** **** **** +1920 Shifter_QuickShiftSlots_2 **** **** **** **** **** **** **** **** +1921 Shifter_QuickSlot_1 **** **** **** **** **** **** **** **** +1922 Shifter_QuickSlot_2 **** **** **** **** **** **** **** **** +1923 Shifter_QuickSlot_3 **** **** **** **** **** **** **** **** +1924 Shifter_QuickSlot_4 **** **** **** **** **** **** **** **** +1925 Shifter_QuickSlot_5 **** **** **** **** **** **** **** **** +1926 Shifter_QuickSlot_6 **** **** **** **** **** **** **** **** +1927 Shifter_QuickSlot_7 **** **** **** **** **** **** **** **** +1928 Shifter_QuickSlot_8 **** **** **** **** **** **** **** **** +1929 Shifter_QuickSlot_9 **** **** **** **** **** **** **** **** +1930 Shifter_QuickSlot_10 **** **** **** **** **** **** **** **** +1931 FEAT_RACE_GAZECONF **** **** **** **** **** **** **** **** +1932 FEAT_RACE_GAZEEVIL **** **** **** **** **** **** **** **** +1933 FEAT_RACE_GAZEPETRIFY **** **** **** **** **** **** **** **** +1934 SlayerOfDomielDetectEvil **** **** **** **** **** **** **** **** +1935 FEAT_RACE_VAMPTOUCH **** **** **** **** **** **** **** **** +1936 FEAT_IRDA_CHANGE_SHAPE **** **** **** **** **** **** **** **** +1937 Irda_Select_Form **** **** **** **** **** **** **** **** +1938 Irda_Options **** **** **** **** **** **** **** **** +1939 Irda_True_Form **** **** **** **** **** **** **** **** +1940 Irda_Quickslot_1 **** **** **** **** **** **** **** **** +1941 Irda_Quickslot_2 **** **** **** **** **** **** **** **** +1942 FEAT_CHANGELING_CHANGE_SHAPE **** **** **** **** **** **** **** **** +1943 Changeling_Select_Form **** **** **** **** **** **** **** **** +1944 Changeling_Options **** **** **** **** **** **** **** **** +1945 Changeling_True_Form **** **** **** **** **** **** **** **** +1946 Changeling_Quickslot_1 **** **** **** **** **** **** **** **** +1947 Changeling_Quickslot_2 **** **** **** **** **** **** **** **** +1948 Nymph_Stunning_Glance **** **** **** **** **** **** **** **** +1949 Nymph_Blinding_Beauty **** **** **** **** **** **** **** **** +1950 SlayerOfDomielDeathTouch1 **** **** **** **** **** **** **** **** +1951 Rakshasa_Disguise **** **** **** **** **** **** **** **** +1952 EndPRCPolymorph **** **** **** **** **** **** **** **** +1953 Shout Sonic Fortitude 1 I 1 **** **** **** +1954 Greater_Shout Sonic Fortitude 1 I 1 **** **** **** +1955 Feyri_Alter **** **** **** **** **** **** **** **** +1956 Nixie_Waterbreathing **** **** **** **** **** **** **** **** +1957 Urdinnir_StoneSkin **** **** **** **** **** **** **** **** +1958 Race_Darkness **** **** **** **** **** **** **** **** +1959 Race_Daze **** **** **** **** **** **** **** **** +1960 Race_Light **** **** **** **** **** **** **** **** +1961 Svirf_BlindDeaf **** **** **** **** **** **** **** **** +1962 Duegar_Invis **** **** **** **** **** **** **** **** +1963 Illithid_Charm_Monster **** **** **** **** **** **** **** **** +1964 Race_Charm_Person **** **** **** **** **** **** **** **** +1965 Faerie_Fire **** **** **** **** **** **** **** **** +1966 Avariel_Dive **** **** **** **** **** **** **** **** +1967 Minotaur_Charge **** **** **** **** **** **** **** **** +1968 Race_Blur **** **** **** **** **** **** **** **** +1969 Feyri_Enervation **** **** **** **** **** **** **** **** +1970 Race_Entangle **** **** **** **** **** **** **** **** +1971 Race_Fear **** **** **** **** **** **** **** **** +1972 Race_Clair **** **** **** **** **** **** **** **** +1973 Race_Neutralize_Poison **** **** **** **** **** **** **** **** +1974 Pixie_Confusion **** **** **** **** **** **** **** **** +1975 Pixie_Invis **** **** **** **** **** **** **** **** +1976 Pixie_Dispel **** **** **** **** **** **** **** **** +1977 Race_Chill_Touch **** **** **** **** **** **** **** **** +1978 Pixie_Polymorph **** **** **** **** **** **** **** **** +1979 Pixie_BROWN_BEAR **** **** **** **** **** **** **** **** +1980 Pixie_PANTHER **** **** **** **** **** **** **** **** +1981 Pixie_WOLF **** **** **** **** **** **** **** **** +1982 Pixie_BOAR **** **** **** **** **** **** **** **** +1983 Pixie_BADGER **** **** **** **** **** **** **** **** +1984 EnergyRay **** **** **** **** **** **** **** **** +1985 EnergyRay_Cold **** **** **** **** **** **** **** **** +1986 EnergyRay_Elec **** **** **** **** **** **** **** **** +1987 EnergyRay_Fire **** **** **** **** **** **** **** **** +1988 EnergyRay_Sonic **** **** **** **** **** **** **** **** +1989 Race_Silence **** **** **** **** **** **** **** **** +1990 Race_Mage_Hand **** **** **** **** **** **** **** **** +1991 Race_Elan_Resistance **** **** **** **** **** **** **** **** +1992 Race_Elan_Resiliance **** **** **** **** **** **** **** **** +1993 Race_Halfgiant_Stomp **** **** **** **** **** **** **** **** +1994 Race_Maenad_Outburst **** **** **** **** **** **** **** **** +1995 Race_Xeph_Burst **** **** **** **** **** **** **** **** +1996 Race_Vampiric_Touch **** **** **** **** **** **** **** **** +1997 SacredPurifier_SacredStrike **** **** **** **** **** **** **** **** +1998 FogCloud **** **** **** **** **** **** **** **** +1999 PsychicRenewal **** **** **** **** **** **** **** **** +2000 Mastery_Elements(Normal) **** **** **** **** **** **** **** **** +2001 Mastery_Elements(Fire) **** **** **** **** **** **** **** **** +2002 Mastery_Elements(Cold) **** **** **** **** **** **** **** **** +2003 Mastery_Elements(Acid) **** **** **** **** **** **** **** **** +2004 Mastery_Elements(Electricity) **** **** **** **** **** **** **** **** +2005 Mastery_Elements(Sonic) **** **** **** **** **** **** **** **** +2006 Mastery_Shaping **** **** **** **** **** **** **** **** +2007 Arcane_Fire **** **** **** **** **** **** **** **** +2008 Spell_Like **** **** **** **** **** **** **** **** +2009 Mastery_Elements(Master) **** **** **** **** **** **** **** **** +2010 MinOozyTouchBrown **** **** **** **** **** **** **** **** +2011 MinOozyTouchGray **** **** **** **** **** **** **** **** +2012 MinOozyTouchOchr **** **** **** **** **** **** **** **** +2013 MinOozyTouchFungus **** **** **** **** **** **** **** **** +2014 MajOozyTouchBlack **** **** **** **** **** **** **** **** +2015 MajOozyTouchCube **** **** **** **** **** **** **** **** +2016 MajOozyTouchSlime **** **** **** **** **** **** **** **** +2017 MajOozyTouchYellow **** **** **** **** **** **** **** **** +2018 OozyGlob **** **** **** **** **** **** **** **** +2019 OozyGlob(Brown) **** **** **** **** **** **** **** **** +2020 OozyGlob(Gray) **** **** **** **** **** **** **** **** +2021 OozyGlob(Ochre) **** **** **** **** **** **** **** **** +2022 OozyGlob(Fungus) **** **** **** **** **** **** **** **** +2023 SlimeWave **** **** **** **** **** **** **** **** +2024 Feat_End_Spell_Effects **** **** **** **** **** **** **** **** +2025 HavocMage_BattleCast **** **** **** **** **** **** **** **** +2026 EndPRCTreeshape **** **** **** **** **** **** **** **** +2027 BAELNORN_EYES **** **** **** **** **** **** **** **** +2028 Cohort **** **** **** **** **** **** **** **** +2029 Hath_GrCommand **** **** **** **** **** **** **** **** +2030 ShadowbaneSmite **** **** **** **** **** **** **** **** +2031 Shadowbane_SacredStealth **** **** **** **** **** **** **** **** +2032 NimbusOfLight **** **** **** **** **** **** **** **** +2033 ServanOfHeaven **** **** **** **** **** **** **** **** +2034 Ranged_Smite **** **** **** **** **** **** **** **** +2035 HathranFear **** **** **** **** **** **** **** **** +2036 SLA_I **** **** **** **** **** **** **** **** +2037 SLA_II **** **** **** **** **** **** **** **** +2038 SLA_III **** **** **** **** **** **** **** **** +2039 SLA_IV **** **** **** **** **** **** **** **** +2040 SLA_V **** **** **** **** **** **** **** **** +2041 MLGreaterTurn **** **** **** **** **** **** **** **** +2042 MLMaximizeTurn **** **** **** **** **** **** **** **** +2043 MLSearingRay **** **** **** **** **** **** **** **** +2044 MLRejuvenationOfMorn **** **** **** **** **** **** **** **** +2045 MLAuraOfRadiance **** **** **** **** **** **** **** **** +2046 MLDaylight **** **** **** **** **** **** **** **** +2047 EXTRA_SUMMONING **** **** **** **** **** **** **** **** +2048 SummonAir **** **** **** **** **** **** **** **** +2049 SummonEarth **** **** **** **** **** **** **** **** +2050 SummonFire **** **** **** **** **** **** **** **** +2051 SummonWater **** **** **** **** **** **** **** **** +2052 Anti-paladin_Summon_Mount **** **** **** **** **** **** **** **** +2053 Rune_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +2054 Rune_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +2055 Rune_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +2056 ShadowInq_PierceShadows **** **** **** **** **** **** **** **** +2057 ShadowInq_BurningLight **** **** **** **** **** **** **** **** +2058 ShadowStk_SacredDefense **** **** **** **** **** **** **** **** +2059 ShadowStk_SacredStrike **** **** **** **** **** **** **** **** +2060 BurnSpell **** **** **** **** **** **** **** **** +2061 KnightWeave_Damage **** **** **** **** **** **** **** **** +2062 KnightWeave_Heal **** **** **** **** **** **** **** **** +2063 Enthrall **** **** **** **** **** **** **** **** +2064 Spelldance_Enthrall **** **** **** **** **** **** **** **** +2065 Spelldance_Sleep **** **** **** **** **** **** **** **** +2066 MountainFortressStance **** **** **** **** **** **** **** **** +2067 CrashingMountainJuggernaught **** **** **** **** **** **** **** **** +2068 DragonsTooth **** **** **** **** **** **** **** **** +2069 AwakenTheStoneDragon **** **** **** **** **** **** **** **** +2070 Spell_Jump **** **** **** **** **** **** **** **** +2071 IRON_BODY **** **** **** **** **** **** **** **** +2072 ENLARGE_PERSON **** **** **** E 0 2 9 -2072 +2073 MASS_ENLARGE_PERSON **** **** **** E 0 2 9 -2072 +2074 REDUCE_PERSON **** Fortitude 1 R 1 **** **** **** +2075 MASS_REDUCE_PERSON **** Fortitude 1 I 1 **** **** **** +2076 ANTIMAGIC_FIELD **** **** **** P 0 3 0 -7 +2077 NONDETECTION **** **** **** **** **** **** **** **** +2078 RAINBOW_PATTERN Mind_Affecting Will 1 I 1 **** **** **** +2079 MAGE_HAND **** **** **** **** **** **** **** **** +2080 DETECT_UNDEAD **** **** **** **** **** **** **** **** +2081 GLIBNESS **** **** **** **** **** **** **** **** +2082 Imbue_Item **** **** **** **** **** **** **** **** +2083 Eldritch_Blast **** **** **** **** **** **** **** **** +2084 FIENDISH_RESILIENCE **** **** **** **** **** **** **** **** +2085 PouncingStrike **** **** **** **** **** **** **** **** +2086 SPELL_AP_DEATHKNELL **** **** **** **** **** **** **** **** +2087 SPELL_AP_CONTAGION **** **** **** **** **** **** **** **** +2088 SPELL_AP_SMITEGOOD **** **** **** **** **** **** **** **** +2089 SPELL_AP_AURAFEAR **** **** **** **** **** **** **** **** +2090 SPELL_INTUTIVATK **** **** **** **** **** **** **** **** +2091 Blacklight **** Will 1 I 1 **** **** **** +2092 DarkBolt **** **** **** **** **** **** **** **** +2093 DarkBolt_all **** **** **** **** **** **** **** **** +2094 DarkBolt_1 **** **** **** **** **** **** **** **** +2095 Darkness_Armor **** **** **** **** **** **** **** **** +2096 Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +2097 Nature_Avatar **** **** **** **** **** **** **** **** +2098 Unyielding_Roots **** **** **** H 0 **** **** **** +2099 Blessing_of_bahamut **** **** **** P 0 2 0 **** +2100 BloodClawShifting **** **** **** **** **** **** **** **** +2101 Adept_Fire_Breath **** **** **** **** **** **** **** **** +2102 Adept_Fire_Cone **** **** **** **** **** **** **** **** +2103 Adept_Fire_Line **** **** **** **** **** **** **** **** +2104 Adept_Frost_Cone **** **** **** **** **** **** **** **** +2105 Adept_Electric_Line **** **** **** **** **** **** **** **** +2106 Adept_Sickness_Cone **** **** **** **** **** **** **** **** +2107 Adept_Acid_Breath **** **** **** **** **** **** **** **** +2108 Adept_Acid_Cone **** **** **** **** **** **** **** **** +2109 Adept_Acid_Line **** **** **** **** **** **** **** **** +2110 Adept_Shaped_Breath **** **** **** **** **** **** **** **** +2111 Adept_Slow_Cone **** **** **** **** **** **** **** **** +2112 Adept_Weakening_Cone **** **** **** **** **** **** **** **** +2113 Adept_Cloud_Breath **** **** **** **** **** **** **** **** +2114 Adept_Enduring_Breath **** **** **** **** **** **** **** **** +2115 Adept_Sleep_Cone **** **** **** **** **** **** **** **** +2116 Adept_Thunder_Cone **** **** **** **** **** **** **** **** +2117 Adept_Bahamut_Line **** **** **** **** **** **** **** **** +2118 Adept_Force_Line **** **** **** **** **** **** **** **** +2119 Adept_Paralyzation_Cone **** **** **** **** **** **** **** **** +2120 Adept_Tiamat_Breath **** **** **** **** **** **** **** **** +2121 RKVDivineRecovery **** **** **** **** **** **** **** **** +2122 Mass_Contagion Disease Fortitude 1 I 1 **** **** **** +2123 SPELL_SACREDSPEED **** **** **** **** **** **** **** **** +2124 SPELL_INNERARMOR **** **** **** **** **** **** **** **** +2125 SPELL_SACREDFLAME **** **** **** **** **** **** **** **** +2126 SPELL_SHADOWSHIELD **** **** **** **** **** **** **** **** +2127 SPELL_SHADOWWALK **** **** **** **** **** **** **** **** +2128 SPELL_SHADOWDOUBLE **** **** **** **** **** **** **** **** +2129 SPELL_NS_INVISIBILITY **** **** **** **** **** **** **** **** +2130 SPELL_NS_WEB **** **** **** **** **** **** **** **** +2131 SPELL_NS_POISON **** **** **** **** **** **** **** **** +2132 SPELL_NS_SHADOWWALK **** **** **** **** **** **** **** **** +2133 SPELL_NS_POISONSPELL **** **** **** **** **** **** **** **** +2134 SPELL_UR_FAVORITE_ENEMY **** **** **** **** **** **** **** **** +2135 SPELL_DSL_SONG_STRENGTH **** **** **** **** **** **** **** **** +2136 SPELL_DSL_SONG_COMPULSION **** **** **** **** **** **** **** **** +2137 SPELL_DSL_SONG_SPEED **** **** **** **** **** **** **** **** +2138 SPELL_DSL_SONG_FEAR **** **** **** **** **** **** **** **** +2139 SPELL_DSL_SONG_HEALING **** **** **** **** **** **** **** **** +2140 SPELL_UR_HAWK_TOTEM **** **** **** **** **** **** **** **** +2141 SPELL_NS_LINGDMG **** **** **** **** **** **** **** **** +2142 SPELL_UR_ANIMALCOMPANION **** **** **** **** **** **** **** **** +2143 SPELL_UR_HIPS **** **** **** **** **** **** **** **** +2144 LuckyShot **** **** **** **** **** **** **** **** +2145 MINSTREL_SONG_CHARM **** **** **** **** **** **** **** **** +2146 RKVDivineImpteus **** **** **** **** **** **** **** **** +2147 MINSTREL_SONG_IMM_FEAR **** **** **** **** **** **** **** **** +2148 MINSTREL_SONG_SHIELD_AC **** **** **** **** **** **** **** **** +2149 MINSTREL_SONG_SONIC_WEAP **** **** **** **** **** **** **** **** +2150 MINSTREL_SONG_STRENGTH **** **** **** **** **** **** **** **** +2151 MINSTREL_SONG_CONSTITUTION **** **** **** **** **** **** **** **** +2152 MINSTREL_SONG_DEXTERITY **** **** **** **** **** **** **** **** +2153 MINSTREL_SONG_INTELLIGENCE **** **** **** **** **** **** **** **** +2154 MINSTREL_SONG_WISDOM **** **** **** **** **** **** **** **** +2155 MINSTREL_SONG_CHARISMA **** **** **** **** **** **** **** **** +2156 MINSTREL_SONG_WOUND_WHISP **** **** **** **** **** **** **** **** +2157 MINSTREL_SONG_SLEEP **** **** **** **** **** **** **** **** +2158 MINSTREL_SONG_SILENCE **** **** **** **** **** **** **** **** +2159 MINSTREL_SONG_HASTE **** **** **** **** **** **** **** **** +2160 MINSTREL_SONG_SLOW **** **** **** **** **** **** **** **** +2161 SPELL_BRAWLER_EXTRA_ATT **** **** **** **** **** **** **** **** +2162 SPELL_EPIC_DIVINE_VIGOR **** **** **** **** **** **** **** **** +2163 SPELL_INVOKE_DIVINE_WRATH **** **** **** **** **** **** **** **** +2164 SPELL_DIVINE_VIGOR **** **** **** **** **** **** **** **** +2165 SPELL_DIVINE_CLEANSING **** **** **** **** **** **** **** **** +2166 SPELL_DIVINE_RESISTANCE **** **** **** **** **** **** **** **** +2167 Consecrate **** **** **** **** **** **** **** **** +2168 BOLT_XAGYA **** **** **** **** **** **** **** **** +2169 SPELL_DISCIPLE_OF_SUN **** **** **** **** **** **** **** **** +2170 PowerAtk_Single_Radial_Master **** **** **** **** **** **** **** **** +2171 PowerAttack_0 **** **** **** **** **** **** **** **** +2172 PowerAttack_1 **** **** **** **** **** **** **** **** +2173 PowerAttack_2 **** **** **** **** **** **** **** **** +2174 PowerAttack_3 **** **** **** **** **** **** **** **** +2175 PowerAttack_4 **** **** **** **** **** **** **** **** +2176 PowerAtk_Fives_Radial **** **** **** **** **** **** **** **** +2177 PowerAttack_0 **** **** **** **** **** **** **** **** +2178 PowerAttack_5 **** **** **** **** **** **** **** **** +2179 PowerAttack_10 **** **** **** **** **** **** **** **** +2180 PowerAttack_15 **** **** **** **** **** **** **** **** +2181 PowerAttack_20 **** **** **** **** **** **** **** **** +2182 SPELL_FURIOUS_ASSAULT **** **** **** **** **** **** **** **** +2183 Summon_Energon **** **** **** **** **** **** **** **** +2184 SPELL_SMITE_UNDEAD **** **** **** **** **** **** **** **** +2185 SPELL_DIVINE_VENGEANCE **** **** **** **** **** **** **** **** +2186 SPELL_POSITIVE_ENERGY_BURST **** **** **** **** **** **** **** **** +2187 SPELL_FIST_OF_IRON **** **** **** **** **** **** **** **** +2188 RKVDivineFury **** **** **** **** **** **** **** **** +2189 Summon_Familiar **** **** **** **** **** **** **** **** +2190 RavageGoldenIce **** **** **** **** **** **** **** **** +2191 SPELL_STIGMATA **** **** **** **** **** **** **** **** +2192 SPELL_STIGMATA5 **** **** **** **** **** **** **** **** +2193 SPELL_STIGMATA2 **** **** **** **** **** **** **** **** +2194 SPELL_STIGMATA3 **** **** **** **** **** **** **** **** +2195 SPELL_STIGMATA4 **** **** **** **** **** **** **** **** +2196 SPELL_HOLYRADIANCE **** **** **** **** **** **** **** **** +2197 FEAT_ANIMALMASTERY **** **** **** **** **** **** **** **** +2198 IncreaseUnarmedEpic **** **** **** **** **** **** **** **** +2199 FEAT_ARCH_RANGEDDISARM **** **** **** **** **** **** **** **** +2200 FEAT_SONG_OF_FURY **** **** **** **** **** **** **** **** +2201 FEAT_EXTRASHOT **** **** **** **** **** **** **** **** +2202 FEAT_RANGEDTRIP **** **** **** **** **** **** **** **** +2203 Pinpoint_Accuracy **** **** **** **** **** **** **** **** +2204 Pinpoint_Accuracy2 **** **** **** **** **** **** **** **** +2205 Pinpoint_Accuracy4 **** **** **** **** **** **** **** **** +2206 Pinpoint_Accuracy6 **** **** **** **** **** **** **** **** +2207 Imp_ManyShot **** **** **** **** **** **** **** **** +2208 Imp_ManyShot5 **** **** **** **** **** **** **** **** +2209 Imp_ManyShot6 **** **** **** **** **** **** **** **** +2210 LIPS_RAPTUR **** **** **** **** **** **** **** **** +2211 TEARS_EVERGOLD **** **** **** **** **** **** **** **** +2212 Elemental_Conflag **** **** **** **** **** **** **** **** +2213 Elemental_FIRE **** **** **** **** **** **** **** **** +2214 Elemental_WATER **** **** **** **** **** **** **** **** +2215 Elemental_EARTH **** **** **** **** **** **** **** **** +2216 Elemental_AIR **** **** **** **** **** **** **** **** +2217 Smite_Evil_Raziel **** **** **** **** **** **** **** **** +2218 FEAT_MAGIC_CIRCLE_EVIL **** **** **** **** **** **** **** **** +2219 Inspire_allies **** **** **** **** **** **** **** **** +2220 TEMPUS_ENCHANT_WEAPON **** **** **** **** **** **** **** **** +2221 TEMPUS_IDENTIFY_ARMS **** **** **** **** **** **** **** **** +2222 Shadowlord_Jump **** **** **** **** **** **** **** **** +2223 Shadowlord_Blur **** **** **** **** **** **** **** **** +2224 DivineSpirit **** **** **** **** **** **** **** **** +2225 InstantClarity **** **** **** **** **** **** **** **** +2226 TrapEngineer **** **** **** **** **** **** **** **** +2227 ContagiousTouch Disease Fortitude 1 T 1 **** **** **** +2228 Blighter_Blightfire **** **** **** **** **** **** **** **** +2229 Blighter_AnimateDeadAnimal **** **** **** **** **** **** **** **** +2230 Blighter_Unbond **** **** **** **** **** **** **** **** +2231 Blighter_Plague **** **** **** **** **** **** **** **** +2232 Battlesmith_TemperedInBlood **** **** **** **** **** **** **** **** +2233 Battlesmith_Boosts **** **** **** **** **** **** **** **** +2234 PsyRogue_ShadowJump **** **** **** **** **** **** **** **** +2235 POLYMORPH_ELEM **** **** **** **** **** **** **** **** +2236 ClawDragon **** **** **** **** **** **** **** **** +2237 FrightfulPresence **** **** **** **** **** **** **** **** +2238 ShapeDragon **** **** **** **** **** **** **** **** +2239 ShapeDragonGold **** **** **** **** **** **** **** **** +2240 ShapeDragonRed **** **** **** **** **** **** **** **** +2241 ShapeDragonPrysmatic **** **** **** **** **** **** **** **** +2242 Dragon_Breath_Fire **** **** **** **** **** **** **** **** +2243 Dragon_Breath_Gas **** **** **** **** **** **** **** **** +2244 Dragon_Breath_Prismatic **** **** **** **** **** **** **** **** +2245 ManyShot **** **** **** **** **** **** **** **** +2246 ManyShot2 **** **** **** **** **** **** **** **** +2247 Magic_Missile **** **** 1 R 1 **** **** **** +2248 ManyShot4 **** **** **** **** **** **** **** **** +2249 ManyShot6 **** **** **** **** **** **** **** **** +2250 Examine_Recipe **** **** **** **** **** **** **** **** +2251 Read **** **** **** **** **** **** **** **** +2252 Item_Creation **** **** **** **** **** **** **** **** +2253 Craft_Item **** **** **** **** **** **** **** **** +2254 Examine_Recipe **** **** **** **** **** **** **** **** +2255 NEW_CRAFTING **** **** **** **** **** **** **** **** +2256 Spelldance_Confuse **** **** **** **** **** **** **** **** +2257 Spelldance **** **** **** **** **** **** **** **** +2258 IncreaseUnarmedShape **** **** **** **** **** **** **** **** +2259 SPELL_AP_TURNOUTS **** **** **** **** **** **** **** **** +2260 Riddle_of_Awareness **** **** **** **** **** **** **** **** +2261 Happo_Zanshin **** **** **** **** **** **** **** **** +2262 Riddle_of_Interaction **** **** **** **** **** **** **** **** +2263 Blind_Sight **** **** **** **** **** **** **** **** +2264 Hitsu_Do **** **** **** **** **** **** **** **** +2265 Walk_Through_the_Mountains **** **** **** **** **** **** **** **** +2266 Riddle_of_Invulnerability **** **** **** **** **** **** **** **** +2267 Spelldance_Max **** **** **** **** **** **** **** **** +2268 Bottle_Proficiency **** **** **** **** **** **** **** **** +2269 Stagger **** **** **** **** **** **** **** **** +2270 Swaying_Waist **** **** **** **** **** **** **** **** +2271 Spelldance_Emp **** **** **** **** **** **** **** **** +2272 Lurch **** **** **** **** **** **** **** **** +2273 Drunken_Embrace **** **** **** **** **** **** **** **** +2274 For_Medicinal_Purposes **** **** **** **** **** **** **** **** +2275 Breath_of_Flame **** **** **** **** **** **** **** **** +2276 Spelldance_Ext **** **** **** **** **** **** **** **** +2277 ACP_Fighting_Stance_change **** **** **** **** **** **** **** **** +2278 ACP_Fighting_Stance_KENSAI **** **** **** **** **** **** **** **** +2279 ACP_Fighting_Stance_ASSASSIN **** **** **** **** **** **** **** **** +2280 ACP_Fighting_Stance_HEAVY **** **** **** **** **** **** **** **** +2281 ACP_Fighting_Stance_FENCING **** **** **** **** **** **** **** **** +2282 ACP_Fighting_Stance_NORMAL **** **** **** **** **** **** **** **** +2283 Undead_Wild_Shape_Master **** **** **** **** **** **** **** **** +2284 Undead_Wild_Shape_BROWN_BEAR **** **** **** **** **** **** **** **** +2285 Undead_Wild_Shape_PANTHER **** **** **** **** **** **** **** **** +2286 Undead_Wild_Shape_WOLF **** **** **** **** **** **** **** **** +2287 Undead_Wild_Shape_BOAR **** **** **** **** **** **** **** **** +2288 Undead_Wild_Shape_BADGER **** **** **** **** **** **** **** **** +2289 Ashrati_Bodylamp **** **** **** **** **** **** **** **** +2290 RAY_CHARM_PERSON **** **** **** **** **** **** **** **** +2291 RAY_CHARM_MONSTER **** **** **** **** **** **** **** **** +2292 RAY_SLEEP **** **** **** **** **** **** **** **** +2293 RAY_FLESH_TO_STONE **** **** **** **** **** **** **** **** +2294 RAY_DISINTIGRATE **** **** **** **** **** **** **** **** +2295 RAY_FEAR **** **** **** **** **** **** **** **** +2296 RAY_SLOW **** **** **** **** **** **** **** **** +2297 RAY_INFLICT_MODERATE_WOUNDS **** **** **** **** **** **** **** **** +2298 RAY_FINGER_OF_DEATH **** **** **** **** **** **** **** **** +2299 PsyRogue_BlindSpot **** **** **** **** **** **** **** **** +2300 SPELL_FOM_DIVINE_SONG_BLESS **** **** **** **** **** **** **** **** +2301 SPELL_FOM_DIVINE_SONG_CONVICTION **** **** **** **** **** **** **** **** +2302 SPELL_FOM_DIVINE_SONG_CURELIGHT **** **** **** **** **** **** **** **** +2303 SPELL_FOM_DIVINE_SONG_REMOVEFEAR **** **** **** **** **** **** **** **** +2304 SPELL_FOM_DIVINE_SONG_SANCTUARY **** **** **** **** **** **** **** **** +2305 SPELL_FOM_DIVINE_SONG_SHIELDFAITH **** **** **** **** **** **** **** **** +2306 SPELL_FOM_DIVINE_SONG_AID **** **** **** **** **** **** **** **** +2307 SPELL_FOM_DIVINE_SONG_BULLSTRENGTH **** **** **** **** **** **** **** **** +2308 SPELL_FOM_DIVINE_SONG_CUREMODERATE **** **** **** **** **** **** **** **** +2309 SPELL_FOM_DIVINE_SONG_EAGLESPLENDOR **** **** **** **** **** **** **** **** +2310 SPELL_FOM_DIVINE_SONG_ENDURANCE **** **** **** **** **** **** **** **** +2311 SPELL_FOM_DIVINE_SONG_FOXCUNNING **** **** **** **** **** **** **** **** +2312 SPELL_FOM_DIVINE_SONG_LESSRESTORE **** **** **** **** **** **** **** **** +2313 SPELL_FOM_DIVINE_SONG_OWLWISDOM **** **** **** **** **** **** **** **** +2314 SPELL_FOM_DIVINE_SONG_CLAIRVOYANCE **** **** **** **** **** **** **** **** +2315 SPELL_FOM_DIVINE_SONG_CLARITY **** **** **** **** **** **** **** **** +2316 SPELL_FOM_DIVINE_SONG_CURESERIOUS **** **** **** **** **** **** **** **** +2317 SPELL_FOM_DIVINE_SONG_NEGATIVEPROT **** **** **** **** **** **** **** **** +2318 SPELL_FOM_DIVINE_SONG_PRAYER **** **** **** **** **** **** **** **** +2319 SPELL_FOM_DIVINE_SONG_PROTELEMENTS **** **** **** **** **** **** **** **** +2320 SPELL_FOM_DIVINE_SONG_REMOVECURSE **** **** **** **** **** **** **** **** +2321 SPELL_FOM_DIVINE_SONG_CURECRITICAL **** **** **** **** **** **** **** **** +2322 SPELL_FOM_DIVINE_SONG_DEATHWARD **** **** **** **** **** **** **** **** +2323 SPELL_FOM_DIVINE_SONG_FREEDOMMOVEMENT **** **** **** **** **** **** **** **** +2324 SPELL_FOM_DIVINE_SONG_PANACEA **** **** **** **** **** **** **** **** +2325 SPELL_FOM_DIVINE_SONG_RESTORATION **** **** **** **** **** **** **** **** +2326 SPELL_FOM_DIVINE_SONG_STONESKIN **** **** **** **** **** **** **** **** +2327 SPELL_FOM_DIVINE_SONG_TRUESEEING **** **** **** **** **** **** **** **** +2328 SPELL_FOM_DIVINE_SONG_MONSTREGEN **** **** **** **** **** **** **** **** +2329 SPELL_FOM_DIVINE_SONG_RAISEDEAD **** **** **** **** **** **** **** **** +2330 SPELL_FOM_DIVINE_SONG_SPELLRESISTANCE **** **** **** **** **** **** **** **** +2331 SPELL_FOM_ENCOREPERFORMANCE **** **** **** **** **** **** **** **** +2332 Ashrati_BodylampDazzle **** **** **** **** **** **** **** **** +2333 Killoren_Aspect_A **** **** **** **** **** **** **** **** +2334 Killoren_Aspect_D **** **** **** **** **** **** **** **** +2335 Killoren_Aspect_H **** **** **** **** **** **** **** **** +2336 Killoren_Hunter **** **** **** **** **** **** **** **** +2337 Skarn_Spines **** **** **** **** **** **** **** **** +2338 ScorpionsGrasp **** **** **** **** **** **** **** **** +2339 CultistShatteredPeak_SmiteMage **** **** **** **** **** **** **** **** +2340 AwesomeBlow **** **** **** **** **** **** **** **** +2341 BloodedOne_War_Cry **** **** **** **** **** **** **** **** +2342 Desecrate **** **** **** **** **** **** **** **** +2343 BlastOfForce **** Fortitude 1 R 1 **** **** **** +2344 ShieldBash **** **** **** **** **** **** **** **** +2345 ShieldCharge **** **** **** **** **** **** **** **** +2346 ShieldSlam **** **** **** **** **** **** **** **** +2347 PhantomSteed **** **** **** **** **** **** **** **** +2348 GaseousForm **** **** **** **** **** **** **** **** +2349 begin_psionics **** **** **** **** **** **** **** **** +2350 Augment_QuickSelects **** **** **** **** **** **** **** **** +2351 Augment_Digits_0_4 **** **** **** **** **** **** **** **** +2352 Augment_Digits_5_9 **** **** **** **** **** **** **** **** +2353 Augment_Tens **** **** **** **** **** **** **** **** +2354 Augment_StartConvo **** **** **** **** **** **** **** **** +2355 Augment_Off **** **** **** **** **** **** **** **** +2356 Augment_ToggleMaxAugment **** **** **** **** **** **** **** **** +2357 Augment_Quickselect1 **** **** **** **** **** **** **** **** +2358 Augment_Quickselect2 **** **** **** **** **** **** **** **** +2359 Augment_0 **** **** **** **** **** **** **** **** +2360 Augment_1 **** **** **** **** **** **** **** **** +2361 Augment_2 **** **** **** **** **** **** **** **** +2362 Augment_3 **** **** **** **** **** **** **** **** +2363 Augment_4 **** **** **** **** **** **** **** **** +2364 Augment_5 **** **** **** **** **** **** **** **** +2365 Augment_6 **** **** **** **** **** **** **** **** +2366 Augment_7 **** **** **** **** **** **** **** **** +2367 Augment_8 **** **** **** **** **** **** **** **** +2368 Augment_9 **** **** **** **** **** **** **** **** +2369 Augment_00 **** **** **** **** **** **** **** **** +2370 Augment_10 **** **** **** **** **** **** **** **** +2371 Augment_20 **** **** **** **** **** **** **** **** +2372 Augment_30 **** **** **** **** **** **** **** **** +2373 Augment_40 **** **** **** **** **** **** **** **** +2374 Augment_QuickSelects_2 **** **** **** **** **** **** **** **** +2375 **** **** **** **** **** **** **** **** **** +2376 **** **** **** **** **** **** **** **** **** +2377 Wilder_WildSurge_Off **** **** **** **** **** **** **** **** +2378 Wilder_WildSurge_1-5_RadialMaster **** **** **** **** **** **** **** **** +2379 Wilder_WildSurge_6-10_RadialMaster **** **** **** **** **** **** **** **** +2380 Wilder_WildSurge_1 **** **** **** **** **** **** **** **** +2381 Wilder_WildSurge_2 **** **** **** **** **** **** **** **** +2382 Wilder_WildSurge_3 **** **** **** **** **** **** **** **** +2383 Wilder_WildSurge_4 **** **** **** **** **** **** **** **** +2384 Wilder_WildSurge_5 **** **** **** **** **** **** **** **** +2385 Wilder_WildSurge_6 **** **** **** **** **** **** **** **** +2386 Wilder_WildSurge_7 **** **** **** **** **** **** **** **** +2387 Wilder_WildSurge_8 **** **** **** **** **** **** **** **** +2388 Wilder_WildSurge_9 **** **** **** **** **** **** **** **** +2389 Wilder_WildSurge_10 **** **** **** **** **** **** **** **** +2390 Wilder_WildSurge_11 **** **** **** **** **** **** **** **** +2391 **** **** **** **** **** **** **** **** **** +2392 Augment_Quickselect3 **** **** **** **** **** **** **** **** +2393 Augment_Quickselect4 **** **** **** **** **** **** **** **** +2394 Augment_Quickselect5 **** **** **** **** **** **** **** **** +2395 Augment_Quickselect6 **** **** **** **** **** **** **** **** +2396 Augment_Quickselect7 **** **** **** **** **** **** **** **** +2397 **** **** **** **** **** **** **** **** **** +2398 Manifest_Shield_of_Thought **** **** **** **** **** **** **** **** +2399 Spiritual_Force **** **** **** **** **** **** **** **** +2400 Manifest_Mindblade **** **** **** **** **** **** **** **** +2401 Throw_Mindblade **** **** **** **** **** **** **** **** +2402 Psychic_Strike **** **** **** **** **** **** **** **** +2403 Free_Draw **** **** **** **** **** **** **** **** +2404 Shape_Mindblade_RadialMaster **** **** **** **** **** **** **** **** +2405 Shape_Mindblade_Shortsword **** **** **** **** **** **** **** **** +2406 Shape_Mindblade_2xShortsword **** **** **** **** **** **** **** **** +2407 Shape_Mindblade_Longsword **** **** **** **** **** **** **** **** +2408 Shape_Mindblade_Bastardsword **** **** **** **** **** **** **** **** +2409 Mindblade_Enhancement **** **** **** **** **** **** **** **** +2410 Bladewind **** **** **** **** **** **** **** **** +2411 KnifeToTheSoul_RadialMaster **** **** **** **** **** **** **** **** +2412 KnifeToTheSoul_Off **** **** **** **** **** **** **** **** +2413 KnifeToTheSoul_Intelligence **** **** **** **** **** **** **** **** +2414 KnifeToTheSoul_Wisdom **** **** **** **** **** **** **** **** +2415 KnifeToTheSoul_Charisma **** **** **** **** **** **** **** **** +2416 KnifeToTheSoul_DieRadial1_Radialmaster **** **** **** **** **** **** **** **** +2417 KnifeToTheSoul_1Die **** **** **** **** **** **** **** **** +2418 KnifeToTheSoul_2Die **** **** **** **** **** **** **** **** +2419 KnifeToTheSoul_3Die **** **** **** **** **** **** **** **** +2420 KnifeToTheSoul_4Die **** **** **** **** **** **** **** **** +2421 KnifeToTheSoul_5Die **** **** **** **** **** **** **** **** +2422 KnifeToTheSoul_DieRadial2_Radialmaster **** **** **** **** **** **** **** **** +2423 KnifeToTheSoul_6Die **** **** **** **** **** **** **** **** +2424 KnifeToTheSoul_7Die **** **** **** **** **** **** **** **** +2425 KnifeToTheSoul_8Die **** **** **** **** **** **** **** **** +2426 KnifeToTheSoul_9Die **** **** **** **** **** **** **** **** +2427 KnifeToTheSoul_10Die **** **** **** **** **** **** **** **** +2428 ChangeHandedness **** **** **** **** **** **** **** **** +2429 Mindblade_Lucky **** **** **** **** **** **** **** **** +2430 Healing_Kicker_1_Sanctuary **** **** **** **** **** **** **** **** +2431 Healing_Kicker_2_ReflexSaves **** **** **** **** **** **** **** **** +2432 Healing_Kicker_3_Aid **** **** **** **** **** **** **** **** +2433 Spontaneous_Heal **** **** **** **** **** **** **** **** +2434 StrengthOfTwo **** **** **** **** **** **** **** **** +2435 OotBI_RangedPrecision **** **** **** **** **** **** **** **** +2436 OotBI_GreaterWeaponFocus **** **** **** **** **** **** **** **** +2437 Thrallherd_Master **** **** **** **** **** **** **** **** +2438 Thrallherd_Fighter **** **** **** **** **** **** **** **** +2439 Thrallherd_Cleric **** **** **** **** **** **** **** **** +2440 Thrallherd_Rogue **** **** **** **** **** **** **** **** +2441 Thrallherd_Wizard **** **** **** **** **** **** **** **** +2442 PsionicCharm **** **** **** **** **** **** **** **** +2443 PsionicDominate **** **** **** **** **** **** **** **** +2444 Twofold_Master **** **** **** **** **** **** **** **** +2445 Twofold_Fighter **** **** **** **** **** **** **** **** +2446 Twofold_Cleric **** **** **** **** **** **** **** **** +2447 Twofold_Rogue **** **** **** **** **** **** **** **** +2448 Twofold_Wizard **** **** **** **** **** **** **** **** +2449 **** **** **** **** **** **** **** **** **** +2450 Warmind_PersSuperior **** **** **** **** **** **** **** **** +2451 Warmind_DefPosture **** **** **** **** **** **** **** **** +2452 Warmind_OverwhelmForce **** **** **** **** **** **** **** **** +2453 **** **** **** **** **** **** **** **** **** +2454 ShadowmindDistract **** **** **** **** **** **** **** **** +2455 ShadowmindCloudMind **** **** **** **** **** **** **** **** +2456 ShadowmindCloudMindMass **** **** **** **** **** **** **** **** +2457 ShadowmindMindStab **** **** **** **** **** **** **** **** +2458 **** **** **** **** **** **** **** **** **** +2459 DiamondDragon_Claws **** **** **** **** **** **** **** **** +2460 DiamondDragon_Breath **** **** **** **** **** **** **** **** +2461 DiamondDragon_Wings **** **** **** **** **** **** **** **** +2462 DiamondDragon_Tail **** **** **** **** **** **** **** **** +2463 DiamondDragon_Aura **** **** **** **** **** **** **** **** +2464 DiamondDragon_Breath_Cold **** **** **** **** **** **** **** **** +2465 DiamondDragon_Breath_Electric **** **** **** **** **** **** **** **** +2466 DiamondDragon_Breath_Fire **** **** **** **** **** **** **** **** +2467 DiamondDragon_Breath_Sonic **** **** **** **** **** **** **** **** +2468 Psionic_Paralysis_Sleep_Immunity **** **** **** **** **** **** **** **** +2469 **** **** **** **** **** **** **** **** **** +2470 FistOfDalQuor_StunningStrike **** **** **** **** **** **** **** **** +2471 **** **** **** **** **** **** **** **** **** +2472 ForestMaster_ForestDominion **** **** **** **** **** **** **** **** +2473 ForestMaster_GreatMalletRadialMaster **** **** **** **** **** **** **** **** +2474 ForestMaster_IcyMallet **** **** **** **** **** **** **** **** +2475 ForestMaster_ShockMallet **** **** **** **** **** **** **** **** +2476 ForestMaster_DeepRoots **** **** **** **** **** **** **** **** +2477 **** **** **** **** **** **** **** **** **** +2478 **** **** **** **** **** **** **** **** **** +2479 SPELL_CHASING_PERFECTION **** **** **** **** **** **** **** **** +2480 SPELL_FORCE_MISSILES **** **** 1 R 1 **** **** **** +2481 SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +2482 SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +2483 SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +2484 SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +2485 SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +2486 SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +2487 SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +2488 SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +2489 ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +2490 ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +2491 ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +2492 ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +2493 ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +2494 SPELL_DIVINE_SACRIFICE_2 **** **** **** **** **** **** **** **** +2495 SPELL_DIVINE_SACRIFICE_4 **** **** **** **** **** **** **** **** +2496 SPELL_DIVINE_SACRIFICE_6 **** **** **** **** **** **** **** **** +2497 SPELL_DIVINE_SACRIFICE_8 **** **** **** **** **** **** **** **** +2498 SPELL_DIVINE_SACRIFICE_10 **** **** **** **** **** **** **** **** +2499 Command_Undead **** **** **** **** **** **** **** **** +2500 SPELL_PRC_EXTRA_STUNNING **** **** **** **** **** **** **** **** +2501 SPELL_EF_FIST_OF_ENERGY **** **** **** **** **** **** **** **** +2502 SPELL_EF_FIST_OF_ENERGY_FIRE **** **** **** **** **** **** **** **** +2503 SPELL_EF_FIST_OF_ENERGY_ELECTRICITY **** **** **** **** **** **** **** **** +2504 SPELL_EF_SPELL_SELECT **** **** **** **** **** **** **** **** +2505 SPELL_EF_SPELL_SELECT_CONVO **** **** **** **** **** **** **** **** +2506 SPELL_EF_SPELL_SELECT_QUICK1 **** **** **** **** **** **** **** **** +2507 SPELL_EF_SPELL_SELECT_QUICK2 **** **** **** **** **** **** **** **** +2508 SPELL_EF_SPELL_SELECT_QUICK3 **** **** **** **** **** **** **** **** +2509 SPELL_EF_SPELL_SELECT_QUICK4 **** **** **** **** **** **** **** **** +2510 SPELL_EF_ARCANE_FIST **** **** **** **** **** **** **** **** +2511 SPELL_EF_ARCANE_REJUVENATION **** **** **** **** **** **** **** **** +2512 ABERRATE **** **** **** **** **** **** **** **** +2513 ABSORB_STRENGTH **** **** **** **** **** **** **** **** +2514 ABYSSAL_MIGHT **** **** **** E 0 3 0 **** +2515 ANGRY_ACHE **** Fortitude 1 R 1 **** **** **** +2516 APOCALYPSE_FROM_THE_SKY **** **** **** **** **** **** **** **** +2517 APOCALYPSE_FROM_THE_SKY_FIRE **** **** **** **** **** **** **** **** +2518 APOCALYPSE_FROM_THE_SKY_ACID **** **** **** **** **** **** **** **** +2519 APOCALYPSE_FROM_THE_SKY_SONIC **** **** **** **** **** **** **** **** +2520 BESTOW_WOUND **** Fortitude 1 T 1 **** **** **** +2521 BODAK_BIRTH **** **** **** **** **** **** **** **** +2522 BONEBLADE **** **** **** **** **** **** **** **** +2523 BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +2524 BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +2525 BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +2526 BONEBLAST **** Fortitude 1 T 1 **** **** **** +2527 CALL_DRETCH_HORDE **** **** **** **** **** **** **** **** +2528 CALL_LEMURE_HORDE **** **** **** **** **** **** **** **** +2529 CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +2530 CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +2531 CLOUD_OF_THE_ACHAIERAI **** Fortitude 1 I 1 **** **** **** +2532 CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +2533 CRUSHING_FIST_OF_SPITE **** Reflex 1 I 1 **** **** **** +2534 CURSE_OF_THE_PUTRID_HUSK Fear Will 1 R 1 **** **** **** +2535 DAMNING_DARKNESS **** **** **** I 1 **** **** **** +2536 DEATH_BY_THORNS **** **** **** **** **** **** **** **** +2537 DEMONCALL **** **** **** **** **** **** **** **** +2538 DEMONFLESH **** **** **** **** **** **** **** **** +2539 DESPOIL **** **** **** **** **** **** **** **** +2540 DEVILS_EGO **** **** **** **** **** **** **** **** +2541 DEVILS_EYE **** **** **** **** **** **** **** **** +2542 DEVILS_TAIL **** **** **** **** **** **** **** **** +2543 DREAD_WORD **** **** **** **** **** **** **** **** +2544 DRUG_RESISTANCE **** **** **** **** **** **** **** **** +2545 ECTOPLASMIC_ENCHANCEMENT **** **** **** **** **** **** **** **** +2546 ETERNITY_OF_TORTURE **** **** **** **** **** **** **** **** +2547 EVIL_EYE **** Will 1 R 1 **** **** **** +2548 EYE_OF_THE_BEHOLDER **** **** **** **** **** **** **** **** +2549 EVIL_WEATHER **** **** **** **** **** **** **** **** +2550 EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +2551 EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +2552 EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +2553 EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +2554 EXTRACT_DRUG **** **** **** **** **** **** **** **** +2555 EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +2556 EXTRACT_VODARE **** **** **** **** **** **** **** **** +2557 EXTRACT_SANNISH **** **** **** **** **** **** **** **** +2558 EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +2559 FANGS_OF_THE_VAMPIRE_KING **** **** **** **** **** **** **** **** +2560 FIENDISH_CLARITY **** **** **** E 0 3 0 **** +2561 FLESH_ARMOR **** **** **** **** **** **** **** **** +2562 FLESH_RIPPER **** **** 1 R 1 **** **** **** +2563 GRIM_REVENGE **** Fortitude 1 R 1 **** **** **** +2564 GUTWRENCH Death Fortitude 1 R 1 **** **** **** +2565 HEARTACHE Mind_Affecting Will 1 R 1 **** **** **** +2566 HEARTCLUTCH **** Fortitude 1 R 1 **** **** **** +2567 HELLFIRE **** **** **** **** **** **** **** **** +2568 HELLFIRE_STORM **** **** **** **** **** **** **** **** +2569 HELLS_POWER **** **** **** **** **** **** **** **** +2570 LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +2571 LIQUID_PAIN **** **** **** **** **** **** **** **** +2572 MORALITY_UNDONE **** **** **** **** **** **** **** **** +2573 POWER_LEECH **** **** **** **** **** **** **** **** +2574 RAPTURE_OF_RUPTURE **** **** **** **** **** **** **** **** +2575 REALITY_BLIND Mind_Affecting Will 1 R 1 **** **** **** +2576 RED_FESTER **** **** **** **** **** **** **** **** +2577 RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +2578 ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +2579 SEETHING_EYEBANE **** **** **** **** **** **** **** **** +2580 SHRIVELING Negative Reflex 1 R 1 **** **** **** +2581 SONG_OF_FESTERING_DEATH **** Fortitude 1 R 1 **** **** **** +2582 SORROW Mind_Affecting Will 1 R 1 **** **** **** +2583 EXALTED_RAIMENT **** **** **** **** **** **** **** **** +2584 SPORES_OF_THE_VROCK **** Fortitude 1 I 1 **** **** **** +2585 STUNNING_SCREECH **** Fortitude 1 I 1 **** **** **** +2586 STOP_HEART **** Fortitude 1 R 1 **** **** **** +2587 THOUSAND_NEEDLES **** Fortitude 1 R 1 **** **** **** +2588 TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +2589 TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +2590 UNHEAVENED **** **** **** P 0 3 14 **** +2591 UNLIVING_WEAPON **** **** **** **** **** **** **** **** +2592 UTTERDARK **** **** **** I 1 **** **** **** +2593 WAVE_OF_GRIEF Mind_Affecting Will 1 I 1 **** **** **** +2594 WAVE_OF_PAIN **** Fortitude 1 I 1 **** **** **** +2595 WRACK **** Fortitude 1 I 1 **** **** **** +2596 WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +2597 AGONY **** **** **** **** **** **** **** **** +2598 BACCARAN **** **** **** **** **** **** **** **** +2599 DEVILWEED **** **** **** **** **** **** **** **** +2600 LUHIX **** **** **** **** **** **** **** **** +2601 MUSHROOM_POWDER **** **** **** **** **** **** **** **** +2602 SANNISH **** **** **** **** **** **** **** **** +2603 TERRAN_BRANDY **** **** **** **** **** **** **** **** +2604 VODARE **** **** **** **** **** **** **** **** +2605 LESSER_SHIVERING_TOUCH **** **** 1 R 1 **** **** **** +2606 SHIVERING_TOUCH **** **** 1 R 1 **** **** **** +2607 AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +2608 BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +2609 DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +2610 DIAMOND_SPRAY **** **** **** **** **** **** **** **** +2611 DRAGON_CLOUD **** **** **** **** **** **** **** **** +2612 EXALTED_FURY **** **** **** **** **** **** **** **** +2613 HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +2614 PHIERANS_RESOLVE **** **** **** **** **** **** **** **** +2615 PHOENIX_FIRE **** **** **** **** **** **** **** **** +2616 RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +2617 SICKEN_EVIL **** **** **** **** **** **** **** **** +2618 STORM_OF_SHARDS **** **** **** **** **** **** **** **** +2619 SUNMANTLE **** **** **** **** **** **** **** **** +2620 TWILIGHT_LUCK **** **** **** **** **** **** **** **** +2621 AMBER_SARCOPHAGUS **** **** 1 R 1 **** **** **** +2622 BLINDING_GLORY **** **** **** I 1 **** **** **** +2623 BOLT_OF_GLORY **** **** **** **** **** **** **** **** +2624 CALL_FAITHFUL_SERVANTS **** **** **** S 0 2 0 **** +2625 CELESTIAL_BLOOD **** **** **** P 0 2 7 **** +2626 CHAAVS_LAUGH **** Will 1 D 1 **** **** **** +2627 CONVERT_WAND **** **** **** **** **** **** **** **** +2628 DANCING_WEB **** Reflex 1 I 1 **** **** **** +2629 DIVINE_SACRIFICE **** **** **** **** **** **** **** **** +2630 ELATION **** **** **** E 0 2 0 **** +2631 ENERGIZE_POTION **** **** **** **** **** **** **** **** +2632 EYES_OF_THE_AVORAL **** **** **** E 0 3 5 **** +2633 VisionOfGlory **** **** **** **** **** **** **** **** +2634 LANTERN_LIGHT **** **** 1 R 1 **** **** **** +2635 LAST_JUDGEMENT **** **** **** **** **** **** **** **** +2636 LUMINOUS_ARMOR **** **** **** P 0 3 8 -3 +2637 GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +2638 RAIN_OF_BLACK_TULIPS **** **** **** **** **** **** **** **** +2639 RAIN_OF_ROSES **** **** **** **** **** **** **** **** +2640 RAY_OF_HOPE **** **** **** E 0 2 9 **** +2641 RIGHTEOUS_SMITE **** Will 1 I 1 **** **** **** +2642 STARMANTLE **** **** **** P 0 2 7 **** +2643 TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +2644 MASOCHISM **** **** **** E 0 2 0 **** +2645 ADDICTION **** **** **** **** **** **** **** **** +2646 ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +2647 ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +2648 ADDICTION_VODARE **** **** **** **** **** **** **** **** +2649 ADDICTION_AGONY **** **** **** **** **** **** **** **** +2650 **StartDomainReserver** **** **** **** **** **** **** **** **** +2651 Sun_Domain_Power **** **** **** **** **** **** **** **** +2652 **** **** **** **** **** **** **** **** **** +2653 **** **** **** **** **** **** **** **** **** +2654 **** **** **** **** **** **** **** **** **** +2655 **** **** **** **** **** **** **** **** **** +2656 **** **** **** **** **** **** **** **** **** +2657 **** **** **** **** **** **** **** **** **** +2658 **** **** **** **** **** **** **** **** **** +2659 **** **** **** **** **** **** **** **** **** +2660 **** **** **** **** **** **** **** **** **** +2661 **** **** **** **** **** **** **** **** **** +2662 **** **** **** **** **** **** **** **** **** +2663 **** **** **** **** **** **** **** **** **** +2664 **** **** **** **** **** **** **** **** **** +2665 **** **** **** **** **** **** **** **** **** +2666 **** **** **** **** **** **** **** **** **** +2667 **** **** **** **** **** **** **** **** **** +2668 **** **** **** **** **** **** **** **** **** +2669 **** **** **** **** **** **** **** **** **** +2670 **** **** **** **** **** **** **** **** **** +2671 **** **** **** **** **** **** **** **** **** +2672 **** **** **** **** **** **** **** **** **** +2673 **** **** **** **** **** **** **** **** **** +2674 **** **** **** **** **** **** **** **** **** +2675 **** **** **** **** **** **** **** **** **** +2676 **** **** **** **** **** **** **** **** **** +2677 **** **** **** **** **** **** **** **** **** +2678 **** **** **** **** **** **** **** **** **** +2679 **** **** **** **** **** **** **** **** **** +2680 **** **** **** **** **** **** **** **** **** +2681 **** **** **** **** **** **** **** **** **** +2682 **** **** **** **** **** **** **** **** **** +2683 **** **** **** **** **** **** **** **** **** +2684 **** **** **** **** **** **** **** **** **** +2685 **** **** **** **** **** **** **** **** **** +2686 **** **** **** **** **** **** **** **** **** +2687 **** **** **** **** **** **** **** **** **** +2688 **** **** **** **** **** **** **** **** **** +2689 **** **** **** **** **** **** **** **** **** +2690 **EndDomainReserver** **** **** **** **** **** **** **** **** +2691 end_psionics **** **** **** **** **** **** **** **** +2692 BATTLE_RAGE **** **** **** **** **** **** **** **** +2693 Teleport_Management_Radial_Master **** **** **** **** **** **** **** **** +2694 Teleport_Mark_Location **** **** **** **** **** **** **** **** +2695 Teleport_Options_Dialog **** **** **** **** **** **** **** **** +2696 Teleport_End_Quickselect **** **** **** **** **** **** **** **** +2697 Teleport_Quickselect_1 **** **** **** **** **** **** **** **** +2698 Teleport_Quickselect_2 **** **** **** **** **** **** **** **** +2699 PnP_Scry_Familiar **** **** **** **** **** **** **** **** +2700 FRENZY **** **** **** **** **** **** **** **** +2701 INSPIRE_FRENZY **** **** **** **** **** **** **** **** +2702 (*Deprecated*)SUPREME_POWER_ATTACK **** **** **** **** **** **** **** **** +2703 REMOVE_FRENZY **** **** **** **** **** **** **** **** +2704 PnP_Familiar **** **** **** **** **** **** **** **** +2705 Frostrager_OneTwoPunch **** **** **** **** **** **** **** **** +2706 RANCOR **** **** **** **** **** **** **** **** +2707 FH_DEATH_ATTACK **** **** **** **** **** **** **** **** +2708 COMMAND_THE_HORDE **** **** **** **** **** **** **** **** +2709 BLINDING_SPITTLE **** **** **** **** **** **** **** **** +2710 BLINDSIGHT_5_FT **** **** **** **** **** **** **** **** +2711 BLINDSIGHT_10_FT **** **** **** **** **** **** **** **** +2712 OW_INSPIRE_COURAGE **** **** **** **** **** **** **** **** +2713 FINAL_RAGE **** **** **** **** **** **** **** **** +2714 RELEASE_HORDE **** **** **** **** **** **** **** **** +2715 GATHER_HORDE_I **** **** **** **** **** **** **** **** +2716 GATHER_HORDE_II **** **** **** **** **** **** **** **** +2717 Gather_Skull_Splitter **** **** **** **** **** **** **** **** +2718 Gather_Weapon_Master **** **** **** **** **** **** **** **** +2719 Gather_Axe_Thrower **** **** **** **** **** **** **** **** +2720 Gather_Shaman **** **** **** **** **** **** **** **** +2721 BLOOD_OF_THE_WARLORD **** **** **** **** **** **** **** **** +2722 Dirge_Sorrow **** **** **** **** **** **** **** **** +2723 InlindlSchool **** **** **** **** **** **** **** **** +2724 SpinningHalberd **** **** **** **** **** **** **** **** +2725 Shou_Flurry_Light **** **** **** **** **** **** **** **** +2726 Shou_Flurry_All **** **** **** **** **** **** **** **** +2727 FEAT_JUMP **** **** **** **** **** **** **** **** +2728 Battlerager_damage **** **** **** **** **** **** **** **** +2729 Hextor_damage **** **** **** **** **** **** **** **** +2730 Thayanknight_damage **** **** **** **** **** **** **** **** +2731 Man_at_arms_damage **** **** **** **** **** **** **** **** +2732 SetCompositeAttackBonus **** **** **** **** **** **** **** **** +2733 KnightChalice_damage **** **** **** **** **** **** **** **** +2734 UnarmedAttackPenetration **** **** **** **** **** **** **** **** +2735 SPELL_TOG_CHARM **** **** **** **** **** **** **** **** +2736 TOG_SUMMON_DEMON **** **** **** **** **** **** **** **** +2737 TOG_SUMMON_SUCCUBUS **** **** **** **** **** **** **** **** +2738 TOG_SUMMON_VROCK **** **** **** **** **** **** **** **** +2739 TOG_SUMMON_GLABREZU **** **** **** **** **** **** **** **** +2740 TOG_SUMMON_MARILITH **** **** **** **** **** **** **** **** +2741 TOG_SUMMON_BALOR **** **** **** **** **** **** **** **** +2742 Ninja_Ghost_Step **** **** **** **** **** **** **** **** +2743 Ninja_Ghost_Strike **** **** **** **** **** **** **** **** +2744 Ninja_Ghost_walk **** **** **** **** **** **** **** **** +2745 Ninja_Greater_Ki_Dodge **** **** **** **** **** **** **** **** +2746 Ninja_Ki_Dodge **** **** **** **** **** **** **** **** +2747 Ninja_Ghost_Step_2 **** **** **** **** **** **** **** **** +2748 SlayerOfDomielDivineGrace **** **** **** **** **** **** **** **** +2749 FEAT_CLIMB **** **** **** **** **** **** **** **** +2750 Unmovable **** **** **** **** **** **** **** **** +2751 Unstoppable **** **** **** **** **** **** **** **** +2752 Beguiling_Nature **** **** **** **** **** **** **** **** +2753 Suggestion **** **** **** **** **** **** **** **** +2754 Baal_Summon_1 **** **** **** **** **** **** **** **** +2755 Baal_Summon_2 **** **** **** **** **** **** **** **** +2756 Insect_Plague **** **** **** **** **** **** **** **** +2757 IAIJUTSU_FINESSE **** **** **** **** **** **** **** **** +2758 Iaijutsu_Attack **** **** **** **** **** **** **** **** +2759 Iaijutsu_Spirit_Stike **** **** **** **** **** **** **** **** +2760 Iaijutsu_Echo_Edge **** **** **** **** **** **** **** **** +2761 Iaijutsu_Two_Cuts **** **** **** **** **** **** **** **** +2762 Iron_Hews **** **** **** **** **** **** **** **** +2763 Rusting_Grasp **** **** **** **** **** **** **** **** +2764 Summon_Erinyes **** **** **** **** **** **** **** **** +2765 Greater_Hews **** **** **** **** **** **** **** **** +2766 Iron_Skin **** **** **** **** **** **** **** **** +2767 Iron_Body **** **** **** **** **** **** **** **** +2768 Pain_Touch **** **** **** **** **** **** **** **** +2769 Cruelest_Cut **** **** **** **** **** **** **** **** +2770 Rava_Aura **** **** **** **** **** **** **** **** +2771 Visage_Terror **** **** **** **** **** **** **** **** +2772 Kiai_Smite **** **** **** **** **** **** **** **** +2773 Staredown **** **** **** **** **** **** **** **** +2774 Mass_Staredown **** **** **** **** **** **** **** **** +2775 WeaponAndTorch **** **** **** **** **** **** **** **** +2776 Contact_Shadowlords **** **** **** **** **** **** **** **** +2777 Scribe_Runescar **** **** **** **** **** **** **** **** +2778 LH_Scribe **** **** **** **** **** **** **** **** +2779 RH_Scribe **** **** **** **** **** **** **** **** +2780 LA_Scribe **** **** **** **** **** **** **** **** +2781 RA_Scribe **** **** **** **** **** **** **** **** +2782 LC_Scribe **** **** **** **** **** **** **** **** +2783 RC_Scribe **** **** **** **** **** **** **** **** +2784 F_Scribe **** **** **** **** **** **** **** **** +2785 Rune_Bers **** **** **** **** **** **** **** **** +2786 Blight_Touch **** **** **** **** **** **** **** **** +2787 SE_Soul_Radiance **** **** **** **** **** **** **** **** +2788 SE_Energy_Drain **** **** **** **** **** **** **** **** +2789 SE_Soul_Blast **** **** **** **** **** **** **** **** +2790 BlightMind **** **** **** **** **** **** **** **** +2791 AnvilofThunder **** **** **** **** **** **** **** **** +2792 HammersEdge **** **** **** **** **** **** **** **** +2793 HighSwordLowAxe **** **** **** **** **** **** **** **** +2794 PowerAttack_Quick_Radial **** **** **** **** **** **** **** **** +2795 PowerAttack_ChangeQuickselect **** **** **** **** **** **** **** **** +2796 PowerAttack_Off **** **** **** **** **** **** **** **** +2797 PowerAttack_Quickslot_1 **** **** **** **** **** **** **** **** +2798 PowerAttack_Quickslot_2 **** **** **** **** **** **** **** **** +2799 PowerAttack_Quickslot_3 **** **** **** **** **** **** **** **** +2800 PsionicFocus_RadialMaster **** **** **** **** **** **** **** **** +2801 CloakDance **** **** **** **** **** **** **** **** +2802 RecklessOffense **** **** **** **** **** **** **** **** +2803 MentalLeap **** **** **** **** **** **** **** **** +2804 PowerPenetration **** **** **** **** **** **** **** **** +2805 GreaterPowerPenetration **** **** **** **** **** **** **** **** +2806 PowerSpecialization **** **** **** **** **** **** **** **** +2807 PsionicEndowment **** **** **** **** **** **** **** **** +2808 GreaterPsionicEndowment **** **** **** **** **** **** **** **** +2809 PsionicFist **** **** **** **** **** **** **** **** +2810 GreaterPsionicFist **** **** **** **** **** **** **** **** +2811 PsionicWeapon **** **** **** **** **** **** **** **** +2812 GreaterPsionicWeapon **** **** **** **** **** **** **** **** +2813 PsionicShot **** **** **** **** **** **** **** **** +2814 GreaterPsionicShot **** **** **** **** **** **** **** **** +2815 OverchannelRadialMaster **** **** **** **** **** **** **** **** +2816 OverchannelOff **** **** **** **** **** **** **** **** +2817 Overchannel_1 **** **** **** **** **** **** **** **** +2818 Overchannel_2 **** **** **** **** **** **** **** **** +2819 Overchannel_3 **** **** **** **** **** **** **** **** +2820 SpeedOfThought_Applying **** **** **** **** **** **** **** **** +2821 Talented **** **** **** **** **** **** **** **** +2822 Psionic_Meditation **** **** **** **** **** **** **** **** +2823 UnavoidableStrike **** **** **** **** **** **** **** **** +2824 WoundingAttackRadialMaster **** **** **** **** **** **** **** **** +2825 WoundingAttackMelee **** **** **** **** **** **** **** **** +2826 WoundingAttackRanged **** **** **** **** **** **** **** **** +2827 DeepImpact **** **** **** **** **** **** **** **** +2828 FellShot **** **** **** **** **** **** **** **** +2829 Metapsi_ChainPower **** **** **** **** **** **** **** **** +2830 Metapsi_EmpowerPower **** **** **** **** **** **** **** **** +2831 Metapsi_ExtendPower **** **** **** **** **** **** **** **** +2832 Metapsi_MaximizePower **** **** **** **** **** **** **** **** +2833 Metapsi_SplitPsionicRay **** **** **** **** **** **** **** **** +2834 Metapsi_TwinPower **** **** **** **** **** **** **** **** +2835 Metapsi_WidenPower **** **** **** **** **** **** **** **** +2836 PsionicFocus_Gain **** **** **** **** **** **** **** **** +2837 PsionicFocus_TurnOffAllFocusUsingAbilities **** **** **** **** **** **** **** **** +2838 Metapsi_QuickenPower **** **** **** **** **** **** **** **** +2839 Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +2840 Disguise_Self_Learn **** **** **** **** **** **** **** **** +2841 Disguise_Self_Options **** **** **** **** **** **** **** **** +2842 Disguise_Self_QS1 **** **** **** **** **** **** **** **** +2843 Disguise_Self_QS2 **** **** **** **** **** **** **** **** +2844 Disguise_Self_QS3 **** **** **** **** **** **** **** **** +2845 Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +2846 Alter_Self_Learn **** **** **** **** **** **** **** **** +2847 Alter_Self_Options **** **** **** **** **** **** **** **** +2848 Alter_Self_QS1 **** **** **** **** **** **** **** **** +2849 Alter_Self_QS2 **** **** **** **** **** **** **** **** +2850 Alter_Self_QS3 **** **** **** **** **** **** **** **** +2851 Avasculate **** Fortitude 1 R 1 **** **** **** +2852 Avascular_Mass **** Fortitude 1 I 1 **** **** **** +2853 Mass_Aid **** **** **** E 0 2 0 **** +2854 Necrotic_Awareness **** **** **** **** **** **** **** **** +2855 Necrotic_Cyst **** **** **** **** **** **** **** **** +2856 Necrotic_Bloat **** **** **** **** **** **** **** **** +2857 Necrotic_Domination **** **** **** **** **** **** **** **** +2858 Necrotic_Burst **** **** **** **** **** **** **** **** +2859 Necrotic_Eruption **** **** **** **** **** **** **** **** +2860 Necrotic_Empowerment **** **** **** **** **** **** **** **** +2861 Necrotic_Termination **** **** **** **** **** **** **** **** +2862 Ghoul_Gauntlet Death Fortitude 1 T 1 **** **** **** +2863 Energy_Ebb Level_Drain Fortitude 1 R 1 **** **** **** +2864 Nights_Caress **** Fortitude 1 T 1 **** **** **** +2865 Agony **** **** **** **** **** **** **** **** +2866 Baccaran **** **** **** **** **** **** **** **** +2867 Devilweed **** **** **** **** **** **** **** **** +2868 Luhix **** **** **** **** **** **** **** **** +2869 Mushroom_Powder **** **** **** **** **** **** **** **** +2870 Sannish **** **** **** **** **** **** **** **** +2871 Terran_Brandy **** **** **** **** **** **** **** **** +2872 Vodare **** **** **** **** **** **** **** **** +2873 ThrowEnergizedPotion **** **** **** **** **** **** **** **** +2874 Teleport_RadialMaster **** **** **** **** **** **** **** **** +2875 Teleport_SelfOnly **** **** **** **** **** **** **** **** +2876 Teleport_Party **** **** **** **** **** **** **** **** +2877 TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +2878 TeleportationCircle_Visible **** **** **** **** **** **** **** **** +2879 TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +2880 PoisonedWeapon **** **** **** **** **** **** **** **** +2881 Grenade_Poisonvial **** **** **** **** **** **** **** **** +2882 Poison_Weapon **** **** **** **** **** **** **** **** +2883 Poison_Item **** **** **** **** **** **** **** **** +2884 Poison_Food **** **** **** **** **** **** **** **** +2885 Clean_Poison_Off **** **** **** **** **** **** **** **** +2886 Pox **** Fortitude 1 I 1 **** **** **** +2887 Pestilence Disease Fortitude 1 T 1 **** **** **** +2888 Maze **** **** 1 R 1 **** **** **** +2889 Dimensional_Anchor **** **** **** **** **** **** **** **** +2890 DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +2891 DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +2892 DimensionDoor_Party **** **** **** **** **** **** **** **** +2893 GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +2894 GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +2895 GreaterTeleport_Party **** **** **** **** **** **** **** **** +2896 DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +2897 DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +2898 Dimensional_Lock **** **** **** **** **** **** **** **** +2899 End_Projection **** **** **** **** **** **** **** **** +2900 Wolf_From **** **** **** **** **** **** **** **** +2901 Werewolf_Form **** **** **** **** **** **** **** **** +2902 PROJECTION **** **** **** **** **** **** **** **** +2903 BAELNORN_TOUCH **** **** **** **** **** **** **** **** +2904 Wolf_Empathy **** **** **** **** **** **** **** **** +2905 FEAT_HOUND_AURAMENACE **** **** **** **** **** **** **** **** +2906 FEAT_RACE_WEB **** **** **** **** **** **** **** **** +2907 FEAT_RACE_MINOR_SHAPE_CHANGE **** **** **** **** **** **** **** **** +2908 FEAT_CHANGELING_QUICK_CHANGE **** **** **** **** **** **** **** **** +2909 Quick_Change_Learn **** **** **** **** **** **** **** **** +2910 Quick_Change_Options **** **** **** **** **** **** **** **** +2911 Quick_Change_True **** **** **** **** **** **** **** **** +2912 Quick_Change_QS1 **** **** **** **** **** **** **** **** +2913 Quick_Change_QS2 **** **** **** **** **** **** **** **** +2914 Grig_Pyrotechnics **** **** **** **** **** **** **** **** +2915 Grig_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +2916 Grig_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +2917 Bralani_Lightning_Bolt **** **** **** **** **** **** **** **** +2918 Bralani_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +2919 Bralani_Gust_of_Wind **** **** **** **** **** **** **** **** +2920 Bralani_Mirror_Image **** **** **** **** **** **** **** **** +2921 CrusaderReadyManeuver **** **** **** **** **** **** **** **** +2922 FEAT_RACE_FLARE **** **** **** **** **** **** **** **** +2923 SwordsageReadyManeuver **** **** **** **** **** **** **** **** +2924 Faerie_Fire **** **** **** **** **** **** **** **** +2925 FEAT_RACE_CONEOFCOLD **** **** **** **** **** **** **** **** +2926 WarbladeReadyManeuver **** **** **** **** **** **** **** **** +2927 FEAT_RACE_CHAINLIGHT **** **** **** **** **** **** **** **** +2928 FEAT_RACE_CALLLIGHT **** **** **** **** **** **** **** **** +2929 FEAT_RACE_BLESS **** **** **** **** **** **** **** **** +2930 FEAT_HOUND_AID **** **** **** **** **** **** **** **** +2931 WarbladeRecoverManeuver **** **** **** **** **** **** **** **** +2932 FEAT_HOUND_CONTFLAME **** **** **** **** **** **** **** **** +2933 FEAT_HOUND_DETECTEVIL **** **** **** **** **** **** **** **** +2934 FEAT_HOUND_MAGICCIRCLE **** **** **** **** **** **** **** **** +2935 FEAT_HOUND_TELEPORT **** **** **** **** **** **** **** **** +2936 FEAT_HOUND_DISGUISE **** **** **** **** **** **** **** **** +2937 FEAT_ZENYTH_TRUE_STRIKE **** **** **** **** **** **** **** **** +2938 Racial_Magic_Circle_vs_Good **** **** **** **** **** **** **** **** +2939 Racial_Magic_Circle_vs_Evil **** **** **** **** **** **** **** **** +2940 Racial_Magic_Circle_vs_Law **** **** **** **** **** **** **** **** +2941 Racial_Magic_Circle_vs_Chaos **** **** **** **** **** **** **** **** +2942 Racial_Magic_Circle_against_Alignment **** **** **** **** **** **** **** **** +2943 FEAT_NATHRI_EXP_RETREAT **** **** **** **** **** **** **** **** +2944 FEAT_BLADELING_RAZOR_STORM **** **** **** **** **** **** **** **** +2945 Racial_Detect_Good **** **** **** **** **** **** **** **** +2946 Racial_Detect_Law **** **** **** **** **** **** **** **** +2947 Kapak_Saliva_Application **** **** **** **** **** **** **** **** +2948 OnHit_Kapak_Saliva **** **** **** **** **** **** **** **** +2949 Shifter_Shifting **** **** **** **** **** **** **** **** +2950 FEAT_FEYRI_CHANGE_SHAPE **** **** **** **** **** **** **** **** +2951 Feyri_Select_Form **** **** **** **** **** **** **** **** +2952 Feyri_Options **** **** **** **** **** **** **** **** +2953 Feyri_True_Form **** **** **** **** **** **** **** **** +2954 Feyri_Quickslot_1 **** **** **** **** **** **** **** **** +2955 Feyri_Quickslot_2 **** **** **** **** **** **** **** **** +2956 Nymph_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +2957 Nymph_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +2958 Nymph_DimensionDoor_Party **** **** **** **** **** **** **** **** +2959 Nymph_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +2960 Nymph_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +2961 FEAT_RAK_CHANGE_SHAPE **** **** **** **** **** **** **** **** +2962 Raksahsa_Select_Form **** **** **** **** **** **** **** **** +2963 Raksahsa_Options **** **** **** **** **** **** **** **** +2964 Rakshasa_True_Form **** **** **** **** **** **** **** **** +2965 Rakshasa_Quickslot_1 **** **** **** **** **** **** **** **** +2966 Rakshasa_Quickslot_2 **** **** **** **** **** **** **** **** +2967 Forestlord_Treewalk_Selected **** **** **** **** **** **** **** **** +2968 Forestlord_Treewalk_Dirdist **** **** **** **** **** **** **** **** +2969 Glimmerskin_Touch_of_Luck **** **** **** **** **** **** **** **** +2970 Forestlord_Treewalk_Master_Radial **** **** **** **** **** **** **** **** +2971 Daylight **** **** **** **** 0 3 0 -15 +2972 Clinging_Breath **** **** **** **** **** **** **** **** +2973 Clinging_Conv **** **** **** **** **** **** **** **** +2974 Clinging_Off **** **** **** **** **** **** **** **** +2975 Clinging_QS1 **** **** **** **** **** **** **** **** +2976 Clinging_QS2 **** **** **** **** **** **** **** **** +2977 Clinging_QS3 **** **** **** **** **** **** **** **** +2978 Lingering_Breath **** **** **** **** **** **** **** **** +2979 Lingering_Conv **** **** **** **** **** **** **** **** +2980 Lingering_Off **** **** **** **** **** **** **** **** +2981 Lingering_QS1 **** **** **** **** **** **** **** **** +2982 Lingering_QS2 **** **** **** **** **** **** **** **** +2983 Lingering_QS3 **** **** **** **** **** **** **** **** +2984 Heighten_Breath **** **** **** **** **** **** **** **** +2985 Heighten_Conv **** **** **** **** **** **** **** **** +2986 Heighten_Off **** **** **** **** **** **** **** **** +2987 Heighten_QS1 **** **** **** **** **** **** **** **** +2988 Heighten_QS2 **** **** **** **** **** **** **** **** +2989 Heighten_Max **** **** **** **** **** **** **** **** +2990 Exhale_Barrier **** **** **** **** **** **** **** **** +2991 Spreading_Breath **** **** **** **** **** **** **** **** +2992 Tempest_Breath **** **** **** **** **** **** **** **** +2993 Exhale_Immunity **** **** **** **** **** **** **** **** +2994 Enlarge_Breath **** **** **** **** **** **** **** **** +2995 Maximize_Breath **** **** **** **** **** **** **** **** +2996 Exhale_Immunity **** **** **** **** **** **** **** **** +2997 Shape_Breath **** **** **** **** **** **** **** **** +2998 Poison_Weapon **** **** **** **** **** **** **** **** +2999 Avenging_Strike **** **** **** **** **** **** **** **** +3000 HellFire_Grasp **** **** **** **** **** **** **** **** +3001 Hellfire_Blast **** **** **** **** **** **** **** **** +3002 Hellfire_Flare **** **** **** **** **** **** **** **** +3003 Summon_Hamatula **** **** **** **** **** **** **** **** +3004 HellFire **** **** **** **** **** **** **** **** +3005 Fire_Shield **** **** **** **** **** **** **** **** +3006 HellFire_Storm **** **** **** **** **** **** **** **** +3007 Body_of_Fire **** **** **** **** **** **** **** **** +3008 Disciple_of_Darkness **** **** **** **** **** **** **** **** +3009 MOS_Summon **** **** **** **** **** **** **** **** +3010 MOS_Summon **** **** **** **** **** **** **** **** +3011 MOS_Summon **** **** **** **** **** **** **** **** +3012 MOS_Summon **** **** **** **** **** **** **** **** +3013 SPELL_SPELLFIRE_WIELDER **** **** **** **** **** **** **** **** +3014 SPELL_SPELLFIRE_INCREASE **** **** **** **** **** **** **** **** +3015 SPELL_SPELLFIRE_DECREASE **** **** **** **** **** **** **** **** +3016 SPELL_SPELLFIRE_QUICKSELECT **** **** **** **** **** **** **** **** +3017 SPELL_SPELLFIRE_ATTACK **** **** **** **** **** **** **** **** +3018 SPELL_SPELLFIRE_HEAL **** **** **** **** **** **** **** **** +3019 SPELL_SPELLFIRE_CHECK **** **** **** **** **** **** **** **** +3020 SPELL_SPELLFIRE_PLUS_ONE **** **** **** **** **** **** **** **** +3021 SPELL_SPELLFIRE_PLUS_FIVE **** **** **** **** **** **** **** **** +3022 SPELL_SPELLFIRE_PLUS_TEN **** **** **** **** **** **** **** **** +3023 SPELL_SPELLFIRE_PLUS_TWENTY **** **** **** **** **** **** **** **** +3024 SPELL_SPELLFIRE_MINUS_ONE **** **** **** **** **** **** **** **** +3025 SPELL_SPELLFIRE_MINUS_FIVE **** **** **** **** **** **** **** **** +3026 SPELL_SPELLFIRE_MINUS_TEN **** **** **** **** **** **** **** **** +3027 SPELL_SPELLFIRE_MINUS_TWENTY **** **** **** **** **** **** **** **** +3028 SPELL_SPELLFIRE_CHECK_EXP **** **** **** **** **** **** **** **** +3029 SPELL_SPELLFIRE_QUICKSELECT_CHANGE **** **** **** **** **** **** **** **** +3030 SPELL_SPELLFIRE_QUICKSELECT_1 **** **** **** **** **** **** **** **** +3031 SPELL_SPELLFIRE_QUICKSELECT_2 **** **** **** **** **** **** **** **** +3032 SPELL_SPELLFIRE_QUICKSELECT_3 **** **** **** **** **** **** **** **** +3033 SPELL_SPELLFIRE_DRAIN_CHARGED **** **** **** **** **** **** **** **** +3034 SPELL_SPELLFIRE_RAPID_BLAST **** **** **** **** **** **** **** **** +3035 SPELL_SPELLFIRE_RAPID_BLAST_TWO **** **** **** **** **** **** **** **** +3036 SPELL_SPELLFIRE_RAPID_BLAST_THREE **** **** **** **** **** **** **** **** +3037 SPELL_SPELLFIRE_DRAIN_PERMANENT **** **** **** **** **** **** **** **** +3038 SPELL_SPELLFIRE_CHARGE_ITEM **** **** **** **** **** **** **** **** +3039 SPELL_SPELLFIRE_CROWN **** **** **** **** **** **** **** **** +3040 SPELL_SPELLFIRE_MAELSTROM **** **** **** **** **** **** **** **** +3041 SPELL_SPELLFIRE_ABSORB **** **** **** **** **** **** **** **** +3042 SPELLS_SPELLS_TOUCH_ATTACK **** **** **** **** **** **** **** **** +3043 SPELLS_SPELLS_RANGED_ATTACK **** **** **** **** **** **** **** **** +3044 SPELLS_SPELLS_CONCENTRATION_TARGET **** **** **** **** **** **** **** **** +3045 SPELLS_SPELLS_HOLD_CHARGE_TOGGLE **** **** **** **** **** **** **** **** +3046 Virtuoso_Sustaining_Song **** **** **** **** **** **** **** **** +3047 Virtuoso_Calumny **** **** **** **** **** **** **** **** +3048 Virtuoso_Jarring_Song **** **** **** **** **** **** **** **** +3049 Virtuoso_Sharp_Note **** **** **** **** **** **** **** **** +3050 Virtuoso_Mindbending_Melody **** **** **** **** **** **** **** **** +3051 Virtuoso_Greater_Calumny **** **** **** **** **** **** **** **** +3052 Virtuoso_Magical_Melody **** **** **** **** **** **** **** **** +3053 Virtuoso_Song_of_Fury **** **** **** **** **** **** **** **** +3054 Virtuoso_Revealing_Melody **** **** **** **** **** **** **** **** +3055 ShockingGrasp Electricity **** 1 T 1 **** **** **** +3056 ScorchingRay Fire **** 1 R 1 **** **** **** +3057 RayofExhaustion **** Fortitude 1 R 1 **** **** **** +3058 WavesofFatigue **** **** 1 I 1 **** **** **** +3059 Asmodeus_DreadMight **** **** **** **** **** **** **** **** +3060 DOA_SUMMON_SUCCUBUS **** **** **** **** **** **** **** **** +3061 DOA_SUMMON_VROCK **** **** **** **** **** **** **** **** +3062 DOA_SUMMON_GLABREZU **** **** **** **** **** **** **** **** +3063 DOA_SUMMON_MARILITH **** **** **** **** **** **** **** **** +3064 DOA_SUMMON_BALOR **** **** **** **** **** **** **** **** +3065 SoheiKiFrenzy **** **** **** **** **** **** **** **** +3066 AsmodeusLearnSecrets1 **** **** **** **** **** **** **** **** +3067 AsmodeusCharm **** **** **** **** **** **** **** **** +3068 AsmodeusHellcat **** **** **** **** **** **** **** **** +3069 AsmodeusEvilAuthority **** **** **** **** **** **** **** **** +3070 AsmodeusSummonDevil **** **** **** **** **** **** **** **** +3071 DoA_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +3072 DoA_GreaterCommand_Approach **** **** **** **** **** **** **** **** +3073 DoA_GreaterCommand_Drop **** **** **** **** **** **** **** **** +3074 DoA_GreaterCommand_Fall **** **** **** **** **** **** **** **** +3075 DoA_GreaterCommand_Flee **** **** **** **** **** **** **** **** +3076 DoA_GreaterCommand_Halt **** **** **** **** **** **** **** **** +3077 DoA_Command_RadialMaster **** **** **** **** **** **** **** **** +3078 DoA_Command_Approach **** **** **** **** **** **** **** **** +3079 DoA_Command_Drop **** **** **** **** **** **** **** **** +3080 DoA_Command_Fall **** **** **** **** **** **** **** **** +3081 DoA_Command_Flee **** **** **** **** **** **** **** **** +3082 DoA_Command_Halt **** **** **** **** **** **** **** **** +3083 VisionOfHeaven Daze Will 1 R 1 **** **** **** +3084 SwordOfConscience **** **** **** **** **** **** **** **** +3085 Obscuring_Mist **** **** **** P 0 2 0 -5 +3086 GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +3087 GreaterCommand_Approach **** **** **** **** **** **** **** **** +3088 GreaterCommand_Drop **** **** **** **** **** **** **** **** +3089 GreaterCommand_Fall **** **** **** **** **** **** **** **** +3090 GreaterCommand_Flee **** **** **** **** **** **** **** **** +3091 GreaterCommand_Halt **** **** **** **** **** **** **** **** +3092 Command_RadialMaster **** **** **** **** **** **** **** **** +3093 Command_Approach **** **** **** **** **** **** **** **** +3094 Command_Drop **** **** **** **** **** **** **** **** +3095 Command_Fall **** **** **** **** **** **** **** **** +3096 Command_Flee **** **** **** **** **** **** **** **** +3097 Command_Halt **** **** **** **** **** **** **** **** +3098 PolarRay Cold **** 1 R 1 **** **** **** +3099 BloodOfTheMartyr **** **** **** **** **** **** **** **** +3100 Acid_Orb Acid Fortitude 0 R 1 **** **** **** +3101 Cold_Orb Cold Fortitude 0 R 1 **** **** **** +3102 Electric_Orb Electricity Fortitude 0 R 1 **** **** **** +3103 Fire_Orb Fire Fortitude 0 R 1 **** **** **** +3104 Sonic_Orb Sonic Fortitude 0 R 1 **** **** **** +3105 Ice_Burst Cold Reflex 1 I 1 **** **** **** +3106 Acid_Storm Acid Reflex 1 I 1 **** **** **** +3107 Mass_Hold_Person Paralysis Will 1 D 1 **** **** **** +3108 Mass_Hold_Monster Paralysis Will 1 D 1 **** **** **** +3109 Burning_Bolt Fire **** 1 R 1 **** **** **** +3110 Blast_of_Flame Fire Reflex 1 I 1 **** **** **** +3111 Disintegrate **** Fortitude 1 R 1 **** **** **** +3112 Mantle_of_Eg_Might **** **** **** E 0 3 9 **** +3113 Energy_Immunity **** **** **** **** **** **** **** **** +3114 EI_Acid **** **** **** **** **** **** **** **** +3115 EI_Cold **** **** **** **** **** **** **** **** +3116 EI_Elec **** **** **** **** **** **** **** **** +3117 EI_Fire **** **** **** **** **** **** **** **** +3118 EI_Sonic **** **** **** **** **** **** **** **** +3119 Mass_Bulls_Strength **** **** **** E 0 3 0 **** +3120 Mass_Cats_Grace **** **** **** E 0 3 0 **** +3121 Mass_Eagle_Splendor **** **** **** E 0 3 0 **** +3122 Mass_Endurance **** **** **** E 0 3 0 **** +3123 Mass_Foxs_Cunning **** **** **** E 0 3 0 **** +3124 Mass_Owls_Wisdom **** **** **** E 0 3 0 **** +3125 Mass_Ultravision **** **** **** P 0 3 0 **** +3126 Lower_Spell_Resistance **** **** **** **** **** **** **** **** +3127 Serpents_Sigh **** **** **** **** **** **** **** **** +3128 SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +3129 SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +3130 SS_Cone_of_Acid **** **** **** **** **** **** **** **** +3131 SS_Cone_of_Cold **** **** **** **** **** **** **** **** +3132 SS_Cone_of_Fire **** **** **** **** **** **** **** **** +3133 Heroism **** **** **** E 0 3 9 -3133 +3134 Greater_Heroism **** **** **** E 0 2 9 -3133 +3135 Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +3136 Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +3137 Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +3138 Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +3139 Righteous_Might **** **** **** E 0 2 0 **** +3140 Recitation **** **** **** E 0 2 0 **** +3141 Forceblast **** Reflex 1 R 1 **** **** **** +3142 Glitterdust **** Will **** I 1 **** **** **** +3143 Mords_Mansion **** **** **** **** **** **** **** **** +3144 Lesser_Acid_Orb Acid **** **** R 1 **** **** **** +3145 Lesser_Cold_Orb Cold **** **** R 1 **** **** **** +3146 Lesser_Electric_Orb Electricity **** **** R 1 **** **** **** +3147 Lesser_Fire_Orb Fire **** **** R 1 **** **** **** +3148 Lesser_Sonic_Orb Sonic **** **** R 1 **** **** **** +3149 Baleful_Transposition **** **** **** **** **** **** **** **** +3150 Benign_Transposition **** **** **** **** **** **** **** **** +3151 Conviction **** **** **** P 0 2 14 -3151 +3152 Legions_Conviction **** **** **** P 0 2 14 -3151 +3153 Curse_of_Impending_Blades **** **** 1 R 1 **** **** **** +3154 Legions_Curse_of_Impending_Blades **** **** 1 R 1 **** **** **** +3155 Curse_of_Petty_Failing **** **** 1 R 1 **** **** **** +3156 Legions_Curse_of_Petty_Failing **** **** 1 R 1 **** **** **** +3157 Divine_Protection **** **** **** P 0 2 0 **** +3158 Fireburst Fire Reflex 1 I 1 **** **** **** +3159 Greater_Fireburst Fire Reflex 1 I 1 **** **** **** +3160 Lionheart **** **** **** P 0 2 13 **** +3161 Living_Undeath **** **** **** P 0 2 12 **** +3162 Panacea **** **** **** **** **** **** **** **** +3163 Legions_Shield_of_Faith **** **** **** P 0 3 7 -3 +3164 Slashing_Darkness Positive **** 1 R 1 **** **** **** +3165 Agnazzars_Scorcher Fire Reflex 0 I 1 **** **** **** +3166 Create_Magic_Tattoo **** **** **** **** **** **** **** **** +3167 CT_Scribe **** **** **** **** **** **** **** **** +3168 Flashburst Blindness Will 1 I 1 **** **** **** +3169 Flensing **** Fortitude 1 R 1 **** **** **** +3170 Shadow_Spray **** Fortitude 1 I 1 **** **** **** +3171 Snillocs_Snowball_Swarm Cold Reflex 1 I 1 **** **** **** +3172 Beltyns_Burning_Blood Fire Fortitude 1 R 1 **** **** **** +3173 Ilyykurs_Mantle **** **** **** P 0 2 0 **** +3174 Improved_Mage_Armor **** **** **** P 0 2 7 -102 +3175 Nybors_Gentle_Reminder Mind_Affecting Fortitude 1 R 1 **** **** **** +3176 Nybors_Stern_Reproof Death Fortitude 1 R 1 **** **** **** +3177 Sinsaburs_Baleful_Bolt **** Reflex 1 I 1 **** **** **** +3178 Snillocs_Snowball Cold **** 1 R 1 **** **** **** +3179 Soulscour Mind_Affecting Will 1 T 1 **** **** **** +3180 Sphere_of_Ultimate_Destruction Death Fortitude 1 R 1 **** **** **** +3181 Clarity_of_Mind **** **** **** P 0 3 13 **** +3182 Mass_Drown **** Fortitude 1 I 1 **** **** **** +3183 Hail_of_Stone **** **** 1 I 1 **** **** **** +3184 Spiderskin **** **** **** P 0 3 7 **** +3185 Viscid_Glob **** Reflex 1 R 1 **** **** **** +3186 Word_of_Balance **** **** 1 I 1 **** **** **** +3187 Greenfire **** **** **** **** **** **** **** **** +3188 Blank **** **** **** **** **** **** **** **** +3189 Summon7Air **** **** **** **** **** **** **** **** +3190 Summon7Earth **** **** **** **** **** **** **** **** +3191 Summon7Fire **** **** **** **** **** **** **** **** +3192 Summon7Water **** **** **** **** **** **** **** **** +3193 Summon8Air **** **** **** **** **** **** **** **** +3194 Summon8Earth **** **** **** **** **** **** **** **** +3195 Summon8Fire **** **** **** **** **** **** **** **** +3196 Summon8Water **** **** **** **** **** **** **** **** +3197 Summon9Air **** **** **** **** **** **** **** **** +3198 Summon9Earth **** **** **** **** **** **** **** **** +3199 Summon9Fire **** **** **** **** **** **** **** **** +3200 Summon9Water **** **** **** **** **** **** **** **** +3201 Detect_Evil **** **** **** **** **** **** **** **** +3202 Detect_Good **** **** **** **** **** **** **** **** +3203 Detect_Law **** **** **** **** **** **** **** **** +3204 Detect_Chaos **** **** **** **** **** **** **** **** +3205 UndetectableAlignment **** **** **** **** **** **** **** **** +3206 Unholy_Sword **** **** **** **** **** **** **** **** +3207 DeeperDarkness **** **** **** I 1 **** **** **** +3208 Blur **** **** **** P 0 2 7 -5 +3209 MirrorImage **** **** **** P 0 2 0 **** +3210 Swashbuckler_damage **** **** **** **** **** **** **** **** +3211 CoC_damage **** **** **** **** **** **** **** **** +3212 Insanity Confusion Will 1 R 1 **** **** **** +3213 Mass_Inflict_Light_Wounds Negative Will 1 I 1 **** **** **** +3214 Mass_Inflict_Moderate_Wounds Negative Will 1 I 1 **** **** **** +3215 Mass_Inflict_Serious_Wounds Negative Will 1 I 1 **** **** **** +3216 Mass_Inflict_Critical_Wounds Negative Will 1 I 1 **** **** **** +3217 Greater_Harm Negative Will 1 T 1 **** **** **** +3218 Mass_Harm Negative Will 1 I 1 **** **** **** +3219 Scrying **** **** **** **** **** **** **** **** +3220 Holy_Word **** **** 1 D 1 **** **** **** +3221 Blasphemy **** **** 1 D 1 **** **** **** +3222 Dictum **** **** 1 D 1 **** **** **** +3223 Word_of_Chaos **** **** 1 D 1 **** **** **** +3224 **Truenaming** **** **** **** **** **** **** **** **** +3225 DefensiveEdge **** **** **** **** **** **** **** **** +3226 DefensiveEdge_Normal **** **** **** **** **** **** **** **** +3227 DefensiveEdge_Reverse **** **** **** **** **** **** **** **** +3228 InertialSurge **** **** **** **** **** **** **** **** +3229 InertialSurge_Normal **** **** **** **** **** **** **** **** +3230 InertialSurge_Reverse **** **** **** **** **** **** **** **** +3231 KnightsPuissance **** **** **** **** **** **** **** **** +3232 KnightsPuissance_Normal **** **** **** **** **** **** **** **** +3233 KnightsPuissance_Reverse **** **** **** **** **** **** **** **** +3234 UniversalAptitude **** **** **** **** **** **** **** **** +3235 UniversalAptitude_Normal **** **** **** **** **** **** **** **** +3236 UniversalAptitude_Reverse **** **** **** **** **** **** **** **** +3237 WordOfNurturingMinor **** **** **** **** **** **** **** **** +3238 WordOfNurturingMinor_Normal **** **** **** **** **** **** **** **** +3239 WordOfNurturingMinor_Reverse **** **** **** **** **** **** **** **** +3240 FortifyArmour **** **** **** **** **** **** **** **** +3241 FortifyArmour_SneakAttacks **** **** **** **** **** **** **** **** +3242 FortifyArmour_Criticals **** **** **** **** **** **** **** **** +3243 KeenWeapon **** **** **** **** **** **** **** **** +3244 FogOfTheVoid **** **** **** **** **** **** **** **** +3245 FogOfTheVoid_FogCloud **** **** **** **** **** **** **** **** +3246 FogOfTheVoid_SolidFog **** **** **** **** **** **** **** **** +3247 ShieldOfTheLandscape **** **** **** **** **** **** **** **** +3248 Shockwave **** **** **** **** **** **** **** **** +3249 ArchersEye **** **** **** **** **** **** **** **** +3250 ArchersEye_Normal **** **** **** **** **** **** **** **** +3251 ArchersEye_Reverse **** **** **** **** **** **** **** **** +3252 HiddenTruth **** **** **** **** **** **** **** **** +3253 HiddenTruth_Normal **** **** **** **** **** **** **** **** +3254 HiddenTruth_Reverse **** **** **** **** **** **** **** **** +3255 PercieveTheUnseen **** **** **** **** **** **** **** **** +3256 PercieveTheUnseen_Normal **** **** **** **** **** **** **** **** +3257 PercieveTheUnseen_Reverse **** **** **** **** **** **** **** **** +3258 SilentCaster **** **** **** **** **** **** **** **** +3259 SilentCaster_Normal **** **** **** **** **** **** **** **** +3260 SilentCaster_Reverse **** **** **** **** **** **** **** **** +3261 SpeedOfTheZephyr **** **** **** **** **** **** **** **** +3262 SpeedOfTheZephyr_Normal **** **** **** **** **** **** **** **** +3263 SpeedOfTheZephyr_Reverse **** **** **** **** **** **** **** **** +3264 StrikeOfMight **** **** **** **** **** **** **** **** +3265 StrikeOfMight_Normal **** **** **** **** **** **** **** **** +3266 StrikeOfMight_Reverse **** **** **** **** **** **** **** **** +3267 TemporalTwist **** **** **** **** **** **** **** **** +3268 TemporalTwist_Normal **** **** **** **** **** **** **** **** +3269 TemporalTwist_Reverse **** **** **** **** **** **** **** **** +3270 WordOfNurturingLesser **** **** **** **** **** **** **** **** +3271 WordOfNurturingLesser_Normal **** **** **** **** **** **** **** **** +3272 WordOfNurturingLesser_Reverse **** **** **** **** **** **** **** **** +3273 AgitateItem **** **** **** **** **** **** **** **** +3274 AgitateItem_Hot **** **** **** **** **** **** **** **** +3275 AgitateItem_Cold **** **** **** **** **** **** **** **** +3276 AnalyzeIten **** **** **** **** **** **** **** **** +3277 EnergyVortex **** **** **** **** **** **** **** **** +3278 EnergyVortex_Acid **** **** **** **** **** **** **** **** +3279 EnergyVortex_Cold **** **** **** **** **** **** **** **** +3280 EnergyVortex_Elec **** **** **** **** **** **** **** **** +3281 EnergyVortex_Fire **** **** **** **** **** **** **** **** +3282 SpeakRockToMud **** **** **** **** **** **** **** **** +3283 TransformTheLandscape **** **** **** **** **** **** **** **** +3284 AcceleratedAttack **** **** **** **** **** **** **** **** +3285 AcceleratedAttack_Normal **** **** **** **** **** **** **** **** +3286 AcceleratedAttack_Reverse **** **** **** **** **** **** **** **** +3287 EnergyNegation **** **** **** **** **** **** **** **** +3288 EnergyNegation_Normal **** **** **** **** **** **** **** **** +3289 EnergyNegation_Reverse **** **** **** **** **** **** **** **** +3290 EnergyNegation_Choice **** **** **** **** **** **** **** **** +3291 IncarnationOfAngels **** **** **** **** **** **** **** **** +3292 IncarnationOfAngels_Normal **** **** **** **** **** **** **** **** +3293 IncarnationOfAngels_Reverse **** **** **** **** **** **** **** **** +3294 SpeedOfTheZephyrGreater **** **** **** **** **** **** **** **** +3295 SpeedOfTheZephyrGreater_Normal **** **** **** **** **** **** **** **** +3296 SpeedOfTheZephyrGreater_Reverse **** **** **** **** **** **** **** **** +3297 TemporalSpiral **** **** **** **** **** **** **** **** +3298 TemporalSpiral_Normal **** **** **** **** **** **** **** **** +3299 TemporalSpiral_Reverse **** **** **** **** **** **** **** **** +3300 VisionSharpened **** **** **** **** **** **** **** **** +3301 VisionSharpened_Normal **** **** **** **** **** **** **** **** +3302 VisionSharpened_Reverse **** **** **** **** **** **** **** **** +3303 WordOfNurturingModerate **** **** **** **** **** **** **** **** +3304 WordOfNurturingModerate_Normal **** **** **** **** **** **** **** **** +3305 WordOfNurturingModerate_Reverse **** **** **** **** **** **** **** **** +3306 RemoveItem **** **** **** **** **** **** **** **** +3307 SuppressWeapon **** **** **** **** **** **** **** **** +3308 LoreOfTheWorld **** **** **** **** **** **** **** **** +3309 MasterTheFourWinds **** **** **** **** **** **** **** **** +3310 ThwartTheTraveller **** **** **** **** **** **** **** **** +3311 BreathOfCleansing **** **** **** **** **** **** **** **** +3312 BreathOfCleansing_Normal **** **** **** **** **** **** **** **** +3313 BreathOfCleansing_Reverse **** **** **** **** **** **** **** **** +3314 CasterLens **** **** **** **** **** **** **** **** +3315 CasterLens_Normal **** **** **** **** **** **** **** **** +3316 CasterLens_Reverse **** **** **** **** **** **** **** **** +3317 ConfoundingResistance **** **** **** **** **** **** **** **** +3318 ConfoundingResistance_Normal **** **** **** **** **** **** **** **** +3319 ConfoundingResistance_Reverse **** **** **** **** **** **** **** **** +3320 MoraleBoost **** **** **** **** **** **** **** **** +3321 MoraleBoost_Normal **** **** **** **** **** **** **** **** +3322 MoraleBoost_Reverse **** **** **** **** **** **** **** **** +3323 MagicalContraction **** **** **** **** **** **** **** **** +3324 MagicalContraction_Normal **** **** **** **** **** **** **** **** +3325 MagicalContraction_Reverse **** **** **** **** **** **** **** **** +3326 SpellRebirth **** **** **** **** **** **** **** **** +3327 SpellRebirth_Normal **** **** **** **** **** **** **** **** +3328 SpellRebirth_Reverse **** **** **** **** **** **** **** **** +3329 WordOfNurturingPotent **** **** **** **** **** **** **** **** +3330 WordOfNurturingPotent_Normal **** **** **** **** **** **** **** **** +3331 WordOfNurturingPotent_Reverse **** **** **** **** **** **** **** **** +3332 WordOfBolstering **** **** **** **** **** **** **** **** +3333 WordOfBolstering_Normal **** **** **** **** **** **** **** **** +3334 WordOfBolstering_Reverse **** **** **** **** **** **** **** **** +3335 WordOfBolstering_Choice **** **** **** **** **** **** **** **** +3336 SuppressItem **** **** **** **** **** **** **** **** +3337 TransmuteWeapon **** **** **** **** **** **** **** **** +3338 AngerTheSleepingEarth **** **** **** **** **** **** **** **** +3339 ConjunctiveGate **** **** **** **** **** **** **** **** +3340 DenyPassage **** **** **** **** **** **** **** **** +3341 EldritchAttraction **** **** **** **** **** **** **** **** +3342 EldritchAttraction_Normal **** **** **** **** **** **** **** **** +3343 EldritchAttraction_Reverse **** **** **** **** **** **** **** **** +3344 EnergyNegationGreater **** **** **** **** **** **** **** **** +3345 EnergyNegationGreater_Normal **** **** **** **** **** **** **** **** +3346 EnergyNegationGreater_Reverse **** **** **** **** **** **** **** **** +3347 EnergyNegationGreater_Choice **** **** **** **** **** **** **** **** +3348 EssenceOfLifespark **** **** **** **** **** **** **** **** +3349 EssenceOfLifespark_Normal **** **** **** **** **** **** **** **** +3350 EssenceOfLifespark_Reverse **** **** **** **** **** **** **** **** +3351 PreturnaturalClarity **** **** **** **** **** **** **** **** +3352 PreturnaturalClarity_Attack **** **** **** **** **** **** **** **** +3353 PreturnaturalClarity_Skill **** **** **** **** **** **** **** **** +3354 PreturnaturalClarity_Save **** **** **** **** **** **** **** **** +3355 PreturnaturalClarity_Reverse **** **** **** **** **** **** **** **** +3356 SensoryFocus **** **** **** **** **** **** **** **** +3357 SensoryFocus_Normal **** **** **** **** **** **** **** **** +3358 SensoryFocus_Reverse **** **** **** **** **** **** **** **** +3359 WardOfPeace **** **** **** **** **** **** **** **** +3360 WardOfPeace_Normal **** **** **** **** **** **** **** **** +3361 WardOfPeace_Reverse **** **** **** **** **** **** **** **** +3362 WordOfNurturingCritical **** **** **** **** **** **** **** **** +3363 WordOfNurturingCritical_Normal **** **** **** **** **** **** **** **** +3364 WordOfNurturingCritical_Reverse **** **** **** **** **** **** **** **** +3365 MetamagicCatalyst **** **** **** **** **** **** **** **** +3366 MetamagicCatalyst_Empower **** **** **** **** **** **** **** **** +3367 MetamagicCatalyst_Extend **** **** **** **** **** **** **** **** +3368 MetamagicCatalyst_Maximize **** **** **** **** **** **** **** **** +3369 SeizeItem **** **** **** **** **** **** **** **** +3370 BreathOfRecovery **** **** **** **** **** **** **** **** +3371 BreathOfRecovery_Normal **** **** **** **** **** **** **** **** +3372 BreathOfRecovery_Reverse **** **** **** **** **** **** **** **** +3373 EtherReforged **** **** **** **** **** **** **** **** +3374 EtherReforged_Normal **** **** **** **** **** **** **** **** +3375 EtherReforged_Reverse **** **** **** **** **** **** **** **** +3376 KnightsPuissanceGreater **** **** **** **** **** **** **** **** +3377 KnightsPuissanceGreater_Normal **** **** **** **** **** **** **** **** +3378 KnightsPuissanceGreater_Reverse **** **** **** **** **** **** **** **** +3379 MysticRampart **** **** **** **** **** **** **** **** +3380 MysticRampart_Normal **** **** **** **** **** **** **** **** +3381 MysticRampart_Reverse **** **** **** **** **** **** **** **** +3382 SingularMind **** **** **** **** **** **** **** **** +3383 SingularMind_Normal **** **** **** **** **** **** **** **** +3384 SingularMind_Reverse **** **** **** **** **** **** **** **** +3385 WordOfNurturingGreater **** **** **** **** **** **** **** **** +3386 WordOfNurturingGreater_Normal **** **** **** **** **** **** **** **** +3387 WordOfNurturingGreater_Reverse **** **** **** **** **** **** **** **** +3388 DRAGON_ALLY **** **** **** **** **** **** **** **** +3389 OnHit_Dragonfire_Inspiration **** **** **** **** **** **** **** **** +3390 Dragonfire_Inspiration_Toggle **** **** **** **** **** **** **** **** +3391 Dragonfire_Assault_Toggle **** **** **** **** **** **** **** **** +3392 Dragonfire_Channeling **** **** **** **** **** **** **** **** +3393 Marrutact_Howl **** **** **** **** **** **** **** **** +3394 BrilliantEnergyArrows **** **** **** R 1 **** **** **** +3395 HideFromAnimals **** **** **** **** **** **** **** **** +3396 Longstrider **** **** **** E 0 3 0 **** +3397 SerpentArrows **** **** **** R 1 **** **** **** +3398 Treeshape **** **** **** **** **** **** **** **** +3399 WaterBreathing **** **** **** **** **** **** **** **** +3400 RECITATION_FORTIFIED **** **** **** **** **** **** **** **** +3401 RECITATION_MEDITATIVE **** **** **** **** **** **** **** **** +3402 RECITATION_MINDFUL **** **** **** **** **** **** **** **** +3403 RECITATION_SANGUINE **** **** **** **** **** **** **** **** +3404 RECITATION_VITAL **** **** **** **** **** **** **** **** +3405 EmpowerUtterance **** **** **** **** **** **** **** **** +3406 ExtendUtterance **** **** **** **** **** **** **** **** +3407 QuickenUtterance **** **** **** **** **** **** **** **** +3408 Truenamer_Ignore_SR **** **** **** **** **** **** **** **** +3409 Truenamer_Crafted_Tool_Target **** **** **** **** **** **** **** **** +3410 Truenamer_Crafted_Tool_Target_Conversation **** **** **** **** **** **** **** **** +3411 Truenamer_Crafted_Tool_Target_Choice1 **** **** **** **** **** **** **** **** +3412 Truenamer_Crafted_Tool_Target_Choice2 **** **** **** **** **** **** **** **** +3413 Truenamer_Crafted_Tool_Target_Choice3 **** **** **** **** **** **** **** **** +3414 Truenamer_Crafted_Tool_Target_Choice4 **** **** **** **** **** **** **** **** +3415 SeeTheNamed **** **** **** **** **** **** **** **** +3416 SpeakUntoTheMasses **** **** **** **** **** **** **** **** +3417 SayMyNameAndIAmThere **** **** **** **** **** **** **** **** +3418 SyllableOfDetachment **** **** **** **** **** **** **** **** +3419 SyllableOfAffliction_Master **** **** **** **** **** **** **** **** +3420 SyllableOfAffliction_Sight **** **** **** **** **** **** **** **** +3421 SyllableOfAffliction_Hearing **** **** **** **** **** **** **** **** +3422 SyllableOfAffliction_Touch **** **** **** **** **** **** **** **** +3423 SyllableOfExile **** **** **** **** **** **** **** **** +3424 SyllableOfDissolution **** **** **** **** **** **** **** **** +3425 SyllableOfEnervation **** **** **** **** **** **** **** **** +3426 Brimstone_TongueOfFire3d6 **** **** **** **** **** **** **** **** +3427 Brimstone_TongueOfFire5d6 **** **** **** **** **** **** **** **** +3428 Brimstone_TongueOfFire8d6 **** **** **** **** **** **** **** **** +3429 Brimstone_LesserHeavenlyEntreaty **** **** **** **** **** **** **** **** +3430 Brimstone_NormalHeavenlyEntreaty **** **** **** **** **** **** **** **** +3431 Brimstone_GreaterHeavenlyEntreaty **** **** **** **** **** **** **** **** +3432 HideFromUndead **** **** **** **** **** **** **** **** +3433 CrushingDespair Mind_Affecting Will 1 I 1 **** **** **** +3434 HaltUndead **** **** **** **** **** **** **** **** +3435 Eyebite **** Fortitude 1 R 1 **** **** **** +3436 SongOfDiscord Mind_Affecting Will 1 I 1 **** **** **** +3437 FireInTheBlood **** **** **** E 0 2 0 **** +3438 VileDeath **** **** **** **** **** **** **** **** +3439 PlagueOfUndead **** **** **** S 0 3 0 -2 +3440 DNecroCharnelTouch **** **** **** **** **** **** **** **** +3441 DNecroScabTouch **** **** **** **** **** **** **** **** +3442 DNecroEnervTouch **** **** **** **** **** **** **** **** +3443 DNecroNegative_Energy_Burst **** **** **** **** **** **** **** **** +3444 DNecroFearAura **** **** **** **** **** **** **** **** +3445 NobleCoord **** **** **** **** **** **** **** **** +3446 NobleFavor **** **** **** **** **** **** **** **** +3447 NobleGreat **** **** **** **** **** **** **** **** +3448 NobleInspire **** **** **** **** **** **** **** **** +3449 Extend_Spell_Ability **** **** **** **** **** **** **** **** +3450 Silent_Spell_Ability **** **** **** **** **** **** **** **** +3451 Still_Spell_Ability **** **** **** **** **** **** **** **** +3452 Empower_Spell_Ability **** **** **** **** **** **** **** **** +3453 Maximize_Spell_Ability **** **** **** **** **** **** **** **** +3454 Quicken_Spell_Ability **** **** **** **** **** **** **** **** +3455 Weapon_Aptitude **** **** **** **** **** **** **** **** +3456 Weapon_Aptitude_Options **** **** **** **** **** **** **** **** +3457 Greater_Resistance **** **** **** P 0 3 14 **** +3458 Superior_Resistance **** **** **** P 0 3 14 **** +3459 Vigor **** **** **** E 0 2 10 -3459 +3460 Lesser_Vigor **** **** **** E 0 2 10 -3459 +3461 Mass_Lesser_Vigor **** **** **** E 0 2 10 -3459 +3462 Vigorous_Circle **** **** **** E 0 2 10 -3459 +3463 Mystic_Barrier **** **** **** **** **** **** **** **** +3464 Cadence_Bull **** **** **** **** **** **** **** **** +3465 Cadence_Iron **** **** **** **** **** **** **** **** +3466 Cadence_Heart **** **** **** **** **** **** **** **** +3467 Cadence_Swallow **** **** **** **** **** **** **** **** +3468 Cadence_Wound **** **** **** **** **** **** **** **** +3469 Cadence_Fool **** **** **** **** **** **** **** **** +3470 Cadence_Fort **** **** **** **** **** **** **** **** +3471 Cadence_Fright **** **** **** **** **** **** **** **** +3472 Cadence_Drake **** **** **** **** **** **** **** **** +3473 Cadence_Step **** **** **** **** **** **** **** **** +3474 ResonantVoice **** **** **** **** **** **** **** **** +3475 Grapple **** **** **** **** **** **** **** **** +3476 Bullrush **** **** **** **** **** **** **** **** +3477 Overrun **** **** **** **** **** **** **** **** +3478 Trip **** **** **** **** **** **** **** **** +3479 Charge **** **** **** **** **** **** **** **** +3480 ChargeBullrush **** **** **** **** **** **** **** **** +3481 GrappleEnd **** **** **** **** **** **** **** **** +3482 CombatMove_RadialMaster **** **** **** **** **** **** **** **** +3483 MasterWand **** **** **** **** **** **** **** **** +3484 RecklessWandWielder **** **** **** **** **** **** **** **** +3485 DoubleWandWielder **** **** **** **** **** **** **** **** +3486 Wandstrike **** **** **** **** **** **** **** **** +3487 WildMage_RandomDeflector **** **** **** **** **** **** **** **** +3488 WildMage_RodOfWonder **** **** **** **** **** **** **** **** +3489 WildMage_Wildstrike **** **** **** **** **** **** **** **** +3490 FMM_SwiftShield **** **** **** **** **** **** **** **** +3491 Disarm **** **** **** **** **** **** **** **** +3492 CombatMove_RadialMaster2 **** **** **** **** **** **** **** **** +3493 RangedDisarm **** **** **** **** **** **** **** **** +3494 Stonechild_Magic_Stone **** **** **** **** **** **** **** **** +3495 FightingDefensively **** **** **** **** **** **** **** **** +3496 CombatMove_RadialMaster3 **** **** **** **** **** **** **** **** +3497 Turn_Cold **** **** **** **** **** **** **** **** +3498 ChosenOfIborighu **** **** **** **** **** **** **** **** +3499 SnowflakeWardance **** **** **** **** **** **** **** **** +3500 Min_aura_1 **** **** **** **** **** **** **** **** +3501 Min_aura_2 **** **** **** **** **** **** **** **** +3502 Min_aura_3 **** **** **** **** **** **** **** **** +3503 Min_aura_4 **** **** **** **** **** **** **** **** +3504 Min_aura_5 **** **** **** **** **** **** **** **** +3505 Min_aura_6 **** **** **** **** **** **** **** **** +3506 Min_aura_7 **** **** **** **** **** **** **** **** +3507 Min_aura_8 **** **** **** **** **** **** **** **** +3508 Min_aura_9 **** **** **** **** **** **** **** **** +3509 Min_aura_10 **** **** **** **** **** **** **** **** +3510 Min_aura_11 **** **** **** **** **** **** **** **** +3511 Maj_aura_1 **** **** **** **** **** **** **** **** +3512 Maj_aura_2 **** **** **** **** **** **** **** **** +3513 Maj_aura_3 **** **** **** **** **** **** **** **** +3514 Maj_aura_4 **** **** **** **** **** **** **** **** +3515 Maj_aura_5 **** **** **** **** **** **** **** **** +3516 Maj_aura_6 **** **** **** **** **** **** **** **** +3517 Maj_aura_7 **** **** **** **** **** **** **** **** +3518 Grant_Move **** **** **** **** **** **** **** **** +3519 Maj_aura_8 **** **** **** **** **** **** **** **** +3520 Maj_aura_9 **** **** **** **** **** **** **** **** +3521 Maj_aura_10 **** **** **** **** **** **** **** **** +3522 Maj_aura_11 **** **** **** **** **** **** **** **** +3523 Maj_aura_12 **** **** **** **** **** **** **** **** +3524 Maj_aura_13 **** **** **** **** **** **** **** **** +3525 **Truenaming_RealUtters** **** **** **** **** **** **** **** **** +3526 Defensive_Edge_Normal **** **** **** **** **** **** **** **** +3527 Defensive_Edge_Reverse **** **** **** **** **** **** **** **** +3528 InertialSurge_Normal **** **** **** **** **** **** **** **** +3529 InertialSurge_Reverse **** **** **** **** **** **** **** **** +3530 KnightsPuissance_Normal **** **** **** **** **** **** **** **** +3531 KnightsPuissance_Reverse **** **** **** **** **** **** **** **** +3532 UniversalAptitude_Normal **** **** **** **** **** **** **** **** +3533 UniversalAptitude_Reverse **** **** **** **** **** **** **** **** +3534 WordOfNurturingMinor_Normal **** **** **** **** **** **** **** **** +3535 WordOfNurturingMinor_Reverse **** **** **** **** **** **** **** **** +3536 FortifyArmour_SneakAttacks **** **** **** **** **** **** **** **** +3537 FortifyArmour_Criticals **** **** **** **** **** **** **** **** +3538 KeenWeapon **** **** **** **** **** **** **** **** +3539 FogOfTheVoid_FogCloud **** **** **** **** **** **** **** **** +3540 FogOfTheVoid_SolidFog **** **** **** **** **** **** **** **** +3541 ShieldOfTheLandscape **** **** **** **** **** **** **** **** +3542 Shockwave **** **** **** **** **** **** **** **** +3543 ArchersEye_Normal **** **** **** **** **** **** **** **** +3544 ArchersEye_Reverse **** **** **** **** **** **** **** **** +3545 HiddenTruth_Normal **** **** **** **** **** **** **** **** +3546 HiddenTruth_Reverse **** **** **** **** **** **** **** **** +3547 PercieveTheUnseen_Normal **** **** **** **** **** **** **** **** +3548 PercieveTheUnseen_Reverse **** **** **** **** **** **** **** **** +3549 SilentCaster_Normal **** **** **** **** **** **** **** **** +3550 SilentCaster_Reverse **** **** **** **** **** **** **** **** +3551 SpeedOfTheZephyr_Normal **** **** **** **** **** **** **** **** +3552 SpeedOfTheZephyr_Reverse **** **** **** **** **** **** **** **** +3553 StrikeOfMight_Normal **** **** **** **** **** **** **** **** +3554 StrikeOfMight_Reverse **** **** **** **** **** **** **** **** +3555 TemporalTwist_Normal **** **** **** **** **** **** **** **** +3556 TemporalTwist_Reverse **** **** **** **** **** **** **** **** +3557 WordOfNurturingLesser_Normal **** **** **** **** **** **** **** **** +3558 WordOfNurturingLesser_Reverse **** **** **** **** **** **** **** **** +3559 AgitateItem_Hot **** **** **** **** **** **** **** **** +3560 AgitateItem_Cold **** **** **** **** **** **** **** **** +3561 AnalyzeIten **** **** **** **** **** **** **** **** +3562 EnergyVortex_Acid **** **** **** **** **** **** **** **** +3563 EnergyVortex_Cold **** **** **** **** **** **** **** **** +3564 EnergyVortex_Elec **** **** **** **** **** **** **** **** +3565 EnergyVortex_Fire **** **** **** **** **** **** **** **** +3566 SpeakRockToMud **** **** **** **** **** **** **** **** +3567 TransformTheLandscape **** **** **** **** **** **** **** **** +3568 AcceleratedAttack_Normal **** **** **** **** **** **** **** **** +3569 AcceleratedAttack_Reverse **** **** **** **** **** **** **** **** +3570 EnergyNegation_Normal **** **** **** **** **** **** **** **** +3571 EnergyNegation_Reverse **** **** **** **** **** **** **** **** +3572 IncarnationOfAngels_Normal **** **** **** **** **** **** **** **** +3573 IncarnationOfAngels_Reverse **** **** **** **** **** **** **** **** +3574 SpeedOfTheZephyrGreater_Normal **** **** **** **** **** **** **** **** +3575 SpeedOfTheZephyrGreater_Reverse **** **** **** **** **** **** **** **** +3576 TemporalSpiral_Normal **** **** **** **** **** **** **** **** +3577 TemporalSpiral_Reverse **** **** **** **** **** **** **** **** +3578 VisionSharpened_Normal **** **** **** **** **** **** **** **** +3579 VisionSharpened_Reverse **** **** **** **** **** **** **** **** +3580 WordOfNurturingModerate_Normal **** **** **** **** **** **** **** **** +3581 WordOfNurturingModerate_Reverse **** **** **** **** **** **** **** **** +3582 RemoveItem **** **** **** **** **** **** **** **** +3583 SuppressWeapon **** **** **** **** **** **** **** **** +3584 LoreOfTheWorld **** **** **** **** **** **** **** **** +3585 MasterTheFourWinds **** **** **** **** **** **** **** **** +3586 ThwartTheTraveller **** **** **** **** **** **** **** **** +3587 BreathOfCleansing_Normal **** **** **** **** **** **** **** **** +3588 BreathOfCleansing_Reverse **** **** **** **** **** **** **** **** +3589 CasterLens_Normal **** **** **** **** **** **** **** **** +3590 CasterLens_Reverse **** **** **** **** **** **** **** **** +3591 ConfoundingResistance_Normal **** **** **** **** **** **** **** **** +3592 ConfoundingResistance_Reverse **** **** **** **** **** **** **** **** +3593 MoraleBoost_Normal **** **** **** **** **** **** **** **** +3594 MoraleBoost_Reverse **** **** **** **** **** **** **** **** +3595 MagicalContraction_Normal **** **** **** **** **** **** **** **** +3596 MagicalContraction_Reverse **** **** **** **** **** **** **** **** +3597 SpellRebirth_Normal **** **** **** **** **** **** **** **** +3598 SpellRebirth_Reverse **** **** **** **** **** **** **** **** +3599 WordOfNurturingPotent_Normal **** **** **** **** **** **** **** **** +3600 WordOfNurturingPotent_Reverse **** **** **** **** **** **** **** **** +3601 WordOfBolstering_Normal **** **** **** **** **** **** **** **** +3602 WordOfBolstering_Reverse **** **** **** **** **** **** **** **** +3603 SuppressItem **** **** **** **** **** **** **** **** +3604 TransmuteWeapon **** **** **** **** **** **** **** **** +3605 AngerTheSleepingEarth **** **** **** **** **** **** **** **** +3606 ConjunctiveGate **** **** **** **** **** **** **** **** +3607 DenyPassage **** **** **** **** **** **** **** **** +3608 EldritchAttraction_Normal **** **** **** **** **** **** **** **** +3609 EldritchAttraction_Reverse **** **** **** **** **** **** **** **** +3610 EnergyNegationGreater_Normal **** **** **** **** **** **** **** **** +3611 EnergyNegationGreater_Reverse **** **** **** **** **** **** **** **** +3612 EssenceOfLifespark_Normal **** **** **** **** **** **** **** **** +3613 EssenceOfLifespark_Reverse **** **** **** **** **** **** **** **** +3614 PreturnaturalClarity_Attack **** **** **** **** **** **** **** **** +3615 PreturnaturalClarity_Skill **** **** **** **** **** **** **** **** +3616 PreturnaturalClarity_Save **** **** **** **** **** **** **** **** +3617 PreturnaturalClarity_Reverse **** **** **** **** **** **** **** **** +3618 SensoryFocus_Normal **** **** **** **** **** **** **** **** +3619 SensoryFocus_Reverse **** **** **** **** **** **** **** **** +3620 WardOfPeace_Normal **** **** **** **** **** **** **** **** +3621 WardOfPeace_Reverse **** **** **** **** **** **** **** **** +3622 WordOfNurturingCritical_Normal **** **** **** **** **** **** **** **** +3623 WordOfNurturingCritical_Reverse **** **** **** **** **** **** **** **** +3624 MetamagicCatalyst_Empower **** **** **** **** **** **** **** **** +3625 MetamagicCatalyst_Extend **** **** **** **** **** **** **** **** +3626 MetamagicCatalyst_Maximize **** **** **** **** **** **** **** **** +3627 SeizeItem **** **** **** **** **** **** **** **** +3628 BreathOfRecovery_Normal **** **** **** **** **** **** **** **** +3629 BreathOfRecovery_Reverse **** **** **** **** **** **** **** **** +3630 EtherReforged_Normal **** **** **** **** **** **** **** **** +3631 EtherReforged_Reverse **** **** **** **** **** **** **** **** +3632 KnightsPuissanceGreater_Normal **** **** **** **** **** **** **** **** +3633 KnightsPuissanceGreater_Reverse **** **** **** **** **** **** **** **** +3634 MysticRampart_Normal **** **** **** **** **** **** **** **** +3635 MysticRampart_Reverse **** **** **** **** **** **** **** **** +3636 SingularMind_Normal **** **** **** **** **** **** **** **** +3637 SingularMind_Reverse **** **** **** **** **** **** **** **** +3638 WordOfNurturingGreater_Normal **** **** **** **** **** **** **** **** +3639 WordOfNurturingGreater_Reverse **** **** **** **** **** **** **** **** +3640 **** **** **** **** **** **** **** **** **** +3641 Wild_Shape_Plant **** **** **** **** **** **** **** **** +3642 Wild_Shape_Plant_01 **** **** **** **** **** **** **** **** +3643 Wild_Shape_Plant_02 **** **** **** **** **** **** **** **** +3644 Wild_Shape_Plant_03 **** **** **** **** **** **** **** **** +3645 Wild_Shape_Plant_04 **** **** **** **** **** **** **** **** +3646 Wild_Shape_Plant_05 **** **** **** **** **** **** **** **** +3647 **** **** **** **** **** **** **** **** **** +3648 **** **** **** **** **** **** **** **** **** +3649 Unseen_Weapon_Activate **** **** **** **** **** **** **** **** +3650 Unseen_Weapon_Unerring_Strike **** **** **** **** **** **** **** **** +3651 Unseen_Weapon_Unexpected_Strike **** **** **** **** **** **** **** **** +3652 Unseen_Weapon_Ephemeral_Weapon **** **** **** **** **** **** **** **** +3653 Unseen_Weapon_Shadowy_Strike **** **** **** **** **** **** **** **** +3654 Unseen_Weapon_Far_Shadow **** **** **** **** **** **** **** **** +3655 GreaterScrying **** **** **** **** **** **** **** **** +3656 DiscernLocation **** **** **** **** **** **** **** **** +3657 LocateCreature **** **** **** **** **** **** **** **** +3658 LocateObject **** **** **** **** **** **** **** **** +3659 ArcaneEye **** **** **** **** **** **** **** **** +3660 ObscureObject **** **** **** **** **** **** **** **** +3661 Sequester **** **** **** **** **** **** **** **** +3662 SarcophagusOfStone **** Reflex **** R 1 **** **** **** +3663 ArrowOfBone **** **** **** **** **** **** **** **** +3664 DraconicMight **** **** **** E 0 2 9 **** +3665 ExtractWaterElemental **** Fortitude 1 R 1 **** **** **** +3666 HeartRipper **** **** **** **** **** **** **** **** +3667 LifeBolt **** **** **** **** **** **** **** **** +3668 RainbowBlast **** Reflex 1 I 1 **** **** **** +3669 ToweringOak **** **** **** E 0 2 0 **** +3670 LifeBolt1Bolt **** **** **** **** **** **** **** **** +3671 LifeBolt2Bolts **** **** **** **** **** **** **** **** +3672 LifeBolt3Bolts **** **** **** **** **** **** **** **** +3673 LifeBolt4Bolts **** **** **** **** **** **** **** **** +3674 LifeBolt5Bolts **** **** **** **** **** **** **** **** +3675 DisruptUndead **** **** **** **** **** **** **** **** +3676 Otilukes_Resilient_Sphere **** Reflex 1 R 1 **** **** **** +3677 FistOfStone **** **** **** E 0 2 0 **** +3678 BladesOfFire **** **** **** E 0 2 15 **** +3679 FireTrap **** **** **** **** **** **** **** **** +3680 Pyrotechnics **** **** **** **** **** **** **** **** +3681 IceKnife **** **** **** **** **** **** **** **** +3682 MassFireShieldRed **** **** **** **** **** **** **** **** +3683 WhirlingBlade **** **** **** I 1 **** **** **** +3684 PnP_FireShield **** **** **** **** **** **** **** **** +3685 RingOfBlades **** **** **** E 0 2 7 **** +3686 SleetStorm **** **** **** I 1 **** **** **** +3687 OrbOfForce **** **** **** R 1 **** **** **** +3688 MassFireShield **** **** **** **** **** **** **** **** +3689 PrismaticRay **** Reflex 1 R 1 **** **** **** +3690 SwordsageRecoverManeuver **** **** **** **** **** **** **** **** +3691 OtilukesFreezingSphere Cold Reflex 1 I 1 **** **** **** +3692 WavesOfExhaustion **** **** 1 I 1 **** **** **** +3693 PrismaticWall **** Reflex 1 I 1 **** **** **** +3694 ScintillatingPattern Mind_Affecting **** 1 I 1 **** **** **** +3695 PrismaticSphere **** **** **** P 0 2 0 **** +3696 Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +3697 Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +3698 GreaterDisruptUndead **** **** **** **** **** **** **** **** +3699 PnP_FireShieldRed **** **** **** **** **** **** **** **** +3700 PnPFireShieldBlue **** **** **** **** **** **** **** **** +3701 MassFireShieldBlue **** **** **** **** **** **** **** **** +3702 ArrowStorm **** **** **** **** **** **** **** **** +3703 ArrowSplit **** **** **** R 1 **** **** **** +3704 BloodfreezeArrow Cold Fortitude 1 R 1 **** **** **** +3705 DischargeCrown **** **** **** **** **** **** **** **** +3706 DoublestrikeArrow **** **** **** D 1 **** **** **** +3707 DetectFavoredEnemies **** **** **** **** **** **** **** **** +3708 DarkflameArrow **** **** 1 R 1 **** **** **** +3709 HealAnimalCompanion **** **** **** **** **** **** **** **** +3710 ShadowArrow **** **** 1 R 1 **** **** **** +3711 Snare **** **** **** **** **** **** **** **** +3712 SpellslayerArrow **** **** 1 R 1 **** **** **** +3713 AcidicFire **** **** **** **** **** **** **** **** +3714 AlchemistsFrost **** **** **** **** **** **** **** **** +3715 AlchemicalSleepingGas **** **** **** **** **** **** **** **** +3716 AlchemistsSpark **** **** **** **** **** **** **** **** +3717 BlendCream **** **** **** **** **** **** **** **** +3718 Brittlebone **** **** **** **** **** **** **** **** +3719 Cracklepowder **** **** **** **** **** **** **** **** +3720 EmbalmingFire **** **** **** **** **** **** **** **** +3721 FareyeOil **** **** **** **** **** **** **** **** +3722 FesteringBomb **** **** **** **** **** **** **** **** +3723 FlashPellet **** **** **** **** **** **** **** **** +3724 HealersBalm **** **** **** **** **** **** **** **** +3725 KeenearPowder **** **** **** **** **** **** **** **** +3726 LockslipGrease **** **** **** **** **** **** **** **** +3727 NaturesDraught **** **** **** **** **** **** **** **** +3728 Nerv **** **** **** **** **** **** **** **** +3729 ScreamingFlask **** **** **** **** **** **** **** **** +3730 Softfoot **** **** **** **** **** **** **** **** +3731 WeepingStone **** **** **** **** **** **** **** **** +3732 BileDroppings **** **** **** **** **** **** **** **** +3733 Shedden **** **** **** **** **** **** **** **** +3734 Shedden2 **** **** **** **** **** **** **** **** +3735 Shedden3 **** **** **** **** **** **** **** **** +3736 Shedden4 **** **** **** **** **** **** **** **** +3737 Shedden5 **** **** **** **** **** **** **** **** +3738 Antitoxin **** **** **** **** **** **** **** **** +3739 SuddenRecover **** **** **** **** **** **** **** **** +3740 SongWhiteRaven **** **** **** **** **** **** **** **** +3741 StonePower **** **** **** **** **** **** **** **** +3742 MorphemeSavant_Master **** **** **** **** **** **** **** **** +3743 ShadowmasterConceal **** **** **** **** **** **** **** **** +3744 Shadowmaster_Shades_Master **** **** **** **** **** **** **** **** +3745 Shadowmaster_Summon_Shadow **** **** **** **** **** **** **** **** +3746 Shadowmaster_Cone_of_Cold **** **** **** **** **** **** **** **** +3747 Shadowmaster_Fireball **** **** **** **** **** **** **** **** +3748 Shadowmaster_Stoneskin **** **** **** **** **** **** **** **** +3749 Shadowmaster_Wall_of_Fire **** **** **** **** **** **** **** **** +3750 MorphemeSavantKill **** **** **** **** **** **** **** **** +3751 MorphemeSavantStun **** **** **** **** **** **** **** **** +3752 MasterOfElements_Master **** **** **** **** **** **** **** **** +3753 MasterOfElements_SummonAir **** **** **** **** **** **** **** **** +3754 MasterOfElements_SummonEarth **** **** **** **** **** **** **** **** +3755 MasterOfElements_SummonFire **** **** **** **** **** **** **** **** +3756 MasterOfElements_SummonWater **** **** **** **** **** **** **** **** +3757 MasterOfElements_Dominate **** **** **** **** **** **** **** **** +3758 LordOfAllEssences **** **** **** **** **** **** **** **** +3759 TouchVitality_Master **** **** **** **** **** **** **** **** +3760 PresenceAura **** **** **** **** **** **** **** **** +3761 VigorAura **** **** **** **** **** **** **** **** +3762 ToughnesAura **** **** **** **** **** **** **** **** +3763 EnergyShldAura **** **** **** **** **** **** **** **** +3764 ResistanceAura **** **** **** **** **** **** **** **** +3765 PowerAura **** **** **** **** **** **** **** **** +3766 SenseAura **** **** **** **** **** **** **** **** +3767 TouchVitality **** **** **** **** **** **** **** **** +3768 TouchVitalityMinor **** **** **** **** **** **** **** **** +3769 TouchVitalityRestore **** **** **** **** **** **** **** **** +3770 TouchVitalityMajor **** **** **** **** **** **** **** **** +3771 DragonShamanBreath **** **** **** **** **** **** **** **** +3772 InsightAura **** **** **** **** **** **** **** **** +3773 ResolveAura **** **** **** **** **** **** **** **** +3774 StaminaAura **** **** **** **** **** **** **** **** +3775 SwiftnessAura **** **** **** **** **** **** **** **** +3776 BonusResistAcidAura **** **** **** **** **** **** **** **** +3777 BonusResistColdAura **** **** **** **** **** **** **** **** +3778 BonusResistElecAura **** **** **** **** **** **** **** **** +3779 BonusResistFireAura **** **** **** **** **** **** **** **** +3780 MarshalInsightAura **** **** **** **** **** **** **** **** +3781 MarshalPresenceAura **** **** **** **** **** **** **** **** +3782 MarshalResistAcidAura **** **** **** **** **** **** **** **** +3783 MarshalResistColdAura **** **** **** **** **** **** **** **** +3784 MarshalResistElecAura **** **** **** **** **** **** **** **** +3785 MarshalResistFireAura **** **** **** **** **** **** **** **** +3786 MarshalResolveAura **** **** **** **** **** **** **** **** +3787 MarshalSensesAura **** **** **** **** **** **** **** **** +3788 MarshalStaminaAura **** **** **** **** **** **** **** **** +3789 MarshalSwiftnessAura **** **** **** **** **** **** **** **** +3790 MarshalToughnessAura **** **** **** **** **** **** **** **** +3791 DivineIntercession **** **** **** **** **** **** **** **** +3792 ProfaneAgony **** **** **** **** **** **** **** **** +3793 LolthsBoon **** **** **** **** **** **** **** **** +3794 Snap_Kick **** **** **** **** **** **** **** **** +3795 Verminlord_Master **** **** **** **** **** **** **** **** +3796 Verminlord_CreepingDoom **** **** **** **** **** **** **** **** +3797 Verminlord_Dominate_Vermin **** **** **** **** **** **** **** **** +3798 DespanaSchool **** **** **** **** **** **** **** **** +3799 Crinti_ShadowRide **** **** **** **** **** **** **** **** +3800 Crinti_ShadowWalk **** **** **** **** **** **** **** **** +3801 Earth_Strike **** **** **** **** **** **** **** **** +3802 FrostFolk_IceBlast **** **** **** **** **** **** **** **** +3803 TouchFatigue **** Fortitude 1 T 1 **** **** **** +3804 Uldra_Ray_of_Frost **** **** **** **** **** **** **** **** +3805 Uldra_TouchFatigue **** **** **** **** **** **** **** **** +3806 BonusInsightAura **** **** **** **** **** **** **** **** +3807 BonusPresenceAura **** **** **** **** **** **** **** **** +3808 BonusResolveAura **** **** **** **** **** **** **** **** +3809 BonusSensesAura **** **** **** **** **** **** **** **** +3810 BonusStaminaAura **** **** **** **** **** **** **** **** +3811 BonusSwiftnessAura **** **** **** **** **** **** **** **** +3812 BonusToughnessAura **** **** **** **** **** **** **** **** +3813 MagicPowerAura **** **** **** **** **** **** **** **** +3814 MarshalMagicPowerAura **** **** **** **** **** **** **** **** +3815 BonusMagicPowerAura **** **** **** **** **** **** **** **** +3816 Marrulurk_NauseatingBreath **** **** **** **** **** **** **** **** +3817 EnergyAura **** **** **** **** **** **** **** **** +3818 MarshalAcidEnergyAura **** **** **** **** **** **** **** **** +3819 MarshalColdEnergyAura **** **** **** **** **** **** **** **** +3820 MarshalElecEnergyAura **** **** **** **** **** **** **** **** +3821 MarshalFireEnergyAura **** **** **** **** **** **** **** **** +3822 BonusAcidEnergyAura **** **** **** **** **** **** **** **** +3823 BonusColdEnergyAura **** **** **** **** **** **** **** **** +3824 BonusElecEnergyAura **** **** **** **** **** **** **** **** +3825 BonusFireEnergyAura **** **** **** **** **** **** **** **** +3826 ExtaminaarCharmAnimal **** **** **** **** **** **** **** **** +3827 SuddenStalagmite **** Reflex **** R 1 **** **** **** +3828 BonesOfTheEarth **** **** **** **** **** **** **** **** +3829 BonesOfTheEarth_Feat **** **** **** **** **** **** **** **** +3830 Hallow **** **** **** **** **** **** **** **** +3831 DauntingPresence **** **** **** **** **** **** **** **** +3832 ProfaneLifeleech **** **** **** **** **** **** **** **** +3833 SacredVitality **** **** **** **** **** **** **** **** +3834 SacredVengeance **** **** **** **** **** **** **** **** +3835 Deformity(eyes) **** **** **** **** **** **** **** **** +3836 Deformity(parasite) **** **** **** **** **** **** **** **** +3837 DarkSpeech **** **** **** **** **** **** **** **** +3838 DarkSpeechDread **** **** **** **** **** **** **** **** +3839 DarkSpeechPower **** **** **** **** **** **** **** **** +3840 DarkWhispers **** **** **** **** **** **** **** **** +3841 Deformity(madness) **** **** **** **** **** **** **** **** +3842 ReflexivePsychosis **** **** **** **** **** **** **** **** +3843 ChosenOfEvil **** **** **** **** **** **** **** **** +3844 MastersWill **** **** **** **** **** **** **** **** +3845 ChosenOfEvilAttack **** **** **** **** **** **** **** **** +3846 ChosenOfEvilSkill **** **** **** **** **** **** **** **** +3847 ChosenOfEvilSave **** **** **** **** **** **** **** **** +3848 ShieldOther **** **** **** P 0 3 9 **** +3849 TensersFloatingDisk **** **** **** **** **** **** **** **** +3850 Wolfskin **** **** **** P 0 2 0 -17 +3851 True_Casting **** **** **** **** **** **** **** **** +3852 Mass_Spell_Resistance **** **** **** P 0 2 14 **** +3853 Magic_Stone **** **** **** **** **** **** **** **** +3854 Control_Weather **** **** **** **** **** **** **** **** +3855 CW_Rain **** **** **** **** **** **** **** **** +3856 CW_Snow **** **** **** **** **** **** **** **** +3857 CW_Clear **** **** **** **** **** **** **** **** +3858 Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +3859 Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +3860 Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +3861 Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +3862 Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +3863 Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +3864 Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +3865 Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +3866 Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +3867 Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +3868 Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +3869 Elder_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +3870 Elder_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +3871 Elder_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +3872 Elder_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +3873 Elder_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +3874 Elder_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +3875 Elemental_Strike **** **** **** **** **** **** **** **** +3876 Elemental_Strike_Acid **** **** **** **** **** **** **** **** +3877 Elemental_Strike_Cold **** **** **** **** **** **** **** **** +3878 Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +3879 Elemental_Strike_Fire **** **** **** **** **** **** **** **** +3880 Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +3881 WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +3882 WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +3883 WordOfRecall_Party **** **** **** **** **** **** **** **** +3884 TransportViaPlants_RadialMaster **** **** **** **** **** **** **** **** +3885 TransportViaPlants_SelfOnly **** **** **** **** **** **** **** **** +3886 TransportViaPlants_Party **** **** **** **** **** **** **** **** +3887 Factotum_ArcaneDilettante_1 **** **** **** **** **** **** **** **** +3888 Factotum_ArcaneDilettante_2 **** **** **** **** **** **** **** **** +3889 Factotum_ArcaneDilettante_3 **** **** **** **** **** **** **** **** +3890 Factotum_ArcaneDilettante_4 **** **** **** **** **** **** **** **** +3891 Factotum_ArcaneDilettante_5 **** **** **** **** **** **** **** **** +3892 Factotum_ArcaneDilettante_6 **** **** **** **** **** **** **** **** +3893 Factotum_ArcaneDilettante_7 **** **** **** **** **** **** **** **** +3894 Factotum_ArcaneDilettante_8 **** **** **** **** **** **** **** **** +3895 Factotum_Cunning_Insight_Attack **** **** **** **** **** **** **** **** +3896 Factotum_Cunning_Insight_Damage **** **** **** **** **** **** **** **** +3897 Factotum_Cunning_Insight_Saves **** **** **** **** **** **** **** **** +3898 Factotum_Cunning_Defense **** **** **** **** **** **** **** **** +3899 Factotum_Cunning_Strike **** **** **** **** **** **** **** **** +3900 Factotum_Cunning_Surge **** **** **** **** **** **** **** **** +3901 Factotum_Cunning_Breach **** **** **** **** **** **** **** **** +3902 Factotum_Cunning_Dodge **** **** **** **** **** **** **** **** +3903 Factotum_Cunning_Knowledge **** **** **** **** **** **** **** **** +3904 Factotum_Opportunistic_Piety_Heal **** **** **** **** **** **** **** **** +3905 Factotum_Opportunistic_Piety_Turn **** **** **** **** **** **** **** **** +3906 Factotum_ArcaneDilettante_SlotCheck **** **** **** **** **** **** **** **** +3907 Sharess_Fascinate **** **** **** **** **** **** **** **** +3908 Sharess_Confuse **** **** **** **** **** **** **** **** +3909 Sharess_Dominate **** **** **** **** **** **** **** **** +3910 Sharess_Sanctuary **** **** **** **** **** **** **** **** +3911 Sharess_Haste **** **** **** **** **** **** **** **** +3912 ForceOrb **** Reflex 1 R 1 **** **** **** +3913 Forsaker_FastHealing **** **** **** **** **** **** **** **** +3914 AugmentTrueFriend **** **** **** **** **** **** **** **** +3915 UrPriestSiphonSpellPower **** **** **** **** **** **** **** **** +3916 UrPriestSiphonSpellPower_Conv **** **** **** **** **** **** **** **** +3917 Factotum_CunningBrilliance_1 **** **** **** **** **** **** **** **** +3918 Factotum_CunningBrilliance_2 **** **** **** **** **** **** **** **** +3919 Factotum_CunningBrilliance_3 **** **** **** **** **** **** **** **** +3920 Factotum_CunningBrilliance_SlotCheck **** **** **** **** **** **** **** **** +3921 Arkamoi_ArcaneMastermind **** **** **** **** **** **** **** **** +3922 AlignedAura **** **** **** **** **** **** **** **** +3923 Angelskin **** **** **** **** **** **** **** **** +3924 AxiomaticStorm **** **** **** **** **** **** **** **** +3925 Bladebane **** **** **** **** **** **** **** **** +3926 BlessedAim **** **** **** **** **** **** **** **** +3927 BlessingOfTheRighteous **** **** **** **** **** **** **** **** +3928 ClearMind **** **** **** **** **** **** **** **** +3929 CloakOfBravery **** **** **** **** **** **** **** **** +3930 Diamondsteel **** **** **** **** **** **** **** **** +3931 LesserAspectOfTheDiety **** **** **** **** **** **** **** **** +3932 LawfulSword **** **** **** **** **** **** **** **** +3933 LesserAuraOfCold **** **** **** **** **** **** **** **** +3934 AuraOfTheSun **** **** **** **** **** **** **** **** +3935 RighteousFury **** **** **** **** **** **** **** **** +3936 SeekEternalRest **** **** **** **** **** **** **** **** +3937 StrengthOfStone **** **** **** **** **** **** **** **** +3938 UndeadBaneWeapon **** **** **** **** **** **** **** **** +3939 LesserViageOfTheDiety **** **** **** **** **** **** **** **** +3940 AlignedAuraChaos **** **** **** **** **** **** **** **** +3941 AlignedAuraEvil **** **** **** **** **** **** **** **** +3942 AlignedAuraGood **** **** **** **** **** **** **** **** +3943 AlignedAuraLaw **** **** **** **** **** **** **** **** +3944 AxiomaticWater **** **** **** **** **** **** **** **** +3945 BlazeOfLight **** **** **** **** **** **** **** **** +3946 CallMount **** **** **** **** **** **** **** **** +3947 Castigate **** **** **** **** **** **** **** **** +3948 CheckmatesLight **** **** **** **** **** **** **** **** +3949 ConduitOfLight **** **** **** **** **** **** **** **** +3950 CurseOfTheBrute **** **** **** **** **** **** **** **** +3951 Denounce **** **** **** **** **** **** **** **** +3952 DevastatingSmite **** **** **** **** **** **** **** **** +3953 DivinePresence **** **** **** **** **** **** **** **** +3954 EmbraceOfEndlessDay **** **** **** **** **** **** **** **** +3955 EnergizedShield **** **** **** **** **** **** **** **** +3956 LesserEnergizedShield **** **** **** **** **** **** **** **** +3957 EstanasStew **** **** **** **** **** **** **** **** +3958 FavorOfTheMartyr **** **** **** **** **** **** **** **** +3959 Forceward **** **** **** **** **** **** **** **** +3960 GloryOfTheMartyr **** **** **** **** **** **** **** **** +3961 HolyFire **** **** **** **** **** **** **** **** +3962 HolyStorm **** **** **** **** **** **** **** **** +3963 InvokeTheCeruleanSign **** **** **** **** **** **** **** **** +3964 IrresistibleForce **** **** **** **** **** **** **** **** +3965 LegionsMagicWeapon **** **** **** **** **** **** **** **** +3966 MajorResistance **** **** **** **** **** **** **** **** +3967 MeteoricStrike **** **** **** **** **** **** **** **** +3968 QuickMarch **** **** **** **** **** **** **** **** +3969 ResistEnergy **** **** **** **** **** **** **** **** +3970 Revenance **** **** **** **** **** **** **** **** +3971 RhinosRush **** **** **** **** **** **** **** **** +3972 RighteousAura **** **** **** **** **** **** **** **** +3973 SeedOfLife **** **** **** **** **** **** **** **** +3974 ShieldOfWarding **** **** **** **** **** **** **** **** +3975 SmiteHeretic **** **** **** **** **** **** **** **** +3976 SmiteOfSacredFire **** **** **** **** **** **** **** **** +3977 SoldiersOfSanctity **** **** **** **** **** **** **** **** +3978 SoulOfLight **** **** **** **** **** **** **** **** +3979 SoulOfOrder **** **** **** **** **** **** **** **** +3980 Stabilize **** **** **** **** **** **** **** **** +3981 StrategicCharge **** **** **** **** **** **** **** **** +3982 TouchOfRestoration **** **** **** **** **** **** **** **** +3983 TruePrayerOfTheChosen **** **** **** **** **** **** **** **** +3984 TruePrayerOfTheFaithful **** **** **** **** **** **** **** **** +3985 UnmovableIbject **** **** **** **** **** **** **** **** +3986 BFZ_FatefulStride **** **** **** **** **** **** **** **** +3987 TN_DES_100 **** **** **** **** **** **** **** **** +3988 TN_DES_20 **** **** **** **** **** **** **** **** +3989 Hext_Fright **** **** **** **** **** **** **** **** +3990 INSTRUMENT **** **** **** **** **** **** **** **** +3991 LLIIRAS_AURA **** **** **** **** **** **** **** **** +3992 MIELIKKI_TRUTH **** **** **** **** **** **** **** **** +3993 LYCANBANE **** **** **** **** **** **** **** **** +3994 CRAFT_MHARPER_ITEM **** **** **** **** **** **** **** **** +3995 Shou_Flurry **** **** **** **** **** **** **** **** +3996 TN_Unsummon **** **** **** **** **** **** **** **** +3997 Summon_fiend **** **** **** **** **** **** **** **** +3998 Pit_Glare **** **** **** **** **** **** **** **** +3999 Fiendish_Glare **** **** **** **** **** **** **** **** +4000 Epic_Spell_Achilles_Heel **** **** **** **** **** **** **** **** +4001 Epic_Spell_All_Hope_Lost **** **** **** **** **** **** **** **** +4002 Epic_Spell_Allied_Martyr **** **** **** **** **** **** **** **** +4003 Epic_Spell_Anarchys_Call **** **** **** **** **** **** **** **** +4004 Epic_Spell_Animus_Blast **** **** **** **** **** **** **** **** +4005 Epic_Spell_Animus_Blizzard **** **** **** **** **** **** **** **** +4006 Epic_Spell_Army_Unfallen **** **** **** **** **** **** **** **** +4007 Epic_Spell_Audience_of_Stone **** **** **** **** **** **** **** **** +4008 Epic_Spell_Battle_Bounding **** **** **** **** **** **** **** **** +4009 Epic_Spell_Celestial_Council **** **** **** **** **** **** **** **** +4010 Epic_Spell_Champions_Valor **** **** **** **** **** **** **** **** +4011 Epic_Spell_Contingent_Resurrection **** **** **** **** **** **** **** **** +4012 Epic_Spell_Contingent_Reunion **** **** **** **** **** **** **** **** +4013 Epic_Spell_Deadeye_Sense **** **** **** **** **** **** **** **** +4014 Epic_Spell_Deathmark **** **** **** **** **** **** **** **** +4015 Epic_Spell_Dire_Winter **** **** **** **** **** **** **** **** +4016 Epic_Spell_Dragon_Knight **** **** **** **** **** **** **** **** +4017 Epic_Spell_Dreamscape **** **** **** **** **** **** **** **** +4018 Epic_Spell_Dullblades **** **** **** **** **** **** **** **** +4019 Epic_Spell_Dweomer_Thief **** **** **** **** **** **** **** **** +4020 Epic_Spell_Enslave **** **** **** **** **** **** **** **** +4021 Epic_Spell_Epic_Mage_Armor **** **** **** **** **** **** **** **** +4022 Epic_Spell_Epic_Repulsion **** **** **** **** **** **** **** **** +4023 Epic_Spell_Epic_Spell_Reflection **** **** **** **** **** **** **** **** +4024 Epic_Spell_Epic_Warding **** **** **** **** **** **** **** **** +4025 Epic_Spell_Eternal_Freedom **** **** **** **** **** **** **** **** +4026 Epic_Spell_Fiendish_Words **** **** **** **** **** **** **** **** +4027 Epic_Spell_Fleetness_of_Foot **** **** **** **** **** **** **** **** +4028 Epic_Spell_Gem_Cage **** **** **** **** **** **** **** **** +4029 Epic_Spell_Godsmite **** **** **** **** **** **** **** **** +4030 Epic_Spell_Greater_Ruin **** **** **** **** **** **** **** **** +4031 Epic_Spell_Greater_Spell_Resistance **** **** **** **** **** **** **** **** +4032 Epic_Spell_Greater_Timestop **** **** **** **** **** **** **** **** +4033 Epic_Spell_Hell_Send **** **** **** **** **** **** **** **** +4034 Epic_Spell_Hellball **** **** **** **** **** **** **** **** +4035 Epic_Spell_Herculean_Alliance **** **** **** **** **** **** **** **** +4036 Epic_Spell_Herculean_Empowerment **** **** **** **** **** **** **** **** +4037 Epic_Spell_Impenetrability **** **** **** **** **** **** **** **** +4038 Epic_Spell_Leech_Field **** **** **** **** **** **** **** **** +4039 Epic_Spell_Legendary_Artisan **** **** **** **** **** **** **** **** +4040 Epic_Spell_Life_Force_Transfer **** **** **** **** **** **** **** **** +4041 Epic_Spell_Magma_Burst **** **** **** **** **** **** **** **** +4042 Epic_Spell_Mass_Penguin **** **** **** **** **** **** **** **** +4043 Epic_Spell_Momento_Mori **** **** **** **** **** **** **** **** +4044 Epic_Spell_Mummy_Dust **** **** **** **** **** **** **** **** +4045 Epic_Spell_Nailed_to_the_Sky **** **** **** **** **** **** **** **** +4046 Epic_Spell_Nights_Undoing **** **** **** **** **** **** **** **** +4047 Epic_Spell_Order_Restored **** **** **** **** **** **** **** **** +4048 Epic_Spell_Paths_Become_Known **** **** **** **** **** **** **** **** +4049 Epic_Spell_Peerless_Penitence **** **** **** **** **** **** **** **** +4050 Epic_Spell_Pestilence **** **** **** **** **** **** **** **** +4051 Epic_Spell_Pious_Parley **** **** **** **** **** **** **** **** +4052 Epic_Spell_Planar_Cell **** **** **** **** **** **** **** **** +4053 Epic_Spell_Psionic_Salvo **** **** **** **** **** **** **** **** +4054 Epic_Spell_Rain_of_Fire **** **** **** **** **** **** **** **** +4055 Epic_Spell_Risen_Reunited **** **** **** **** **** **** **** **** +4056 Epic_Spell_Ruin **** **** **** **** **** **** **** **** +4057 Epic_Spell_Singular_Sunder **** **** **** **** **** **** **** **** +4058 Epic_Spell_Spell_Worm **** **** **** **** **** **** **** **** +4059 Epic_Spell_Storm_Mantle **** **** **** **** **** **** **** **** +4060 Epic_Spell_Summon_Aberration **** **** **** **** **** **** **** **** +4061 Epic_Spell_Superb_Dispelling **** **** **** **** **** **** **** **** +4062 Epic_Spell_Symrustars_Spellbinding **** **** **** **** **** **** **** **** +4063 Epic_Spell_The_Withering **** **** **** **** **** **** **** **** +4064 Epic_Spell_Tolodines_Killing_Wind **** **** **** **** **** **** **** **** +4065 Epic_Spell_Transcendent_Vitality **** **** **** **** **** **** **** **** +4066 Epic_Spell_Twinfiend **** **** **** **** **** **** **** **** +4067 Epic_Spell_Unholy_Disciple **** **** **** **** **** **** **** **** +4068 Epic_Spell_Unimpinged **** **** **** **** **** **** **** **** +4069 Epic_Spell_Unseen_Wanderer **** **** **** **** **** **** **** **** +4070 Epic_Spell_Whip_of_Shar **** **** **** **** **** **** **** **** +4071 Wander_Unseen **** **** **** **** **** **** **** **** +4072 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4073 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4074 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4075 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4076 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4077 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4078 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4079 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4080 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4081 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4082 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4083 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4084 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4085 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4086 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4087 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4088 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4089 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4090 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4091 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4092 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4093 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4094 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4095 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4096 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4097 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4098 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4099 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4100 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4101 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4102 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4103 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4104 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4105 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4106 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4107 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4108 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4109 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4110 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4111 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4112 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4113 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4114 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4115 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4116 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4117 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4118 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4119 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4120 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4121 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4122 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4123 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4124 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4125 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4126 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4127 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4128 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4129 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4130 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4131 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4132 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4133 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4134 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4135 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4136 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4137 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4138 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4139 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4140 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4141 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4142 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4143 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4144 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4145 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4146 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4147 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4148 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4149 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4150 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4151 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4152 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4153 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4154 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4155 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4156 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4157 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4158 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4159 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4160 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4161 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4162 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4163 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4164 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4165 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4166 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4167 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4168 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4169 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4170 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4171 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4172 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4173 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4174 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4175 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4176 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4177 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4178 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4179 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4180 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4181 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4182 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4183 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4184 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4185 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4186 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4187 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4188 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4189 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4190 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4191 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4192 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4193 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4194 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4195 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4196 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4197 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4198 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4199 ReservedForISCAndESS **** **** **** **** **** **** **** **** +4200 ####START_OF_NEW_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +4201 Bard_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +4202 Bard_Dancing_Lights **** **** **** **** **** **** **** **** +4203 Bard_Daze **** **** **** **** **** **** **** **** +4204 Bard_Flare **** **** **** **** **** **** **** **** +4205 Bard_Light **** **** **** **** **** **** **** **** +4206 Bard_MAGE_HAND **** **** **** **** **** **** **** **** +4207 Bard_Read_Magic **** **** **** **** **** **** **** **** +4208 Bard_Resistance **** **** **** **** **** **** **** **** +4209 Bard_Amplify **** **** **** **** **** **** **** **** +4210 Bard_BalagarnsIronHorn **** **** **** **** **** **** **** **** +4211 Bard_Cause_Fear **** **** **** **** **** **** **** **** +4212 Bard_Charm_Person **** **** **** **** **** **** **** **** +4213 Bard_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4214 Bard_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +4215 Bard_Disguise_Self_Learn **** **** **** **** **** **** **** **** +4216 Bard_Disguise_Self_Options **** **** **** **** **** **** **** **** +4217 Bard_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +4218 Bard_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +4219 Bard_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +4220 Bard_Expeditious_Retreat **** **** **** **** **** **** **** **** +4221 Bard_EXTRACT_DRUG **** **** **** **** **** **** **** **** +4222 Bard_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +4223 Bard_EXTRACT_VODARE **** **** **** **** **** **** **** **** +4224 Bard_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +4225 Bard_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +4226 Bard_Grease **** **** **** **** **** **** **** **** +4227 Bard_Identify **** **** **** **** **** **** **** **** +4228 Bard_Lesser_Dispel **** **** **** **** **** **** **** **** +4229 Bard_Mage_Armor **** **** **** **** **** **** **** **** +4230 Bard_Magic_Weapon **** **** **** **** **** **** **** **** +4231 Bard_ObscureObject **** **** **** **** **** **** **** **** +4232 Bard_Protection_from_Chaos **** **** **** **** **** **** **** **** +4233 Bard_Protection_from_Evil **** **** **** **** **** **** **** **** +4234 Bard_Protection_from_Good **** **** **** **** **** **** **** **** +4235 Bard_Protection_from_Law **** **** **** **** **** **** **** **** +4236 Bard_RAY_OF_HOPE **** **** **** **** **** **** **** **** +4237 Bard_Sleep **** **** **** **** **** **** **** **** +4238 Bard_SORROW **** **** **** **** **** **** **** **** +4239 Bard_Summon_Creature_I **** **** **** **** **** **** **** **** +4240 Bard_ADDICTION **** **** **** **** **** **** **** **** +4241 Bard_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +4242 Bard_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +4243 Bard_ADDICTION_VODARE **** **** **** **** **** **** **** **** +4244 Bard_ADDICTION_AGONY **** **** **** **** **** **** **** **** +4245 Bard_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +4246 Bard_Alter_Self_Learn **** **** **** **** **** **** **** **** +4247 Bard_Alter_Self_Options **** **** **** **** **** **** **** **** +4248 Bard_Alter_Self_QS1 **** **** **** **** **** **** **** **** +4249 Bard_Alter_Self_QS2 **** **** **** **** **** **** **** **** +4250 Bard_Alter_Self_QS3 **** **** **** **** **** **** **** **** +4251 Bard_Blindness_and_Deafness **** **** **** **** **** **** **** **** +4252 Bard_Blur **** **** **** **** **** **** **** **** +4253 Bard_Bulls_Strength **** **** **** **** **** **** **** **** +4254 Bard_Calm_Emotions **** **** **** **** **** **** **** **** +4255 Bard_Cats_Grace **** **** **** **** **** **** **** **** +4256 Bard_Clarity **** **** **** **** **** **** **** **** +4257 Bard_Cloud_of_Bewilderment **** **** **** **** **** **** **** **** +4258 Bard_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +4259 Bard_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +4260 Bard_Darkness **** **** **** **** **** **** **** **** +4261 Bard_Daze_Monster **** **** **** **** **** **** **** **** +4262 Bard_Eagle_Splendor **** **** **** **** **** **** **** **** +4263 Bard_ELATION **** **** **** **** **** **** **** **** +4264 Bard_Foxs_Cunning **** **** **** **** **** **** **** **** +4265 Bard_Ghostly_Visage **** **** **** **** **** **** **** **** +4266 Bard_Glitterdust **** **** **** **** **** **** **** **** +4267 Bard_Heroism **** **** **** **** **** **** **** **** +4268 Bard_Hold_Person **** **** **** **** **** **** **** **** +4269 Bard_Invisibility **** **** **** **** **** **** **** **** +4270 Bard_LocateObject **** **** **** **** **** **** **** **** +4271 Bard_MirrorImage **** **** **** **** **** **** **** **** +4272 Bard_Owls_Wisdom **** **** **** **** **** **** **** **** +4273 Bard_Pyrotechnics **** **** **** **** **** **** **** **** +4274 Bard_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +4275 Bard_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +4276 Bard_Scare **** **** **** **** **** **** **** **** +4277 Bard_See_Invisibility **** **** **** **** **** **** **** **** +4278 Bard_Silence **** **** **** **** **** **** **** **** +4279 Bard_SONG_OF_FESTERING_DEATH **** **** **** **** **** **** **** **** +4280 Bard_Sound_Burst **** **** **** **** **** **** **** **** +4281 Bard_Summon_Creature_II **** **** **** **** **** **** **** **** +4282 Bard_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +4283 Bard_Ultravision **** **** **** **** **** **** **** **** +4284 Bard_UndetectableAlignment **** **** **** **** **** **** **** **** +4285 Bard_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +4286 Bard_WhirlingBlade **** **** **** **** **** **** **** **** +4287 Bard_Bestow_Curse **** **** **** **** **** **** **** **** +4288 Bard_Charm_Monster **** **** **** **** **** **** **** **** +4289 Bard_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +4290 Bard_Confusion **** **** **** **** **** **** **** **** +4291 Bard_CrushingDespair **** **** **** **** **** **** **** **** +4292 Bard_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +4293 Bard_CURSE_OF_THE_PUTRID_HUSK **** **** **** **** **** **** **** **** +4294 Bard_Daylight **** **** **** **** **** **** **** **** +4295 Bard_Dispel_Magic **** **** **** **** **** **** **** **** +4296 Bard_Displacement **** **** **** **** **** **** **** **** +4297 Bard_Fear **** **** **** **** **** **** **** **** +4298 Bard_Find_Traps **** **** **** **** **** **** **** **** +4299 Bard_GLIBNESS **** **** **** **** **** **** **** **** +4300 Bard_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +4301 Bard_Gust_of_Wind **** **** **** **** **** **** **** **** +4302 Bard_Halt **** **** **** **** **** **** **** **** +4303 Bard_Haste **** **** **** **** **** **** **** **** +4304 Bard_Invisibility_Sphere **** **** **** **** **** **** **** **** +4305 Bard_Keen_Edge **** **** **** **** **** **** **** **** +4306 Bard_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +4307 Bard_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +4308 Bard_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +4309 Bard_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +4310 Bard_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +4311 Bard_Remove_Curse **** **** **** **** **** **** **** **** +4312 Bard_Remove_Disease **** **** **** **** **** **** **** **** +4313 Bard_Scrying **** **** **** **** **** **** **** **** +4314 Bard_Slow **** **** **** **** **** **** **** **** +4315 Bard_Sonic_Shield **** **** **** **** **** **** **** **** +4316 Bard_STUNNING_SCREECH **** **** **** **** **** **** **** **** +4317 Bard_Summon_Creature_III **** **** **** **** **** **** **** **** +4318 Bard_Weapon_of_Impact **** **** **** **** **** **** **** **** +4319 Bard_Wounding_Whispers **** **** **** **** **** **** **** **** +4320 Bard_BreakEnchantment **** **** **** **** **** **** **** **** +4321 Bard_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +4322 Bard_DetectScrying **** **** **** **** **** **** **** **** +4323 Bard_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +4324 Bard_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +4325 Bard_DimensionDoor_Party **** **** **** **** **** **** **** **** +4326 Bard_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +4327 Bard_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +4328 Bard_Dismissal **** **** **** **** **** **** **** **** +4329 Bard_Dominate_Person **** **** **** **** **** **** **** **** +4330 Bard_Greater_Resistance **** **** **** **** **** **** **** **** +4331 Bard_Hold_Monster **** **** **** **** **** **** **** **** +4332 Bard_Improved_Invisibility **** **** **** **** **** **** **** **** +4333 Bard_Legend_Lore **** **** **** **** **** **** **** **** +4334 Bard_LocateCreature **** **** **** **** **** **** **** **** +4335 Bard_Mass_Ultravision **** **** **** **** **** **** **** **** +4336 Bard_Neutralize_Poison **** **** **** **** **** **** **** **** +4337 Bard_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +4338 Bard_RepelVermin **** **** **** **** **** **** **** **** +4339 Bard_Shout **** **** **** **** **** **** **** **** +4340 Bard_Summon_Creature_IV **** **** **** **** **** **** **** **** +4341 Bard_War_Cry **** **** **** **** **** **** **** **** +4342 Bard_Ethereal_Visage **** **** **** **** **** **** **** **** +4343 Bard_Greater_Dispelling **** **** **** **** **** **** **** **** +4344 Bard_Greater_Heroism **** **** **** **** **** **** **** **** +4345 Bard_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +4346 Bard_Healing_Circle **** **** **** **** **** **** **** **** +4347 Bard_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4348 Bard_Mind_Fog **** **** **** **** **** **** **** **** +4349 Bard_Mislead **** **** **** **** **** **** **** **** +4350 Bard_MORALITY_UNDONE **** **** **** **** **** **** **** **** +4351 Bard_SongOfDiscord **** **** **** **** **** **** **** **** +4352 Bard_Summon_Creature_V **** **** **** **** **** **** **** **** +4353 Bard_Animate_Object **** **** **** **** **** **** **** **** +4354 Bard_Dirge **** **** **** **** **** **** **** **** +4355 Bard_Energy_Buffer **** **** **** **** **** **** **** **** +4356 Bard_Eyebite **** **** **** **** **** **** **** **** +4357 Bard_Greater_Shout **** **** **** **** **** **** **** **** +4358 Bard_GreaterScrying **** **** **** **** **** **** **** **** +4359 Bard_Ice_Storm **** **** **** **** **** **** **** **** +4360 Bard_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +4361 Bard_Mass_Cats_Grace **** **** **** **** **** **** **** **** +4362 Bard_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +4363 Bard_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +4364 Bard_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +4365 Bard_Mass_Haste **** **** **** **** **** **** **** **** +4366 Bard_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +4367 Bard_Summon_Creature_VI **** **** **** **** **** **** **** **** +4368 Bard_Superior_Resistance **** **** **** **** **** **** **** **** +4369 Bard_WAVE_OF_PAIN **** **** **** **** **** **** **** **** +4370 Sorcerer_Acid_Splash **** **** **** **** **** **** **** **** +4371 Sorcerer_Dancing_Lights **** **** **** **** **** **** **** **** +4372 Sorcerer_Daze **** **** **** **** **** **** **** **** +4373 Sorcerer_DisruptUndead **** **** **** **** **** **** **** **** +4374 Sorcerer_Electric_Jolt **** **** **** **** **** **** **** **** +4375 Sorcerer_Flare **** **** **** **** **** **** **** **** +4376 Sorcerer_Light **** **** **** **** **** **** **** **** +4377 Sorcerer_MAGE_HAND **** **** **** **** **** **** **** **** +4378 Sorcerer_Ray_of_Frost **** **** **** **** **** **** **** **** +4379 Sorcerer_Read_Magic **** **** **** **** **** **** **** **** +4380 Sorcerer_Resistance **** **** **** **** **** **** **** **** +4381 Sorcerer_ABERRATE **** **** **** **** **** **** **** **** +4382 Sorcerer_Benign_Transposition **** **** **** **** **** **** **** **** +4383 Sorcerer_BESTOW_WOUND **** **** **** **** **** **** **** **** +4384 Sorcerer_Bigbys_Tripping_Hand **** **** **** **** **** **** **** **** +4385 Sorcerer_Blade_of_Blood **** **** **** **** **** **** **** **** +4386 Sorcerer_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +4387 Sorcerer_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +4388 Sorcerer_Burning_Bolt **** **** **** **** **** **** **** **** +4389 Sorcerer_Burning_Hands **** **** **** **** **** **** **** **** +4390 Sorcerer_Cause_Fear **** **** **** **** **** **** **** **** +4391 Sorcerer_Charm_Person **** **** **** **** **** **** **** **** +4392 Sorcerer_Chill_Touch **** **** **** **** **** **** **** **** +4393 Sorcerer_Color_Spray **** **** **** **** **** **** **** **** +4394 Sorcerer_DETECT_UNDEAD **** **** **** **** **** **** **** **** +4395 Sorcerer_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +4396 Sorcerer_Disguise_Self_Learn **** **** **** **** **** **** **** **** +4397 Sorcerer_Disguise_Self_Options **** **** **** **** **** **** **** **** +4398 Sorcerer_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +4399 Sorcerer_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +4400 Sorcerer_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +4401 Sorcerer_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +4402 Sorcerer_Endure_Elements **** **** **** **** **** **** **** **** +4403 Sorcerer_ENLARGE_PERSON **** **** **** **** **** **** **** **** +4404 Sorcerer_Expeditious_Retreat **** **** **** **** **** **** **** **** +4405 Sorcerer_EXTRACT_DRUG **** **** **** **** **** **** **** **** +4406 Sorcerer_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +4407 Sorcerer_EXTRACT_VODARE **** **** **** **** **** **** **** **** +4408 Sorcerer_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +4409 Sorcerer_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +4410 Sorcerer_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +4411 Sorcerer_FistOfStone **** **** **** **** **** **** **** **** +4412 Sorcerer_Grease **** **** **** **** **** **** **** **** +4413 Sorcerer_Hail_of_Stone **** **** **** **** **** **** **** **** +4414 Sorcerer_Horizikauls_Boom **** **** **** **** **** **** **** **** +4415 Sorcerer_Ice_Dagger **** **** **** **** **** **** **** **** +4416 Sorcerer_Identify **** **** **** **** **** **** **** **** +4417 Sorcerer_Ironguts **** **** **** **** **** **** **** **** +4418 Sorcerer_Kelgores_Fire_Bolt **** **** **** **** **** **** **** **** +4419 Sorcerer_LANTERN_LIGHT **** **** **** **** **** **** **** **** +4420 Sorcerer_Lesser_Acid_Orb **** **** **** **** **** **** **** **** +4421 Sorcerer_Lesser_Cold_Orb **** **** **** **** **** **** **** **** +4422 Sorcerer_Lesser_Deflect **** **** **** **** **** **** **** **** +4423 Sorcerer_Lesser_Electric_Orb **** **** **** **** **** **** **** **** +4424 Sorcerer_Lesser_Fire_Orb **** **** **** **** **** **** **** **** +4425 Sorcerer_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +4426 Sorcerer_Lesser_Sonic_Orb **** **** **** **** **** **** **** **** +4427 Sorcerer_Mage_Armor **** **** **** **** **** **** **** **** +4428 Sorcerer_Magic_Missile **** **** **** **** **** **** **** **** +4429 Sorcerer_Magic_Weapon **** **** **** **** **** **** **** **** +4430 Sorcerer_Necrotic_Awareness **** **** **** **** **** **** **** **** +4431 Sorcerer_Negative_Energy_Ray **** **** **** **** **** **** **** **** +4432 Sorcerer_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +4433 Sorcerer_Obscuring_Mist **** **** **** **** **** **** **** **** +4434 Sorcerer_Protection_from_Chaos **** **** **** **** **** **** **** **** +4435 Sorcerer_Protection_from_Evil **** **** **** **** **** **** **** **** +4436 Sorcerer_Protection_from_Good **** **** **** **** **** **** **** **** +4437 Sorcerer_Protection_from_Law **** **** **** **** **** **** **** **** +4438 Sorcerer_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +4439 Sorcerer_REDUCE_PERSON **** **** **** **** **** **** **** **** +4440 Sorcerer_Rouse **** **** **** **** **** **** **** **** +4441 Sorcerer_Shelgarns_Persistent_Blade **** **** **** **** **** **** **** **** +4442 Sorcerer_Shield **** **** **** **** **** **** **** **** +4443 Sorcerer_ShockingGrasp **** **** **** **** **** **** **** **** +4444 Sorcerer_Sleep **** **** **** **** **** **** **** **** +4445 Sorcerer_Snillocs_Snowball **** **** **** **** **** **** **** **** +4446 Sorcerer_Spell_Jump **** **** **** **** **** **** **** **** +4447 Sorcerer_Summon_Creature_I **** **** **** **** **** **** **** **** +4448 Sorcerer_SummonUndeadI **** **** **** **** **** **** **** **** +4449 Sorcerer_TensersFloatingDisk **** **** **** **** **** **** **** **** +4450 Sorcerer_True_Casting **** **** **** **** **** **** **** **** +4451 Sorcerer_True_Strike **** **** **** **** **** **** **** **** +4452 Sorcerer_ADDICTION **** **** **** **** **** **** **** **** +4453 Sorcerer_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +4454 Sorcerer_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +4455 Sorcerer_ADDICTION_VODARE **** **** **** **** **** **** **** **** +4456 Sorcerer_ADDICTION_AGONY **** **** **** **** **** **** **** **** +4457 Sorcerer_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +4458 Sorcerer_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +4459 Sorcerer_Alter_Self_Learn **** **** **** **** **** **** **** **** +4460 Sorcerer_Alter_Self_Options **** **** **** **** **** **** **** **** +4461 Sorcerer_Alter_Self_QS1 **** **** **** **** **** **** **** **** +4462 Sorcerer_Alter_Self_QS2 **** **** **** **** **** **** **** **** +4463 Sorcerer_Alter_Self_QS3 **** **** **** **** **** **** **** **** +4464 Sorcerer_Animalistic_Power **** **** **** **** **** **** **** **** +4465 Sorcerer_AugmentFamiliar **** **** **** **** **** **** **** **** +4466 Sorcerer_BalagarnsIronHorn **** **** **** **** **** **** **** **** +4467 Sorcerer_Baleful_Transposition **** **** **** **** **** **** **** **** +4468 Sorcerer_Bigbys_Striking_Fist **** **** **** **** **** **** **** **** +4469 Sorcerer_BladesOfFire **** **** **** **** **** **** **** **** +4470 Sorcerer_Blindness_and_Deafness **** **** **** **** **** **** **** **** +4471 Sorcerer_Blur **** **** **** **** **** **** **** **** +4472 Sorcerer_Bulls_Strength **** **** **** **** **** **** **** **** +4473 Sorcerer_Cats_Grace **** **** **** **** **** **** **** **** +4474 Sorcerer_Cloud_of_Bewilderment **** **** **** **** **** **** **** **** +4475 Sorcerer_Combust **** **** **** **** **** **** **** **** +4476 Sorcerer_Command_Undead **** **** **** **** **** **** **** **** +4477 Sorcerer_Continual_Flame **** **** **** **** **** **** **** **** +4478 Sorcerer_Create_Magic_Tattoo **** **** **** **** **** **** **** **** +4479 Sorcerer_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +4480 Sorcerer_Darkness **** **** **** **** **** **** **** **** +4481 Sorcerer_Daze_Monster **** **** **** **** **** **** **** **** +4482 Sorcerer_Death_Armor **** **** **** **** **** **** **** **** +4483 Sorcerer_Deflect **** **** **** **** **** **** **** **** +4484 Sorcerer_Dimension_Hop **** **** **** **** **** **** **** **** +4485 Sorcerer_Dispelling_Touch **** **** **** **** **** **** **** **** +4486 Sorcerer_Eagle_Splendor **** **** **** **** **** **** **** **** +4487 Sorcerer_Endurance **** **** **** **** **** **** **** **** +4488 Sorcerer_ENERGIZE_POTION **** **** **** **** **** **** **** **** +4489 Sorcerer_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +4490 Sorcerer_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +4491 Sorcerer_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +4492 Sorcerer_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +4493 Sorcerer_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +4494 Sorcerer_FalseLife **** **** **** **** **** **** **** **** +4495 Sorcerer_Fireburst **** **** **** **** **** **** **** **** +4496 Sorcerer_Flame_Weapon **** **** **** **** **** **** **** **** +4497 Sorcerer_FogCloud **** **** **** **** **** **** **** **** +4498 Sorcerer_Foxs_Cunning **** **** **** **** **** **** **** **** +4499 Sorcerer_Gedlees_Electric_Loop **** **** **** **** **** **** **** **** +4500 Sorcerer_Ghostly_Visage **** **** **** **** **** **** **** **** +4501 Sorcerer_Ghoul_Touch **** **** **** **** **** **** **** **** +4502 Sorcerer_Glitterdust **** **** **** **** **** **** **** **** +4503 Sorcerer_Invisibility **** **** **** **** **** **** **** **** +4504 Sorcerer_Knock **** **** **** **** **** **** **** **** +4505 Sorcerer_Lesser_Dispel **** **** **** **** **** **** **** **** +4506 Sorcerer_LifeBolt **** **** **** **** **** **** **** **** +4507 Sorcerer_LifeBolt1Bolt **** **** **** **** **** **** **** **** +4508 Sorcerer_LifeBolt2Bolts **** **** **** **** **** **** **** **** +4509 Sorcerer_LifeBolt3Bolts **** **** **** **** **** **** **** **** +4510 Sorcerer_LifeBolt4Bolts **** **** **** **** **** **** **** **** +4511 Sorcerer_LifeBolt5Bolts **** **** **** **** **** **** **** **** +4512 Sorcerer_LocateObject **** **** **** **** **** **** **** **** +4513 Sorcerer_MASOCHISM **** **** **** **** **** **** **** **** +4514 Sorcerer_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +4515 Sorcerer_MirrorImage **** **** **** **** **** **** **** **** +4516 Sorcerer_Necrotic_Cyst **** **** **** **** **** **** **** **** +4517 Sorcerer_ObscureObject **** **** **** **** **** **** **** **** +4518 Sorcerer_Owls_Wisdom **** **** **** **** **** **** **** **** +4519 Sorcerer_ProtectionArrows **** **** **** **** **** **** **** **** +4520 Sorcerer_Pyrotechnics **** **** **** **** **** **** **** **** +4521 Sorcerer_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +4522 Sorcerer_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +4523 Sorcerer_Resist_Elements **** **** **** **** **** **** **** **** +4524 Sorcerer_Scare **** **** **** **** **** **** **** **** +4525 Sorcerer_ScorchingRay **** **** **** **** **** **** **** **** +4526 Sorcerer_See_Invisibility **** **** **** **** **** **** **** **** +4527 Sorcerer_Seeking_Ray **** **** **** **** **** **** **** **** +4528 Sorcerer_Shadow_Spray **** **** **** **** **** **** **** **** +4529 Sorcerer_SHRIVELING **** **** **** **** **** **** **** **** +4530 Sorcerer_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +4531 Sorcerer_Stone_Bones **** **** **** **** **** **** **** **** +4532 Sorcerer_Summon_Creature_II **** **** **** **** **** **** **** **** +4533 Sorcerer_SummonUndeadII **** **** **** **** **** **** **** **** +4534 Sorcerer_Sure_Strike **** **** **** **** **** **** **** **** +4535 Sorcerer_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +4536 Sorcerer_TouchIdiocy **** **** **** **** **** **** **** **** +4537 Sorcerer_Ultravision **** **** **** **** **** **** **** **** +4538 Sorcerer_UNHEAVENED **** **** **** **** **** **** **** **** +4539 Sorcerer_Web **** **** **** **** **** **** **** **** +4540 Sorcerer_WhirlingBlade **** **** **** **** **** **** **** **** +4541 Sorcerer_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +4542 Sorcerer_Clarity **** **** **** **** **** **** **** **** +4543 Sorcerer_Crown_Might **** **** **** **** **** **** **** **** +4544 Sorcerer_Crown_Protection **** **** **** **** **** **** **** **** +4545 Sorcerer_CURSE_OF_THE_PUTRID_HUSK **** **** **** **** **** **** **** **** +4546 Sorcerer_Daylight **** **** **** **** **** **** **** **** +4547 Sorcerer_DeepSlumber **** **** **** **** **** **** **** **** +4548 Sorcerer_DEVILS_EYE **** **** **** **** **** **** **** **** +4549 Sorcerer_Dispel_Magic **** **** **** **** **** **** **** **** +4550 Sorcerer_Displacement **** **** **** **** **** **** **** **** +4551 Sorcerer_DREAD_WORD **** **** **** **** **** **** **** **** +4552 Sorcerer_ELATION **** **** **** **** **** **** **** **** +4553 Sorcerer_Energy_Aegis **** **** **** **** **** **** **** **** +4554 Sorcerer_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +4555 Sorcerer_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +4556 Sorcerer_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +4557 Sorcerer_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +4558 Sorcerer_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +4559 Sorcerer_Energy_Surge **** **** **** **** **** **** **** **** +4560 Sorcerer_Energy_Surge_Acid **** **** **** **** **** **** **** **** +4561 Sorcerer_Energy_Surge_Cold **** **** **** **** **** **** **** **** +4562 Sorcerer_Energy_Surge_Elec **** **** **** **** **** **** **** **** +4563 Sorcerer_Energy_Surge_Fire **** **** **** **** **** **** **** **** +4564 Sorcerer_Energy_Surge_Sonic **** **** **** **** **** **** **** **** +4565 Sorcerer_EVIL_EYE **** **** **** **** **** **** **** **** +4566 Sorcerer_Find_Traps **** **** **** **** **** **** **** **** +4567 Sorcerer_Fireball **** **** **** **** **** **** **** **** +4568 Sorcerer_Flame_Arrow **** **** **** **** **** **** **** **** +4569 Sorcerer_Flashburst **** **** **** **** **** **** **** **** +4570 Sorcerer_Forceblast **** **** **** **** **** **** **** **** +4571 Sorcerer_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +4572 Sorcerer_GreaterDisruptUndead **** **** **** **** **** **** **** **** +4573 Sorcerer_Gust_of_Wind **** **** **** **** **** **** **** **** +4574 Sorcerer_Halt **** **** **** **** **** **** **** **** +4575 Sorcerer_HaltUndead **** **** **** **** **** **** **** **** +4576 Sorcerer_Haste **** **** **** **** **** **** **** **** +4577 Sorcerer_Heroism **** **** **** **** **** **** **** **** +4578 Sorcerer_Hold_Person **** **** **** **** **** **** **** **** +4579 Sorcerer_Ice_Burst **** **** **** **** **** **** **** **** +4580 Sorcerer_Improved_Mage_Armor **** **** **** **** **** **** **** **** +4581 Sorcerer_Invisibility_Sphere **** **** **** **** **** **** **** **** +4582 Sorcerer_Keen_Edge **** **** **** **** **** **** **** **** +4583 Sorcerer_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +4584 Sorcerer_Lightning_Bolt **** **** **** **** **** **** **** **** +4585 Sorcerer_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +4586 Sorcerer_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +4587 Sorcerer_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +4588 Sorcerer_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +4589 Sorcerer_Mestils_Acid_Breath **** **** **** **** **** **** **** **** +4590 Sorcerer_Necrotic_Bloat **** **** **** **** **** **** **** **** +4591 Sorcerer_Negative_Energy_Burst **** **** **** **** **** **** **** **** +4592 Sorcerer_NONDETECTION **** **** **** **** **** **** **** **** +4593 Sorcerer_Protection_from_Elements **** **** **** **** **** **** **** **** +4594 Sorcerer_RainbowBlast **** **** **** **** **** **** **** **** +4595 Sorcerer_RayofExhaustion **** **** **** **** **** **** **** **** +4596 Sorcerer_REALITY_BLIND **** **** **** **** **** **** **** **** +4597 Sorcerer_Regroup **** **** **** **** **** **** **** **** +4598 Sorcerer_Scintillating_Sphere **** **** **** **** **** **** **** **** +4599 Sorcerer_Serpents_Sigh **** **** **** **** **** **** **** **** +4600 Sorcerer_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +4601 Sorcerer_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +4602 Sorcerer_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +4603 Sorcerer_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +4604 Sorcerer_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +4605 Sorcerer_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +4606 Sorcerer_SleetStorm **** **** **** **** **** **** **** **** +4607 Sorcerer_Slow **** **** **** **** **** **** **** **** +4608 Sorcerer_Spiderskin **** **** **** **** **** **** **** **** +4609 Sorcerer_Stinking_Cloud **** **** **** **** **** **** **** **** +4610 Sorcerer_Summon_Creature_III **** **** **** **** **** **** **** **** +4611 Sorcerer_SummonUndeadIII **** **** **** **** **** **** **** **** +4612 Sorcerer_Vampiric_Touch **** **** **** **** **** **** **** **** +4613 Sorcerer_WaterBreathing **** **** **** **** **** **** **** **** +4614 Sorcerer_Weapon_of_Impact **** **** **** **** **** **** **** **** +4615 Sorcerer_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +4616 Sorcerer_Acid_Orb **** **** **** **** **** **** **** **** +4617 Sorcerer_ArcaneEye **** **** **** **** **** **** **** **** +4618 Sorcerer_Bestow_Curse **** **** **** **** **** **** **** **** +4619 Sorcerer_Blast_of_Flame **** **** **** **** **** **** **** **** +4620 Sorcerer_Channeled_Pyroburst **** **** **** **** **** **** **** **** +4621 Sorcerer_Channeled_Pyroburst_Swift **** **** **** **** **** **** **** **** +4622 Sorcerer_Channeled_Pyroburst_Standard **** **** **** **** **** **** **** **** +4623 Sorcerer_Channeled_Pyroburst_Full **** **** **** **** **** **** **** **** +4624 Sorcerer_Channeled_Pyroburst_Two **** **** **** **** **** **** **** **** +4625 Sorcerer_Charm_Monster **** **** **** **** **** **** **** **** +4626 Sorcerer_Cold_Orb **** **** **** **** **** **** **** **** +4627 Sorcerer_Confusion **** **** **** **** **** **** **** **** +4628 Sorcerer_Contagion **** **** **** **** **** **** **** **** +4629 Sorcerer_CrushingDespair **** **** **** **** **** **** **** **** +4630 Sorcerer_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +4631 Sorcerer_DANCING_WEB **** **** **** **** **** **** **** **** +4632 Sorcerer_DetectScrying **** **** **** **** **** **** **** **** +4633 Sorcerer_Dimensional_Anchor **** **** **** **** **** **** **** **** +4634 Sorcerer_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +4635 Sorcerer_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +4636 Sorcerer_DimensionDoor_Party **** **** **** **** **** **** **** **** +4637 Sorcerer_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +4638 Sorcerer_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +4639 Sorcerer_Doom_Scarabs **** **** **** **** **** **** **** **** +4640 Sorcerer_Electric_Orb **** **** **** **** **** **** **** **** +4641 Sorcerer_Elemental_Shield **** **** **** **** **** **** **** **** +4642 Sorcerer_Enervation **** **** **** **** **** **** **** **** +4643 Sorcerer_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +4644 Sorcerer_Fear **** **** **** **** **** **** **** **** +4645 Sorcerer_Fire_Orb **** **** **** **** **** **** **** **** +4646 Sorcerer_FireTrap **** **** **** **** **** **** **** **** +4647 Sorcerer_Greater_Resistance **** **** **** **** **** **** **** **** +4648 Sorcerer_GRIM_REVENGE **** **** **** **** **** **** **** **** +4649 Sorcerer_Ice_Storm **** **** **** **** **** **** **** **** +4650 Sorcerer_Ilyykurs_Mantle **** **** **** **** **** **** **** **** +4651 Sorcerer_Improved_Invisibility **** **** **** **** **** **** **** **** +4652 Sorcerer_Isaacs_Lesser_Missile_Storm **** **** **** **** **** **** **** **** +4653 Sorcerer_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +4654 Sorcerer_LIQUID_PAIN **** **** **** **** **** **** **** **** +4655 Sorcerer_LocateCreature **** **** **** **** **** **** **** **** +4656 Sorcerer_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +4657 Sorcerer_MASS_ENLARGE_PERSON **** **** **** **** **** **** **** **** +4658 Sorcerer_MASS_REDUCE_PERSON **** **** **** **** **** **** **** **** +4659 Sorcerer_Mass_Ultravision **** **** **** **** **** **** **** **** +4660 Sorcerer_Minor_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +4661 Sorcerer_Necrotic_Domination **** **** **** **** **** **** **** **** +4662 Sorcerer_OrbOfForce **** **** **** **** **** **** **** **** +4663 Sorcerer_Otilukes_Resilient_Sphere **** **** **** **** **** **** **** **** +4664 Sorcerer_Phantasmal_Killer **** **** **** **** **** **** **** **** +4665 Sorcerer_PnP_FireShield **** **** **** **** **** **** **** **** +4666 Sorcerer_PnP_FireShieldRed **** **** **** **** **** **** **** **** +4667 Sorcerer_PnPFireShieldBlue **** **** **** **** **** **** **** **** +4668 Sorcerer_Polymorph_Self **** **** **** **** **** **** **** **** +4669 Sorcerer_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +4670 Sorcerer_Polymorph_TROLL **** **** **** **** **** **** **** **** +4671 Sorcerer_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +4672 Sorcerer_Polymorph_PIXIE **** **** **** **** **** **** **** **** +4673 Sorcerer_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +4674 Sorcerer_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +4675 Sorcerer_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +4676 Sorcerer_Remove_Curse **** **** **** **** **** **** **** **** +4677 Sorcerer_Scrying **** **** **** **** **** **** **** **** +4678 Sorcerer_SerpentArrows **** **** **** **** **** **** **** **** +4679 Sorcerer_Shadow_Conjuration **** **** **** **** **** **** **** **** +4680 Sorcerer_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +4681 Sorcerer_SHADOW_CON_Darkness **** **** **** **** **** **** **** **** +4682 Sorcerer_SHADOW_CON_Inivsibility **** **** **** **** **** **** **** **** +4683 Sorcerer_SHADOW_CON_Mage_Armor **** **** **** **** **** **** **** **** +4684 Sorcerer_SHADOW_CON_Magic_Missile **** **** **** **** **** **** **** **** +4685 Sorcerer_Shout **** **** **** **** **** **** **** **** +4686 Sorcerer_Sinsaburs_Baleful_Bolt **** **** **** **** **** **** **** **** +4687 Sorcerer_Slashing_Dispel **** **** **** **** **** **** **** **** +4688 Sorcerer_SolidFog **** **** **** **** **** **** **** **** +4689 Sorcerer_Sonic_Orb **** **** **** **** **** **** **** **** +4690 Sorcerer_Stoneskin **** **** **** **** **** **** **** **** +4691 Sorcerer_Summon_Creature_IV **** **** **** **** **** **** **** **** +4692 Sorcerer_SummonUndeadIV **** **** **** **** **** **** **** **** +4693 Sorcerer_Viscid_Glob **** **** **** **** **** **** **** **** +4694 Sorcerer_Wall_of_Fire **** **** **** **** **** **** **** **** +4695 Sorcerer_WRACK **** **** **** **** **** **** **** **** +4696 Sorcerer_Animate_Dead **** **** **** **** **** **** **** **** +4697 Sorcerer_BalefulPolymorph **** **** **** **** **** **** **** **** +4698 Sorcerer_Ball_Lightning **** **** **** **** **** **** **** **** +4699 Sorcerer_Beltyns_Burning_Blood **** **** **** **** **** **** **** **** +4700 Sorcerer_Bigbys_Interposing_Hand **** **** **** **** **** **** **** **** +4701 Sorcerer_BreakEnchantment **** **** **** **** **** **** **** **** +4702 Sorcerer_CALL_DRETCH_HORDE **** **** **** **** **** **** **** **** +4703 Sorcerer_CALL_LEMURE_HORDE **** **** **** **** **** **** **** **** +4704 Sorcerer_Cloudkill **** **** **** **** **** **** **** **** +4705 Sorcerer_Cone_of_Cold **** **** **** **** **** **** **** **** +4706 Sorcerer_Dismissal **** **** **** **** **** **** **** **** +4707 Sorcerer_Dominate_Person **** **** **** **** **** **** **** **** +4708 Sorcerer_DraconicMight **** **** **** **** **** **** **** **** +4709 Sorcerer_Energy_Buffer **** **** **** **** **** **** **** **** +4710 Sorcerer_Feeblemind **** **** **** **** **** **** **** **** +4711 Sorcerer_Firebrand **** **** **** **** **** **** **** **** +4712 Sorcerer_Greater_Fireburst **** **** **** **** **** **** **** **** +4713 Sorcerer_Greater_Shadow_Conjuration **** **** **** **** **** **** **** **** +4714 Sorcerer_GR_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +4715 Sorcerer_GR_SHADOW_CON_Acid_Arrow **** **** **** **** **** **** **** **** +4716 Sorcerer_GR_SHADOW_CON_Ghostly_Visage **** **** **** **** **** **** **** **** +4717 Sorcerer_GR_SHADOW_CON_Web **** **** **** **** **** **** **** **** +4718 Sorcerer_GR_SHADOW_CON_Minor_Globe **** **** **** **** **** **** **** **** +4719 Sorcerer_Hold_Monster **** **** **** **** **** **** **** **** +4720 Sorcerer_Lesser_Mind_Blank **** **** **** **** **** **** **** **** +4721 Sorcerer_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +4722 Sorcerer_Lesser_Spell_Mantle **** **** **** **** **** **** **** **** +4723 Sorcerer_Magic_Missile **** **** **** **** **** **** **** **** +4724 Sorcerer_MassFireShield **** **** **** **** **** **** **** **** +4725 Sorcerer_MassFireShieldRed **** **** **** **** **** **** **** **** +4726 Sorcerer_MassFireShieldBlue **** **** **** **** **** **** **** **** +4727 Sorcerer_Mestils_Acid_Sheath **** **** **** **** **** **** **** **** +4728 Sorcerer_Mind_Fog **** **** **** **** **** **** **** **** +4729 Sorcerer_Necrotic_Burst **** **** **** **** **** **** **** **** +4730 Sorcerer_Nights_Caress **** **** **** **** **** **** **** **** +4731 Sorcerer_PrismaticRay **** **** **** **** **** **** **** **** +4732 Sorcerer_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +4733 Sorcerer_Sonic_Shield **** **** **** **** **** **** **** **** +4734 Sorcerer_STOP_HEART **** **** **** **** **** **** **** **** +4735 Sorcerer_Summon_Creature_V **** **** **** **** **** **** **** **** +4736 Sorcerer_SummonUndeadV **** **** **** **** **** **** **** **** +4737 Sorcerer_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +4738 Sorcerer_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +4739 Sorcerer_Teleport_RadialMaster **** **** **** **** **** **** **** **** +4740 Sorcerer_Teleport_SelfOnly **** **** **** **** **** **** **** **** +4741 Sorcerer_Teleport_Party **** **** **** **** **** **** **** **** +4742 Sorcerer_WavesofFatigue **** **** **** **** **** **** **** **** +4743 Sorcerer_Acid_Fog **** **** **** **** **** **** **** **** +4744 Sorcerer_Acid_Storm **** **** **** **** **** **** **** **** +4745 Sorcerer_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +4746 Sorcerer_Bigbys_Forceful_Hand **** **** **** **** **** **** **** **** +4747 Sorcerer_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +4748 Sorcerer_Chain_Lightning **** **** **** **** **** **** **** **** +4749 Sorcerer_Circle_of_Death **** **** **** **** **** **** **** **** +4750 Sorcerer_Disintegrate **** **** **** **** **** **** **** **** +4751 Sorcerer_ECTOPLASMIC_ENCHANCEMENT **** **** **** **** **** **** **** **** +4752 Sorcerer_Ethereal_Visage **** **** **** **** **** **** **** **** +4753 Sorcerer_ExtractWaterElemental **** **** **** **** **** **** **** **** +4754 Sorcerer_Eyebite **** **** **** **** **** **** **** **** +4755 Sorcerer_Flesh_to_stone **** **** **** **** **** **** **** **** +4756 Sorcerer_Ghoul_Gauntlet **** **** **** **** **** **** **** **** +4757 Sorcerer_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +4758 Sorcerer_Greater_Dispelling **** **** **** **** **** **** **** **** +4759 Sorcerer_Greater_Heroism **** **** **** **** **** **** **** **** +4760 Sorcerer_Greater_Spell_Breach **** **** **** **** **** **** **** **** +4761 Sorcerer_Greater_Stoneskin **** **** **** **** **** **** **** **** +4762 Sorcerer_Isaacs_Greater_Missile_Storm **** **** **** **** **** **** **** **** +4763 Sorcerer_Legend_Lore **** **** **** **** **** **** **** **** +4764 Sorcerer_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +4765 Sorcerer_Mass_Cats_Grace **** **** **** **** **** **** **** **** +4766 Sorcerer_Mass_Contagion **** **** **** **** **** **** **** **** +4767 Sorcerer_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +4768 Sorcerer_Mass_Endurance **** **** **** **** **** **** **** **** +4769 Sorcerer_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +4770 Sorcerer_Mass_Haste **** **** **** **** **** **** **** **** +4771 Sorcerer_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +4772 Sorcerer_Mislead **** **** **** **** **** **** **** **** +4773 Sorcerer_Necrotic_Eruption **** **** **** **** **** **** **** **** +4774 Sorcerer_OtilukesFreezingSphere **** **** **** **** **** **** **** **** +4775 Sorcerer_Planar_Binding **** **** **** **** **** **** **** **** +4776 Sorcerer_Repulsion **** **** **** **** **** **** **** **** +4777 Sorcerer_Shades **** **** **** **** **** **** **** **** +4778 Sorcerer_SHADES_Summon_Shadow **** **** **** **** **** **** **** **** +4779 Sorcerer_SHADES_Cone_of_Cold **** **** **** **** **** **** **** **** +4780 Sorcerer_SHADES_Fireball **** **** **** **** **** **** **** **** +4781 Sorcerer_SHADES_Stoneskin **** **** **** **** **** **** **** **** +4782 Sorcerer_SHADES_Wall_of_Fire **** **** **** **** **** **** **** **** +4783 Sorcerer_STARMANTLE **** **** **** **** **** **** **** **** +4784 Sorcerer_Stone_to_flesh **** **** **** **** **** **** **** **** +4785 Sorcerer_Summon_Creature_VI **** **** **** **** **** **** **** **** +4786 Sorcerer_Superior_Resistance **** **** **** **** **** **** **** **** +4787 Sorcerer_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +4788 Sorcerer_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +4789 Sorcerer_Tensers_Transformation **** **** **** **** **** **** **** **** +4790 Sorcerer_True_Seeing **** **** **** **** **** **** **** **** +4791 Sorcerer_Undeath_to_Death **** **** **** **** **** **** **** **** +4792 Sorcerer_AMBER_SARCOPHAGUS **** **** **** **** **** **** **** **** +4793 Sorcerer_ArrowOfBone **** **** **** **** **** **** **** **** +4794 Sorcerer_Avasculate **** **** **** **** **** **** **** **** +4795 Sorcerer_Banishment **** **** **** **** **** **** **** **** +4796 Sorcerer_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +4797 Sorcerer_Control_Undead **** **** **** **** **** **** **** **** +4798 Sorcerer_Control_Weather **** **** **** **** **** **** **** **** +4799 Sorcerer_CW_Rain **** **** **** **** **** **** **** **** +4800 Sorcerer_CW_Snow **** **** **** **** **** **** **** **** +4801 Sorcerer_CW_Clear **** **** **** **** **** **** **** **** +4802 Sorcerer_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +4803 Sorcerer_DRAGON_ALLY **** **** **** **** **** **** **** **** +4804 Sorcerer_Energy_Ebb **** **** **** **** **** **** **** **** +4805 Sorcerer_Energy_Immunity **** **** **** **** **** **** **** **** +4806 Sorcerer_EI_Acid **** **** **** **** **** **** **** **** +4807 Sorcerer_EI_Cold **** **** **** **** **** **** **** **** +4808 Sorcerer_EI_Elec **** **** **** **** **** **** **** **** +4809 Sorcerer_EI_Fire **** **** **** **** **** **** **** **** +4810 Sorcerer_EI_Sonic **** **** **** **** **** **** **** **** +4811 Sorcerer_EYE_OF_THE_BEHOLDER **** **** **** **** **** **** **** **** +4812 Sorcerer_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +4813 Sorcerer_Finger_of_Death **** **** **** **** **** **** **** **** +4814 Sorcerer_Great_Thunderclap **** **** **** **** **** **** **** **** +4815 Sorcerer_GreaterScrying **** **** **** **** **** **** **** **** +4816 Sorcerer_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +4817 Sorcerer_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +4818 Sorcerer_GreaterTeleport_Party **** **** **** **** **** **** **** **** +4819 Sorcerer_Insanity **** **** **** **** **** **** **** **** +4820 Sorcerer_Mass_Hold_Person **** **** **** **** **** **** **** **** +4821 Sorcerer_Mordenkainens_Sword **** **** **** **** **** **** **** **** +4822 Sorcerer_Mords_Mansion **** **** **** **** **** **** **** **** +4823 Sorcerer_Nybors_Stern_Reproof **** **** **** **** **** **** **** **** +4824 Sorcerer_Power_Word_Blind **** **** **** **** **** **** **** **** +4825 Sorcerer_Power_Word_Stun **** **** **** **** **** **** **** **** +4826 Sorcerer_Prismatic_Spray **** **** **** **** **** **** **** **** +4827 Sorcerer_Protection_from_Spells **** **** **** **** **** **** **** **** +4828 Sorcerer_Sequester **** **** **** **** **** **** **** **** +4829 Sorcerer_Shadow_Shield **** **** **** **** **** **** **** **** +4830 Sorcerer_Spell_Mantle **** **** **** **** **** **** **** **** +4831 Sorcerer_Spell_Turning **** **** **** **** **** **** **** **** +4832 Sorcerer_Summon_Creature_VII **** **** **** **** **** **** **** **** +4833 Sorcerer_Summon7Air **** **** **** **** **** **** **** **** +4834 Sorcerer_Summon7Earth **** **** **** **** **** **** **** **** +4835 Sorcerer_Summon7Fire **** **** **** **** **** **** **** **** +4836 Sorcerer_Summon7Water **** **** **** **** **** **** **** **** +4837 Sorcerer_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +4838 Sorcerer_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +4839 Sorcerer_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +4840 Sorcerer_WavesOfExhaustion **** **** **** **** **** **** **** **** +4841 Sorcerer_Avascular_Mass **** **** **** **** **** **** **** **** +4842 Sorcerer_Bigbys_Clenched_Fist **** **** **** **** **** **** **** **** +4843 Sorcerer_Blackstaff **** **** **** **** **** **** **** **** +4844 Sorcerer_Create_Undead **** **** **** **** **** **** **** **** +4845 Sorcerer_Dimensional_Lock **** **** **** **** **** **** **** **** +4846 Sorcerer_DiscernLocation **** **** **** **** **** **** **** **** +4847 Sorcerer_Etherealness **** **** **** **** **** **** **** **** +4848 Sorcerer_Flensing **** **** **** **** **** **** **** **** +4849 Sorcerer_Greater_Planar_Binding **** **** **** **** **** **** **** **** +4850 Sorcerer_Greater_Shout **** **** **** **** **** **** **** **** +4851 Sorcerer_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +4852 Sorcerer_GUTWRENCH **** **** **** **** **** **** **** **** +4853 Sorcerer_Horrid_Wilting **** **** **** **** **** **** **** **** +4854 Sorcerer_Incendiary_Cloud **** **** **** **** **** **** **** **** +4855 Sorcerer_IRON_BODY **** **** **** **** **** **** **** **** +4856 Sorcerer_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +4857 Sorcerer_Mantle_of_Eg_Might **** **** **** **** **** **** **** **** +4858 Sorcerer_Mass_Blindness_and_Deafness **** **** **** **** **** **** **** **** +4859 Sorcerer_Mass_Charm **** **** **** **** **** **** **** **** +4860 Sorcerer_Maze **** **** **** **** **** **** **** **** +4861 Sorcerer_Mind_Blank **** **** **** **** **** **** **** **** +4862 Sorcerer_Necrotic_Empowerment **** **** **** **** **** **** **** **** +4863 Sorcerer_PolarRay **** **** **** **** **** **** **** **** +4864 Sorcerer_Premonition **** **** **** **** **** **** **** **** +4865 Sorcerer_PrismaticWall **** **** **** **** **** **** **** **** +4866 Sorcerer_ScintillatingPattern **** **** **** **** **** **** **** **** +4867 Sorcerer_Summon_Creature_VIII **** **** **** **** **** **** **** **** +4868 Sorcerer_Summon8Air **** **** **** **** **** **** **** **** +4869 Sorcerer_Summon8Earth **** **** **** **** **** **** **** **** +4870 Sorcerer_Summon8Fire **** **** **** **** **** **** **** **** +4871 Sorcerer_Summon8Water **** **** **** **** **** **** **** **** +4872 Sorcerer_Sunburst **** **** **** **** **** **** **** **** +4873 Sorcerer_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +4874 Sorcerer_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +4875 Sorcerer_Bigbys_Crushing_Hand **** **** **** **** **** **** **** **** +4876 Sorcerer_Black_Blade_of_Disaster **** **** **** **** **** **** **** **** +4877 Sorcerer_BLINDING_GLORY **** **** **** **** **** **** **** **** +4878 Sorcerer_CRUSHING_FIST_OF_SPITE **** **** **** **** **** **** **** **** +4879 Sorcerer_Dominate_Monster **** **** **** **** **** **** **** **** +4880 Sorcerer_Energy_Drain **** **** **** **** **** **** **** **** +4881 Sorcerer_Foresight **** **** **** **** **** **** **** **** +4882 Sorcerer_Gate **** **** **** **** **** **** **** **** +4883 Sorcerer_Greater_Spell_Mantle **** **** **** **** **** **** **** **** +4884 Sorcerer_Mass_Hold_Monster **** **** **** **** **** **** **** **** +4885 Sorcerer_Meteor_Swarm **** **** **** **** **** **** **** **** +4886 Sorcerer_Mordenkainens_Disjunction **** **** **** **** **** **** **** **** +4887 Sorcerer_Necrotic_Termination **** **** **** **** **** **** **** **** +4888 Sorcerer_PlagueOfUndead **** **** **** **** **** **** **** **** +4889 Sorcerer_Power_Word_Kill **** **** **** **** **** **** **** **** +4890 Sorcerer_PrismaticSphere **** **** **** **** **** **** **** **** +4891 Sorcerer_Shapechange **** **** **** **** **** **** **** **** +4892 Sorcerer_Shapechange_RED_DRAGON **** **** **** **** **** **** **** **** +4893 Sorcerer_Shapechange_FIRE_GIANT **** **** **** **** **** **** **** **** +4894 Sorcerer_Shapechange_BALOR **** **** **** **** **** **** **** **** +4895 Sorcerer_Shapechange_DEATH_SLAAD **** **** **** **** **** **** **** **** +4896 Sorcerer_Shapechange_IRON_GOLEM **** **** **** **** **** **** **** **** +4897 Sorcerer_Sphere_of_Ultimate_Destruction **** **** **** **** **** **** **** **** +4898 Sorcerer_Summon_Creature_IX **** **** **** **** **** **** **** **** +4899 Sorcerer_Summon9Air **** **** **** **** **** **** **** **** +4900 Sorcerer_Summon9Earth **** **** **** **** **** **** **** **** +4901 Sorcerer_Summon9Fire **** **** **** **** **** **** **** **** +4902 Sorcerer_Summon9Water **** **** **** **** **** **** **** **** +4903 Sorcerer_TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +4904 Sorcerer_TeleportationCircle_Visible **** **** **** **** **** **** **** **** +4905 Sorcerer_TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +4906 Sorcerer_Time_Stop **** **** **** **** **** **** **** **** +4907 Sorcerer_UTTERDARK **** **** **** **** **** **** **** **** +4908 Sorcerer_VileDeath **** **** **** **** **** **** **** **** +4909 Sorcerer_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +4910 Sorcerer_Weird **** **** **** **** **** **** **** **** +4911 Harper_Camoflage **** **** **** **** **** **** **** **** +4912 Harper_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +4913 Harper_Alter_Self_Learn **** **** **** **** **** **** **** **** +4914 Harper_Alter_Self_Options **** **** **** **** **** **** **** **** +4915 Harper_Alter_Self_QS1 **** **** **** **** **** **** **** **** +4916 Harper_Alter_Self_QS2 **** **** **** **** **** **** **** **** +4917 Harper_Alter_Self_QS3 **** **** **** **** **** **** **** **** +4918 Harper_Charm_Person **** **** **** **** **** **** **** **** +4919 Harper_Spell_Jump **** **** **** **** **** **** **** **** +4920 Harper_Light **** **** **** **** **** **** **** **** +4921 Harper_Read_Magic **** **** **** **** **** **** **** **** +4922 Harper_Sleep **** **** **** **** **** **** **** **** +4923 Harper_Cats_Grace **** **** **** **** **** **** **** **** +4924 Harper_Eagle_Splendor **** **** **** **** **** **** **** **** +4925 Harper_Invisibility **** **** **** **** **** **** **** **** +4926 Harper_Knock **** **** **** **** **** **** **** **** +4927 Harper_LocateObject **** **** **** **** **** **** **** **** +4928 Harper_See_Invisibility **** **** **** **** **** **** **** **** +4929 Harper_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +4930 Harper_NONDETECTION **** **** **** **** **** **** **** **** +4931 Harper_UndetectableAlignment **** **** **** **** **** **** **** **** +4932 Assassin_ADDICTION **** **** **** **** **** **** **** **** +4933 Assassin_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +4934 Assassin_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +4935 Assassin_ADDICTION_VODARE **** **** **** **** **** **** **** **** +4936 Assassin_ADDICTION_AGONY **** **** **** **** **** **** **** **** +4937 Assassin_ANGRY_ACHE **** **** **** **** **** **** **** **** +4938 Assassin_Blade_of_Blood **** **** **** **** **** **** **** **** +4939 Assassin_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +4940 Assassin_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +4941 Assassin_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +4942 Assassin_Disguise_Self_Learn **** **** **** **** **** **** **** **** +4943 Assassin_Disguise_Self_Options **** **** **** **** **** **** **** **** +4944 Assassin_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +4945 Assassin_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +4946 Assassin_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +4947 Assassin_Spell_Jump **** **** **** **** **** **** **** **** +4948 Assassin_Obscuring_Mist **** **** **** **** **** **** **** **** +4949 Assassin_Sleep **** **** **** **** **** **** **** **** +4950 Assassin_True_Strike **** **** **** **** **** **** **** **** +4951 Assassin_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +4952 Assassin_Alter_Self_Learn **** **** **** **** **** **** **** **** +4953 Assassin_Alter_Self_Options **** **** **** **** **** **** **** **** +4954 Assassin_Alter_Self_QS1 **** **** **** **** **** **** **** **** +4955 Assassin_Alter_Self_QS2 **** **** **** **** **** **** **** **** +4956 Assassin_Alter_Self_QS3 **** **** **** **** **** **** **** **** +4957 Assassin_Cats_Grace **** **** **** **** **** **** **** **** +4958 Assassin_Darkness **** **** **** **** **** **** **** **** +4959 Assassin_Foxs_Cunning **** **** **** **** **** **** **** **** +4960 Assassin_IceKnife **** **** **** **** **** **** **** **** +4961 Assassin_Invisibility **** **** **** **** **** **** **** **** +4962 Assassin_UndetectableAlignment **** **** **** **** **** **** **** **** +4963 Assassin_DeeperDarkness **** **** **** **** **** **** **** **** +4964 Assassin_DeepSlumber **** **** **** **** **** **** **** **** +4965 Assassin_FalseLife **** **** **** **** **** **** **** **** +4966 Assassin_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +4967 Assassin_MASOCHISM **** **** **** **** **** **** **** **** +4968 Assassin_NONDETECTION **** **** **** **** **** **** **** **** +4969 Assassin_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +4970 Assassin_CursedBlade **** **** **** **** **** **** **** **** +4971 Assassin_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +4972 Assassin_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +4973 Assassin_DimensionDoor_Party **** **** **** **** **** **** **** **** +4974 Assassin_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +4975 Assassin_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +4976 Assassin_FLESH_ARMOR **** **** **** **** **** **** **** **** +4977 Assassin_Freedom_of_Movement **** **** **** **** **** **** **** **** +4978 Assassin_GLIBNESS **** **** **** **** **** **** **** **** +4979 Assassin_HeartRipper **** **** **** **** **** **** **** **** +4980 Assassin_Improved_Invisibility **** **** **** **** **** **** **** **** +4981 Assassin_LocateCreature **** **** **** **** **** **** **** **** +4982 Assassin_Poison **** **** **** **** **** **** **** **** +4983 Assassin_STOP_HEART **** **** **** **** **** **** **** **** +4984 Blackguard_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4985 Blackguard_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4986 Blackguard_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4987 Blackguard_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4988 Blackguard_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +4989 Blackguard_Cause_Fear **** **** **** **** **** **** **** **** +4990 Blackguard_Exteneded_Cause_Fear **** **** **** **** **** **** **** **** +4991 Blackguard_Still_Cause_Fear **** **** **** **** **** **** **** **** +4992 Blackguard_Doom **** **** **** **** **** **** **** **** +4993 Blackguard_Exteneded_Doom **** **** **** **** **** **** **** **** +4994 Blackguard_Silent_Doom **** **** **** **** **** **** **** **** +4995 Blackguard_Still_Doom **** **** **** **** **** **** **** **** +4996 Blackguard_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +4997 Blackguard_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +4998 Blackguard_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +4999 Blackguard_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5000 Blackguard_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5001 Blackguard_Magic_Weapon **** **** **** **** **** **** **** **** +5002 Blackguard_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +5003 Blackguard_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +5004 Blackguard_Still_Magic_Weapon **** **** **** **** **** **** **** **** +5005 Blackguard_Summon_Creature_I **** **** **** **** **** **** **** **** +5006 Blackguard_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +5007 Blackguard_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +5008 Blackguard_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +5009 Blackguard_Blade_of_Blood **** **** **** **** **** **** **** **** +5010 Blackguard_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5011 Blackguard_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5012 Blackguard_Empowered_Blade_of_Blood **** **** **** **** **** **** **** **** +5013 Blackguard_Empowered_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5014 Blackguard_Empowered_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5015 Blackguard_Exteneded_Blade_of_Blood **** **** **** **** **** **** **** **** +5016 Blackguard_Exteneded_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5017 Blackguard_Exteneded_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5018 Blackguard_Maximized_Blade_of_Blood **** **** **** **** **** **** **** **** +5019 Blackguard_Maximized_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5020 Blackguard_Maximized_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5021 Blackguard_Silent_Blade_of_Blood **** **** **** **** **** **** **** **** +5022 Blackguard_Silent_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5023 Blackguard_Silent_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5024 Blackguard_Still_Blade_of_Blood **** **** **** **** **** **** **** **** +5025 Blackguard_Still_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5026 Blackguard_Still_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5027 Blackguard_BONEBLAST **** **** **** **** **** **** **** **** +5028 Blackguard_Silent_BONEBLAST **** **** **** **** **** **** **** **** +5029 Blackguard_Still_BONEBLAST **** **** **** **** **** **** **** **** +5030 Blackguard_DEMONFLESH **** **** **** **** **** **** **** **** +5031 Blackguard_Exteneded_DEMONFLESH **** **** **** **** **** **** **** **** +5032 Blackguard_Silent_DEMONFLESH **** **** **** **** **** **** **** **** +5033 Blackguard_Still_DEMONFLESH **** **** **** **** **** **** **** **** +5034 Blackguard_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5035 Blackguard_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5036 Blackguard_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5037 Blackguard_SummonUndeadI **** **** **** **** **** **** **** **** +5038 Blackguard_Exteneded_SummonUndeadI **** **** **** **** **** **** **** **** +5039 Blackguard_Silent_SummonUndeadI **** **** **** **** **** **** **** **** +5040 Blackguard_Still_SummonUndeadI **** **** **** **** **** **** **** **** +5041 Blackguard_Bulls_Strength **** **** **** **** **** **** **** **** +5042 Blackguard_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +5043 Blackguard_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +5044 Blackguard_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +5045 Blackguard_Still_Bulls_Strength **** **** **** **** **** **** **** **** +5046 Blackguard_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5047 Blackguard_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5048 Blackguard_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5049 Blackguard_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5050 Blackguard_Darkness **** **** **** **** **** **** **** **** +5051 Blackguard_Exteneded_Darkness **** **** **** **** **** **** **** **** +5052 Blackguard_Silent_Darkness **** **** **** **** **** **** **** **** +5053 Blackguard_Eagle_Splendor **** **** **** **** **** **** **** **** +5054 Blackguard_Empowered_Eagle_Splendor **** **** **** **** **** **** **** **** +5055 Blackguard_Exteneded_Eagle_Splendor **** **** **** **** **** **** **** **** +5056 Blackguard_Silent_Eagle_Splendor **** **** **** **** **** **** **** **** +5057 Blackguard_Still_Eagle_Splendor **** **** **** **** **** **** **** **** +5058 Blackguard_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5059 Blackguard_Empowered_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5060 Blackguard_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5061 Blackguard_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5062 Blackguard_Summon_Creature_II **** **** **** **** **** **** **** **** +5063 Blackguard_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +5064 Blackguard_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +5065 Blackguard_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +5066 Blackguard_BONEBLADE **** **** **** **** **** **** **** **** +5067 Blackguard_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5068 Blackguard_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5069 Blackguard_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5070 Blackguard_Exteneded_BONEBLADE **** **** **** **** **** **** **** **** +5071 Blackguard_Exteneded_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5072 Blackguard_Exteneded_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5073 Blackguard_Exteneded_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5074 Blackguard_Silent_BONEBLADE **** **** **** **** **** **** **** **** +5075 Blackguard_Silent_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5076 Blackguard_Silent_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5077 Blackguard_Silent_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5078 Blackguard_Still_BONEBLADE **** **** **** **** **** **** **** **** +5079 Blackguard_Still_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5080 Blackguard_Still_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5081 Blackguard_Still_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5082 Blackguard_Death_Knell **** **** **** **** **** **** **** **** +5083 Blackguard_Empowered_Death_Knell **** **** **** **** **** **** **** **** +5084 Blackguard_Exteneded_Death_Knell **** **** **** **** **** **** **** **** +5085 Blackguard_Silent_Death_Knell **** **** **** **** **** **** **** **** +5086 Blackguard_Still_Death_Knell **** **** **** **** **** **** **** **** +5087 Blackguard_DEMONCALL **** **** **** **** **** **** **** **** +5088 Blackguard_Silent_DEMONCALL **** **** **** **** **** **** **** **** +5089 Blackguard_Still_DEMONCALL **** **** **** **** **** **** **** **** +5090 Blackguard_DEVILS_EYE **** **** **** **** **** **** **** **** +5091 Blackguard_Silent_DEVILS_EYE **** **** **** **** **** **** **** **** +5092 Blackguard_Still_DEVILS_EYE **** **** **** **** **** **** **** **** +5093 Blackguard_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5094 Blackguard_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5095 Blackguard_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5096 Blackguard_SummonUndeadII **** **** **** **** **** **** **** **** +5097 Blackguard_Exteneded_SummonUndeadII **** **** **** **** **** **** **** **** +5098 Blackguard_Silent_SummonUndeadII **** **** **** **** **** **** **** **** +5099 Blackguard_Still_SummonUndeadII **** **** **** **** **** **** **** **** +5100 Blackguard_Contagion **** **** **** **** **** **** **** **** +5101 Blackguard_Silent_Contagion **** **** **** **** **** **** **** **** +5102 Blackguard_Still_Contagion **** **** **** **** **** **** **** **** +5103 Blackguard_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5104 Blackguard_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5105 Blackguard_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5106 Blackguard_DeeperDarkness **** **** **** **** **** **** **** **** +5107 Blackguard_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +5108 Blackguard_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +5109 Blackguard_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5110 Blackguard_Silent_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5111 Blackguard_Still_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5112 Blackguard_Protection_from_Elements **** **** **** **** **** **** **** **** +5113 Blackguard_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +5114 Blackguard_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +5115 Blackguard_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +5116 Blackguard_Summon_Creature_III **** **** **** **** **** **** **** **** +5117 Blackguard_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +5118 Blackguard_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +5119 Blackguard_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +5120 Blackguard_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5121 Blackguard_Exteneded_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5122 Blackguard_Silent_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5123 Blackguard_Still_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5124 Blackguard_RED_FESTER **** **** **** **** **** **** **** **** +5125 Blackguard_Silent_RED_FESTER **** **** **** **** **** **** **** **** +5126 Blackguard_Still_RED_FESTER **** **** **** **** **** **** **** **** +5127 Blackguard_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5128 Blackguard_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5129 Blackguard_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5130 Blackguard_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5131 Blackguard_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5132 Blackguard_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5133 Blackguard_MASOCHISM **** **** **** **** **** **** **** **** +5134 Blackguard_Exteneded_MASOCHISM **** **** **** **** **** **** **** **** +5135 Blackguard_SummonUndeadIII **** **** **** **** **** **** **** **** +5136 Blackguard_Exteneded_SummonUndeadIII **** **** **** **** **** **** **** **** +5137 Blackguard_Silent_SummonUndeadIII **** **** **** **** **** **** **** **** +5138 Blackguard_Still_SummonUndeadIII **** **** **** **** **** **** **** **** +5139 Blackguard_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +5140 Blackguard_Freedom_of_Movement **** **** **** **** **** **** **** **** +5141 Blackguard_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +5142 Blackguard_Poison **** **** **** **** **** **** **** **** +5143 Blackguard_Summon_Creature_IV **** **** **** **** **** **** **** **** +5144 Blackguard_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +5145 Blackguard_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +5146 Blackguard_SummonUndeadIV **** **** **** **** **** **** **** **** +5147 Ocular_Adept_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +5148 Ocular_Adept_Quickened_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +5149 Ocular_Adept_Silent_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +5150 Ocular_Adept_Still_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +5151 Ocular_Adept_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +5152 Ocular_Adept_Quickened_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +5153 Ocular_Adept_Silent_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +5154 Ocular_Adept_Still_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +5155 Ocular_Adept_Light **** **** **** **** **** **** **** **** +5156 Ocular_Adept_Exteneded_Light **** **** **** **** **** **** **** **** +5157 Ocular_Adept_Quickened_Light **** **** **** **** **** **** **** **** +5158 Ocular_Adept_Silent_Light **** **** **** **** **** **** **** **** +5159 Ocular_Adept_Read_Magic **** **** **** **** **** **** **** **** +5160 Ocular_Adept_Quickened_Read_Magic **** **** **** **** **** **** **** **** +5161 Ocular_Adept_Silent_Read_Magic **** **** **** **** **** **** **** **** +5162 Ocular_Adept_Still_Read_Magic **** **** **** **** **** **** **** **** +5163 Ocular_Adept_Resistance **** **** **** **** **** **** **** **** +5164 Ocular_Adept_Exteneded_Resistance **** **** **** **** **** **** **** **** +5165 Ocular_Adept_Quickened_Resistance **** **** **** **** **** **** **** **** +5166 Ocular_Adept_Silent_Resistance **** **** **** **** **** **** **** **** +5167 Ocular_Adept_Still_Resistance **** **** **** **** **** **** **** **** +5168 Ocular_Adept_Virtue **** **** **** **** **** **** **** **** +5169 Ocular_Adept_Exteneded_Virtue **** **** **** **** **** **** **** **** +5170 Ocular_Adept_Quickened_Virtue **** **** **** **** **** **** **** **** +5171 Ocular_Adept_Silent_Virtue **** **** **** **** **** **** **** **** +5172 Ocular_Adept_Still_Virtue **** **** **** **** **** **** **** **** +5173 Ocular_Adept_ANGRY_ACHE **** **** **** **** **** **** **** **** +5174 Ocular_Adept_Exteneded_ANGRY_ACHE **** **** **** **** **** **** **** **** +5175 Ocular_Adept_Quickened_ANGRY_ACHE **** **** **** **** **** **** **** **** +5176 Ocular_Adept_Silent_ANGRY_ACHE **** **** **** **** **** **** **** **** +5177 Ocular_Adept_Still_ANGRY_ACHE **** **** **** **** **** **** **** **** +5178 Ocular_Adept_Bane **** **** **** **** **** **** **** **** +5179 Ocular_Adept_Exteneded_Bane **** **** **** **** **** **** **** **** +5180 Ocular_Adept_Quickened_Bane **** **** **** **** **** **** **** **** +5181 Ocular_Adept_Silent_Bane **** **** **** **** **** **** **** **** +5182 Ocular_Adept_Still_Bane **** **** **** **** **** **** **** **** +5183 Ocular_Adept_Blade_of_Blood **** **** **** **** **** **** **** **** +5184 Ocular_Adept_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5185 Ocular_Adept_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5186 Ocular_Adept_Empowered_Blade_of_Blood **** **** **** **** **** **** **** **** +5187 Ocular_Adept_Empowered_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5188 Ocular_Adept_Empowered_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5189 Ocular_Adept_Exteneded_Blade_of_Blood **** **** **** **** **** **** **** **** +5190 Ocular_Adept_Exteneded_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5191 Ocular_Adept_Exteneded_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5192 Ocular_Adept_Maximized_Blade_of_Blood **** **** **** **** **** **** **** **** +5193 Ocular_Adept_Maximized_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5194 Ocular_Adept_Maximized_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5195 Ocular_Adept_Quickened_Blade_of_Blood **** **** **** **** **** **** **** **** +5196 Ocular_Adept_Quickened_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5197 Ocular_Adept_Quickened_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5198 Ocular_Adept_Silent_Blade_of_Blood **** **** **** **** **** **** **** **** +5199 Ocular_Adept_Silent_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5200 Ocular_Adept_Silent_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5201 Ocular_Adept_Still_Blade_of_Blood **** **** **** **** **** **** **** **** +5202 Ocular_Adept_Still_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +5203 Ocular_Adept_Still_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +5204 Ocular_Adept_Bless **** **** **** **** **** **** **** **** +5205 Ocular_Adept_Exteneded_Bless **** **** **** **** **** **** **** **** +5206 Ocular_Adept_Quickened_Bless **** **** **** **** **** **** **** **** +5207 Ocular_Adept_Silent_Bless **** **** **** **** **** **** **** **** +5208 Ocular_Adept_Still_Bless **** **** **** **** **** **** **** **** +5209 Ocular_Adept_Bless_Water **** **** **** **** **** **** **** **** +5210 Ocular_Adept_Quickened_Bless_Water **** **** **** **** **** **** **** **** +5211 Ocular_Adept_Silent_Bless_Water **** **** **** **** **** **** **** **** +5212 Ocular_Adept_Still_Bless_Water **** **** **** **** **** **** **** **** +5213 Ocular_Adept_Cause_Fear **** **** **** **** **** **** **** **** +5214 Ocular_Adept_Exteneded_Cause_Fear **** **** **** **** **** **** **** **** +5215 Ocular_Adept_Quickened_Cause_Fear **** **** **** **** **** **** **** **** +5216 Ocular_Adept_Still_Cause_Fear **** **** **** **** **** **** **** **** +5217 Ocular_Adept_Command_RadialMaster **** **** **** **** **** **** **** **** +5218 Ocular_Adept_Command_Approach **** **** **** **** **** **** **** **** +5219 Ocular_Adept_Command_Drop **** **** **** **** **** **** **** **** +5220 Ocular_Adept_Command_Fall **** **** **** **** **** **** **** **** +5221 Ocular_Adept_Command_Flee **** **** **** **** **** **** **** **** +5222 Ocular_Adept_Command_Halt **** **** **** **** **** **** **** **** +5223 Ocular_Adept_Exteneded_Command_RadialMaster **** **** **** **** **** **** **** **** +5224 Ocular_Adept_Exteneded_Command_Approach **** **** **** **** **** **** **** **** +5225 Ocular_Adept_Exteneded_Command_Drop **** **** **** **** **** **** **** **** +5226 Ocular_Adept_Exteneded_Command_Fall **** **** **** **** **** **** **** **** +5227 Ocular_Adept_Exteneded_Command_Flee **** **** **** **** **** **** **** **** +5228 Ocular_Adept_Exteneded_Command_Halt **** **** **** **** **** **** **** **** +5229 Ocular_Adept_Quickened_Command_RadialMaster **** **** **** **** **** **** **** **** +5230 Ocular_Adept_Quickened_Command_Approach **** **** **** **** **** **** **** **** +5231 Ocular_Adept_Quickened_Command_Drop **** **** **** **** **** **** **** **** +5232 Ocular_Adept_Quickened_Command_Fall **** **** **** **** **** **** **** **** +5233 Ocular_Adept_Quickened_Command_Flee **** **** **** **** **** **** **** **** +5234 Ocular_Adept_Quickened_Command_Halt **** **** **** **** **** **** **** **** +5235 Ocular_Adept_Silent_Command_RadialMaster **** **** **** **** **** **** **** **** +5236 Ocular_Adept_Silent_Command_Approach **** **** **** **** **** **** **** **** +5237 Ocular_Adept_Silent_Command_Drop **** **** **** **** **** **** **** **** +5238 Ocular_Adept_Silent_Command_Fall **** **** **** **** **** **** **** **** +5239 Ocular_Adept_Silent_Command_Flee **** **** **** **** **** **** **** **** +5240 Ocular_Adept_Silent_Command_Halt **** **** **** **** **** **** **** **** +5241 Ocular_Adept_Still_Command_RadialMaster **** **** **** **** **** **** **** **** +5242 Ocular_Adept_Still_Command_Approach **** **** **** **** **** **** **** **** +5243 Ocular_Adept_Still_Command_Drop **** **** **** **** **** **** **** **** +5244 Ocular_Adept_Still_Command_Fall **** **** **** **** **** **** **** **** +5245 Ocular_Adept_Still_Command_Flee **** **** **** **** **** **** **** **** +5246 Ocular_Adept_Still_Command_Halt **** **** **** **** **** **** **** **** +5247 Ocular_Adept_Conviction **** **** **** **** **** **** **** **** +5248 Ocular_Adept_Exteneded_Conviction **** **** **** **** **** **** **** **** +5249 Ocular_Adept_Quickened_Conviction **** **** **** **** **** **** **** **** +5250 Ocular_Adept_Silent_Conviction **** **** **** **** **** **** **** **** +5251 Ocular_Adept_Still_Conviction **** **** **** **** **** **** **** **** +5252 Ocular_Adept_Crafters_Blessing **** **** **** **** **** **** **** **** +5253 Ocular_Adept_Exteneded_Crafters_Blessing **** **** **** **** **** **** **** **** +5254 Ocular_Adept_Quickened_Crafters_Blessing **** **** **** **** **** **** **** **** +5255 Ocular_Adept_Silent_Crafters_Blessing **** **** **** **** **** **** **** **** +5256 Ocular_Adept_Still_Crafters_Blessing **** **** **** **** **** **** **** **** +5257 Ocular_Adept_Crafters_Curse **** **** **** **** **** **** **** **** +5258 Ocular_Adept_Exteneded_Crafters_Curse **** **** **** **** **** **** **** **** +5259 Ocular_Adept_Quickened_Crafters_Curse **** **** **** **** **** **** **** **** +5260 Ocular_Adept_Silent_Crafters_Curse **** **** **** **** **** **** **** **** +5261 Ocular_Adept_Still_Crafters_Curse **** **** **** **** **** **** **** **** +5262 Ocular_Adept_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5263 Ocular_Adept_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5264 Ocular_Adept_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5265 Ocular_Adept_Quickened_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5266 Ocular_Adept_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5267 Ocular_Adept_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +5268 Ocular_Adept_Curse_Water **** **** **** **** **** **** **** **** +5269 Ocular_Adept_Quickened_Curse_Water **** **** **** **** **** **** **** **** +5270 Ocular_Adept_Silent_Curse_Water **** **** **** **** **** **** **** **** +5271 Ocular_Adept_Still_Curse_Water **** **** **** **** **** **** **** **** +5272 Ocular_Adept_Detect_Chaos **** **** **** **** **** **** **** **** +5273 Ocular_Adept_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +5274 Ocular_Adept_Quickened_Detect_Chaos **** **** **** **** **** **** **** **** +5275 Ocular_Adept_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +5276 Ocular_Adept_Still_Detect_Chaos **** **** **** **** **** **** **** **** +5277 Ocular_Adept_Detect_Evil **** **** **** **** **** **** **** **** +5278 Ocular_Adept_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +5279 Ocular_Adept_Quickened_Detect_Evil **** **** **** **** **** **** **** **** +5280 Ocular_Adept_Silent_Detect_Evil **** **** **** **** **** **** **** **** +5281 Ocular_Adept_Still_Detect_Evil **** **** **** **** **** **** **** **** +5282 Ocular_Adept_Detect_Good **** **** **** **** **** **** **** **** +5283 Ocular_Adept_Exteneded_Detect_Good **** **** **** **** **** **** **** **** +5284 Ocular_Adept_Quickened_Detect_Good **** **** **** **** **** **** **** **** +5285 Ocular_Adept_Silent_Detect_Good **** **** **** **** **** **** **** **** +5286 Ocular_Adept_Still_Detect_Good **** **** **** **** **** **** **** **** +5287 Ocular_Adept_Detect_Law **** **** **** **** **** **** **** **** +5288 Ocular_Adept_Exteneded_Detect_Law **** **** **** **** **** **** **** **** +5289 Ocular_Adept_Quickened_Detect_Law **** **** **** **** **** **** **** **** +5290 Ocular_Adept_Silent_Detect_Law **** **** **** **** **** **** **** **** +5291 Ocular_Adept_Still_Detect_Law **** **** **** **** **** **** **** **** +5292 Ocular_Adept_DETECT_UNDEAD **** **** **** **** **** **** **** **** +5293 Ocular_Adept_Exteneded_DETECT_UNDEAD **** **** **** **** **** **** **** **** +5294 Ocular_Adept_Quickened_DETECT_UNDEAD **** **** **** **** **** **** **** **** +5295 Ocular_Adept_Silent_DETECT_UNDEAD **** **** **** **** **** **** **** **** +5296 Ocular_Adept_Still_DETECT_UNDEAD **** **** **** **** **** **** **** **** +5297 Ocular_Adept_Divine_Favor **** **** **** **** **** **** **** **** +5298 Ocular_Adept_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +5299 Ocular_Adept_Quickened_Divine_Favor **** **** **** **** **** **** **** **** +5300 Ocular_Adept_Silent_Divine_Favor **** **** **** **** **** **** **** **** +5301 Ocular_Adept_Still_Divine_Favor **** **** **** **** **** **** **** **** +5302 Ocular_Adept_Doom **** **** **** **** **** **** **** **** +5303 Ocular_Adept_Exteneded_Doom **** **** **** **** **** **** **** **** +5304 Ocular_Adept_Quickened_Doom **** **** **** **** **** **** **** **** +5305 Ocular_Adept_Silent_Doom **** **** **** **** **** **** **** **** +5306 Ocular_Adept_Still_Doom **** **** **** **** **** **** **** **** +5307 Ocular_Adept_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +5308 Ocular_Adept_Quickened_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +5309 Ocular_Adept_Silent_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +5310 Ocular_Adept_Endure_Elements **** **** **** **** **** **** **** **** +5311 Ocular_Adept_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +5312 Ocular_Adept_Quickened_Endure_Elements **** **** **** **** **** **** **** **** +5313 Ocular_Adept_Silent_Endure_Elements **** **** **** **** **** **** **** **** +5314 Ocular_Adept_Still_Endure_Elements **** **** **** **** **** **** **** **** +5315 Ocular_Adept_Entropic_Shield **** **** **** **** **** **** **** **** +5316 Ocular_Adept_Exteneded_Entropic_Shield **** **** **** **** **** **** **** **** +5317 Ocular_Adept_Quickened_Entropic_Shield **** **** **** **** **** **** **** **** +5318 Ocular_Adept_Silent_Entropic_Shield **** **** **** **** **** **** **** **** +5319 Ocular_Adept_Still_Entropic_Shield **** **** **** **** **** **** **** **** +5320 Ocular_Adept_EXTRACT_DRUG **** **** **** **** **** **** **** **** +5321 Ocular_Adept_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +5322 Ocular_Adept_EXTRACT_VODARE **** **** **** **** **** **** **** **** +5323 Ocular_Adept_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +5324 Ocular_Adept_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5325 Ocular_Adept_Quickened_EXTRACT_DRUG **** **** **** **** **** **** **** **** +5326 Ocular_Adept_Quickened_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +5327 Ocular_Adept_Quickened_EXTRACT_VODARE **** **** **** **** **** **** **** **** +5328 Ocular_Adept_Quickened_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +5329 Ocular_Adept_Quickened_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5330 Ocular_Adept_Silent_EXTRACT_DRUG **** **** **** **** **** **** **** **** +5331 Ocular_Adept_Silent_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +5332 Ocular_Adept_Silent_EXTRACT_VODARE **** **** **** **** **** **** **** **** +5333 Ocular_Adept_Silent_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +5334 Ocular_Adept_Silent_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5335 Ocular_Adept_Still_EXTRACT_DRUG **** **** **** **** **** **** **** **** +5336 Ocular_Adept_Still_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +5337 Ocular_Adept_Still_EXTRACT_VODARE **** **** **** **** **** **** **** **** +5338 Ocular_Adept_Still_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +5339 Ocular_Adept_Still_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5340 Ocular_Adept_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +5341 Ocular_Adept_Exteneded_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +5342 Ocular_Adept_Quickened_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +5343 Ocular_Adept_Still_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +5344 Ocular_Adept_HEARTACHE **** **** **** **** **** **** **** **** +5345 Ocular_Adept_Exteneded_HEARTACHE **** **** **** **** **** **** **** **** +5346 Ocular_Adept_Quickened_HEARTACHE **** **** **** **** **** **** **** **** +5347 Ocular_Adept_Silent_HEARTACHE **** **** **** **** **** **** **** **** +5348 Ocular_Adept_Still_HEARTACHE **** **** **** **** **** **** **** **** +5349 Ocular_Adept_HideFromUndead **** **** **** **** **** **** **** **** +5350 Ocular_Adept_Exteneded_HideFromUndead **** **** **** **** **** **** **** **** +5351 Ocular_Adept_Quickened_HideFromUndead **** **** **** **** **** **** **** **** +5352 Ocular_Adept_Still_HideFromUndead **** **** **** **** **** **** **** **** +5353 Ocular_Adept_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5354 Ocular_Adept_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5355 Ocular_Adept_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5356 Ocular_Adept_Quickened_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5357 Ocular_Adept_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5358 Ocular_Adept_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +5359 Ocular_Adept_LANTERN_LIGHT **** **** **** **** **** **** **** **** +5360 Ocular_Adept_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +5361 Ocular_Adept_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +5362 Ocular_Adept_Quickened_LANTERN_LIGHT **** **** **** **** **** **** **** **** +5363 Ocular_Adept_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +5364 Ocular_Adept_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5365 Ocular_Adept_Empowered_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5366 Ocular_Adept_Exteneded_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5367 Ocular_Adept_Maximized_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5368 Ocular_Adept_Quickened_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5369 Ocular_Adept_Silent_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5370 Ocular_Adept_Still_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5371 Ocular_Adept_Lesser_Vigor **** **** **** **** **** **** **** **** +5372 Ocular_Adept_Exteneded_Lesser_Vigor **** **** **** **** **** **** **** **** +5373 Ocular_Adept_Quickened_Lesser_Vigor **** **** **** **** **** **** **** **** +5374 Ocular_Adept_Silent_Lesser_Vigor **** **** **** **** **** **** **** **** +5375 Ocular_Adept_Still_Lesser_Vigor **** **** **** **** **** **** **** **** +5376 Ocular_Adept_Magic_Stone **** **** **** **** **** **** **** **** +5377 Ocular_Adept_Exteneded_Magic_Stone **** **** **** **** **** **** **** **** +5378 Ocular_Adept_Quickened_Magic_Stone **** **** **** **** **** **** **** **** +5379 Ocular_Adept_Silent_Magic_Stone **** **** **** **** **** **** **** **** +5380 Ocular_Adept_Still_Magic_Stone **** **** **** **** **** **** **** **** +5381 Ocular_Adept_Magic_Weapon **** **** **** **** **** **** **** **** +5382 Ocular_Adept_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +5383 Ocular_Adept_Quickened_Magic_Weapon **** **** **** **** **** **** **** **** +5384 Ocular_Adept_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +5385 Ocular_Adept_Still_Magic_Weapon **** **** **** **** **** **** **** **** +5386 Ocular_Adept_Necrotic_Awareness **** **** **** **** **** **** **** **** +5387 Ocular_Adept_Quickened_Necrotic_Awareness **** **** **** **** **** **** **** **** +5388 Ocular_Adept_Silent_Necrotic_Awareness **** **** **** **** **** **** **** **** +5389 Ocular_Adept_Still_Necrotic_Awareness **** **** **** **** **** **** **** **** +5390 Ocular_Adept_Obscuring_Mist **** **** **** **** **** **** **** **** +5391 Ocular_Adept_Exteneded_Obscuring_Mist **** **** **** **** **** **** **** **** +5392 Ocular_Adept_Quickened_Obscuring_Mist **** **** **** **** **** **** **** **** +5393 Ocular_Adept_Silent_Obscuring_Mist **** **** **** **** **** **** **** **** +5394 Ocular_Adept_Still_Obscuring_Mist **** **** **** **** **** **** **** **** +5395 Ocular_Adept_Protection_from_Chaos **** **** **** **** **** **** **** **** +5396 Ocular_Adept_Exteneded_Protection_from_Chaos **** **** **** **** **** **** **** **** +5397 Ocular_Adept_Quickened_Protection_from_Chaos **** **** **** **** **** **** **** **** +5398 Ocular_Adept_Silent_Protection_from_Chaos **** **** **** **** **** **** **** **** +5399 Ocular_Adept_Still_Protection_from_Chaos **** **** **** **** **** **** **** **** +5400 Ocular_Adept_Protection_from_Evil **** **** **** **** **** **** **** **** +5401 Ocular_Adept_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +5402 Ocular_Adept_Quickened_Protection_from_Evil **** **** **** **** **** **** **** **** +5403 Ocular_Adept_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +5404 Ocular_Adept_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +5405 Ocular_Adept_Protection_from_Good **** **** **** **** **** **** **** **** +5406 Ocular_Adept_Exteneded_Protection_from_Good **** **** **** **** **** **** **** **** +5407 Ocular_Adept_Quickened_Protection_from_Good **** **** **** **** **** **** **** **** +5408 Ocular_Adept_Silent_Protection_from_Good **** **** **** **** **** **** **** **** +5409 Ocular_Adept_Still_Protection_from_Good **** **** **** **** **** **** **** **** +5410 Ocular_Adept_Protection_from_Law **** **** **** **** **** **** **** **** +5411 Ocular_Adept_Exteneded_Protection_from_Law **** **** **** **** **** **** **** **** +5412 Ocular_Adept_Quickened_Protection_from_Law **** **** **** **** **** **** **** **** +5413 Ocular_Adept_Silent_Protection_from_Law **** **** **** **** **** **** **** **** +5414 Ocular_Adept_Still_Protection_from_Law **** **** **** **** **** **** **** **** +5415 Ocular_Adept_RAY_OF_HOPE **** **** **** **** **** **** **** **** +5416 Ocular_Adept_Exteneded_RAY_OF_HOPE **** **** **** **** **** **** **** **** +5417 Ocular_Adept_Quickened_RAY_OF_HOPE **** **** **** **** **** **** **** **** +5418 Ocular_Adept_Silent_RAY_OF_HOPE **** **** **** **** **** **** **** **** +5419 Ocular_Adept_Still_RAY_OF_HOPE **** **** **** **** **** **** **** **** +5420 Ocular_Adept_Remove_Fear **** **** **** **** **** **** **** **** +5421 Ocular_Adept_Exteneded_Remove_Fear **** **** **** **** **** **** **** **** +5422 Ocular_Adept_Quickened_Remove_Fear **** **** **** **** **** **** **** **** +5423 Ocular_Adept_Silent_Remove_Fear **** **** **** **** **** **** **** **** +5424 Ocular_Adept_Still_Remove_Fear **** **** **** **** **** **** **** **** +5425 Ocular_Adept_Sanctuary **** **** **** **** **** **** **** **** +5426 Ocular_Adept_Exteneded_Sanctuary **** **** **** **** **** **** **** **** +5427 Ocular_Adept_Quickened_Sanctuary **** **** **** **** **** **** **** **** +5428 Ocular_Adept_Silent_Sanctuary **** **** **** **** **** **** **** **** +5429 Ocular_Adept_Still_Sanctuary **** **** **** **** **** **** **** **** +5430 Ocular_Adept_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5431 Ocular_Adept_Quickened_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5432 Ocular_Adept_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5433 Ocular_Adept_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +5434 Ocular_Adept_Shield_of_Faith **** **** **** **** **** **** **** **** +5435 Ocular_Adept_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +5436 Ocular_Adept_Quickened_Shield_of_Faith **** **** **** **** **** **** **** **** +5437 Ocular_Adept_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +5438 Ocular_Adept_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +5439 Ocular_Adept_SORROW **** **** **** **** **** **** **** **** +5440 Ocular_Adept_Quickened_SORROW **** **** **** **** **** **** **** **** +5441 Ocular_Adept_Silent_SORROW **** **** **** **** **** **** **** **** +5442 Ocular_Adept_Still_SORROW **** **** **** **** **** **** **** **** +5443 Ocular_Adept_Summon_Creature_I **** **** **** **** **** **** **** **** +5444 Ocular_Adept_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +5445 Ocular_Adept_Quickened_Summon_Creature_I **** **** **** **** **** **** **** **** +5446 Ocular_Adept_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +5447 Ocular_Adept_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +5448 Ocular_Adept_SummonUndeadI **** **** **** **** **** **** **** **** +5449 Ocular_Adept_Exteneded_SummonUndeadI **** **** **** **** **** **** **** **** +5450 Ocular_Adept_Quickened_SummonUndeadI **** **** **** **** **** **** **** **** +5451 Ocular_Adept_Silent_SummonUndeadI **** **** **** **** **** **** **** **** +5452 Ocular_Adept_Still_SummonUndeadI **** **** **** **** **** **** **** **** +5453 Ocular_Adept_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +5454 Ocular_Adept_Exteneded_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +5455 Ocular_Adept_Quickened_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +5456 Ocular_Adept_Silent_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +5457 Ocular_Adept_Still_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +5458 Ocular_Adept_VisionOfHeaven **** **** **** **** **** **** **** **** +5459 Ocular_Adept_Exteneded_VisionOfHeaven **** **** **** **** **** **** **** **** +5460 Ocular_Adept_Quickened_VisionOfHeaven **** **** **** **** **** **** **** **** +5461 Ocular_Adept_Silent_VisionOfHeaven **** **** **** **** **** **** **** **** +5462 Ocular_Adept_ADDICTION **** **** **** **** **** **** **** **** +5463 Ocular_Adept_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +5464 Ocular_Adept_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5465 Ocular_Adept_ADDICTION_VODARE **** **** **** **** **** **** **** **** +5466 Ocular_Adept_ADDICTION_AGONY **** **** **** **** **** **** **** **** +5467 Ocular_Adept_Silent_ADDICTION **** **** **** **** **** **** **** **** +5468 Ocular_Adept_Silent_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +5469 Ocular_Adept_Silent_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5470 Ocular_Adept_Silent_ADDICTION_VODARE **** **** **** **** **** **** **** **** +5471 Ocular_Adept_Silent_ADDICTION_AGONY **** **** **** **** **** **** **** **** +5472 Ocular_Adept_Still_ADDICTION **** **** **** **** **** **** **** **** +5473 Ocular_Adept_Still_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +5474 Ocular_Adept_Still_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +5475 Ocular_Adept_Still_ADDICTION_VODARE **** **** **** **** **** **** **** **** +5476 Ocular_Adept_Still_ADDICTION_AGONY **** **** **** **** **** **** **** **** +5477 Ocular_Adept_Aid **** **** **** **** **** **** **** **** +5478 Ocular_Adept_Empowered_Aid **** **** **** **** **** **** **** **** +5479 Ocular_Adept_Exteneded_Aid **** **** **** **** **** **** **** **** +5480 Ocular_Adept_Maximized_Aid **** **** **** **** **** **** **** **** +5481 Ocular_Adept_Silent_Aid **** **** **** **** **** **** **** **** +5482 Ocular_Adept_Still_Aid **** **** **** **** **** **** **** **** +5483 Ocular_Adept_Animalistic_Power **** **** **** **** **** **** **** **** +5484 Ocular_Adept_Exteneded_Animalistic_Power **** **** **** **** **** **** **** **** +5485 Ocular_Adept_BONEBLAST **** **** **** **** **** **** **** **** +5486 Ocular_Adept_Silent_BONEBLAST **** **** **** **** **** **** **** **** +5487 Ocular_Adept_Still_BONEBLAST **** **** **** **** **** **** **** **** +5488 Ocular_Adept_Bulls_Strength **** **** **** **** **** **** **** **** +5489 Ocular_Adept_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +5490 Ocular_Adept_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +5491 Ocular_Adept_Maximized_Bulls_Strength **** **** **** **** **** **** **** **** +5492 Ocular_Adept_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +5493 Ocular_Adept_Still_Bulls_Strength **** **** **** **** **** **** **** **** +5494 Ocular_Adept_Calm_Emotions **** **** **** **** **** **** **** **** +5495 Ocular_Adept_Exteneded_Calm_Emotions **** **** **** **** **** **** **** **** +5496 Ocular_Adept_Silent_Calm_Emotions **** **** **** **** **** **** **** **** +5497 Ocular_Adept_Still_Calm_Emotions **** **** **** **** **** **** **** **** +5498 Ocular_Adept_Consecrated_Aura **** **** **** **** **** **** **** **** +5499 Ocular_Adept_Exteneded_Consecrated_Aura **** **** **** **** **** **** **** **** +5500 Ocular_Adept_Silent_Consecrated_Aura **** **** **** **** **** **** **** **** +5501 Ocular_Adept_Still_Consecrated_Aura **** **** **** **** **** **** **** **** +5502 Ocular_Adept_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5503 Ocular_Adept_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5504 Ocular_Adept_Maximized_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5505 Ocular_Adept_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5506 Ocular_Adept_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +5507 Ocular_Adept_Darkness **** **** **** **** **** **** **** **** +5508 Ocular_Adept_Exteneded_Darkness **** **** **** **** **** **** **** **** +5509 Ocular_Adept_Silent_Darkness **** **** **** **** **** **** **** **** +5510 Ocular_Adept_Death_Knell **** **** **** **** **** **** **** **** +5511 Ocular_Adept_Empowered_Death_Knell **** **** **** **** **** **** **** **** +5512 Ocular_Adept_Exteneded_Death_Knell **** **** **** **** **** **** **** **** +5513 Ocular_Adept_Maximized_Death_Knell **** **** **** **** **** **** **** **** +5514 Ocular_Adept_Silent_Death_Knell **** **** **** **** **** **** **** **** +5515 Ocular_Adept_Still_Death_Knell **** **** **** **** **** **** **** **** +5516 Ocular_Adept_Divine_Protection **** **** **** **** **** **** **** **** +5517 Ocular_Adept_Exteneded_Divine_Protection **** **** **** **** **** **** **** **** +5518 Ocular_Adept_Silent_Divine_Protection **** **** **** **** **** **** **** **** +5519 Ocular_Adept_Still_Divine_Protection **** **** **** **** **** **** **** **** +5520 Ocular_Adept_Eagle_Splendor **** **** **** **** **** **** **** **** +5521 Ocular_Adept_Empowered_Eagle_Splendor **** **** **** **** **** **** **** **** +5522 Ocular_Adept_Exteneded_Eagle_Splendor **** **** **** **** **** **** **** **** +5523 Ocular_Adept_Maximized_Eagle_Splendor **** **** **** **** **** **** **** **** +5524 Ocular_Adept_Silent_Eagle_Splendor **** **** **** **** **** **** **** **** +5525 Ocular_Adept_Still_Eagle_Splendor **** **** **** **** **** **** **** **** +5526 Ocular_Adept_ELATION **** **** **** **** **** **** **** **** +5527 Ocular_Adept_Exteneded_ELATION **** **** **** **** **** **** **** **** +5528 Ocular_Adept_Silent_ELATION **** **** **** **** **** **** **** **** +5529 Ocular_Adept_Still_ELATION **** **** **** **** **** **** **** **** +5530 Ocular_Adept_Endurance **** **** **** **** **** **** **** **** +5531 Ocular_Adept_Empowered_Endurance **** **** **** **** **** **** **** **** +5532 Ocular_Adept_Exteneded_Endurance **** **** **** **** **** **** **** **** +5533 Ocular_Adept_Maximized_Endurance **** **** **** **** **** **** **** **** +5534 Ocular_Adept_Silent_Endurance **** **** **** **** **** **** **** **** +5535 Ocular_Adept_Still_Endurance **** **** **** **** **** **** **** **** +5536 Ocular_Adept_Find_Traps **** **** **** **** **** **** **** **** +5537 Ocular_Adept_Exteneded_Find_Traps **** **** **** **** **** **** **** **** +5538 Ocular_Adept_Silent_Find_Traps **** **** **** **** **** **** **** **** +5539 Ocular_Adept_Still_Find_Traps **** **** **** **** **** **** **** **** +5540 Ocular_Adept_Foxs_Cunning **** **** **** **** **** **** **** **** +5541 Ocular_Adept_Empowered_Foxs_Cunning **** **** **** **** **** **** **** **** +5542 Ocular_Adept_Exteneded_Foxs_Cunning **** **** **** **** **** **** **** **** +5543 Ocular_Adept_Maximized_Foxs_Cunning **** **** **** **** **** **** **** **** +5544 Ocular_Adept_Silent_Foxs_Cunning **** **** **** **** **** **** **** **** +5545 Ocular_Adept_Still_Foxs_Cunning **** **** **** **** **** **** **** **** +5546 Ocular_Adept_Hold_Person **** **** **** **** **** **** **** **** +5547 Ocular_Adept_Exteneded_Hold_Person **** **** **** **** **** **** **** **** +5548 Ocular_Adept_Silent_Hold_Person **** **** **** **** **** **** **** **** +5549 Ocular_Adept_Still_Hold_Person **** **** **** **** **** **** **** **** +5550 Ocular_Adept_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5551 Ocular_Adept_Empowered_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5552 Ocular_Adept_Maximized_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5553 Ocular_Adept_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5554 Ocular_Adept_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +5555 Ocular_Adept_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5556 Ocular_Adept_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5557 Ocular_Adept_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +5558 Ocular_Adept_Lesser_Dispel **** **** **** **** **** **** **** **** +5559 Ocular_Adept_Silent_Lesser_Dispel **** **** **** **** **** **** **** **** +5560 Ocular_Adept_Still_Lesser_Dispel **** **** **** **** **** **** **** **** +5561 Ocular_Adept_Lesser_Restoration **** **** **** **** **** **** **** **** +5562 Ocular_Adept_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +5563 Ocular_Adept_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +5564 Ocular_Adept_Living_Undeath **** **** **** **** **** **** **** **** +5565 Ocular_Adept_Exteneded_Living_Undeath **** **** **** **** **** **** **** **** +5566 Ocular_Adept_Silent_Living_Undeath **** **** **** **** **** **** **** **** +5567 Ocular_Adept_Still_Living_Undeath **** **** **** **** **** **** **** **** +5568 Ocular_Adept_Necrotic_Cyst **** **** **** **** **** **** **** **** +5569 Ocular_Adept_Silent_Necrotic_Cyst **** **** **** **** **** **** **** **** +5570 Ocular_Adept_Still_Necrotic_Cyst **** **** **** **** **** **** **** **** +5571 Ocular_Adept_Negative_Energy_Ray **** **** **** **** **** **** **** **** +5572 Ocular_Adept_Empowered_Negative_Energy_Ray **** **** **** **** **** **** **** **** +5573 Ocular_Adept_Maximized_Negative_Energy_Ray **** **** **** **** **** **** **** **** +5574 Ocular_Adept_Silent_Negative_Energy_Ray **** **** **** **** **** **** **** **** +5575 Ocular_Adept_Still_Negative_Energy_Ray **** **** **** **** **** **** **** **** +5576 Ocular_Adept_Owls_Wisdom **** **** **** **** **** **** **** **** +5577 Ocular_Adept_Empowered_Owls_Wisdom **** **** **** **** **** **** **** **** +5578 Ocular_Adept_Exteneded_Owls_Wisdom **** **** **** **** **** **** **** **** +5579 Ocular_Adept_Maximized_Owls_Wisdom **** **** **** **** **** **** **** **** +5580 Ocular_Adept_Silent_Owls_Wisdom **** **** **** **** **** **** **** **** +5581 Ocular_Adept_Still_Owls_Wisdom **** **** **** **** **** **** **** **** +5582 Ocular_Adept_Remove_Paralysis **** **** **** **** **** **** **** **** +5583 Ocular_Adept_Silent_Remove_Paralysis **** **** **** **** **** **** **** **** +5584 Ocular_Adept_Still_Remove_Paralysis **** **** **** **** **** **** **** **** +5585 Ocular_Adept_Resist_Elements **** **** **** **** **** **** **** **** +5586 Ocular_Adept_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +5587 Ocular_Adept_Silent_Resist_Elements **** **** **** **** **** **** **** **** +5588 Ocular_Adept_Still_Resist_Elements **** **** **** **** **** **** **** **** +5589 Ocular_Adept_ShieldOther **** **** **** **** **** **** **** **** +5590 Ocular_Adept_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +5591 Ocular_Adept_Silent_ShieldOther **** **** **** **** **** **** **** **** +5592 Ocular_Adept_Still_ShieldOther **** **** **** **** **** **** **** **** +5593 Ocular_Adept_Silence **** **** **** **** **** **** **** **** +5594 Ocular_Adept_Exteneded_Silence **** **** **** **** **** **** **** **** +5595 Ocular_Adept_Silent_Silence **** **** **** **** **** **** **** **** +5596 Ocular_Adept_Still_Silence **** **** **** **** **** **** **** **** +5597 Ocular_Adept_Sound_Burst **** **** **** **** **** **** **** **** +5598 Ocular_Adept_Maximized_Sound_Burst **** **** **** **** **** **** **** **** +5599 Ocular_Adept_Silent_Sound_Burst **** **** **** **** **** **** **** **** +5600 Ocular_Adept_Still_Sound_Burst **** **** **** **** **** **** **** **** +5601 Ocular_Adept_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +5602 Ocular_Adept_Empowered_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +5603 Ocular_Adept_Maximized_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +5604 Ocular_Adept_Silent_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +5605 Ocular_Adept_Still_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +5606 Ocular_Adept_Stone_Bones **** **** **** **** **** **** **** **** +5607 Ocular_Adept_Exteneded_Stone_Bones **** **** **** **** **** **** **** **** +5608 Ocular_Adept_Silent_Stone_Bones **** **** **** **** **** **** **** **** +5609 Ocular_Adept_Still_Stone_Bones **** **** **** **** **** **** **** **** +5610 Ocular_Adept_Summon_Creature_II **** **** **** **** **** **** **** **** +5611 Ocular_Adept_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +5612 Ocular_Adept_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +5613 Ocular_Adept_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +5614 Ocular_Adept_SummonUndeadII **** **** **** **** **** **** **** **** +5615 Ocular_Adept_Exteneded_SummonUndeadII **** **** **** **** **** **** **** **** +5616 Ocular_Adept_Silent_SummonUndeadII **** **** **** **** **** **** **** **** +5617 Ocular_Adept_Still_SummonUndeadII **** **** **** **** **** **** **** **** +5618 Ocular_Adept_Ultravision **** **** **** **** **** **** **** **** +5619 Ocular_Adept_Exteneded_Ultravision **** **** **** **** **** **** **** **** +5620 Ocular_Adept_Silent_Ultravision **** **** **** **** **** **** **** **** +5621 Ocular_Adept_Still_Ultravision **** **** **** **** **** **** **** **** +5622 Ocular_Adept_UndetectableAlignment **** **** **** **** **** **** **** **** +5623 Ocular_Adept_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +5624 Ocular_Adept_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +5625 Ocular_Adept_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +5626 Ocular_Adept_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +5627 Ocular_Adept_Exteneded_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +5628 Ocular_Adept_Still_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +5629 Ocular_Adept_Animate_Dead **** **** **** **** **** **** **** **** +5630 Ocular_Adept_Exteneded_Animate_Dead **** **** **** **** **** **** **** **** +5631 Ocular_Adept_Silent_Animate_Dead **** **** **** **** **** **** **** **** +5632 Ocular_Adept_Still_Animate_Dead **** **** **** **** **** **** **** **** +5633 Ocular_Adept_Bestow_Curse **** **** **** **** **** **** **** **** +5634 Ocular_Adept_Silent_Bestow_Curse **** **** **** **** **** **** **** **** +5635 Ocular_Adept_Still_Bestow_Curse **** **** **** **** **** **** **** **** +5636 Ocular_Adept_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5637 Ocular_Adept_Exteneded_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5638 Ocular_Adept_Silent_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5639 Ocular_Adept_BONEBLADE **** **** **** **** **** **** **** **** +5640 Ocular_Adept_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5641 Ocular_Adept_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5642 Ocular_Adept_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5643 Ocular_Adept_Exteneded_BONEBLADE **** **** **** **** **** **** **** **** +5644 Ocular_Adept_Exteneded_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5645 Ocular_Adept_Exteneded_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5646 Ocular_Adept_Exteneded_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5647 Ocular_Adept_Silent_BONEBLADE **** **** **** **** **** **** **** **** +5648 Ocular_Adept_Silent_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5649 Ocular_Adept_Silent_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5650 Ocular_Adept_Silent_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5651 Ocular_Adept_Still_BONEBLADE **** **** **** **** **** **** **** **** +5652 Ocular_Adept_Still_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +5653 Ocular_Adept_Still_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +5654 Ocular_Adept_Still_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +5655 Ocular_Adept_Clarity **** **** **** **** **** **** **** **** +5656 Ocular_Adept_Exteneded_Clarity **** **** **** **** **** **** **** **** +5657 Ocular_Adept_Still_Clarity **** **** **** **** **** **** **** **** +5658 Ocular_Adept_Close_Wounds **** **** **** **** **** **** **** **** +5659 Ocular_Adept_Empowered_Close_Wounds **** **** **** **** **** **** **** **** +5660 Ocular_Adept_Silent_Close_Wounds **** **** **** **** **** **** **** **** +5661 Ocular_Adept_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +5662 Ocular_Adept_Silent_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +5663 Ocular_Adept_Still_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +5664 Ocular_Adept_Contagion **** **** **** **** **** **** **** **** +5665 Ocular_Adept_Silent_Contagion **** **** **** **** **** **** **** **** +5666 Ocular_Adept_Still_Contagion **** **** **** **** **** **** **** **** +5667 Ocular_Adept_Continual_Flame **** **** **** **** **** **** **** **** +5668 Ocular_Adept_Silent_Continual_Flame **** **** **** **** **** **** **** **** +5669 Ocular_Adept_Still_Continual_Flame **** **** **** **** **** **** **** **** +5670 Ocular_Adept_Crown_Might **** **** **** **** **** **** **** **** +5671 Ocular_Adept_Exteneded_Crown_Might **** **** **** **** **** **** **** **** +5672 Ocular_Adept_Silent_Crown_Might **** **** **** **** **** **** **** **** +5673 Ocular_Adept_Still_Crown_Might **** **** **** **** **** **** **** **** +5674 Ocular_Adept_Crown_Protection **** **** **** **** **** **** **** **** +5675 Ocular_Adept_Exteneded_Crown_Protection **** **** **** **** **** **** **** **** +5676 Ocular_Adept_Silent_Crown_Protection **** **** **** **** **** **** **** **** +5677 Ocular_Adept_Still_Crown_Protection **** **** **** **** **** **** **** **** +5678 Ocular_Adept_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5679 Ocular_Adept_Empowered_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5680 Ocular_Adept_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5681 Ocular_Adept_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +5682 Ocular_Adept_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +5683 Ocular_Adept_Exteneded_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +5684 Ocular_Adept_Silent_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +5685 Ocular_Adept_Still_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +5686 Ocular_Adept_Darkfire **** **** **** **** **** **** **** **** +5687 Ocular_Adept_Exteneded_Darkfire **** **** **** **** **** **** **** **** +5688 Ocular_Adept_Silent_Darkfire **** **** **** **** **** **** **** **** +5689 Ocular_Adept_Still_Darkfire **** **** **** **** **** **** **** **** +5690 Ocular_Adept_Daylight **** **** **** **** **** **** **** **** +5691 Ocular_Adept_Exteneded_Daylight **** **** **** **** **** **** **** **** +5692 Ocular_Adept_Silent_Daylight **** **** **** **** **** **** **** **** +5693 Ocular_Adept_Still_Daylight **** **** **** **** **** **** **** **** +5694 Ocular_Adept_DeeperDarkness **** **** **** **** **** **** **** **** +5695 Ocular_Adept_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +5696 Ocular_Adept_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +5697 Ocular_Adept_DEVILS_EYE **** **** **** **** **** **** **** **** +5698 Ocular_Adept_Silent_DEVILS_EYE **** **** **** **** **** **** **** **** +5699 Ocular_Adept_Still_DEVILS_EYE **** **** **** **** **** **** **** **** +5700 Ocular_Adept_Dispel_Magic **** **** **** **** **** **** **** **** +5701 Ocular_Adept_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +5702 Ocular_Adept_Still_Dispel_Magic **** **** **** **** **** **** **** **** +5703 Ocular_Adept_ENERGIZE_POTION **** **** **** **** **** **** **** **** +5704 Ocular_Adept_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +5705 Ocular_Adept_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +5706 Ocular_Adept_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +5707 Ocular_Adept_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +5708 Ocular_Adept_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +5709 Ocular_Adept_Silent_ENERGIZE_POTION **** **** **** **** **** **** **** **** +5710 Ocular_Adept_Silent_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +5711 Ocular_Adept_Silent_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +5712 Ocular_Adept_Silent_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +5713 Ocular_Adept_Silent_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +5714 Ocular_Adept_Silent_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +5715 Ocular_Adept_Still_ENERGIZE_POTION **** **** **** **** **** **** **** **** +5716 Ocular_Adept_Still_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +5717 Ocular_Adept_Still_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +5718 Ocular_Adept_Still_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +5719 Ocular_Adept_Still_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +5720 Ocular_Adept_Still_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +5721 Ocular_Adept_Energy_Aegis **** **** **** **** **** **** **** **** +5722 Ocular_Adept_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +5723 Ocular_Adept_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +5724 Ocular_Adept_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +5725 Ocular_Adept_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +5726 Ocular_Adept_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +5727 Ocular_Adept_Exteneded_Energy_Aegis **** **** **** **** **** **** **** **** +5728 Ocular_Adept_Exteneded_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +5729 Ocular_Adept_Exteneded_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +5730 Ocular_Adept_Exteneded_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +5731 Ocular_Adept_Exteneded_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +5732 Ocular_Adept_Exteneded_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +5733 Ocular_Adept_Silent_Energy_Aegis **** **** **** **** **** **** **** **** +5734 Ocular_Adept_Silent_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +5735 Ocular_Adept_Silent_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +5736 Ocular_Adept_Silent_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +5737 Ocular_Adept_Silent_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +5738 Ocular_Adept_Silent_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +5739 Ocular_Adept_Still_Energy_Aegis **** **** **** **** **** **** **** **** +5740 Ocular_Adept_Still_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +5741 Ocular_Adept_Still_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +5742 Ocular_Adept_Still_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +5743 Ocular_Adept_Still_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +5744 Ocular_Adept_Still_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +5745 Ocular_Adept_FLESH_RIPPER **** **** **** **** **** **** **** **** +5746 Ocular_Adept_Empowered_FLESH_RIPPER **** **** **** **** **** **** **** **** +5747 Ocular_Adept_Silent_FLESH_RIPPER **** **** **** **** **** **** **** **** +5748 Ocular_Adept_Still_FLESH_RIPPER **** **** **** **** **** **** **** **** +5749 Ocular_Adept_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +5750 Ocular_Adept_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +5751 Ocular_Adept_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +5752 Ocular_Adept_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +5753 Ocular_Adept_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +5754 Ocular_Adept_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +5755 Ocular_Adept_Empowered_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +5756 Ocular_Adept_Empowered_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +5757 Ocular_Adept_Empowered_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +5758 Ocular_Adept_Empowered_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +5759 Ocular_Adept_Empowered_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +5760 Ocular_Adept_Empowered_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +5761 Ocular_Adept_Exteneded_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +5762 Ocular_Adept_Exteneded_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +5763 Ocular_Adept_Exteneded_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +5764 Ocular_Adept_Exteneded_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +5765 Ocular_Adept_Exteneded_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +5766 Ocular_Adept_Exteneded_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +5767 Ocular_Adept_Silent_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +5768 Ocular_Adept_Silent_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +5769 Ocular_Adept_Silent_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +5770 Ocular_Adept_Silent_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +5771 Ocular_Adept_Silent_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +5772 Ocular_Adept_Silent_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +5773 Ocular_Adept_Still_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +5774 Ocular_Adept_Still_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +5775 Ocular_Adept_Still_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +5776 Ocular_Adept_Still_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +5777 Ocular_Adept_Still_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +5778 Ocular_Adept_Still_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +5779 Ocular_Adept_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5780 Ocular_Adept_Empowered_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5781 Ocular_Adept_Silent_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5782 Ocular_Adept_Still_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +5783 Ocular_Adept_Invisibility_Purge **** **** **** **** **** **** **** **** +5784 Ocular_Adept_Exteneded_Invisibility_Purge **** **** **** **** **** **** **** **** +5785 Ocular_Adept_Silent_Invisibility_Purge **** **** **** **** **** **** **** **** +5786 Ocular_Adept_Still_Invisibility_Purge **** **** **** **** **** **** **** **** +5787 Ocular_Adept_Legions_Conviction **** **** **** **** **** **** **** **** +5788 Ocular_Adept_Exteneded_Legions_Conviction **** **** **** **** **** **** **** **** +5789 Ocular_Adept_Silent_Legions_Conviction **** **** **** **** **** **** **** **** +5790 Ocular_Adept_Still_Legions_Conviction **** **** **** **** **** **** **** **** +5791 Ocular_Adept_LocateObject **** **** **** **** **** **** **** **** +5792 Ocular_Adept_Exteneded_LocateObject **** **** **** **** **** **** **** **** +5793 Ocular_Adept_Silent_LocateObject **** **** **** **** **** **** **** **** +5794 Ocular_Adept_Still_LocateObject **** **** **** **** **** **** **** **** +5795 Ocular_Adept_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +5796 Ocular_Adept_Exteneded_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +5797 Ocular_Adept_Silent_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +5798 Ocular_Adept_Still_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +5799 Ocular_Adept_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +5800 Ocular_Adept_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +5801 Ocular_Adept_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +5802 Ocular_Adept_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +5803 Ocular_Adept_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +5804 Ocular_Adept_Exteneded_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +5805 Ocular_Adept_Silent_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +5806 Ocular_Adept_Still_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +5807 Ocular_Adept_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +5808 Ocular_Adept_Exteneded_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +5809 Ocular_Adept_Silent_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +5810 Ocular_Adept_Still_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +5811 Ocular_Adept_Magic_Vestment **** **** **** **** **** **** **** **** +5812 Ocular_Adept_Exteneded_Magic_Vestment **** **** **** **** **** **** **** **** +5813 Ocular_Adept_Silent_Magic_Vestment **** **** **** **** **** **** **** **** +5814 Ocular_Adept_Still_Magic_Vestment **** **** **** **** **** **** **** **** +5815 Ocular_Adept_MASOCHISM **** **** **** **** **** **** **** **** +5816 Ocular_Adept_Exteneded_MASOCHISM **** **** **** **** **** **** **** **** +5817 Ocular_Adept_Mass_Aid **** **** **** **** **** **** **** **** +5818 Ocular_Adept_Empowered_Mass_Aid **** **** **** **** **** **** **** **** +5819 Ocular_Adept_Exteneded_Mass_Aid **** **** **** **** **** **** **** **** +5820 Ocular_Adept_Silent_Mass_Aid **** **** **** **** **** **** **** **** +5821 Ocular_Adept_Still_Mass_Aid **** **** **** **** **** **** **** **** +5822 Ocular_Adept_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +5823 Ocular_Adept_Exteneded_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +5824 Ocular_Adept_Silent_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +5825 Ocular_Adept_Still_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +5826 Ocular_Adept_Necrotic_Bloat **** **** **** **** **** **** **** **** +5827 Ocular_Adept_Empowered_Necrotic_Bloat **** **** **** **** **** **** **** **** +5828 Ocular_Adept_Negative_Energy_Protection **** **** **** **** **** **** **** **** +5829 Ocular_Adept_Exteneded_Negative_Energy_Protection **** **** **** **** **** **** **** **** +5830 Ocular_Adept_Silent_Negative_Energy_Protection **** **** **** **** **** **** **** **** +5831 Ocular_Adept_Still_Negative_Energy_Protection **** **** **** **** **** **** **** **** +5832 Ocular_Adept_ObscureObject **** **** **** **** **** **** **** **** +5833 Ocular_Adept_Exteneded_ObscureObject **** **** **** **** **** **** **** **** +5834 Ocular_Adept_Silent_ObscureObject **** **** **** **** **** **** **** **** +5835 Ocular_Adept_Still_ObscureObject **** **** **** **** **** **** **** **** +5836 Ocular_Adept_Prayer **** **** **** **** **** **** **** **** +5837 Ocular_Adept_Exteneded_Prayer **** **** **** **** **** **** **** **** +5838 Ocular_Adept_Silent_Prayer **** **** **** **** **** **** **** **** +5839 Ocular_Adept_Still_Prayer **** **** **** **** **** **** **** **** +5840 Ocular_Adept_Protection_from_Elements **** **** **** **** **** **** **** **** +5841 Ocular_Adept_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +5842 Ocular_Adept_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +5843 Ocular_Adept_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +5844 Ocular_Adept_RED_FESTER **** **** **** **** **** **** **** **** +5845 Ocular_Adept_Silent_RED_FESTER **** **** **** **** **** **** **** **** +5846 Ocular_Adept_Still_RED_FESTER **** **** **** **** **** **** **** **** +5847 Ocular_Adept_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5848 Ocular_Adept_Silent_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5849 Ocular_Adept_Still_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +5850 Ocular_Adept_Remove_Curse **** **** **** **** **** **** **** **** +5851 Ocular_Adept_Silent_Remove_Curse **** **** **** **** **** **** **** **** +5852 Ocular_Adept_Still_Remove_Curse **** **** **** **** **** **** **** **** +5853 Ocular_Adept_Remove_Disease **** **** **** **** **** **** **** **** +5854 Ocular_Adept_Silent_Remove_Disease **** **** **** **** **** **** **** **** +5855 Ocular_Adept_Still_Remove_Disease **** **** **** **** **** **** **** **** +5856 Ocular_Adept_RingOfBlades **** **** **** **** **** **** **** **** +5857 Ocular_Adept_Exteneded_RingOfBlades **** **** **** **** **** **** **** **** +5858 Ocular_Adept_Silent_RingOfBlades **** **** **** **** **** **** **** **** +5859 Ocular_Adept_Still_RingOfBlades **** **** **** **** **** **** **** **** +5860 Ocular_Adept_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5861 Ocular_Adept_Empowered_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5862 Ocular_Adept_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5863 Ocular_Adept_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +5864 Ocular_Adept_Searing_Light **** **** **** **** **** **** **** **** +5865 Ocular_Adept_Empowered_Searing_Light **** **** **** **** **** **** **** **** +5866 Ocular_Adept_Silent_Searing_Light **** **** **** **** **** **** **** **** +5867 Ocular_Adept_Still_Searing_Light **** **** **** **** **** **** **** **** +5868 Ocular_Adept_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5869 Ocular_Adept_Empowered_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5870 Ocular_Adept_Exteneded_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5871 Ocular_Adept_Silent_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5872 Ocular_Adept_Still_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +5873 Ocular_Adept_SHRIVELING **** **** **** **** **** **** **** **** +5874 Ocular_Adept_Empowered_SHRIVELING **** **** **** **** **** **** **** **** +5875 Ocular_Adept_Silent_SHRIVELING **** **** **** **** **** **** **** **** +5876 Ocular_Adept_Still_SHRIVELING **** **** **** **** **** **** **** **** +5877 Ocular_Adept_Slashing_Darkness **** **** **** **** **** **** **** **** +5878 Ocular_Adept_Empowered_Slashing_Darkness **** **** **** **** **** **** **** **** +5879 Ocular_Adept_Silent_Slashing_Darkness **** **** **** **** **** **** **** **** +5880 Ocular_Adept_Still_Slashing_Darkness **** **** **** **** **** **** **** **** +5881 Ocular_Adept_Summon_Creature_III **** **** **** **** **** **** **** **** +5882 Ocular_Adept_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +5883 Ocular_Adept_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +5884 Ocular_Adept_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +5885 Ocular_Adept_SummonUndeadIII **** **** **** **** **** **** **** **** +5886 Ocular_Adept_Exteneded_SummonUndeadIII **** **** **** **** **** **** **** **** +5887 Ocular_Adept_Silent_SummonUndeadIII **** **** **** **** **** **** **** **** +5888 Ocular_Adept_Still_SummonUndeadIII **** **** **** **** **** **** **** **** +5889 Ocular_Adept_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5890 Ocular_Adept_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5891 Ocular_Adept_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +5892 Ocular_Adept_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +5893 Ocular_Adept_Empowered_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +5894 Ocular_Adept_Silent_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +5895 Ocular_Adept_Still_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +5896 Ocular_Adept_Vigor **** **** **** **** **** **** **** **** +5897 Ocular_Adept_Exteneded_Vigor **** **** **** **** **** **** **** **** +5898 Ocular_Adept_Silent_Vigor **** **** **** **** **** **** **** **** +5899 Ocular_Adept_Still_Vigor **** **** **** **** **** **** **** **** +5900 Ocular_Adept_WaterBreathing **** **** **** **** **** **** **** **** +5901 Ocular_Adept_Exteneded_WaterBreathing **** **** **** **** **** **** **** **** +5902 Ocular_Adept_Silent_WaterBreathing **** **** **** **** **** **** **** **** +5903 Ocular_Adept_Still_WaterBreathing **** **** **** **** **** **** **** **** +5904 Ocular_Adept_WRACK **** **** **** **** **** **** **** **** +5905 Ocular_Adept_Exteneded_WRACK **** **** **** **** **** **** **** **** +5906 Ocular_Adept_Silent_WRACK **** **** **** **** **** **** **** **** +5907 Ocular_Adept_Still_WRACK **** **** **** **** **** **** **** **** +5908 Ocular_Adept_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +5909 Ocular_Adept_Exteneded_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +5910 Ocular_Adept_Silent_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +5911 Ocular_Adept_Still_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +5912 Ocular_Adept_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5913 Ocular_Adept_Exteneded_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5914 Ocular_Adept_Silent_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5915 Ocular_Adept_Still_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +5916 Ocular_Adept_BloodOfTheMartyr **** **** **** **** **** **** **** **** +5917 Ocular_Adept_Silent_BloodOfTheMartyr **** **** **** **** **** **** **** **** +5918 Ocular_Adept_Still_BloodOfTheMartyr **** **** **** **** **** **** **** **** +5919 Ocular_Adept_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +5920 Ocular_Adept_Exteneded_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +5921 Ocular_Adept_Silent_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +5922 Ocular_Adept_Still_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +5923 Ocular_Adept_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +5924 Ocular_Adept_Silent_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +5925 Ocular_Adept_Still_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +5926 Ocular_Adept_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +5927 Ocular_Adept_Exteneded_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +5928 Ocular_Adept_Silent_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +5929 Ocular_Adept_Death_Ward **** **** **** **** **** **** **** **** +5930 Ocular_Adept_Exteneded_Death_Ward **** **** **** **** **** **** **** **** +5931 Ocular_Adept_Silent_Death_Ward **** **** **** **** **** **** **** **** +5932 Ocular_Adept_Still_Death_Ward **** **** **** **** **** **** **** **** +5933 Ocular_Adept_Dimensional_Anchor **** **** **** **** **** **** **** **** +5934 Ocular_Adept_Exteneded_Dimensional_Anchor **** **** **** **** **** **** **** **** +5935 Ocular_Adept_Silent_Dimensional_Anchor **** **** **** **** **** **** **** **** +5936 Ocular_Adept_Still_Dimensional_Anchor **** **** **** **** **** **** **** **** +5937 Ocular_Adept_Dismissal **** **** **** **** **** **** **** **** +5938 Ocular_Adept_Silent_Dismissal **** **** **** **** **** **** **** **** +5939 Ocular_Adept_Still_Dismissal **** **** **** **** **** **** **** **** +5940 Ocular_Adept_Divine_Power **** **** **** **** **** **** **** **** +5941 Ocular_Adept_Exteneded_Divine_Power **** **** **** **** **** **** **** **** +5942 Ocular_Adept_Silent_Divine_Power **** **** **** **** **** **** **** **** +5943 Ocular_Adept_Still_Divine_Power **** **** **** **** **** **** **** **** +5944 Ocular_Adept_Freedom_of_Movement **** **** **** **** **** **** **** **** +5945 Ocular_Adept_Exteneded_Freedom_of_Movement **** **** **** **** **** **** **** **** +5946 Ocular_Adept_Silent_Freedom_of_Movement **** **** **** **** **** **** **** **** +5947 Ocular_Adept_Still_Freedom_of_Movement **** **** **** **** **** **** **** **** +5948 Ocular_Adept_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +5949 Ocular_Adept_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +5950 Ocular_Adept_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +5951 Ocular_Adept_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +5952 Ocular_Adept_Greater_Resistance **** **** **** **** **** **** **** **** +5953 Ocular_Adept_Exteneded_Greater_Resistance **** **** **** **** **** **** **** **** +5954 Ocular_Adept_Silent_Greater_Resistance **** **** **** **** **** **** **** **** +5955 Ocular_Adept_Still_Greater_Resistance **** **** **** **** **** **** **** **** +5956 Ocular_Adept_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +5957 Ocular_Adept_Silent_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +5958 Ocular_Adept_Still_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +5959 Ocular_Adept_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +5960 Ocular_Adept_Silent_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +5961 Ocular_Adept_Still_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +5962 Ocular_Adept_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +5963 Ocular_Adept_Exteneded_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +5964 Ocular_Adept_Silent_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +5965 Ocular_Adept_Still_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +5966 Ocular_Adept_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +5967 Ocular_Adept_Exteneded_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +5968 Ocular_Adept_Silent_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +5969 Ocular_Adept_Still_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +5970 Ocular_Adept_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +5971 Ocular_Adept_Exteneded_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +5972 Ocular_Adept_Silent_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +5973 Ocular_Adept_Still_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +5974 Ocular_Adept_Mass_Ultravision **** **** **** **** **** **** **** **** +5975 Ocular_Adept_Exteneded_Mass_Ultravision **** **** **** **** **** **** **** **** +5976 Ocular_Adept_Silent_Mass_Ultravision **** **** **** **** **** **** **** **** +5977 Ocular_Adept_Still_Mass_Ultravision **** **** **** **** **** **** **** **** +5978 Ocular_Adept_Necrotic_Domination **** **** **** **** **** **** **** **** +5979 Ocular_Adept_Exteneded_Necrotic_Domination **** **** **** **** **** **** **** **** +5980 Ocular_Adept_Silent_Necrotic_Domination **** **** **** **** **** **** **** **** +5981 Ocular_Adept_Still_Necrotic_Domination **** **** **** **** **** **** **** **** +5982 Ocular_Adept_Neutralize_Poison **** **** **** **** **** **** **** **** +5983 Ocular_Adept_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +5984 Ocular_Adept_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +5985 Ocular_Adept_Panacea **** **** **** **** **** **** **** **** +5986 Ocular_Adept_Silent_Panacea **** **** **** **** **** **** **** **** +5987 Ocular_Adept_Still_Panacea **** **** **** **** **** **** **** **** +5988 Ocular_Adept_Poison **** **** **** **** **** **** **** **** +5989 Ocular_Adept_Silent_Poison **** **** **** **** **** **** **** **** +5990 Ocular_Adept_Still_Poison **** **** **** **** **** **** **** **** +5991 Ocular_Adept_Recitation **** **** **** **** **** **** **** **** +5992 Ocular_Adept_Exteneded_Recitation **** **** **** **** **** **** **** **** +5993 Ocular_Adept_Silent_Recitation **** **** **** **** **** **** **** **** +5994 Ocular_Adept_Still_Recitation **** **** **** **** **** **** **** **** +5995 Ocular_Adept_RepelVermin **** **** **** **** **** **** **** **** +5996 Ocular_Adept_Exteneded_RepelVermin **** **** **** **** **** **** **** **** +5997 Ocular_Adept_Silent_RepelVermin **** **** **** **** **** **** **** **** +5998 Ocular_Adept_Still_RepelVermin **** **** **** **** **** **** **** **** +5999 Ocular_Adept_Restoration **** **** **** **** **** **** **** **** +6000 Ocular_Adept_Silent_Restoration **** **** **** **** **** **** **** **** +6001 Ocular_Adept_Still_Restoration **** **** **** **** **** **** **** **** +6002 Ocular_Adept_STOP_HEART **** **** **** **** **** **** **** **** +6003 Ocular_Adept_Still_STOP_HEART **** **** **** **** **** **** **** **** +6004 Ocular_Adept_Summon_Creature_IV **** **** **** **** **** **** **** **** +6005 Ocular_Adept_Exteneded_Summon_Creature_IV **** **** **** **** **** **** **** **** +6006 Ocular_Adept_Silent_Summon_Creature_IV **** **** **** **** **** **** **** **** +6007 Ocular_Adept_Still_Summon_Creature_IV **** **** **** **** **** **** **** **** +6008 Ocular_Adept_SummonUndeadIV **** **** **** **** **** **** **** **** +6009 Ocular_Adept_Exteneded_SummonUndeadIV **** **** **** **** **** **** **** **** +6010 Ocular_Adept_Silent_SummonUndeadIV **** **** **** **** **** **** **** **** +6011 Ocular_Adept_Still_SummonUndeadIV **** **** **** **** **** **** **** **** +6012 Ocular_Adept_SwordOfConscience **** **** **** **** **** **** **** **** +6013 Ocular_Adept_Silent_SwordOfConscience **** **** **** **** **** **** **** **** +6014 Ocular_Adept_Battletide **** **** **** **** **** **** **** **** +6015 Ocular_Adept_BreakEnchantment **** **** **** **** **** **** **** **** +6016 Ocular_Adept_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +6017 Ocular_Adept_Circle_of_Doom **** **** **** **** **** **** **** **** +6018 Ocular_Adept_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +6019 Ocular_Adept_CONVERT_WAND **** **** **** **** **** **** **** **** +6020 Ocular_Adept_DANCING_WEB **** **** **** **** **** **** **** **** +6021 Ocular_Adept_FireInTheBlood **** **** **** **** **** **** **** **** +6022 Ocular_Adept_Flame_Strike **** **** **** **** **** **** **** **** +6023 Ocular_Adept_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6024 Ocular_Adept_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +6025 Ocular_Adept_GreaterCommand_Approach **** **** **** **** **** **** **** **** +6026 Ocular_Adept_GreaterCommand_Drop **** **** **** **** **** **** **** **** +6027 Ocular_Adept_GreaterCommand_Fall **** **** **** **** **** **** **** **** +6028 Ocular_Adept_GreaterCommand_Flee **** **** **** **** **** **** **** **** +6029 Ocular_Adept_GreaterCommand_Halt **** **** **** **** **** **** **** **** +6030 Ocular_Adept_Healing_Circle **** **** **** **** **** **** **** **** +6031 Ocular_Adept_HEARTCLUTCH **** **** **** **** **** **** **** **** +6032 Ocular_Adept_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +6033 Ocular_Adept_Mass_Contagion **** **** **** **** **** **** **** **** +6034 Ocular_Adept_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6035 Ocular_Adept_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +6036 Ocular_Adept_MORALITY_UNDONE **** **** **** **** **** **** **** **** +6037 Ocular_Adept_Necrotic_Burst **** **** **** **** **** **** **** **** +6038 Ocular_Adept_POWER_LEECH **** **** **** **** **** **** **** **** +6039 Ocular_Adept_Raise_Dead **** **** **** **** **** **** **** **** +6040 Ocular_Adept_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +6041 Ocular_Adept_Revivify **** **** **** **** **** **** **** **** +6042 Ocular_Adept_Righteous_Might **** **** **** **** **** **** **** **** +6043 Ocular_Adept_Scrying **** **** **** **** **** **** **** **** +6044 Ocular_Adept_Slay_Living **** **** **** **** **** **** **** **** +6045 Ocular_Adept_Soulscour **** **** **** **** **** **** **** **** +6046 Ocular_Adept_Spell_Resistance **** **** **** **** **** **** **** **** +6047 Ocular_Adept_Summon_Creature_V **** **** **** **** **** **** **** **** +6048 Ocular_Adept_SummonUndeadV **** **** **** **** **** **** **** **** +6049 Ocular_Adept_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +6050 Ocular_Adept_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +6051 Ocular_Adept_True_Seeing **** **** **** **** **** **** **** **** +6052 Hexblade_AugmentFamiliar **** **** **** **** **** **** **** **** +6053 Hexblade_Light **** **** **** **** **** **** **** **** +6054 Hexblade_Cause_Fear **** **** **** **** **** **** **** **** +6055 Hexblade_Charm_Person **** **** **** **** **** **** **** **** +6056 Hexblade_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +6057 Hexblade_Disguise_Self_Learn **** **** **** **** **** **** **** **** +6058 Hexblade_Disguise_Self_Options **** **** **** **** **** **** **** **** +6059 Hexblade_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +6060 Hexblade_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +6061 Hexblade_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +6062 Hexblade_Entropic_Shield **** **** **** **** **** **** **** **** +6063 Hexblade_Expeditious_Retreat **** **** **** **** **** **** **** **** +6064 Hexblade_Identify **** **** **** **** **** **** **** **** +6065 Hexblade_Magic_Weapon **** **** **** **** **** **** **** **** +6066 Hexblade_Protection_from_Chaos **** **** **** **** **** **** **** **** +6067 Hexblade_Protection_from_Evil **** **** **** **** **** **** **** **** +6068 Hexblade_Protection_from_Good **** **** **** **** **** **** **** **** +6069 Hexblade_Protection_from_Law **** **** **** **** **** **** **** **** +6070 Hexblade_Read_Magic **** **** **** **** **** **** **** **** +6071 Hexblade_Sleep **** **** **** **** **** **** **** **** +6072 Hexblade_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6073 Hexblade_UndetectableAlignment **** **** **** **** **** **** **** **** +6074 Hexblade_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +6075 Hexblade_Alter_Self_Learn **** **** **** **** **** **** **** **** +6076 Hexblade_Alter_Self_Options **** **** **** **** **** **** **** **** +6077 Hexblade_Alter_Self_QS1 **** **** **** **** **** **** **** **** +6078 Hexblade_Alter_Self_QS2 **** **** **** **** **** **** **** **** +6079 Hexblade_Alter_Self_QS3 **** **** **** **** **** **** **** **** +6080 Hexblade_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6081 Hexblade_Blood_Frenzy **** **** **** **** **** **** **** **** +6082 Hexblade_Bulls_Strength **** **** **** **** **** **** **** **** +6083 Hexblade_Darkness **** **** **** **** **** **** **** **** +6084 Hexblade_Eagle_Splendor **** **** **** **** **** **** **** **** +6085 Hexblade_FalseLife **** **** **** **** **** **** **** **** +6086 Hexblade_Glitterdust **** **** **** **** **** **** **** **** +6087 Hexblade_Invisibility **** **** **** **** **** **** **** **** +6088 Hexblade_MirrorImage **** **** **** **** **** **** **** **** +6089 Hexblade_ProtectionArrows **** **** **** **** **** **** **** **** +6090 Hexblade_Pyrotechnics **** **** **** **** **** **** **** **** +6091 Hexblade_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +6092 Hexblade_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +6093 Hexblade_Resist_Elements **** **** **** **** **** **** **** **** +6094 Hexblade_See_Invisibility **** **** **** **** **** **** **** **** +6095 Hexblade_TouchIdiocy **** **** **** **** **** **** **** **** +6096 Hexblade_Charm_Monster **** **** **** **** **** **** **** **** +6097 Hexblade_Confusion **** **** **** **** **** **** **** **** +6098 Hexblade_DeepSlumber **** **** **** **** **** **** **** **** +6099 Hexblade_Dispel_Magic **** **** **** **** **** **** **** **** +6100 Hexblade_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +6101 Hexblade_HoundDoom **** **** **** **** **** **** **** **** +6102 Hexblade_Invisibility_Sphere **** **** **** **** **** **** **** **** +6103 Hexblade_NONDETECTION **** **** **** **** **** **** **** **** +6104 Hexblade_Poison **** **** **** **** **** **** **** **** +6105 Hexblade_Protection_from_Elements **** **** **** **** **** **** **** **** +6106 Hexblade_RepelVermin **** **** **** **** **** **** **** **** +6107 Hexblade_Slow **** **** **** **** **** **** **** **** +6108 Hexblade_Stinking_Cloud **** **** **** **** **** **** **** **** +6109 Hexblade_Vampiric_Touch **** **** **** **** **** **** **** **** +6110 Hexblade_BalefulPolymorph **** **** **** **** **** **** **** **** +6111 Hexblade_BreakEnchantment **** **** **** **** **** **** **** **** +6112 Hexblade_CursedBlade **** **** **** **** **** **** **** **** +6113 Hexblade_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +6114 Hexblade_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +6115 Hexblade_DimensionDoor_Party **** **** **** **** **** **** **** **** +6116 Hexblade_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +6117 Hexblade_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +6118 Hexblade_Dominate_Person **** **** **** **** **** **** **** **** +6119 Hexblade_Enervation **** **** **** **** **** **** **** **** +6120 Hexblade_Improved_Invisibility **** **** **** **** **** **** **** **** +6121 Hexblade_Phantasmal_Killer **** **** **** **** **** **** **** **** +6122 Hexblade_Polymorph_Self **** **** **** **** **** **** **** **** +6123 Hexblade_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +6124 Hexblade_Polymorph_TROLL **** **** **** **** **** **** **** **** +6125 Hexblade_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +6126 Hexblade_Polymorph_PIXIE **** **** **** **** **** **** **** **** +6127 Hexblade_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +6128 Hexblade_Fear **** **** **** **** **** **** **** **** +6129 Hexblade_Scrying **** **** **** **** **** **** **** **** +6130 Hexblade_SolidFog **** **** **** **** **** **** **** **** +6131 Duskblade_Acid_Splash **** **** **** **** **** **** **** **** +6132 Duskblade_DisruptUndead **** **** **** **** **** **** **** **** +6133 Duskblade_Ray_of_Frost **** **** **** **** **** **** **** **** +6134 Duskblade_Blade_of_Blood **** **** **** **** **** **** **** **** +6135 Duskblade_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +6136 Duskblade_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +6137 Duskblade_Kelgores_Fire_Bolt **** **** **** **** **** **** **** **** +6138 Duskblade_Lesser_Deflect **** **** **** **** **** **** **** **** +6139 Duskblade_Rouse **** **** **** **** **** **** **** **** +6140 Duskblade_Bigbys_Tripping_Hand **** **** **** **** **** **** **** **** +6141 Duskblade_Burning_Hands **** **** **** **** **** **** **** **** +6142 Duskblade_Chill_Touch **** **** **** **** **** **** **** **** +6143 Duskblade_Color_Spray **** **** **** **** **** **** **** **** +6144 Duskblade_Expeditious_Retreat **** **** **** **** **** **** **** **** +6145 Duskblade_Spell_Jump **** **** **** **** **** **** **** **** +6146 Duskblade_Magic_Weapon **** **** **** **** **** **** **** **** +6147 Duskblade_Obscuring_Mist **** **** **** **** **** **** **** **** +6148 Duskblade_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +6149 Duskblade_Cause_Fear **** **** **** **** **** **** **** **** +6150 Duskblade_True_Strike **** **** **** **** **** **** **** **** +6151 Duskblade_Resist_Elements **** **** **** **** **** **** **** **** +6152 Duskblade_ShockingGrasp **** **** **** **** **** **** **** **** +6153 Duskblade_Animalistic_Power **** **** **** **** **** **** **** **** +6154 Duskblade_Deflect **** **** **** **** **** **** **** **** +6155 Duskblade_Dimension_Hop **** **** **** **** **** **** **** **** +6156 Duskblade_Seeking_Ray **** **** **** **** **** **** **** **** +6157 Duskblade_Sure_Strike **** **** **** **** **** **** **** **** +6158 Duskblade_Bigbys_Striking_Fist **** **** **** **** **** **** **** **** +6159 Duskblade_Bulls_Strength **** **** **** **** **** **** **** **** +6160 Duskblade_Cats_Grace **** **** **** **** **** **** **** **** +6161 Duskblade_Endurance **** **** **** **** **** **** **** **** +6162 Duskblade_Ghoul_Touch **** **** **** **** **** **** **** **** +6163 Duskblade_Invisibility **** **** **** **** **** **** **** **** +6164 Duskblade_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +6165 Duskblade_TouchIdiocy **** **** **** **** **** **** **** **** +6166 Duskblade_See_Invisibility **** **** **** **** **** **** **** **** +6167 Duskblade_ScorchingRay **** **** **** **** **** **** **** **** +6168 Duskblade_Crown_Might **** **** **** **** **** **** **** **** +6169 Duskblade_Crown_Protection **** **** **** **** **** **** **** **** +6170 Duskblade_Dispelling_Touch **** **** **** **** **** **** **** **** +6171 Duskblade_Doom_Scarabs **** **** **** **** **** **** **** **** +6172 Duskblade_Energy_Aegis **** **** **** **** **** **** **** **** +6173 Duskblade_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +6174 Duskblade_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +6175 Duskblade_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +6176 Duskblade_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +6177 Duskblade_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +6178 Duskblade_Energy_Surge **** **** **** **** **** **** **** **** +6179 Duskblade_Energy_Surge_Acid **** **** **** **** **** **** **** **** +6180 Duskblade_Energy_Surge_Cold **** **** **** **** **** **** **** **** +6181 Duskblade_Energy_Surge_Elec **** **** **** **** **** **** **** **** +6182 Duskblade_Energy_Surge_Fire **** **** **** **** **** **** **** **** +6183 Duskblade_Energy_Surge_Sonic **** **** **** **** **** **** **** **** +6184 Duskblade_Halt **** **** **** **** **** **** **** **** +6185 Duskblade_Regroup **** **** **** **** **** **** **** **** +6186 Duskblade_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +6187 Duskblade_Keen_Edge **** **** **** **** **** **** **** **** +6188 Duskblade_Protection_from_Elements **** **** **** **** **** **** **** **** +6189 Duskblade_Vampiric_Touch **** **** **** **** **** **** **** **** +6190 Duskblade_RayofExhaustion **** **** **** **** **** **** **** **** +6191 Duskblade_Channeled_Pyroburst **** **** **** **** **** **** **** **** +6192 Duskblade_Channeled_Pyroburst_Swift **** **** **** **** **** **** **** **** +6193 Duskblade_Channeled_Pyroburst_Standard **** **** **** **** **** **** **** **** +6194 Duskblade_Channeled_Pyroburst_Full **** **** **** **** **** **** **** **** +6195 Duskblade_Channeled_Pyroburst_Two **** **** **** **** **** **** **** **** +6196 Duskblade_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +6197 Duskblade_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +6198 Duskblade_DimensionDoor_Party **** **** **** **** **** **** **** **** +6199 Duskblade_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +6200 Duskblade_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +6201 Duskblade_Elemental_Shield **** **** **** **** **** **** **** **** +6202 Duskblade_Enervation **** **** **** **** **** **** **** **** +6203 Duskblade_Phantasmal_Killer **** **** **** **** **** **** **** **** +6204 Duskblade_Shout **** **** **** **** **** **** **** **** +6205 Duskblade_Bigbys_Interposing_Hand **** **** **** **** **** **** **** **** +6206 Duskblade_Dispel_Magic **** **** **** **** **** **** **** **** +6207 Duskblade_Slashing_Dispel **** **** **** **** **** **** **** **** +6208 Duskblade_Sonic_Shield **** **** **** **** **** **** **** **** +6209 Duskblade_Hold_Monster **** **** **** **** **** **** **** **** +6210 Duskblade_Chain_Lightning **** **** **** **** **** **** **** **** +6211 Duskblade_Disintegrate **** **** **** **** **** **** **** **** +6212 Duskblade_Bigbys_Clenched_Fist **** **** **** **** **** **** **** **** +6213 Duskblade_PolarRay **** **** **** **** **** **** **** **** +6214 Duskblade_WavesofFatigue **** **** **** **** **** **** **** **** +6215 Healer_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +6216 Healer_Quickened_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +6217 Healer_Silent_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +6218 Healer_Still_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +6219 Healer_Light **** **** **** **** **** **** **** **** +6220 Healer_Exteneded_Light **** **** **** **** **** **** **** **** +6221 Healer_Quickened_Light **** **** **** **** **** **** **** **** +6222 Healer_Silent_Light **** **** **** **** **** **** **** **** +6223 Healer_Read_Magic **** **** **** **** **** **** **** **** +6224 Healer_Quickened_Read_Magic **** **** **** **** **** **** **** **** +6225 Healer_Silent_Read_Magic **** **** **** **** **** **** **** **** +6226 Healer_Still_Read_Magic **** **** **** **** **** **** **** **** +6227 Healer_Bless_Water **** **** **** **** **** **** **** **** +6228 Healer_Quickened_Bless_Water **** **** **** **** **** **** **** **** +6229 Healer_Silent_Bless_Water **** **** **** **** **** **** **** **** +6230 Healer_Still_Bless_Water **** **** **** **** **** **** **** **** +6231 Healer_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6232 Healer_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6233 Healer_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6234 Healer_Quickened_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6235 Healer_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6236 Healer_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6237 Healer_Lesser_Vigor **** **** **** **** **** **** **** **** +6238 Healer_Exteneded_Lesser_Vigor **** **** **** **** **** **** **** **** +6239 Healer_Quickened_Lesser_Vigor **** **** **** **** **** **** **** **** +6240 Healer_Silent_Lesser_Vigor **** **** **** **** **** **** **** **** +6241 Healer_Still_Lesser_Vigor **** **** **** **** **** **** **** **** +6242 Healer_Protection_from_Evil **** **** **** **** **** **** **** **** +6243 Healer_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +6244 Healer_Quickened_Protection_from_Evil **** **** **** **** **** **** **** **** +6245 Healer_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +6246 Healer_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +6247 Healer_Remove_Fear **** **** **** **** **** **** **** **** +6248 Healer_Exteneded_Remove_Fear **** **** **** **** **** **** **** **** +6249 Healer_Quickened_Remove_Fear **** **** **** **** **** **** **** **** +6250 Healer_Silent_Remove_Fear **** **** **** **** **** **** **** **** +6251 Healer_Still_Remove_Fear **** **** **** **** **** **** **** **** +6252 Healer_Remove_Paralysis **** **** **** **** **** **** **** **** +6253 Healer_Quickened_Remove_Paralysis **** **** **** **** **** **** **** **** +6254 Healer_Silent_Remove_Paralysis **** **** **** **** **** **** **** **** +6255 Healer_Still_Remove_Paralysis **** **** **** **** **** **** **** **** +6256 Healer_Sanctuary **** **** **** **** **** **** **** **** +6257 Healer_Exteneded_Sanctuary **** **** **** **** **** **** **** **** +6258 Healer_Quickened_Sanctuary **** **** **** **** **** **** **** **** +6259 Healer_Silent_Sanctuary **** **** **** **** **** **** **** **** +6260 Healer_Still_Sanctuary **** **** **** **** **** **** **** **** +6261 Healer_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6262 Healer_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6263 Healer_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6264 Healer_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +6265 Healer_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +6266 Healer_Quickened_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +6267 Healer_Calm_Emotions **** **** **** **** **** **** **** **** +6268 Healer_Exteneded_Calm_Emotions **** **** **** **** **** **** **** **** +6269 Healer_Quickened_Calm_Emotions **** **** **** **** **** **** **** **** +6270 Healer_Silent_Calm_Emotions **** **** **** **** **** **** **** **** +6271 Healer_Still_Calm_Emotions **** **** **** **** **** **** **** **** +6272 Healer_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6273 Healer_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6274 Healer_Maximized_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6275 Healer_Quickened_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6276 Healer_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6277 Healer_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6278 Healer_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6279 Healer_Quickened_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6280 Healer_Silent_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6281 Healer_Still_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6282 Healer_Remove_Disease **** **** **** **** **** **** **** **** +6283 Healer_Quickened_Remove_Disease **** **** **** **** **** **** **** **** +6284 Healer_Silent_Remove_Disease **** **** **** **** **** **** **** **** +6285 Healer_Still_Remove_Disease **** **** **** **** **** **** **** **** +6286 Healer_Lesser_Restoration **** **** **** **** **** **** **** **** +6287 Healer_Quickened_Lesser_Restoration **** **** **** **** **** **** **** **** +6288 Healer_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +6289 Healer_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +6290 Healer_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6291 Healer_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6292 Healer_Quickened_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6293 Healer_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6294 Healer_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6295 Healer_Maximized_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6296 Healer_Quickened_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6297 Healer_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6298 Healer_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6299 Healer_Close_Wounds **** **** **** **** **** **** **** **** +6300 Healer_Empowered_Close_Wounds **** **** **** **** **** **** **** **** +6301 Healer_Maximized_Close_Wounds **** **** **** **** **** **** **** **** +6302 Healer_Quickened_Close_Wounds **** **** **** **** **** **** **** **** +6303 Healer_Silent_Close_Wounds **** **** **** **** **** **** **** **** +6304 Healer_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6305 Healer_Empowered_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6306 Healer_Maximized_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6307 Healer_Quickened_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6308 Healer_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6309 Healer_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6310 Healer_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +6311 Healer_Exteneded_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +6312 Healer_Quickened_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +6313 Healer_Silent_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +6314 Healer_Still_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +6315 Healer_Neutralize_Poison **** **** **** **** **** **** **** **** +6316 Healer_Quickened_Neutralize_Poison **** **** **** **** **** **** **** **** +6317 Healer_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +6318 Healer_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +6319 Healer_Remove_Curse **** **** **** **** **** **** **** **** +6320 Healer_Quickened_Remove_Curse **** **** **** **** **** **** **** **** +6321 Healer_Silent_Remove_Curse **** **** **** **** **** **** **** **** +6322 Healer_Still_Remove_Curse **** **** **** **** **** **** **** **** +6323 Healer_Restoration **** **** **** **** **** **** **** **** +6324 Healer_Quickened_Restoration **** **** **** **** **** **** **** **** +6325 Healer_Silent_Restoration **** **** **** **** **** **** **** **** +6326 Healer_Still_Restoration **** **** **** **** **** **** **** **** +6327 Healer_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6328 Healer_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6329 Healer_Quickened_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6330 Healer_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6331 Healer_Empowered_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6332 Healer_Maximized_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6333 Healer_Quickened_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6334 Healer_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6335 Healer_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6336 Healer_Vigor **** **** **** **** **** **** **** **** +6337 Healer_Exteneded_Vigor **** **** **** **** **** **** **** **** +6338 Healer_Quickened_Vigor **** **** **** **** **** **** **** **** +6339 Healer_Silent_Vigor **** **** **** **** **** **** **** **** +6340 Healer_Still_Vigor **** **** **** **** **** **** **** **** +6341 Healer_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6342 Healer_Empowered_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6343 Healer_Maximized_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6344 Healer_Quickened_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6345 Healer_Silent_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6346 Healer_Still_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6347 Healer_Death_Ward **** **** **** **** **** **** **** **** +6348 Healer_Exteneded_Death_Ward **** **** **** **** **** **** **** **** +6349 Healer_Quickened_Death_Ward **** **** **** **** **** **** **** **** +6350 Healer_Silent_Death_Ward **** **** **** **** **** **** **** **** +6351 Healer_Still_Death_Ward **** **** **** **** **** **** **** **** +6352 Healer_Freedom_of_Movement **** **** **** **** **** **** **** **** +6353 Healer_Exteneded_Freedom_of_Movement **** **** **** **** **** **** **** **** +6354 Healer_Quickened_Freedom_of_Movement **** **** **** **** **** **** **** **** +6355 Healer_Silent_Freedom_of_Movement **** **** **** **** **** **** **** **** +6356 Healer_Still_Freedom_of_Movement **** **** **** **** **** **** **** **** +6357 Healer_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6358 Healer_Empowered_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6359 Healer_Maximized_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6360 Healer_Quickened_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6361 Healer_Silent_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6362 Healer_Still_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +6363 Healer_Panacea **** **** **** **** **** **** **** **** +6364 Healer_Empowered_Panacea **** **** **** **** **** **** **** **** +6365 Healer_Maximized_Panacea **** **** **** **** **** **** **** **** +6366 Healer_Quickened_Panacea **** **** **** **** **** **** **** **** +6367 Healer_Silent_Panacea **** **** **** **** **** **** **** **** +6368 Healer_Still_Panacea **** **** **** **** **** **** **** **** +6369 Healer_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6370 Healer_Exteneded_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6371 Healer_Quickened_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6372 Healer_SUNMANTLE **** **** **** **** **** **** **** **** +6373 Healer_Exteneded_SUNMANTLE **** **** **** **** **** **** **** **** +6374 Healer_Quickened_SUNMANTLE **** **** **** **** **** **** **** **** +6375 Healer_Still_SUNMANTLE **** **** **** **** **** **** **** **** +6376 Healer_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6377 Healer_Empowered_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6378 Healer_Exteneded_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6379 Healer_Maximized_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6380 Healer_Quickened_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6381 Healer_Silent_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6382 Healer_Still_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6383 Healer_BreakEnchantment **** **** **** **** **** **** **** **** +6384 Healer_Quickened_BreakEnchantment **** **** **** **** **** **** **** **** +6385 Healer_Silent_BreakEnchantment **** **** **** **** **** **** **** **** +6386 Healer_Still_BreakEnchantment **** **** **** **** **** **** **** **** +6387 Healer_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6388 Healer_Exteneded_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6389 Healer_Quickened_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6390 Healer_Silent_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6391 Healer_Still_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +6392 Healer_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6393 Healer_Empowered_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6394 Healer_Maximized_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6395 Healer_Quickened_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6396 Healer_Silent_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6397 Healer_Still_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +6398 Healer_Raise_Dead **** **** **** **** **** **** **** **** +6399 Healer_Quickened_Raise_Dead **** **** **** **** **** **** **** **** +6400 Healer_Silent_Raise_Dead **** **** **** **** **** **** **** **** +6401 Healer_Still_Raise_Dead **** **** **** **** **** **** **** **** +6402 Healer_Revivify **** **** **** **** **** **** **** **** +6403 Healer_Quickened_Revivify **** **** **** **** **** **** **** **** +6404 Healer_Silent_Revivify **** **** **** **** **** **** **** **** +6405 Healer_Still_Revivify **** **** **** **** **** **** **** **** +6406 Healer_Stone_to_flesh **** **** **** **** **** **** **** **** +6407 Healer_Exteneded_Stone_to_flesh **** **** **** **** **** **** **** **** +6408 Healer_Quickened_Stone_to_flesh **** **** **** **** **** **** **** **** +6409 Healer_Silent_Stone_to_flesh **** **** **** **** **** **** **** **** +6410 Healer_Still_Stone_to_flesh **** **** **** **** **** **** **** **** +6411 Healer_True_Seeing **** **** **** **** **** **** **** **** +6412 Healer_Exteneded_True_Seeing **** **** **** **** **** **** **** **** +6413 Healer_Quickened_True_Seeing **** **** **** **** **** **** **** **** +6414 Healer_Silent_True_Seeing **** **** **** **** **** **** **** **** +6415 Healer_Still_True_Seeing **** **** **** **** **** **** **** **** +6416 Healer_SICKEN_EVIL **** **** **** **** **** **** **** **** +6417 Healer_Exteneded_SICKEN_EVIL **** **** **** **** **** **** **** **** +6418 Healer_Quickened_SICKEN_EVIL **** **** **** **** **** **** **** **** +6419 Healer_Silent_SICKEN_EVIL **** **** **** **** **** **** **** **** +6420 Healer_Still_SICKEN_EVIL **** **** **** **** **** **** **** **** +6421 Healer_Greater_Restoration **** **** **** **** **** **** **** **** +6422 Healer_Silent_Greater_Restoration **** **** **** **** **** **** **** **** +6423 Healer_Still_Greater_Restoration **** **** **** **** **** **** **** **** +6424 Healer_Heal **** **** **** **** **** **** **** **** +6425 Healer_Silent_Heal **** **** **** **** **** **** **** **** +6426 Healer_Still_Heal **** **** **** **** **** **** **** **** +6427 Healer_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6428 Healer_Empowered_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6429 Healer_Maximized_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6430 Healer_Silent_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6431 Healer_Still_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +6432 Healer_Regenerate **** **** **** **** **** **** **** **** +6433 Healer_Exteneded_Regenerate **** **** **** **** **** **** **** **** +6434 Healer_Silent_Regenerate **** **** **** **** **** **** **** **** +6435 Healer_Still_Regenerate **** **** **** **** **** **** **** **** +6436 Healer_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +6437 Healer_Exteneded_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +6438 Healer_Silent_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +6439 Healer_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +6440 Healer_Empowered_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +6441 Healer_Maximized_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +6442 Healer_Silent_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +6443 Healer_Still_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +6444 Healer_Vigorous_Circle **** **** **** **** **** **** **** **** +6445 Healer_Exteneded_Vigorous_Circle **** **** **** **** **** **** **** **** +6446 Healer_Silent_Vigorous_Circle **** **** **** **** **** **** **** **** +6447 Healer_Still_Vigorous_Circle **** **** **** **** **** **** **** **** +6448 Healer_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6449 Healer_Empowered_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6450 Healer_Silent_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6451 Healer_Still_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +6452 Healer_Resurrection **** **** **** **** **** **** **** **** +6453 Healer_Silent_Resurrection **** **** **** **** **** **** **** **** +6454 Healer_Still_Resurrection **** **** **** **** **** **** **** **** +6455 Healer_Repulsion **** **** **** **** **** **** **** **** +6456 Healer_Exteneded_Repulsion **** **** **** **** **** **** **** **** +6457 Healer_Silent_Repulsion **** **** **** **** **** **** **** **** +6458 Healer_Still_Repulsion **** **** **** **** **** **** **** **** +6459 Healer_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +6460 Healer_Empowered_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +6461 Healer_Exteneded_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +6462 Healer_Silent_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +6463 Healer_Still_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +6464 Healer_PHOENIX_FIRE **** **** **** **** **** **** **** **** +6465 Healer_Empowered_PHOENIX_FIRE **** **** **** **** **** **** **** **** +6466 Healer_Silent_PHOENIX_FIRE **** **** **** **** **** **** **** **** +6467 Healer_Still_PHOENIX_FIRE **** **** **** **** **** **** **** **** +6468 Healer_DiscernLocation **** **** **** **** **** **** **** **** +6469 Healer_Exteneded_DiscernLocation **** **** **** **** **** **** **** **** +6470 Healer_Silent_DiscernLocation **** **** **** **** **** **** **** **** +6471 Healer_Still_DiscernLocation **** **** **** **** **** **** **** **** +6472 Healer_Holy_Aura **** **** **** **** **** **** **** **** +6473 Healer_Exteneded_Holy_Aura **** **** **** **** **** **** **** **** +6474 Healer_Silent_Holy_Aura **** **** **** **** **** **** **** **** +6475 Healer_Still_Holy_Aura **** **** **** **** **** **** **** **** +6476 Healer_Mass_Heal **** **** **** **** **** **** **** **** +6477 Healer_Silent_Mass_Heal **** **** **** **** **** **** **** **** +6478 Healer_Still_Mass_Heal **** **** **** **** **** **** **** **** +6479 Healer_DRAGON_CLOUD **** **** **** **** **** **** **** **** +6480 Healer_Silent_DRAGON_CLOUD **** **** **** **** **** **** **** **** +6481 Healer_Still_DRAGON_CLOUD **** **** **** **** **** **** **** **** +6482 Healer_Foresight **** **** **** **** **** **** **** **** +6483 Healer_Gate **** **** **** **** **** **** **** **** +6484 Healer_True_Resurrection **** **** **** **** **** **** **** **** +6485 Healer_EXALTED_FURY **** **** **** **** **** **** **** **** +6486 CelebrantSharess_Cause_Fear **** **** **** **** **** **** **** **** +6487 CelebrantSharess_Charm_Person **** **** **** **** **** **** **** **** +6488 CelebrantSharess_Daze **** **** **** **** **** **** **** **** +6489 CelebrantSharess_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +6490 CelebrantSharess_Disguise_Self_Learn **** **** **** **** **** **** **** **** +6491 CelebrantSharess_Disguise_Self_Options **** **** **** **** **** **** **** **** +6492 CelebrantSharess_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +6493 CelebrantSharess_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +6494 CelebrantSharess_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +6495 CelebrantSharess_RAY_OF_HOPE **** **** **** **** **** **** **** **** +6496 CelebrantSharess_Read_Magic **** **** **** **** **** **** **** **** +6497 CelebrantSharess_Remove_Fear **** **** **** **** **** **** **** **** +6498 CelebrantSharess_Sleep **** **** **** **** **** **** **** **** +6499 CelebrantSharess_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6500 CelebrantSharess_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +6501 CelebrantSharess_Alter_Self_Learn **** **** **** **** **** **** **** **** +6502 CelebrantSharess_Alter_Self_Options **** **** **** **** **** **** **** **** +6503 CelebrantSharess_Alter_Self_QS1 **** **** **** **** **** **** **** **** +6504 CelebrantSharess_Alter_Self_QS2 **** **** **** **** **** **** **** **** +6505 CelebrantSharess_Alter_Self_QS3 **** **** **** **** **** **** **** **** +6506 CelebrantSharess_Calm_Emotions **** **** **** **** **** **** **** **** +6507 CelebrantSharess_Cats_Grace **** **** **** **** **** **** **** **** +6508 CelebrantSharess_Daze_Monster **** **** **** **** **** **** **** **** +6509 CelebrantSharess_Eagle_Splendor **** **** **** **** **** **** **** **** +6510 CelebrantSharess_ELATION **** **** **** **** **** **** **** **** +6511 CelebrantSharess_Enthrall **** **** **** **** **** **** **** **** +6512 CelebrantSharess_Heroism **** **** **** **** **** **** **** **** +6513 CelebrantSharess_Hold_Person **** **** **** **** **** **** **** **** +6514 CelebrantSharess_Rage **** **** **** **** **** **** **** **** +6515 CelebrantSharess_Scare **** **** **** **** **** **** **** **** +6516 CelebrantSharess_Charm_Monster **** **** **** **** **** **** **** **** +6517 CelebrantSharess_Confusion **** **** **** **** **** **** **** **** +6518 CelebrantSharess_CrushingDespair **** **** **** **** **** **** **** **** +6519 CelebrantSharess_DeepSlumber **** **** **** **** **** **** **** **** +6520 CelebrantSharess_Fear **** **** **** **** **** **** **** **** +6521 CelebrantSharess_GLIBNESS **** **** **** **** **** **** **** **** +6522 CelebrantSharess_Slow **** **** **** **** **** **** **** **** +6523 CelebrantSharess_War_Cry **** **** **** **** **** **** **** **** +6524 CelebrantSharess_BreakEnchantment **** **** **** **** **** **** **** **** +6525 CelebrantSharess_Dominate_Person **** **** **** **** **** **** **** **** +6526 CelebrantSharess_Hold_Monster **** **** **** **** **** **** **** **** +6527 CelebrantSharess_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +6528 CultistShatteredP_Endure_Elements **** **** **** **** **** **** **** **** +6529 CultistShatteredP_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +6530 CultistShatteredP_Silent_Endure_Elements **** **** **** **** **** **** **** **** +6531 CultistShatteredP_Still_Endure_Elements **** **** **** **** **** **** **** **** +6532 CultistShatteredP_Protection_from_Chaos **** **** **** **** **** **** **** **** +6533 CultistShatteredP_Exteneded_Protection_from_Chaos **** **** **** **** **** **** **** **** +6534 CultistShatteredP_Silent_Protection_from_Chaos **** **** **** **** **** **** **** **** +6535 CultistShatteredP_Still_Protection_from_Chaos **** **** **** **** **** **** **** **** +6536 CultistShatteredP_Protection_from_Evil **** **** **** **** **** **** **** **** +6537 CultistShatteredP_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +6538 CultistShatteredP_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +6539 CultistShatteredP_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +6540 CultistShatteredP_Protection_from_Good **** **** **** **** **** **** **** **** +6541 CultistShatteredP_Exteneded_Protection_from_Good **** **** **** **** **** **** **** **** +6542 CultistShatteredP_Silent_Protection_from_Good **** **** **** **** **** **** **** **** +6543 CultistShatteredP_Still_Protection_from_Good **** **** **** **** **** **** **** **** +6544 CultistShatteredP_Protection_from_Law **** **** **** **** **** **** **** **** +6545 CultistShatteredP_Exteneded_Protection_from_Law **** **** **** **** **** **** **** **** +6546 CultistShatteredP_Silent_Protection_from_Law **** **** **** **** **** **** **** **** +6547 CultistShatteredP_Still_Protection_from_Law **** **** **** **** **** **** **** **** +6548 CultistShatteredP_Shield **** **** **** **** **** **** **** **** +6549 CultistShatteredP_Exteneded_Shield **** **** **** **** **** **** **** **** +6550 CultistShatteredP_Silent_Shield **** **** **** **** **** **** **** **** +6551 CultistShatteredP_Still_Shield **** **** **** **** **** **** **** **** +6552 CultistShatteredP_Ironguts **** **** **** **** **** **** **** **** +6553 CultistShatteredP_Exteneded_Ironguts **** **** **** **** **** **** **** **** +6554 CultistShatteredP_Silent_Ironguts **** **** **** **** **** **** **** **** +6555 CultistShatteredP_Still_Ironguts **** **** **** **** **** **** **** **** +6556 CultistShatteredP_Lesser_Deflect **** **** **** **** **** **** **** **** +6557 CultistShatteredP_Exteneded_Lesser_Deflect **** **** **** **** **** **** **** **** +6558 CultistShatteredP_Silent_Lesser_Deflect **** **** **** **** **** **** **** **** +6559 CultistShatteredP_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6560 CultistShatteredP_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6561 CultistShatteredP_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6562 CultistShatteredP_Charm_Person **** **** **** **** **** **** **** **** +6563 CultistShatteredP_Exteneded_Charm_Person **** **** **** **** **** **** **** **** +6564 CultistShatteredP_Silent_Charm_Person **** **** **** **** **** **** **** **** +6565 CultistShatteredP_Still_Charm_Person **** **** **** **** **** **** **** **** +6566 CultistShatteredP_Sleep **** **** **** **** **** **** **** **** +6567 CultistShatteredP_Empowered_Sleep **** **** **** **** **** **** **** **** +6568 CultistShatteredP_Exteneded_Sleep **** **** **** **** **** **** **** **** +6569 CultistShatteredP_Silent_Sleep **** **** **** **** **** **** **** **** +6570 CultistShatteredP_Still_Sleep **** **** **** **** **** **** **** **** +6571 CultistShatteredP_Rouse **** **** **** **** **** **** **** **** +6572 CultistShatteredP_Silent_Rouse **** **** **** **** **** **** **** **** +6573 CultistShatteredP_Still_Rouse **** **** **** **** **** **** **** **** +6574 CultistShatteredP_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +6575 CultistShatteredP_Silent_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +6576 CultistShatteredP_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +6577 CultistShatteredP_Exteneded_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +6578 CultistShatteredP_Silent_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +6579 CultistShatteredP_Still_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +6580 CultistShatteredP_Lesser_Dispel **** **** **** **** **** **** **** **** +6581 CultistShatteredP_Silent_Lesser_Dispel **** **** **** **** **** **** **** **** +6582 CultistShatteredP_Still_Lesser_Dispel **** **** **** **** **** **** **** **** +6583 CultistShatteredP_Resist_Elements **** **** **** **** **** **** **** **** +6584 CultistShatteredP_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +6585 CultistShatteredP_Silent_Resist_Elements **** **** **** **** **** **** **** **** +6586 CultistShatteredP_Still_Resist_Elements **** **** **** **** **** **** **** **** +6587 CultistShatteredP_Deflect **** **** **** **** **** **** **** **** +6588 CultistShatteredP_Exteneded_Deflect **** **** **** **** **** **** **** **** +6589 CultistShatteredP_Silent_Deflect **** **** **** **** **** **** **** **** +6590 CultistShatteredP_ProtectionArrows **** **** **** **** **** **** **** **** +6591 CultistShatteredP_Exteneded_ProtectionArrows **** **** **** **** **** **** **** **** +6592 CultistShatteredP_Silent_ProtectionArrows **** **** **** **** **** **** **** **** +6593 CultistShatteredP_Still_ProtectionArrows **** **** **** **** **** **** **** **** +6594 CultistShatteredP_Dispelling_Touch **** **** **** **** **** **** **** **** +6595 CultistShatteredP_Silent_Dispelling_Touch **** **** **** **** **** **** **** **** +6596 CultistShatteredP_Still_Dispelling_Touch **** **** **** **** **** **** **** **** +6597 CultistShatteredP_UNHEAVENED **** **** **** **** **** **** **** **** +6598 CultistShatteredP_Silent_UNHEAVENED **** **** **** **** **** **** **** **** +6599 CultistShatteredP_Still_UNHEAVENED **** **** **** **** **** **** **** **** +6600 CultistShatteredP_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6601 CultistShatteredP_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6602 CultistShatteredP_ObscureObject **** **** **** **** **** **** **** **** +6603 CultistShatteredP_Exteneded_ObscureObject **** **** **** **** **** **** **** **** +6604 CultistShatteredP_Silent_ObscureObject **** **** **** **** **** **** **** **** +6605 CultistShatteredP_Still_ObscureObject **** **** **** **** **** **** **** **** +6606 CultistShatteredP_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6607 CultistShatteredP_Exteneded_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6608 CultistShatteredP_Silent_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6609 CultistShatteredP_Still_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6610 CultistShatteredP_Daze_Monster **** **** **** **** **** **** **** **** +6611 CultistShatteredP_Exteneded_Daze_Monster **** **** **** **** **** **** **** **** +6612 CultistShatteredP_Silent_Daze_Monster **** **** **** **** **** **** **** **** +6613 CultistShatteredP_Still_Daze_Monster **** **** **** **** **** **** **** **** +6614 CultistShatteredP_TouchIdiocy **** **** **** **** **** **** **** **** +6615 CultistShatteredP_Exteneded_TouchIdiocy **** **** **** **** **** **** **** **** +6616 CultistShatteredP_Silent_TouchIdiocy **** **** **** **** **** **** **** **** +6617 CultistShatteredP_Still_TouchIdiocy **** **** **** **** **** **** **** **** +6618 CultistShatteredP_MASOCHISM **** **** **** **** **** **** **** **** +6619 CultistShatteredP_Exteneded_MASOCHISM **** **** **** **** **** **** **** **** +6620 CultistShatteredP_ADDICTION **** **** **** **** **** **** **** **** +6621 CultistShatteredP_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +6622 CultistShatteredP_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +6623 CultistShatteredP_ADDICTION_VODARE **** **** **** **** **** **** **** **** +6624 CultistShatteredP_ADDICTION_AGONY **** **** **** **** **** **** **** **** +6625 CultistShatteredP_Silent_ADDICTION **** **** **** **** **** **** **** **** +6626 CultistShatteredP_Silent_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +6627 CultistShatteredP_Silent_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +6628 CultistShatteredP_Silent_ADDICTION_VODARE **** **** **** **** **** **** **** **** +6629 CultistShatteredP_Silent_ADDICTION_AGONY **** **** **** **** **** **** **** **** +6630 CultistShatteredP_Still_ADDICTION **** **** **** **** **** **** **** **** +6631 CultistShatteredP_Still_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +6632 CultistShatteredP_Still_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +6633 CultistShatteredP_Still_ADDICTION_VODARE **** **** **** **** **** **** **** **** +6634 CultistShatteredP_Still_ADDICTION_AGONY **** **** **** **** **** **** **** **** +6635 CultistShatteredP_Clarity **** **** **** **** **** **** **** **** +6636 CultistShatteredP_Dispel_Magic **** **** **** **** **** **** **** **** +6637 CultistShatteredP_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +6638 CultistShatteredP_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +6639 CultistShatteredP_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +6640 CultistShatteredP_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +6641 CultistShatteredP_Protection_from_Elements **** **** **** **** **** **** **** **** +6642 CultistShatteredP_Energy_Aegis **** **** **** **** **** **** **** **** +6643 CultistShatteredP_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +6644 CultistShatteredP_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +6645 CultistShatteredP_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +6646 CultistShatteredP_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +6647 CultistShatteredP_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +6648 CultistShatteredP_NONDETECTION **** **** **** **** **** **** **** **** +6649 CultistShatteredP_Hold_Person **** **** **** **** **** **** **** **** +6650 CultistShatteredP_Rage **** **** **** **** **** **** **** **** +6651 CultistShatteredP_DeepSlumber **** **** **** **** **** **** **** **** +6652 CultistShatteredP_EVIL_EYE **** **** **** **** **** **** **** **** +6653 CultistShatteredP_ELATION **** **** **** **** **** **** **** **** +6654 CultistShatteredP_Heroism **** **** **** **** **** **** **** **** +6655 Beguiler_Dancing_Lights **** **** **** **** **** **** **** **** +6656 Beguiler_Daze **** **** **** **** **** **** **** **** +6657 Beguiler_Read_Magic **** **** **** **** **** **** **** **** +6658 Beguiler_Charm_Person **** **** **** **** **** **** **** **** +6659 Beguiler_Color_Spray **** **** **** **** **** **** **** **** +6660 Beguiler_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +6661 Beguiler_Disguise_Self_Learn **** **** **** **** **** **** **** **** +6662 Beguiler_Disguise_Self_Options **** **** **** **** **** **** **** **** +6663 Beguiler_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +6664 Beguiler_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +6665 Beguiler_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +6666 Beguiler_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +6667 Beguiler_Expeditious_Retreat **** **** **** **** **** **** **** **** +6668 Beguiler_Mage_Armor **** **** **** **** **** **** **** **** +6669 Beguiler_Nybors_Gentle_Reminder **** **** **** **** **** **** **** **** +6670 Beguiler_Obscuring_Mist **** **** **** **** **** **** **** **** +6671 Beguiler_Rouse **** **** **** **** **** **** **** **** +6672 Beguiler_Sleep **** **** **** **** **** **** **** **** +6673 Beguiler_UndetectableAlignment **** **** **** **** **** **** **** **** +6674 Beguiler_ADDICTION **** **** **** **** **** **** **** **** +6675 Beguiler_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +6676 Beguiler_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +6677 Beguiler_ADDICTION_VODARE **** **** **** **** **** **** **** **** +6678 Beguiler_ADDICTION_AGONY **** **** **** **** **** **** **** **** +6679 Beguiler_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6680 Beguiler_Blur **** **** **** **** **** **** **** **** +6681 Beguiler_Continual_Flame **** **** **** **** **** **** **** **** +6682 Beguiler_Daze_Monster **** **** **** **** **** **** **** **** +6683 Beguiler_FogCloud **** **** **** **** **** **** **** **** +6684 Beguiler_Ghostly_Visage **** **** **** **** **** **** **** **** +6685 Beguiler_Glitterdust **** **** **** **** **** **** **** **** +6686 Beguiler_Invisibility **** **** **** **** **** **** **** **** +6687 Beguiler_Knock **** **** **** **** **** **** **** **** +6688 Beguiler_MASOCHISM **** **** **** **** **** **** **** **** +6689 Beguiler_MirrorImage **** **** **** **** **** **** **** **** +6690 Beguiler_See_Invisibility **** **** **** **** **** **** **** **** +6691 Beguiler_Shadow_Spray **** **** **** **** **** **** **** **** +6692 Beguiler_Silence **** **** **** **** **** **** **** **** +6693 Beguiler_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +6694 Beguiler_TouchIdiocy **** **** **** **** **** **** **** **** +6695 Beguiler_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +6696 Beguiler_CURSE_OF_THE_PUTRID_HUSK **** **** **** **** **** **** **** **** +6697 Beguiler_DeepSlumber **** **** **** **** **** **** **** **** +6698 Beguiler_Dispel_Magic **** **** **** **** **** **** **** **** +6699 Beguiler_Displacement **** **** **** **** **** **** **** **** +6700 Beguiler_ELATION **** **** **** **** **** **** **** **** +6701 Beguiler_EVIL_EYE **** **** **** **** **** **** **** **** +6702 Beguiler_GLIBNESS **** **** **** **** **** **** **** **** +6703 Beguiler_Halt **** **** **** **** **** **** **** **** +6704 Beguiler_Haste **** **** **** **** **** **** **** **** +6705 Beguiler_Heroism **** **** **** **** **** **** **** **** +6706 Beguiler_Hold_Person **** **** **** **** **** **** **** **** +6707 Beguiler_Invisibility_Sphere **** **** **** **** **** **** **** **** +6708 Beguiler_NONDETECTION **** **** **** **** **** **** **** **** +6709 Beguiler_REALITY_BLIND **** **** **** **** **** **** **** **** +6710 Beguiler_Slow **** **** **** **** **** **** **** **** +6711 Beguiler_Charm_Monster **** **** **** **** **** **** **** **** +6712 Beguiler_Confusion **** **** **** **** **** **** **** **** +6713 Beguiler_CrushingDespair **** **** **** **** **** **** **** **** +6714 Beguiler_Freedom_of_Movement **** **** **** **** **** **** **** **** +6715 Beguiler_Improved_Invisibility **** **** **** **** **** **** **** **** +6716 Beguiler_LocateCreature **** **** **** **** **** **** **** **** +6717 Beguiler_Phantasmal_Killer **** **** **** **** **** **** **** **** +6718 Beguiler_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +6719 Beguiler_Shadow_Conjuration **** **** **** **** **** **** **** **** +6720 Beguiler_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +6721 Beguiler_SHADOW_CON_Darkness **** **** **** **** **** **** **** **** +6722 Beguiler_SHADOW_CON_Inivsibility **** **** **** **** **** **** **** **** +6723 Beguiler_SHADOW_CON_Mage_Armor **** **** **** **** **** **** **** **** +6724 Beguiler_SHADOW_CON_Magic_Missile **** **** **** **** **** **** **** **** +6725 Beguiler_SolidFog **** **** **** **** **** **** **** **** +6726 Beguiler_BreakEnchantment **** **** **** **** **** **** **** **** +6727 Beguiler_Dominate_Person **** **** **** **** **** **** **** **** +6728 Beguiler_Feeblemind **** **** **** **** **** **** **** **** +6729 Beguiler_Greater_Shadow_Conjuration **** **** **** **** **** **** **** **** +6730 Beguiler_GR_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +6731 Beguiler_GR_SHADOW_CON_Acid_Arrow **** **** **** **** **** **** **** **** +6732 Beguiler_GR_SHADOW_CON_Ghostly_Visage **** **** **** **** **** **** **** **** +6733 Beguiler_GR_SHADOW_CON_Web **** **** **** **** **** **** **** **** +6734 Beguiler_GR_SHADOW_CON_Minor_Globe **** **** **** **** **** **** **** **** +6735 Beguiler_Hold_Monster **** **** **** **** **** **** **** **** +6736 Beguiler_Mind_Fog **** **** **** **** **** **** **** **** +6737 Beguiler_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +6738 Beguiler_Ethereal_Visage **** **** **** **** **** **** **** **** +6739 Beguiler_Greater_Dispelling **** **** **** **** **** **** **** **** +6740 Beguiler_Greater_Heroism **** **** **** **** **** **** **** **** +6741 Beguiler_Mass_Haste **** **** **** **** **** **** **** **** +6742 Beguiler_Mislead **** **** **** **** **** **** **** **** +6743 Beguiler_Repulsion **** **** **** **** **** **** **** **** +6744 Beguiler_Shades **** **** **** **** **** **** **** **** +6745 Beguiler_SHADES_Summon_Shadow **** **** **** **** **** **** **** **** +6746 Beguiler_SHADES_Cone_of_Cold **** **** **** **** **** **** **** **** +6747 Beguiler_SHADES_Fireball **** **** **** **** **** **** **** **** +6748 Beguiler_SHADES_Stoneskin **** **** **** **** **** **** **** **** +6749 Beguiler_SHADES_Wall_of_Fire **** **** **** **** **** **** **** **** +6750 Beguiler_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +6751 Beguiler_True_Seeing **** **** **** **** **** **** **** **** +6752 Beguiler_Etherealness **** **** **** **** **** **** **** **** +6753 Beguiler_Insanity **** **** **** **** **** **** **** **** +6754 Beguiler_Mass_Hold_Person **** **** **** **** **** **** **** **** +6755 Beguiler_Nybors_Stern_Reproof **** **** **** **** **** **** **** **** +6756 Beguiler_Power_Word_Blind **** **** **** **** **** **** **** **** +6757 Beguiler_Protection_from_Spells **** **** **** **** **** **** **** **** +6758 Beguiler_Shadow_Shield **** **** **** **** **** **** **** **** +6759 Beguiler_Spell_Turning **** **** **** **** **** **** **** **** +6760 Beguiler_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +6761 Beguiler_DiscernLocation **** **** **** **** **** **** **** **** +6762 Beguiler_Mass_Blindness_and_Deafness **** **** **** **** **** **** **** **** +6763 Beguiler_Mass_Charm **** **** **** **** **** **** **** **** +6764 Beguiler_Mind_Blank **** **** **** **** **** **** **** **** +6765 Beguiler_Power_Word_Stun **** **** **** **** **** **** **** **** +6766 Beguiler_ScintillatingPattern **** **** **** **** **** **** **** **** +6767 Beguiler_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +6768 Beguiler_Dominate_Monster **** **** **** **** **** **** **** **** +6769 Beguiler_Foresight **** **** **** **** **** **** **** **** +6770 Beguiler_Mass_Hold_Monster **** **** **** **** **** **** **** **** +6771 Beguiler_Power_Word_Kill **** **** **** **** **** **** **** **** +6772 Beguiler_Time_Stop **** **** **** **** **** **** **** **** +6773 Beguiler_Weird **** **** **** **** **** **** **** **** +6774 KnightOfTheChalic_Bless_Water **** **** **** **** **** **** **** **** +6775 KnightOfTheChalic_Silent_Bless_Water **** **** **** **** **** **** **** **** +6776 KnightOfTheChalic_Still_Bless_Water **** **** **** **** **** **** **** **** +6777 KnightOfTheChalic_Bless_Weapon **** **** **** **** **** **** **** **** +6778 KnightOfTheChalic_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +6779 KnightOfTheChalic_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +6780 KnightOfTheChalic_Still_Bless_Weapon **** **** **** **** **** **** **** **** +6781 KnightOfTheChalic_Divine_Favor **** **** **** **** **** **** **** **** +6782 KnightOfTheChalic_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +6783 KnightOfTheChalic_Silent_Divine_Favor **** **** **** **** **** **** **** **** +6784 KnightOfTheChalic_Still_Divine_Favor **** **** **** **** **** **** **** **** +6785 KnightOfTheChalic_Detect_Chaos **** **** **** **** **** **** **** **** +6786 KnightOfTheChalic_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +6787 KnightOfTheChalic_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +6788 KnightOfTheChalic_Still_Detect_Chaos **** **** **** **** **** **** **** **** +6789 KnightOfTheChalic_Detect_Evil **** **** **** **** **** **** **** **** +6790 KnightOfTheChalic_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +6791 KnightOfTheChalic_Silent_Detect_Evil **** **** **** **** **** **** **** **** +6792 KnightOfTheChalic_Still_Detect_Evil **** **** **** **** **** **** **** **** +6793 KnightOfTheChalic_Doom **** **** **** **** **** **** **** **** +6794 KnightOfTheChalic_Exteneded_Doom **** **** **** **** **** **** **** **** +6795 KnightOfTheChalic_Silent_Doom **** **** **** **** **** **** **** **** +6796 KnightOfTheChalic_Still_Doom **** **** **** **** **** **** **** **** +6797 KnightOfTheChalic_Endure_Elements **** **** **** **** **** **** **** **** +6798 KnightOfTheChalic_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +6799 KnightOfTheChalic_Silent_Endure_Elements **** **** **** **** **** **** **** **** +6800 KnightOfTheChalic_Still_Endure_Elements **** **** **** **** **** **** **** **** +6801 KnightOfTheChalic_Magic_Weapon **** **** **** **** **** **** **** **** +6802 KnightOfTheChalic_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +6803 KnightOfTheChalic_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +6804 KnightOfTheChalic_Still_Magic_Weapon **** **** **** **** **** **** **** **** +6805 KnightOfTheChalic_Protection_from_Evil **** **** **** **** **** **** **** **** +6806 KnightOfTheChalic_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +6807 KnightOfTheChalic_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +6808 KnightOfTheChalic_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +6809 KnightOfTheChalic_Remove_Fear **** **** **** **** **** **** **** **** +6810 KnightOfTheChalic_Exteneded_Remove_Fear **** **** **** **** **** **** **** **** +6811 KnightOfTheChalic_Silent_Remove_Fear **** **** **** **** **** **** **** **** +6812 KnightOfTheChalic_Still_Remove_Fear **** **** **** **** **** **** **** **** +6813 KnightOfTheChalic_Summon_Creature_I **** **** **** **** **** **** **** **** +6814 KnightOfTheChalic_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +6815 KnightOfTheChalic_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +6816 KnightOfTheChalic_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +6817 KnightOfTheChalic_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +6818 KnightOfTheChalic_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +6819 KnightOfTheChalic_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6820 KnightOfTheChalic_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6821 KnightOfTheChalic_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6822 KnightOfTheChalic_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6823 KnightOfTheChalic_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6824 KnightOfTheChalic_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6825 KnightOfTheChalic_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6826 KnightOfTheChalic_Aid **** **** **** **** **** **** **** **** +6827 KnightOfTheChalic_Empowered_Aid **** **** **** **** **** **** **** **** +6828 KnightOfTheChalic_Exteneded_Aid **** **** **** **** **** **** **** **** +6829 KnightOfTheChalic_Silent_Aid **** **** **** **** **** **** **** **** +6830 KnightOfTheChalic_Still_Aid **** **** **** **** **** **** **** **** +6831 KnightOfTheChalic_Bulls_Strength **** **** **** **** **** **** **** **** +6832 KnightOfTheChalic_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +6833 KnightOfTheChalic_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +6834 KnightOfTheChalic_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +6835 KnightOfTheChalic_Still_Bulls_Strength **** **** **** **** **** **** **** **** +6836 KnightOfTheChalic_Consecrated_Aura **** **** **** **** **** **** **** **** +6837 KnightOfTheChalic_Exteneded_Consecrated_Aura **** **** **** **** **** **** **** **** +6838 KnightOfTheChalic_Silent_Consecrated_Aura **** **** **** **** **** **** **** **** +6839 KnightOfTheChalic_Still_Consecrated_Aura **** **** **** **** **** **** **** **** +6840 KnightOfTheChalic_Endurance **** **** **** **** **** **** **** **** +6841 KnightOfTheChalic_Empowered_Endurance **** **** **** **** **** **** **** **** +6842 KnightOfTheChalic_Exteneded_Endurance **** **** **** **** **** **** **** **** +6843 KnightOfTheChalic_Silent_Endurance **** **** **** **** **** **** **** **** +6844 KnightOfTheChalic_Still_Endurance **** **** **** **** **** **** **** **** +6845 KnightOfTheChalic_Resist_Elements **** **** **** **** **** **** **** **** +6846 KnightOfTheChalic_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +6847 KnightOfTheChalic_Silent_Resist_Elements **** **** **** **** **** **** **** **** +6848 KnightOfTheChalic_Still_Resist_Elements **** **** **** **** **** **** **** **** +6849 KnightOfTheChalic_Sound_Burst **** **** **** **** **** **** **** **** +6850 KnightOfTheChalic_Silent_Sound_Burst **** **** **** **** **** **** **** **** +6851 KnightOfTheChalic_Still_Sound_Burst **** **** **** **** **** **** **** **** +6852 KnightOfTheChalic_Summon_Creature_II **** **** **** **** **** **** **** **** +6853 KnightOfTheChalic_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +6854 KnightOfTheChalic_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +6855 KnightOfTheChalic_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +6856 KnightOfTheChalic_UndetectableAlignment **** **** **** **** **** **** **** **** +6857 KnightOfTheChalic_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +6858 KnightOfTheChalic_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +6859 KnightOfTheChalic_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +6860 KnightOfTheChalic_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6861 KnightOfTheChalic_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6862 KnightOfTheChalic_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6863 KnightOfTheChalic_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6864 KnightOfTheChalic_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6865 KnightOfTheChalic_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6866 KnightOfTheChalic_Dispel_Magic **** **** **** **** **** **** **** **** +6867 KnightOfTheChalic_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +6868 KnightOfTheChalic_Still_Dispel_Magic **** **** **** **** **** **** **** **** +6869 KnightOfTheChalic_Summon_Creature_III **** **** **** **** **** **** **** **** +6870 KnightOfTheChalic_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +6871 KnightOfTheChalic_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +6872 KnightOfTheChalic_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +6873 KnightOfTheChalic_Invisibility_Purge **** **** **** **** **** **** **** **** +6874 KnightOfTheChalic_Exteneded_Invisibility_Purge **** **** **** **** **** **** **** **** +6875 KnightOfTheChalic_Silent_Invisibility_Purge **** **** **** **** **** **** **** **** +6876 KnightOfTheChalic_Still_Invisibility_Purge **** **** **** **** **** **** **** **** +6877 KnightOfTheChalic_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +6878 KnightOfTheChalic_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +6879 KnightOfTheChalic_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +6880 KnightOfTheChalic_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +6881 KnightOfTheChalic_Magic_Vestment **** **** **** **** **** **** **** **** +6882 KnightOfTheChalic_Exteneded_Magic_Vestment **** **** **** **** **** **** **** **** +6883 KnightOfTheChalic_Silent_Magic_Vestment **** **** **** **** **** **** **** **** +6884 KnightOfTheChalic_Still_Magic_Vestment **** **** **** **** **** **** **** **** +6885 KnightOfTheChalic_Prayer **** **** **** **** **** **** **** **** +6886 KnightOfTheChalic_Exteneded_Prayer **** **** **** **** **** **** **** **** +6887 KnightOfTheChalic_Silent_Prayer **** **** **** **** **** **** **** **** +6888 KnightOfTheChalic_Still_Prayer **** **** **** **** **** **** **** **** +6889 KnightOfTheChalic_Protection_from_Elements **** **** **** **** **** **** **** **** +6890 KnightOfTheChalic_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +6891 KnightOfTheChalic_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +6892 KnightOfTheChalic_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +6893 KnightOfTheChalic_Searing_Light **** **** **** **** **** **** **** **** +6894 KnightOfTheChalic_Silent_Searing_Light **** **** **** **** **** **** **** **** +6895 KnightOfTheChalic_Still_Searing_Light **** **** **** **** **** **** **** **** +6896 KnightOfTheChalic_Shout **** **** **** **** **** **** **** **** +6897 KnightOfTheChalic_Silent_Shout **** **** **** **** **** **** **** **** +6898 KnightOfTheChalic_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6899 KnightOfTheChalic_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6900 KnightOfTheChalic_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6901 KnightOfTheChalic_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6902 KnightOfTheChalic_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6903 KnightOfTheChalic_Dimensional_Anchor **** **** **** **** **** **** **** **** +6904 KnightOfTheChalic_Dismissal **** **** **** **** **** **** **** **** +6905 KnightOfTheChalic_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +6906 KnightOfTheChalic_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +6907 KnightOfTheChalic_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +6908 KnightOfTheChalic_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6909 KnightOfTheChalic_SUNMANTLE **** **** **** **** **** **** **** **** +6910 KnightOfTheChalic_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6911 Vigilant_Blur **** **** **** **** **** **** **** **** +6912 Vigilant_Exteneded_Blur **** **** **** **** **** **** **** **** +6913 Vigilant_Silent_Blur **** **** **** **** **** **** **** **** +6914 Vigilant_Expeditious_Retreat **** **** **** **** **** **** **** **** +6915 Vigilant_Exteneded_Expeditious_Retreat **** **** **** **** **** **** **** **** +6916 Vigilant_Silent_Expeditious_Retreat **** **** **** **** **** **** **** **** +6917 Vigilant_Still_Expeditious_Retreat **** **** **** **** **** **** **** **** +6918 Vigilant_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6919 Vigilant_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6920 Vigilant_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6921 Vigilant_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +6922 Vigilant_Resist_Elements **** **** **** **** **** **** **** **** +6923 Vigilant_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +6924 Vigilant_Silent_Resist_Elements **** **** **** **** **** **** **** **** +6925 Vigilant_Still_Resist_Elements **** **** **** **** **** **** **** **** +6926 Vigilant_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6927 Vigilant_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6928 Vigilant_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +6929 Vigilant_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6930 Vigilant_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6931 Vigilant_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6932 Vigilant_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +6933 Vigilant_Detect_Chaos **** **** **** **** **** **** **** **** +6934 Vigilant_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +6935 Vigilant_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +6936 Vigilant_Still_Detect_Chaos **** **** **** **** **** **** **** **** +6937 Vigilant_Detect_Evil **** **** **** **** **** **** **** **** +6938 Vigilant_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +6939 Vigilant_Silent_Detect_Evil **** **** **** **** **** **** **** **** +6940 Vigilant_Still_Detect_Evil **** **** **** **** **** **** **** **** +6941 Vigilant_Detect_Good **** **** **** **** **** **** **** **** +6942 Vigilant_Exteneded_Detect_Good **** **** **** **** **** **** **** **** +6943 Vigilant_Silent_Detect_Good **** **** **** **** **** **** **** **** +6944 Vigilant_Still_Detect_Good **** **** **** **** **** **** **** **** +6945 Vigilant_Detect_Law **** **** **** **** **** **** **** **** +6946 Vigilant_Exteneded_Detect_Law **** **** **** **** **** **** **** **** +6947 Vigilant_Silent_Detect_Law **** **** **** **** **** **** **** **** +6948 Vigilant_Still_Detect_Law **** **** **** **** **** **** **** **** +6949 Vigilant_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6950 Vigilant_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6951 Vigilant_Protection_from_Elements **** **** **** **** **** **** **** **** +6952 Vigilant_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +6953 Vigilant_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +6954 Vigilant_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +6955 Vigilant_Snare **** **** **** **** **** **** **** **** +6956 Vigilant_Silent_Snare **** **** **** **** **** **** **** **** +6957 Vigilant_Still_Snare **** **** **** **** **** **** **** **** +6958 Vigilant_Silence **** **** **** **** **** **** **** **** +6959 Vigilant_Exteneded_Silence **** **** **** **** **** **** **** **** +6960 Vigilant_Silent_Silence **** **** **** **** **** **** **** **** +6961 Vigilant_Still_Silence **** **** **** **** **** **** **** **** +6962 Vigilant_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6963 Vigilant_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +6964 Vigilant_Endurance **** **** **** **** **** **** **** **** +6965 Vigilant_Exteneded_Endurance **** **** **** **** **** **** **** **** +6966 Vigilant_Silent_Endurance **** **** **** **** **** **** **** **** +6967 Vigilant_Still_Endurance **** **** **** **** **** **** **** **** +6968 Vigilant_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6969 Vigilant_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6970 Vigilant_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +6971 Vigilant_Neutralize_Poison **** **** **** **** **** **** **** **** +6972 Vigilant_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +6973 Vigilant_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +6974 Vigilant_Remove_Disease **** **** **** **** **** **** **** **** +6975 Vigilant_Silent_Remove_Disease **** **** **** **** **** **** **** **** +6976 Vigilant_Still_Remove_Disease **** **** **** **** **** **** **** **** +6977 Vigilant_Spike_Growth **** **** **** **** **** **** **** **** +6978 Vigilant_Exteneded_Spike_Growth **** **** **** **** **** **** **** **** +6979 Vigilant_Silent_Spike_Growth **** **** **** **** **** **** **** **** +6980 Vigilant_Still_Spike_Growth **** **** **** **** **** **** **** **** +6981 Vigilant_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +6982 Vigilant_Freedom_of_Movement **** **** **** **** **** **** **** **** +6983 Vigilant_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +6984 Vigilant_RepelVermin **** **** **** **** **** **** **** **** +6985 Vigilant_SUNMANTLE **** **** **** **** **** **** **** **** +6986 Vassal_Shield_of_Faith **** **** **** **** **** **** **** **** +6987 Vassal_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +6988 Vassal_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +6989 Vassal_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +6990 Vassal_Protection_from_Evil **** **** **** **** **** **** **** **** +6991 Vassal_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +6992 Vassal_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +6993 Vassal_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +6994 Vassal_Endure_Elements **** **** **** **** **** **** **** **** +6995 Vassal_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +6996 Vassal_Silent_Endure_Elements **** **** **** **** **** **** **** **** +6997 Vassal_Still_Endure_Elements **** **** **** **** **** **** **** **** +6998 Vassal_Divine_Favor **** **** **** **** **** **** **** **** +6999 Vassal_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +7000 Vassal_Silent_Divine_Favor **** **** **** **** **** **** **** **** +7001 Vassal_Still_Divine_Favor **** **** **** **** **** **** **** **** +7002 Vassal_Bless_Weapon **** **** **** **** **** **** **** **** +7003 Vassal_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +7004 Vassal_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +7005 Vassal_Still_Bless_Weapon **** **** **** **** **** **** **** **** +7006 Vassal_Bless **** **** **** **** **** **** **** **** +7007 Vassal_Exteneded_Bless **** **** **** **** **** **** **** **** +7008 Vassal_Silent_Bless **** **** **** **** **** **** **** **** +7009 Vassal_Still_Bless **** **** **** **** **** **** **** **** +7010 Vassal_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7011 Vassal_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7012 Vassal_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7013 Vassal_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7014 Vassal_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7015 Vassal_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7016 Vassal_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7017 Vassal_Protection_from_Elements **** **** **** **** **** **** **** **** +7018 Vassal_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +7019 Vassal_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +7020 Vassal_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +7021 Vassal_Bulls_Strength **** **** **** **** **** **** **** **** +7022 Vassal_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +7023 Vassal_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +7024 Vassal_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +7025 Vassal_Still_Bulls_Strength **** **** **** **** **** **** **** **** +7026 Vassal_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +7027 Vassal_Alter_Self_Learn **** **** **** **** **** **** **** **** +7028 Vassal_Alter_Self_Options **** **** **** **** **** **** **** **** +7029 Vassal_Alter_Self_QS1 **** **** **** **** **** **** **** **** +7030 Vassal_Alter_Self_QS2 **** **** **** **** **** **** **** **** +7031 Vassal_Alter_Self_QS3 **** **** **** **** **** **** **** **** +7032 Vassal_Exteneded_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +7033 Vassal_Exteneded_Alter_Self_Learn **** **** **** **** **** **** **** **** +7034 Vassal_Exteneded_Alter_Self_Options **** **** **** **** **** **** **** **** +7035 Vassal_Exteneded_Alter_Self_QS1 **** **** **** **** **** **** **** **** +7036 Vassal_Exteneded_Alter_Self_QS2 **** **** **** **** **** **** **** **** +7037 Vassal_Exteneded_Alter_Self_QS3 **** **** **** **** **** **** **** **** +7038 Vassal_Silent_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +7039 Vassal_Silent_Alter_Self_Learn **** **** **** **** **** **** **** **** +7040 Vassal_Silent_Alter_Self_Options **** **** **** **** **** **** **** **** +7041 Vassal_Silent_Alter_Self_QS1 **** **** **** **** **** **** **** **** +7042 Vassal_Silent_Alter_Self_QS2 **** **** **** **** **** **** **** **** +7043 Vassal_Silent_Alter_Self_QS3 **** **** **** **** **** **** **** **** +7044 Vassal_Still_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +7045 Vassal_Still_Alter_Self_Learn **** **** **** **** **** **** **** **** +7046 Vassal_Still_Alter_Self_Options **** **** **** **** **** **** **** **** +7047 Vassal_Still_Alter_Self_QS1 **** **** **** **** **** **** **** **** +7048 Vassal_Still_Alter_Self_QS2 **** **** **** **** **** **** **** **** +7049 Vassal_Still_Alter_Self_QS3 **** **** **** **** **** **** **** **** +7050 Vassal_Endurance **** **** **** **** **** **** **** **** +7051 Vassal_Empowered_Endurance **** **** **** **** **** **** **** **** +7052 Vassal_Exteneded_Endurance **** **** **** **** **** **** **** **** +7053 Vassal_Silent_Endurance **** **** **** **** **** **** **** **** +7054 Vassal_Still_Endurance **** **** **** **** **** **** **** **** +7055 Vassal_ShieldOther **** **** **** **** **** **** **** **** +7056 Vassal_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +7057 Vassal_Silent_ShieldOther **** **** **** **** **** **** **** **** +7058 Vassal_Still_ShieldOther **** **** **** **** **** **** **** **** +7059 Vassal_UndetectableAlignment **** **** **** **** **** **** **** **** +7060 Vassal_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +7061 Vassal_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +7062 Vassal_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +7063 Vassal_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7064 Vassal_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7065 Vassal_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7066 Vassal_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7067 Vassal_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7068 Vassal_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7069 Vassal_Searing_Light **** **** **** **** **** **** **** **** +7070 Vassal_Silent_Searing_Light **** **** **** **** **** **** **** **** +7071 Vassal_Still_Searing_Light **** **** **** **** **** **** **** **** +7072 Vassal_Resist_Elements **** **** **** **** **** **** **** **** +7073 Vassal_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +7074 Vassal_Silent_Resist_Elements **** **** **** **** **** **** **** **** +7075 Vassal_Still_Resist_Elements **** **** **** **** **** **** **** **** +7076 Vassal_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7077 Vassal_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7078 Vassal_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7079 Vassal_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7080 Vassal_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +7081 Vassal_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +7082 Vassal_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7083 Vassal_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7084 Vassal_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7085 Vassal_Holy_Sword **** **** **** **** **** **** **** **** +7086 Vassal_Divine_Power **** **** **** **** **** **** **** **** +7087 Vassal_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +7088 Vassal_SUNMANTLE **** **** **** **** **** **** **** **** +7089 Vassal_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7090 SublimeChord_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +7091 SublimeChord_Acid_Orb **** **** **** **** **** **** **** **** +7092 SublimeChord_ArcaneEye **** **** **** **** **** **** **** **** +7093 SublimeChord_Bestow_Curse **** **** **** **** **** **** **** **** +7094 SublimeChord_Blast_of_Flame **** **** **** **** **** **** **** **** +7095 SublimeChord_BreakEnchantment **** **** **** **** **** **** **** **** +7096 SublimeChord_Channeled_Pyroburst **** **** **** **** **** **** **** **** +7097 SublimeChord_Channeled_Pyroburst_Swift **** **** **** **** **** **** **** **** +7098 SublimeChord_Channeled_Pyroburst_Standard **** **** **** **** **** **** **** **** +7099 SublimeChord_Channeled_Pyroburst_Full **** **** **** **** **** **** **** **** +7100 SublimeChord_Channeled_Pyroburst_Two **** **** **** **** **** **** **** **** +7101 SublimeChord_Charm_Monster **** **** **** **** **** **** **** **** +7102 SublimeChord_Cold_Orb **** **** **** **** **** **** **** **** +7103 SublimeChord_Confusion **** **** **** **** **** **** **** **** +7104 SublimeChord_Contagion **** **** **** **** **** **** **** **** +7105 SublimeChord_CrushingDespair **** **** **** **** **** **** **** **** +7106 SublimeChord_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +7107 SublimeChord_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +7108 SublimeChord_DANCING_WEB **** **** **** **** **** **** **** **** +7109 SublimeChord_DetectScrying **** **** **** **** **** **** **** **** +7110 SublimeChord_Dimensional_Anchor **** **** **** **** **** **** **** **** +7111 SublimeChord_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +7112 SublimeChord_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +7113 SublimeChord_DimensionDoor_Party **** **** **** **** **** **** **** **** +7114 SublimeChord_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +7115 SublimeChord_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +7116 SublimeChord_Dismissal **** **** **** **** **** **** **** **** +7117 SublimeChord_Dominate_Person **** **** **** **** **** **** **** **** +7118 SublimeChord_Doom_Scarabs **** **** **** **** **** **** **** **** +7119 SublimeChord_Electric_Orb **** **** **** **** **** **** **** **** +7120 SublimeChord_Elemental_Shield **** **** **** **** **** **** **** **** +7121 SublimeChord_Enervation **** **** **** **** **** **** **** **** +7122 SublimeChord_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +7123 SublimeChord_Fear **** **** **** **** **** **** **** **** +7124 SublimeChord_Fire_Orb **** **** **** **** **** **** **** **** +7125 SublimeChord_FireTrap **** **** **** **** **** **** **** **** +7126 SublimeChord_Greater_Resistance **** **** **** **** **** **** **** **** +7127 SublimeChord_GRIM_REVENGE **** **** **** **** **** **** **** **** +7128 SublimeChord_Hold_Monster **** **** **** **** **** **** **** **** +7129 SublimeChord_Ilyykurs_Mantle **** **** **** **** **** **** **** **** +7130 SublimeChord_Improved_Invisibility **** **** **** **** **** **** **** **** +7131 SublimeChord_Isaacs_Lesser_Missile_Storm **** **** **** **** **** **** **** **** +7132 SublimeChord_Legend_Lore **** **** **** **** **** **** **** **** +7133 SublimeChord_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +7134 SublimeChord_LIQUID_PAIN **** **** **** **** **** **** **** **** +7135 SublimeChord_LocateCreature **** **** **** **** **** **** **** **** +7136 SublimeChord_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +7137 SublimeChord_MASS_ENLARGE_PERSON **** **** **** **** **** **** **** **** +7138 SublimeChord_MASS_REDUCE_PERSON **** **** **** **** **** **** **** **** +7139 SublimeChord_Mass_Ultravision **** **** **** **** **** **** **** **** +7140 SublimeChord_Minor_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +7141 SublimeChord_Necrotic_Domination **** **** **** **** **** **** **** **** +7142 SublimeChord_Neutralize_Poison **** **** **** **** **** **** **** **** +7143 SublimeChord_OrbOfForce **** **** **** **** **** **** **** **** +7144 SublimeChord_Otilukes_Resilient_Sphere **** **** **** **** **** **** **** **** +7145 SublimeChord_Phantasmal_Killer **** **** **** **** **** **** **** **** +7146 SublimeChord_PnP_FireShield **** **** **** **** **** **** **** **** +7147 SublimeChord_PnP_FireShieldRed **** **** **** **** **** **** **** **** +7148 SublimeChord_PnPFireShieldBlue **** **** **** **** **** **** **** **** +7149 SublimeChord_Polymorph_Self **** **** **** **** **** **** **** **** +7150 SublimeChord_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +7151 SublimeChord_Polymorph_TROLL **** **** **** **** **** **** **** **** +7152 SublimeChord_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +7153 SublimeChord_Polymorph_PIXIE **** **** **** **** **** **** **** **** +7154 SublimeChord_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +7155 SublimeChord_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +7156 SublimeChord_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7157 SublimeChord_Remove_Curse **** **** **** **** **** **** **** **** +7158 SublimeChord_RepelVermin **** **** **** **** **** **** **** **** +7159 SublimeChord_Scrying **** **** **** **** **** **** **** **** +7160 SublimeChord_SerpentArrows **** **** **** **** **** **** **** **** +7161 SublimeChord_Shadow_Conjuration **** **** **** **** **** **** **** **** +7162 SublimeChord_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +7163 SublimeChord_SHADOW_CON_Darkness **** **** **** **** **** **** **** **** +7164 SublimeChord_SHADOW_CON_Inivsibility **** **** **** **** **** **** **** **** +7165 SublimeChord_SHADOW_CON_Mage_Armor **** **** **** **** **** **** **** **** +7166 SublimeChord_SHADOW_CON_Magic_Missile **** **** **** **** **** **** **** **** +7167 SublimeChord_Shout **** **** **** **** **** **** **** **** +7168 SublimeChord_Sinsaburs_Baleful_Bolt **** **** **** **** **** **** **** **** +7169 SublimeChord_Slashing_Dispel **** **** **** **** **** **** **** **** +7170 SublimeChord_SolidFog **** **** **** **** **** **** **** **** +7171 SublimeChord_Sonic_Orb **** **** **** **** **** **** **** **** +7172 SublimeChord_Stoneskin **** **** **** **** **** **** **** **** +7173 SublimeChord_Summon_Creature_IV **** **** **** **** **** **** **** **** +7174 SublimeChord_SummonUndeadIV **** **** **** **** **** **** **** **** +7175 SublimeChord_Viscid_Glob **** **** **** **** **** **** **** **** +7176 SublimeChord_Wall_of_Fire **** **** **** **** **** **** **** **** +7177 SublimeChord_War_Cry **** **** **** **** **** **** **** **** +7178 SublimeChord_WRACK **** **** **** **** **** **** **** **** +7179 SublimeChord_Animate_Dead **** **** **** **** **** **** **** **** +7180 SublimeChord_BalefulPolymorph **** **** **** **** **** **** **** **** +7181 SublimeChord_Ball_Lightning **** **** **** **** **** **** **** **** +7182 SublimeChord_Beltyns_Burning_Blood **** **** **** **** **** **** **** **** +7183 SublimeChord_Bigbys_Interposing_Hand **** **** **** **** **** **** **** **** +7184 SublimeChord_CALL_DRETCH_HORDE **** **** **** **** **** **** **** **** +7185 SublimeChord_CALL_LEMURE_HORDE **** **** **** **** **** **** **** **** +7186 SublimeChord_Cloudkill **** **** **** **** **** **** **** **** +7187 SublimeChord_Cone_of_Cold **** **** **** **** **** **** **** **** +7188 SublimeChord_DraconicMight **** **** **** **** **** **** **** **** +7189 SublimeChord_Ethereal_Visage **** **** **** **** **** **** **** **** +7190 SublimeChord_Feeblemind **** **** **** **** **** **** **** **** +7191 SublimeChord_Firebrand **** **** **** **** **** **** **** **** +7192 SublimeChord_Greater_Dispelling **** **** **** **** **** **** **** **** +7193 SublimeChord_Greater_Fireburst **** **** **** **** **** **** **** **** +7194 SublimeChord_Greater_Heroism **** **** **** **** **** **** **** **** +7195 SublimeChord_Greater_Shadow_Conjuration **** **** **** **** **** **** **** **** +7196 SublimeChord_GR_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +7197 SublimeChord_GR_SHADOW_CON_Acid_Arrow **** **** **** **** **** **** **** **** +7198 SublimeChord_GR_SHADOW_CON_Ghostly_Visage **** **** **** **** **** **** **** **** +7199 SublimeChord_GR_SHADOW_CON_Web **** **** **** **** **** **** **** **** +7200 SublimeChord_GR_SHADOW_CON_Minor_Globe **** **** **** **** **** **** **** **** +7201 SublimeChord_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +7202 SublimeChord_Healing_Circle **** **** **** **** **** **** **** **** +7203 SublimeChord_Lesser_Mind_Blank **** **** **** **** **** **** **** **** +7204 SublimeChord_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +7205 SublimeChord_Lesser_Spell_Mantle **** **** **** **** **** **** **** **** +7206 SublimeChord_Magic_Missile **** **** **** **** **** **** **** **** +7207 SublimeChord_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7208 SublimeChord_MassFireShield **** **** **** **** **** **** **** **** +7209 SublimeChord_MassFireShieldRed **** **** **** **** **** **** **** **** +7210 SublimeChord_MassFireShieldBlue **** **** **** **** **** **** **** **** +7211 SublimeChord_Mestils_Acid_Sheath **** **** **** **** **** **** **** **** +7212 SublimeChord_Mind_Fog **** **** **** **** **** **** **** **** +7213 SublimeChord_Mislead **** **** **** **** **** **** **** **** +7214 SublimeChord_MORALITY_UNDONE **** **** **** **** **** **** **** **** +7215 SublimeChord_Necrotic_Burst **** **** **** **** **** **** **** **** +7216 SublimeChord_Nights_Caress **** **** **** **** **** **** **** **** +7217 SublimeChord_PrismaticRay **** **** **** **** **** **** **** **** +7218 SublimeChord_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +7219 SublimeChord_SongOfDiscord **** **** **** **** **** **** **** **** +7220 SublimeChord_Sonic_Shield **** **** **** **** **** **** **** **** +7221 SublimeChord_STOP_HEART **** **** **** **** **** **** **** **** +7222 SublimeChord_Summon_Creature_V **** **** **** **** **** **** **** **** +7223 SublimeChord_SummonUndeadV **** **** **** **** **** **** **** **** +7224 SublimeChord_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +7225 SublimeChord_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +7226 SublimeChord_Teleport_RadialMaster **** **** **** **** **** **** **** **** +7227 SublimeChord_Teleport_SelfOnly **** **** **** **** **** **** **** **** +7228 SublimeChord_Teleport_Party **** **** **** **** **** **** **** **** +7229 SublimeChord_WavesofFatigue **** **** **** **** **** **** **** **** +7230 SublimeChord_Acid_Fog **** **** **** **** **** **** **** **** +7231 SublimeChord_Acid_Storm **** **** **** **** **** **** **** **** +7232 SublimeChord_Animate_Object **** **** **** **** **** **** **** **** +7233 SublimeChord_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +7234 SublimeChord_Bigbys_Forceful_Hand **** **** **** **** **** **** **** **** +7235 SublimeChord_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +7236 SublimeChord_Chain_Lightning **** **** **** **** **** **** **** **** +7237 SublimeChord_Circle_of_Death **** **** **** **** **** **** **** **** +7238 SublimeChord_Dirge **** **** **** **** **** **** **** **** +7239 SublimeChord_Disintegrate **** **** **** **** **** **** **** **** +7240 SublimeChord_ECTOPLASMIC_ENCHANCEMENT **** **** **** **** **** **** **** **** +7241 SublimeChord_Energy_Buffer **** **** **** **** **** **** **** **** +7242 SublimeChord_ExtractWaterElemental **** **** **** **** **** **** **** **** +7243 SublimeChord_Eyebite **** **** **** **** **** **** **** **** +7244 SublimeChord_Flesh_to_stone **** **** **** **** **** **** **** **** +7245 SublimeChord_Ghoul_Gauntlet **** **** **** **** **** **** **** **** +7246 SublimeChord_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +7247 SublimeChord_Greater_Shout **** **** **** **** **** **** **** **** +7248 SublimeChord_Greater_Spell_Breach **** **** **** **** **** **** **** **** +7249 SublimeChord_Greater_Stoneskin **** **** **** **** **** **** **** **** +7250 SublimeChord_GreaterScrying **** **** **** **** **** **** **** **** +7251 SublimeChord_Ice_Storm **** **** **** **** **** **** **** **** +7252 SublimeChord_Isaacs_Greater_Missile_Storm **** **** **** **** **** **** **** **** +7253 SublimeChord_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +7254 SublimeChord_Mass_Cats_Grace **** **** **** **** **** **** **** **** +7255 SublimeChord_Mass_Contagion **** **** **** **** **** **** **** **** +7256 SublimeChord_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7257 SublimeChord_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +7258 SublimeChord_Mass_Endurance **** **** **** **** **** **** **** **** +7259 SublimeChord_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +7260 SublimeChord_Mass_Haste **** **** **** **** **** **** **** **** +7261 SublimeChord_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +7262 SublimeChord_Necrotic_Eruption **** **** **** **** **** **** **** **** +7263 SublimeChord_OtilukesFreezingSphere **** **** **** **** **** **** **** **** +7264 SublimeChord_Planar_Binding **** **** **** **** **** **** **** **** +7265 SublimeChord_Repulsion **** **** **** **** **** **** **** **** +7266 SublimeChord_Shades **** **** **** **** **** **** **** **** +7267 SublimeChord_SHADES_Summon_Shadow **** **** **** **** **** **** **** **** +7268 SublimeChord_SHADES_Cone_of_Cold **** **** **** **** **** **** **** **** +7269 SublimeChord_SHADES_Fireball **** **** **** **** **** **** **** **** +7270 SublimeChord_SHADES_Stoneskin **** **** **** **** **** **** **** **** +7271 SublimeChord_SHADES_Wall_of_Fire **** **** **** **** **** **** **** **** +7272 SublimeChord_STARMANTLE **** **** **** **** **** **** **** **** +7273 SublimeChord_Stone_to_flesh **** **** **** **** **** **** **** **** +7274 SublimeChord_Summon_Creature_VI **** **** **** **** **** **** **** **** +7275 SublimeChord_Superior_Resistance **** **** **** **** **** **** **** **** +7276 SublimeChord_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +7277 SublimeChord_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +7278 SublimeChord_Tensers_Transformation **** **** **** **** **** **** **** **** +7279 SublimeChord_True_Seeing **** **** **** **** **** **** **** **** +7280 SublimeChord_Undeath_to_Death **** **** **** **** **** **** **** **** +7281 SublimeChord_WAVE_OF_PAIN **** **** **** **** **** **** **** **** +7282 SublimeChord_AMBER_SARCOPHAGUS **** **** **** **** **** **** **** **** +7283 SublimeChord_ArrowOfBone **** **** **** **** **** **** **** **** +7284 SublimeChord_Avasculate **** **** **** **** **** **** **** **** +7285 SublimeChord_Banishment **** **** **** **** **** **** **** **** +7286 SublimeChord_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +7287 SublimeChord_Control_Undead **** **** **** **** **** **** **** **** +7288 SublimeChord_Control_Weather **** **** **** **** **** **** **** **** +7289 SublimeChord_CW_Rain **** **** **** **** **** **** **** **** +7290 SublimeChord_CW_Snow **** **** **** **** **** **** **** **** +7291 SublimeChord_CW_Clear **** **** **** **** **** **** **** **** +7292 SublimeChord_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +7293 SublimeChord_DRAGON_ALLY **** **** **** **** **** **** **** **** +7294 SublimeChord_Energy_Ebb **** **** **** **** **** **** **** **** +7295 SublimeChord_Energy_Immunity **** **** **** **** **** **** **** **** +7296 SublimeChord_EI_Acid **** **** **** **** **** **** **** **** +7297 SublimeChord_EI_Cold **** **** **** **** **** **** **** **** +7298 SublimeChord_EI_Elec **** **** **** **** **** **** **** **** +7299 SublimeChord_EI_Fire **** **** **** **** **** **** **** **** +7300 SublimeChord_EI_Sonic **** **** **** **** **** **** **** **** +7301 SublimeChord_EYE_OF_THE_BEHOLDER **** **** **** **** **** **** **** **** +7302 SublimeChord_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +7303 SublimeChord_Finger_of_Death **** **** **** **** **** **** **** **** +7304 SublimeChord_Great_Thunderclap **** **** **** **** **** **** **** **** +7305 SublimeChord_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +7306 SublimeChord_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +7307 SublimeChord_GreaterTeleport_Party **** **** **** **** **** **** **** **** +7308 SublimeChord_Insanity **** **** **** **** **** **** **** **** +7309 SublimeChord_Mass_Hold_Person **** **** **** **** **** **** **** **** +7310 SublimeChord_Mordenkainens_Sword **** **** **** **** **** **** **** **** +7311 SublimeChord_Mords_Mansion **** **** **** **** **** **** **** **** +7312 SublimeChord_Nybors_Stern_Reproof **** **** **** **** **** **** **** **** +7313 SublimeChord_Power_Word_Blind **** **** **** **** **** **** **** **** +7314 SublimeChord_Power_Word_Stun **** **** **** **** **** **** **** **** +7315 SublimeChord_Prismatic_Spray **** **** **** **** **** **** **** **** +7316 SublimeChord_Protection_from_Spells **** **** **** **** **** **** **** **** +7317 SublimeChord_Sequester **** **** **** **** **** **** **** **** +7318 SublimeChord_Shadow_Shield **** **** **** **** **** **** **** **** +7319 SublimeChord_Spell_Mantle **** **** **** **** **** **** **** **** +7320 SublimeChord_Spell_Turning **** **** **** **** **** **** **** **** +7321 SublimeChord_Summon_Creature_VII **** **** **** **** **** **** **** **** +7322 SublimeChord_Summon7Air **** **** **** **** **** **** **** **** +7323 SublimeChord_Summon7Earth **** **** **** **** **** **** **** **** +7324 SublimeChord_Summon7Fire **** **** **** **** **** **** **** **** +7325 SublimeChord_Summon7Water **** **** **** **** **** **** **** **** +7326 SublimeChord_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +7327 SublimeChord_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +7328 SublimeChord_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +7329 SublimeChord_WavesOfExhaustion **** **** **** **** **** **** **** **** +7330 SublimeChord_Avascular_Mass **** **** **** **** **** **** **** **** +7331 SublimeChord_Bigbys_Clenched_Fist **** **** **** **** **** **** **** **** +7332 SublimeChord_Blackstaff **** **** **** **** **** **** **** **** +7333 SublimeChord_Create_Undead **** **** **** **** **** **** **** **** +7334 SublimeChord_Dimensional_Lock **** **** **** **** **** **** **** **** +7335 SublimeChord_DiscernLocation **** **** **** **** **** **** **** **** +7336 SublimeChord_Etherealness **** **** **** **** **** **** **** **** +7337 SublimeChord_Flensing **** **** **** **** **** **** **** **** +7338 SublimeChord_Greater_Planar_Binding **** **** **** **** **** **** **** **** +7339 SublimeChord_GUTWRENCH **** **** **** **** **** **** **** **** +7340 SublimeChord_Horrid_Wilting **** **** **** **** **** **** **** **** +7341 SublimeChord_Incendiary_Cloud **** **** **** **** **** **** **** **** +7342 SublimeChord_IRON_BODY **** **** **** **** **** **** **** **** +7343 SublimeChord_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +7344 SublimeChord_Mantle_of_Eg_Might **** **** **** **** **** **** **** **** +7345 SublimeChord_Mass_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7346 SublimeChord_Mass_Charm **** **** **** **** **** **** **** **** +7347 SublimeChord_Maze **** **** **** **** **** **** **** **** +7348 SublimeChord_Mind_Blank **** **** **** **** **** **** **** **** +7349 SublimeChord_Necrotic_Empowerment **** **** **** **** **** **** **** **** +7350 SublimeChord_PolarRay **** **** **** **** **** **** **** **** +7351 SublimeChord_Premonition **** **** **** **** **** **** **** **** +7352 SublimeChord_PrismaticWall **** **** **** **** **** **** **** **** +7353 SublimeChord_ScintillatingPattern **** **** **** **** **** **** **** **** +7354 SublimeChord_Summon_Creature_VIII **** **** **** **** **** **** **** **** +7355 SublimeChord_Summon8Air **** **** **** **** **** **** **** **** +7356 SublimeChord_Summon8Earth **** **** **** **** **** **** **** **** +7357 SublimeChord_Summon8Fire **** **** **** **** **** **** **** **** +7358 SublimeChord_Summon8Water **** **** **** **** **** **** **** **** +7359 SublimeChord_Sunburst **** **** **** **** **** **** **** **** +7360 SublimeChord_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +7361 SublimeChord_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +7362 SublimeChord_Bigbys_Crushing_Hand **** **** **** **** **** **** **** **** +7363 SublimeChord_Black_Blade_of_Disaster **** **** **** **** **** **** **** **** +7364 SublimeChord_BLINDING_GLORY **** **** **** **** **** **** **** **** +7365 SublimeChord_CRUSHING_FIST_OF_SPITE **** **** **** **** **** **** **** **** +7366 SublimeChord_Dominate_Monster **** **** **** **** **** **** **** **** +7367 SublimeChord_Energy_Drain **** **** **** **** **** **** **** **** +7368 SublimeChord_Foresight **** **** **** **** **** **** **** **** +7369 SublimeChord_Gate **** **** **** **** **** **** **** **** +7370 SublimeChord_Greater_Spell_Mantle **** **** **** **** **** **** **** **** +7371 SublimeChord_Mass_Hold_Monster **** **** **** **** **** **** **** **** +7372 SublimeChord_Meteor_Swarm **** **** **** **** **** **** **** **** +7373 SublimeChord_Mordenkainens_Disjunction **** **** **** **** **** **** **** **** +7374 SublimeChord_Necrotic_Termination **** **** **** **** **** **** **** **** +7375 SublimeChord_PlagueOfUndead **** **** **** **** **** **** **** **** +7376 SublimeChord_Power_Word_Kill **** **** **** **** **** **** **** **** +7377 SublimeChord_PrismaticSphere **** **** **** **** **** **** **** **** +7378 SublimeChord_Shapechange **** **** **** **** **** **** **** **** +7379 SublimeChord_Shapechange_RED_DRAGON **** **** **** **** **** **** **** **** +7380 SublimeChord_Shapechange_FIRE_GIANT **** **** **** **** **** **** **** **** +7381 SublimeChord_Shapechange_BALOR **** **** **** **** **** **** **** **** +7382 SublimeChord_Shapechange_DEATH_SLAAD **** **** **** **** **** **** **** **** +7383 SublimeChord_Shapechange_IRON_GOLEM **** **** **** **** **** **** **** **** +7384 SublimeChord_Sphere_of_Ultimate_Destruction **** **** **** **** **** **** **** **** +7385 SublimeChord_Summon_Creature_IX **** **** **** **** **** **** **** **** +7386 SublimeChord_Summon9Air **** **** **** **** **** **** **** **** +7387 SublimeChord_Summon9Earth **** **** **** **** **** **** **** **** +7388 SublimeChord_Summon9Fire **** **** **** **** **** **** **** **** +7389 SublimeChord_Summon9Water **** **** **** **** **** **** **** **** +7390 SublimeChord_TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +7391 SublimeChord_TeleportationCircle_Visible **** **** **** **** **** **** **** **** +7392 SublimeChord_TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +7393 SublimeChord_Time_Stop **** **** **** **** **** **** **** **** +7394 SublimeChord_UTTERDARK **** **** **** **** **** **** **** **** +7395 SublimeChord_VileDeath **** **** **** **** **** **** **** **** +7396 SublimeChord_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +7397 SublimeChord_Weird **** **** **** **** **** **** **** **** +7398 KnightoftheWeave_Bless **** **** **** **** **** **** **** **** +7399 KnightoftheWeave_Bless_Weapon **** **** **** **** **** **** **** **** +7400 KnightoftheWeave_Charm_Person **** **** **** **** **** **** **** **** +7401 KnightoftheWeave_Command_RadialMaster **** **** **** **** **** **** **** **** +7402 KnightoftheWeave_Command_Approach **** **** **** **** **** **** **** **** +7403 KnightoftheWeave_Command_Drop **** **** **** **** **** **** **** **** +7404 KnightoftheWeave_Command_Fall **** **** **** **** **** **** **** **** +7405 KnightoftheWeave_Command_Flee **** **** **** **** **** **** **** **** +7406 KnightoftheWeave_Command_Halt **** **** **** **** **** **** **** **** +7407 KnightoftheWeave_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7408 KnightoftheWeave_Divine_Favor **** **** **** **** **** **** **** **** +7409 KnightoftheWeave_Lesser_Restoration **** **** **** **** **** **** **** **** +7410 KnightoftheWeave_Mage_Armor **** **** **** **** **** **** **** **** +7411 KnightoftheWeave_Magic_Missile **** **** **** **** **** **** **** **** +7412 KnightoftheWeave_Magic_Weapon **** **** **** **** **** **** **** **** +7413 KnightoftheWeave_Read_Magic **** **** **** **** **** **** **** **** +7414 KnightoftheWeave_Shield **** **** **** **** **** **** **** **** +7415 KnightoftheWeave_Bulls_Strength **** **** **** **** **** **** **** **** +7416 KnightoftheWeave_Cats_Grace **** **** **** **** **** **** **** **** +7417 KnightoftheWeave_Endurance **** **** **** **** **** **** **** **** +7418 KnightoftheWeave_Ultravision **** **** **** **** **** **** **** **** +7419 KnightoftheWeave_Eagle_Splendor **** **** **** **** **** **** **** **** +7420 KnightoftheWeave_Resist_Elements **** **** **** **** **** **** **** **** +7421 KnightoftheWeave_See_Invisibility **** **** **** **** **** **** **** **** +7422 KnightoftheWeave_ShieldOther **** **** **** **** **** **** **** **** +7423 KnightoftheWeave_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7424 KnightoftheWeave_Daylight **** **** **** **** **** **** **** **** +7425 KnightoftheWeave_Dispel_Magic **** **** **** **** **** **** **** **** +7426 KnightoftheWeave_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7427 KnightoftheWeave_Remove_Curse **** **** **** **** **** **** **** **** +7428 KnightoftheWeave_BreakEnchantment **** **** **** **** **** **** **** **** +7429 KnightoftheWeave_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +7430 KnightoftheWeave_Death_Ward **** **** **** **** **** **** **** **** +7431 KnightoftheWeave_Minor_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +7432 KnightoftheWeave_Neutralize_Poison **** **** **** **** **** **** **** **** +7433 KnightoftheWeave_Restoration **** **** **** **** **** **** **** **** +7434 KnightoftheWeave_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +7435 KnightoftheWeave_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +7436 KnightoftheWeave_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +7437 KnightoftheWeave_DimensionDoor_Party **** **** **** **** **** **** **** **** +7438 KnightoftheWeave_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +7439 KnightoftheWeave_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +7440 KnightoftheWeave_Spell_Resistance **** **** **** **** **** **** **** **** +7441 KnightoftheWeave_True_Seeing **** **** **** **** **** **** **** **** +7442 KnightoftheWeave_Banishment **** **** **** **** **** **** **** **** +7443 KnightoftheWeave_Greater_Dispelling **** **** **** **** **** **** **** **** +7444 KnightoftheWeave_Teleport_RadialMaster **** **** **** **** **** **** **** **** +7445 KnightoftheWeave_Teleport_SelfOnly **** **** **** **** **** **** **** **** +7446 KnightoftheWeave_Teleport_Party **** **** **** **** **** **** **** **** +7447 Anti_Paladin_Bane **** **** **** **** **** **** **** **** +7448 Anti_Paladin_Exteneded_Bane **** **** **** **** **** **** **** **** +7449 Anti_Paladin_Silent_Bane **** **** **** **** **** **** **** **** +7450 Anti_Paladin_Still_Bane **** **** **** **** **** **** **** **** +7451 Anti_Paladin_Cause_Fear **** **** **** **** **** **** **** **** +7452 Anti_Paladin_Exteneded_Cause_Fear **** **** **** **** **** **** **** **** +7453 Anti_Paladin_Still_Cause_Fear **** **** **** **** **** **** **** **** +7454 Anti_Paladin_Curse_Water **** **** **** **** **** **** **** **** +7455 Anti_Paladin_Silent_Curse_Water **** **** **** **** **** **** **** **** +7456 Anti_Paladin_Still_Curse_Water **** **** **** **** **** **** **** **** +7457 Anti_Paladin_Doom **** **** **** **** **** **** **** **** +7458 Anti_Paladin_Exteneded_Doom **** **** **** **** **** **** **** **** +7459 Anti_Paladin_Silent_Doom **** **** **** **** **** **** **** **** +7460 Anti_Paladin_Still_Doom **** **** **** **** **** **** **** **** +7461 Anti_Paladin_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7462 Anti_Paladin_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7463 Anti_Paladin_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7464 Anti_Paladin_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7465 Anti_Paladin_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7466 Anti_Paladin_Magic_Weapon **** **** **** **** **** **** **** **** +7467 Anti_Paladin_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +7468 Anti_Paladin_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +7469 Anti_Paladin_Still_Magic_Weapon **** **** **** **** **** **** **** **** +7470 Anti_Paladin_Protection_from_Good **** **** **** **** **** **** **** **** +7471 Anti_Paladin_Exteneded_Protection_from_Good **** **** **** **** **** **** **** **** +7472 Anti_Paladin_Silent_Protection_from_Good **** **** **** **** **** **** **** **** +7473 Anti_Paladin_Still_Protection_from_Good **** **** **** **** **** **** **** **** +7474 Anti_Paladin_Protection_from_Law **** **** **** **** **** **** **** **** +7475 Anti_Paladin_Exteneded_Protection_from_Law **** **** **** **** **** **** **** **** +7476 Anti_Paladin_Silent_Protection_from_Law **** **** **** **** **** **** **** **** +7477 Anti_Paladin_Still_Protection_from_Law **** **** **** **** **** **** **** **** +7478 Anti_Paladin_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7479 Anti_Paladin_Empowered_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7480 Anti_Paladin_Exteneded_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7481 Anti_Paladin_Maximized_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7482 Anti_Paladin_Silent_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7483 Anti_Paladin_Still_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7484 Anti_Paladin_Read_Magic **** **** **** **** **** **** **** **** +7485 Anti_Paladin_Silent_Read_Magic **** **** **** **** **** **** **** **** +7486 Anti_Paladin_Still_Read_Magic **** **** **** **** **** **** **** **** +7487 Anti_Paladin_Summon_Creature_I **** **** **** **** **** **** **** **** +7488 Anti_Paladin_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +7489 Anti_Paladin_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +7490 Anti_Paladin_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +7491 Anti_Paladin_ANGRY_ACHE **** **** **** **** **** **** **** **** +7492 Anti_Paladin_Exteneded_ANGRY_ACHE **** **** **** **** **** **** **** **** +7493 Anti_Paladin_Silent_ANGRY_ACHE **** **** **** **** **** **** **** **** +7494 Anti_Paladin_Still_ANGRY_ACHE **** **** **** **** **** **** **** **** +7495 Anti_Paladin_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7496 Anti_Paladin_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7497 Anti_Paladin_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7498 Anti_Paladin_Bulls_Strength **** **** **** **** **** **** **** **** +7499 Anti_Paladin_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +7500 Anti_Paladin_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +7501 Anti_Paladin_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +7502 Anti_Paladin_Still_Bulls_Strength **** **** **** **** **** **** **** **** +7503 Anti_Paladin_Darkness **** **** **** **** **** **** **** **** +7504 Anti_Paladin_Exteneded_Darkness **** **** **** **** **** **** **** **** +7505 Anti_Paladin_Silent_Darkness **** **** **** **** **** **** **** **** +7506 Anti_Paladin_Summon_Creature_II **** **** **** **** **** **** **** **** +7507 Anti_Paladin_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +7508 Anti_Paladin_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +7509 Anti_Paladin_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +7510 Anti_Paladin_UndetectableAlignment **** **** **** **** **** **** **** **** +7511 Anti_Paladin_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +7512 Anti_Paladin_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +7513 Anti_Paladin_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +7514 Anti_Paladin_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7515 Anti_Paladin_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7516 Anti_Paladin_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7517 Anti_Paladin_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7518 Anti_Paladin_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7519 Anti_Paladin_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7520 Anti_Paladin_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7521 Anti_Paladin_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +7522 Anti_Paladin_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +7523 Anti_Paladin_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +7524 Anti_Paladin_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +7525 Anti_Paladin_Exteneded_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +7526 Anti_Paladin_Silent_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +7527 Anti_Paladin_Still_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +7528 Anti_Paladin_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +7529 Anti_Paladin_Exteneded_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +7530 Anti_Paladin_Silent_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +7531 Anti_Paladin_Still_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +7532 Anti_Paladin_Summon_Creature_III **** **** **** **** **** **** **** **** +7533 Anti_Paladin_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +7534 Anti_Paladin_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +7535 Anti_Paladin_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +7536 Anti_Paladin_Bestow_Curse **** **** **** **** **** **** **** **** +7537 Anti_Paladin_Silent_Bestow_Curse **** **** **** **** **** **** **** **** +7538 Anti_Paladin_Still_Bestow_Curse **** **** **** **** **** **** **** **** +7539 Anti_Paladin_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7540 Anti_Paladin_Exteneded_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7541 Anti_Paladin_Silent_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7542 Anti_Paladin_DeeperDarkness **** **** **** **** **** **** **** **** +7543 Anti_Paladin_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +7544 Anti_Paladin_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +7545 Anti_Paladin_RED_FESTER **** **** **** **** **** **** **** **** +7546 Anti_Paladin_Silent_RED_FESTER **** **** **** **** **** **** **** **** +7547 Anti_Paladin_Still_RED_FESTER **** **** **** **** **** **** **** **** +7548 Anti_Paladin_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +7549 Anti_Paladin_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +7550 Anti_Paladin_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +7551 Anti_Paladin_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +7552 Anti_Paladin_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +7553 Anti_Paladin_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +7554 Anti_Paladin_MASOCHISM **** **** **** **** **** **** **** **** +7555 Anti_Paladin_Exteneded_MASOCHISM **** **** **** **** **** **** **** **** +7556 Anti_Paladin_Death_Ward **** **** **** **** **** **** **** **** +7557 Anti_Paladin_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +7558 Anti_Paladin_Fear **** **** **** **** **** **** **** **** +7559 Anti_Paladin_Poison **** **** **** **** **** **** **** **** +7560 Anti_Paladin_Unholy_Sword **** **** **** **** **** **** **** **** +7561 Anti_Paladin_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +7562 Soldier_of_Light_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7563 Soldier_of_Light_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7564 Soldier_of_Light_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7565 Soldier_of_Light_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7566 Soldier_of_Light_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7567 Soldier_of_Light_Bless_Water **** **** **** **** **** **** **** **** +7568 Soldier_of_Light_Silent_Bless_Water **** **** **** **** **** **** **** **** +7569 Soldier_of_Light_Still_Bless_Water **** **** **** **** **** **** **** **** +7570 Soldier_of_Light_Bless_Weapon **** **** **** **** **** **** **** **** +7571 Soldier_of_Light_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +7572 Soldier_of_Light_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +7573 Soldier_of_Light_Still_Bless_Weapon **** **** **** **** **** **** **** **** +7574 Soldier_of_Light_Bless **** **** **** **** **** **** **** **** +7575 Soldier_of_Light_Exteneded_Bless **** **** **** **** **** **** **** **** +7576 Soldier_of_Light_Silent_Bless **** **** **** **** **** **** **** **** +7577 Soldier_of_Light_Still_Bless **** **** **** **** **** **** **** **** +7578 Soldier_of_Light_Detect_Evil **** **** **** **** **** **** **** **** +7579 Soldier_of_Light_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +7580 Soldier_of_Light_Silent_Detect_Evil **** **** **** **** **** **** **** **** +7581 Soldier_of_Light_Still_Detect_Evil **** **** **** **** **** **** **** **** +7582 Soldier_of_Light_HideFromUndead **** **** **** **** **** **** **** **** +7583 Soldier_of_Light_Exteneded_HideFromUndead **** **** **** **** **** **** **** **** +7584 Soldier_of_Light_Still_HideFromUndead **** **** **** **** **** **** **** **** +7585 Soldier_of_Light_Magic_Weapon **** **** **** **** **** **** **** **** +7586 Soldier_of_Light_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +7587 Soldier_of_Light_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +7588 Soldier_of_Light_Still_Magic_Weapon **** **** **** **** **** **** **** **** +7589 Soldier_of_Light_Shield_of_Faith **** **** **** **** **** **** **** **** +7590 Soldier_of_Light_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +7591 Soldier_of_Light_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +7592 Soldier_of_Light_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +7593 Soldier_of_Light_Protection_from_Evil **** **** **** **** **** **** **** **** +7594 Soldier_of_Light_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +7595 Soldier_of_Light_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +7596 Soldier_of_Light_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +7597 Soldier_of_Light_Light **** **** **** **** **** **** **** **** +7598 Soldier_of_Light_Exteneded_Light **** **** **** **** **** **** **** **** +7599 Soldier_of_Light_Silent_Light **** **** **** **** **** **** **** **** +7600 Soldier_of_Light_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7601 Soldier_of_Light_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7602 Soldier_of_Light_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7603 Soldier_of_Light_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7604 Soldier_of_Light_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7605 Soldier_of_Light_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7606 Soldier_of_Light_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7607 Soldier_of_Light_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7608 Soldier_of_Light_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7609 Soldier_of_Light_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7610 Soldier_of_Light_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7611 Soldier_of_Light_Aid **** **** **** **** **** **** **** **** +7612 Soldier_of_Light_Empowered_Aid **** **** **** **** **** **** **** **** +7613 Soldier_of_Light_Exteneded_Aid **** **** **** **** **** **** **** **** +7614 Soldier_of_Light_Silent_Aid **** **** **** **** **** **** **** **** +7615 Soldier_of_Light_Still_Aid **** **** **** **** **** **** **** **** +7616 Soldier_of_Light_Consecrated_Aura **** **** **** **** **** **** **** **** +7617 Soldier_of_Light_Exteneded_Consecrated_Aura **** **** **** **** **** **** **** **** +7618 Soldier_of_Light_Silent_Consecrated_Aura **** **** **** **** **** **** **** **** +7619 Soldier_of_Light_Still_Consecrated_Aura **** **** **** **** **** **** **** **** +7620 Soldier_of_Light_Daylight **** **** **** **** **** **** **** **** +7621 Soldier_of_Light_Exteneded_Daylight **** **** **** **** **** **** **** **** +7622 Soldier_of_Light_Silent_Daylight **** **** **** **** **** **** **** **** +7623 Soldier_of_Light_Still_Daylight **** **** **** **** **** **** **** **** +7624 Soldier_of_Light_Lesser_Restoration **** **** **** **** **** **** **** **** +7625 Soldier_of_Light_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +7626 Soldier_of_Light_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +7627 Soldier_of_Light_ShieldOther **** **** **** **** **** **** **** **** +7628 Soldier_of_Light_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +7629 Soldier_of_Light_Silent_ShieldOther **** **** **** **** **** **** **** **** +7630 Soldier_of_Light_Still_ShieldOther **** **** **** **** **** **** **** **** +7631 Soldier_of_Light_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7632 Soldier_of_Light_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7633 Soldier_of_Light_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7634 Soldier_of_Light_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7635 Soldier_of_Light_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7636 Soldier_of_Light_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7637 Soldier_of_Light_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +7638 Soldier_of_Light_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +7639 Soldier_of_Light_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +7640 Soldier_of_Light_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7641 Soldier_of_Light_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7642 Soldier_of_Light_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7643 Soldier_of_Light_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7644 Soldier_of_Light_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7645 Soldier_of_Light_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7646 Soldier_of_Light_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7647 Soldier_of_Light_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7648 Soldier_of_Light_Searing_Light **** **** **** **** **** **** **** **** +7649 Soldier_of_Light_Silent_Searing_Light **** **** **** **** **** **** **** **** +7650 Soldier_of_Light_Still_Searing_Light **** **** **** **** **** **** **** **** +7651 Soldier_of_Light_Negative_Energy_Protection **** **** **** **** **** **** **** **** +7652 Soldier_of_Light_Exteneded_Negative_Energy_Protection **** **** **** **** **** **** **** **** +7653 Soldier_of_Light_Silent_Negative_Energy_Protection **** **** **** **** **** **** **** **** +7654 Soldier_of_Light_Still_Negative_Energy_Protection **** **** **** **** **** **** **** **** +7655 Soldier_of_Light_Prayer **** **** **** **** **** **** **** **** +7656 Soldier_of_Light_Exteneded_Prayer **** **** **** **** **** **** **** **** +7657 Soldier_of_Light_Silent_Prayer **** **** **** **** **** **** **** **** +7658 Soldier_of_Light_Still_Prayer **** **** **** **** **** **** **** **** +7659 Soldier_of_Light_Remove_Disease **** **** **** **** **** **** **** **** +7660 Soldier_of_Light_Silent_Remove_Disease **** **** **** **** **** **** **** **** +7661 Soldier_of_Light_Still_Remove_Disease **** **** **** **** **** **** **** **** +7662 Soldier_of_Light_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +7663 Soldier_of_Light_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +7664 Soldier_of_Light_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7665 Soldier_of_Light_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7666 Soldier_of_Light_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7667 Soldier_of_Light_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +7668 Soldier_of_Light_Death_Ward **** **** **** **** **** **** **** **** +7669 Soldier_of_Light_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +7670 Soldier_of_Light_Holy_Sword **** **** **** **** **** **** **** **** +7671 Soldier_of_Light_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +7672 Soldier_of_Light_Restoration **** **** **** **** **** **** **** **** +7673 Soldier_of_Light_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +7674 Soldier_of_Light_SUNMANTLE **** **** **** **** **** **** **** **** +7675 Soldier_of_Light_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7676 Telflammar_Shadow_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7677 Telflammar_Shadow_Exteneded_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7678 Telflammar_Shadow_Silent_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7679 Telflammar_Shadow_Ultravision **** **** **** **** **** **** **** **** +7680 Telflammar_Shadow_Exteneded_Ultravision **** **** **** **** **** **** **** **** +7681 Telflammar_Shadow_Silent_Ultravision **** **** **** **** **** **** **** **** +7682 Telflammar_Shadow_Still_Ultravision **** **** **** **** **** **** **** **** +7683 Telflammar_Shadow_Chill_Touch **** **** **** **** **** **** **** **** +7684 Telflammar_Shadow_Empowered_Chill_Touch **** **** **** **** **** **** **** **** +7685 Telflammar_Shadow_Exteneded_Chill_Touch **** **** **** **** **** **** **** **** +7686 Telflammar_Shadow_Silent_Chill_Touch **** **** **** **** **** **** **** **** +7687 Telflammar_Shadow_Still_Chill_Touch **** **** **** **** **** **** **** **** +7688 Telflammar_Shadow_Darkness **** **** **** **** **** **** **** **** +7689 Telflammar_Shadow_Exteneded_Darkness **** **** **** **** **** **** **** **** +7690 Telflammar_Shadow_Silent_Darkness **** **** **** **** **** **** **** **** +7691 Telflammar_Shadow_Shadow_Spray **** **** **** **** **** **** **** **** +7692 Telflammar_Shadow_Empowered_Shadow_Spray **** **** **** **** **** **** **** **** +7693 Telflammar_Shadow_Exteneded_Shadow_Spray **** **** **** **** **** **** **** **** +7694 Telflammar_Shadow_Silent_Shadow_Spray **** **** **** **** **** **** **** **** +7695 Telflammar_Shadow_Still_Shadow_Spray **** **** **** **** **** **** **** **** +7696 Telflammar_Shadow_Invisibility **** **** **** **** **** **** **** **** +7697 Telflammar_Shadow_Exteneded_Invisibility **** **** **** **** **** **** **** **** +7698 Telflammar_Shadow_Silent_Invisibility **** **** **** **** **** **** **** **** +7699 Telflammar_Shadow_Still_Invisibility **** **** **** **** **** **** **** **** +7700 Telflammar_Shadow_Knock **** **** **** **** **** **** **** **** +7701 Telflammar_Shadow_Still_Knock **** **** **** **** **** **** **** **** +7702 Telflammar_Shadow_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7703 Telflammar_Shadow_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7704 Telflammar_Shadow_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +7705 Telflammar_Shadow_Blacklight **** **** **** **** **** **** **** **** +7706 Telflammar_Shadow_Exteneded_Blacklight **** **** **** **** **** **** **** **** +7707 Telflammar_Shadow_Silent_Blacklight **** **** **** **** **** **** **** **** +7708 Telflammar_Shadow_Still_Blacklight **** **** **** **** **** **** **** **** +7709 Telflammar_Shadow_Displacement **** **** **** **** **** **** **** **** +7710 Telflammar_Shadow_Exteneded_Displacement **** **** **** **** **** **** **** **** +7711 Telflammar_Shadow_Silent_Displacement **** **** **** **** **** **** **** **** +7712 Telflammar_Shadow_Haste **** **** **** **** **** **** **** **** +7713 Telflammar_Shadow_Exteneded_Haste **** **** **** **** **** **** **** **** +7714 Telflammar_Shadow_Silent_Haste **** **** **** **** **** **** **** **** +7715 Telflammar_Shadow_Still_Haste **** **** **** **** **** **** **** **** +7716 Telflammar_Shadow_Improved_Invisibility **** **** **** **** **** **** **** **** +7717 Telflammar_Shadow_Exteneded_Improved_Invisibility **** **** **** **** **** **** **** **** +7718 Telflammar_Shadow_Silent_Improved_Invisibility **** **** **** **** **** **** **** **** +7719 Telflammar_Shadow_Still_Improved_Invisibility **** **** **** **** **** **** **** **** +7720 Telflammar_Shadow_Vampiric_Touch **** **** **** **** **** **** **** **** +7721 Telflammar_Shadow_Silent_Vampiric_Touch **** **** **** **** **** **** **** **** +7722 Telflammar_Shadow_Still_Vampiric_Touch **** **** **** **** **** **** **** **** +7723 Telflammar_Shadow_NONDETECTION **** **** **** **** **** **** **** **** +7724 Telflammar_Shadow_Exteneded_NONDETECTION **** **** **** **** **** **** **** **** +7725 Telflammar_Shadow_Silent_NONDETECTION **** **** **** **** **** **** **** **** +7726 Telflammar_Shadow_Still_NONDETECTION **** **** **** **** **** **** **** **** +7727 Telflammar_Shadow_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7728 Telflammar_Shadow_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7729 Telflammar_Shadow_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +7730 Telflammar_Shadow_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +7731 Telflammar_Shadow_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +7732 Telflammar_Shadow_DimensionDoor_Party **** **** **** **** **** **** **** **** +7733 Telflammar_Shadow_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +7734 Telflammar_Shadow_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +7735 Telflammar_Shadow_Confusion **** **** **** **** **** **** **** **** +7736 Telflammar_Shadow_DarkBolt **** **** **** **** **** **** **** **** +7737 Telflammar_Shadow_DarkBolt_all **** **** **** **** **** **** **** **** +7738 Telflammar_Shadow_DarkBolt_1 **** **** **** **** **** **** **** **** +7739 Telflammar_Shadow_Invisibility_Sphere **** **** **** **** **** **** **** **** +7740 Telflammar_Shadow_Mislead **** **** **** **** **** **** **** **** +7741 Telflammar_Shadow_DetectScrying **** **** **** **** **** **** **** **** +7742 Telflammar_Shadow_RED_FESTER **** **** **** **** **** **** **** **** +7743 Telflammar_Shadow_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +7744 Telflammar_Shadow_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +7745 Telflammar_Shadow_MASOCHISM **** **** **** **** **** **** **** **** +7746 JusticeOfWealdAnd_Camoflage **** **** **** **** **** **** **** **** +7747 JusticeOfWealdAnd_Endure_Elements **** **** **** **** **** **** **** **** +7748 JusticeOfWealdAnd_Faerie_Fire **** **** **** **** **** **** **** **** +7749 JusticeOfWealdAnd_HideFromAnimals **** **** **** **** **** **** **** **** +7750 JusticeOfWealdAnd_Spell_Jump **** **** **** **** **** **** **** **** +7751 JusticeOfWealdAnd_Longstrider **** **** **** **** **** **** **** **** +7752 JusticeOfWealdAnd_Obscuring_Mist **** **** **** **** **** **** **** **** +7753 JusticeOfWealdAnd_Barkskin **** **** **** **** **** **** **** **** +7754 JusticeOfWealdAnd_BrilliantEnergyArrows **** **** **** **** **** **** **** **** +7755 JusticeOfWealdAnd_Cats_Grace **** **** **** **** **** **** **** **** +7756 JusticeOfWealdAnd_FogCloud **** **** **** **** **** **** **** **** +7757 JusticeOfWealdAnd_Snare **** **** **** **** **** **** **** **** +7758 JusticeOfWealdAnd_SpellslayerArrow **** **** **** **** **** **** **** **** +7759 JusticeOfWealdAnd_Treeshape **** **** **** **** **** **** **** **** +7760 JusticeOfWealdAnd_ArrowSplit **** **** **** **** **** **** **** **** +7761 JusticeOfWealdAnd_DarkflameArrow **** **** **** **** **** **** **** **** +7762 JusticeOfWealdAnd_Ultravision **** **** **** **** **** **** **** **** +7763 JusticeOfWealdAnd_SerpentArrows **** **** **** **** **** **** **** **** +7764 JusticeOfWealdAnd_Spike_Growth **** **** **** **** **** **** **** **** +7765 JusticeOfWealdAnd_WaterBreathing **** **** **** **** **** **** **** **** +7766 JusticeOfWealdAnd_BloodfreezeArrow **** **** **** **** **** **** **** **** +7767 JusticeOfWealdAnd_DoublestrikeArrow **** **** **** **** **** **** **** **** +7768 JusticeOfWealdAnd_Freedom_of_Movement **** **** **** **** **** **** **** **** +7769 JusticeOfWealdAnd_Poison **** **** **** **** **** **** **** **** +7770 JusticeOfWealdAnd_Scrying **** **** **** **** **** **** **** **** +7771 JusticeOfWealdAnd_ShadowArrow **** **** **** **** **** **** **** **** +7772 KnightMiddleCircl_Bless **** **** **** **** **** **** **** **** +7773 KnightMiddleCircl_Exteneded_Bless **** **** **** **** **** **** **** **** +7774 KnightMiddleCircl_Silent_Bless **** **** **** **** **** **** **** **** +7775 KnightMiddleCircl_Still_Bless **** **** **** **** **** **** **** **** +7776 KnightMiddleCircl_Bless_Weapon **** **** **** **** **** **** **** **** +7777 KnightMiddleCircl_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +7778 KnightMiddleCircl_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +7779 KnightMiddleCircl_Still_Bless_Weapon **** **** **** **** **** **** **** **** +7780 KnightMiddleCircl_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7781 KnightMiddleCircl_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7782 KnightMiddleCircl_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7783 KnightMiddleCircl_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +7784 KnightMiddleCircl_DETECT_UNDEAD **** **** **** **** **** **** **** **** +7785 KnightMiddleCircl_Exteneded_DETECT_UNDEAD **** **** **** **** **** **** **** **** +7786 KnightMiddleCircl_Silent_DETECT_UNDEAD **** **** **** **** **** **** **** **** +7787 KnightMiddleCircl_Still_DETECT_UNDEAD **** **** **** **** **** **** **** **** +7788 KnightMiddleCircl_Divine_Favor **** **** **** **** **** **** **** **** +7789 KnightMiddleCircl_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +7790 KnightMiddleCircl_Silent_Divine_Favor **** **** **** **** **** **** **** **** +7791 KnightMiddleCircl_Still_Divine_Favor **** **** **** **** **** **** **** **** +7792 KnightMiddleCircl_Magic_Weapon **** **** **** **** **** **** **** **** +7793 KnightMiddleCircl_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +7794 KnightMiddleCircl_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +7795 KnightMiddleCircl_Still_Magic_Weapon **** **** **** **** **** **** **** **** +7796 KnightMiddleCircl_Protection_from_Evil **** **** **** **** **** **** **** **** +7797 KnightMiddleCircl_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +7798 KnightMiddleCircl_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +7799 KnightMiddleCircl_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +7800 KnightMiddleCircl_Read_Magic **** **** **** **** **** **** **** **** +7801 KnightMiddleCircl_Silent_Read_Magic **** **** **** **** **** **** **** **** +7802 KnightMiddleCircl_Still_Read_Magic **** **** **** **** **** **** **** **** +7803 KnightMiddleCircl_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +7804 KnightMiddleCircl_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +7805 KnightMiddleCircl_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7806 KnightMiddleCircl_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7807 KnightMiddleCircl_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +7808 KnightMiddleCircl_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7809 KnightMiddleCircl_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7810 KnightMiddleCircl_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +7811 KnightMiddleCircl_Aid **** **** **** **** **** **** **** **** +7812 KnightMiddleCircl_Exteneded_Aid **** **** **** **** **** **** **** **** +7813 KnightMiddleCircl_Silent_Aid **** **** **** **** **** **** **** **** +7814 KnightMiddleCircl_Still_Aid **** **** **** **** **** **** **** **** +7815 KnightMiddleCircl_Divine_Protection **** **** **** **** **** **** **** **** +7816 KnightMiddleCircl_Exteneded_Divine_Protection **** **** **** **** **** **** **** **** +7817 KnightMiddleCircl_Silent_Divine_Protection **** **** **** **** **** **** **** **** +7818 KnightMiddleCircl_Still_Divine_Protection **** **** **** **** **** **** **** **** +7819 KnightMiddleCircl_Conviction **** **** **** **** **** **** **** **** +7820 KnightMiddleCircl_Exteneded_Conviction **** **** **** **** **** **** **** **** +7821 KnightMiddleCircl_Silent_Conviction **** **** **** **** **** **** **** **** +7822 KnightMiddleCircl_Still_Conviction **** **** **** **** **** **** **** **** +7823 KnightMiddleCircl_ShieldOther **** **** **** **** **** **** **** **** +7824 KnightMiddleCircl_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +7825 KnightMiddleCircl_Silent_ShieldOther **** **** **** **** **** **** **** **** +7826 KnightMiddleCircl_Still_ShieldOther **** **** **** **** **** **** **** **** +7827 KnightMiddleCircl_UndetectableAlignment **** **** **** **** **** **** **** **** +7828 KnightMiddleCircl_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +7829 KnightMiddleCircl_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +7830 KnightMiddleCircl_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +7831 KnightMiddleCircl_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7832 KnightMiddleCircl_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7833 KnightMiddleCircl_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +7834 KnightMiddleCircl_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7835 KnightMiddleCircl_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +7836 KnightMiddleCircl_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +7837 KnightMiddleCircl_Dispel_Magic **** **** **** **** **** **** **** **** +7838 KnightMiddleCircl_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +7839 KnightMiddleCircl_Prayer **** **** **** **** **** **** **** **** +7840 KnightMiddleCircl_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +7841 KnightMiddleCircl_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +7842 DreadNecromancer_ANGRY_ACHE **** **** **** **** **** **** **** **** +7843 DreadNecromancer_Bane **** **** **** **** **** **** **** **** +7844 DreadNecromancer_BESTOW_WOUND **** **** **** **** **** **** **** **** +7845 DreadNecromancer_Blade_of_Blood **** **** **** **** **** **** **** **** +7846 DreadNecromancer_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +7847 DreadNecromancer_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +7848 DreadNecromancer_Cause_Fear **** **** **** **** **** **** **** **** +7849 DreadNecromancer_Chill_Touch **** **** **** **** **** **** **** **** +7850 DreadNecromancer_DETECT_UNDEAD **** **** **** **** **** **** **** **** +7851 DreadNecromancer_Doom **** **** **** **** **** **** **** **** +7852 DreadNecromancer_HideFromUndead **** **** **** **** **** **** **** **** +7853 DreadNecromancer_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7854 DreadNecromancer_Necrotic_Awareness **** **** **** **** **** **** **** **** +7855 DreadNecromancer_Negative_Energy_Ray **** **** **** **** **** **** **** **** +7856 DreadNecromancer_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +7857 DreadNecromancer_SummonUndeadI **** **** **** **** **** **** **** **** +7858 DreadNecromancer_UndetectableAlignment **** **** **** **** **** **** **** **** +7859 DreadNecromancer_Blindness_and_Deafness **** **** **** **** **** **** **** **** +7860 DreadNecromancer_BONEBLAST **** **** **** **** **** **** **** **** +7861 DreadNecromancer_Command_Undead **** **** **** **** **** **** **** **** +7862 DreadNecromancer_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +7863 DreadNecromancer_Darkness **** **** **** **** **** **** **** **** +7864 DreadNecromancer_Death_Armor **** **** **** **** **** **** **** **** +7865 DreadNecromancer_Death_Knell **** **** **** **** **** **** **** **** +7866 DreadNecromancer_FalseLife **** **** **** **** **** **** **** **** +7867 DreadNecromancer_Ghoul_Touch **** **** **** **** **** **** **** **** +7868 DreadNecromancer_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +7869 DreadNecromancer_LifeBolt **** **** **** **** **** **** **** **** +7870 DreadNecromancer_LifeBolt1Bolt **** **** **** **** **** **** **** **** +7871 DreadNecromancer_LifeBolt2Bolts **** **** **** **** **** **** **** **** +7872 DreadNecromancer_LifeBolt3Bolts **** **** **** **** **** **** **** **** +7873 DreadNecromancer_LifeBolt4Bolts **** **** **** **** **** **** **** **** +7874 DreadNecromancer_LifeBolt5Bolts **** **** **** **** **** **** **** **** +7875 DreadNecromancer_Living_Undeath **** **** **** **** **** **** **** **** +7876 DreadNecromancer_Necrotic_Cyst **** **** **** **** **** **** **** **** +7877 DreadNecromancer_Scare **** **** **** **** **** **** **** **** +7878 DreadNecromancer_SHRIVELING **** **** **** **** **** **** **** **** +7879 DreadNecromancer_SummonUndeadII **** **** **** **** **** **** **** **** +7880 DreadNecromancer_Animate_Dead **** **** **** **** **** **** **** **** +7881 DreadNecromancer_BONEBLADE **** **** **** **** **** **** **** **** +7882 DreadNecromancer_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +7883 DreadNecromancer_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +7884 DreadNecromancer_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +7885 DreadNecromancer_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +7886 DreadNecromancer_CrushingDespair **** **** **** **** **** **** **** **** +7887 DreadNecromancer_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +7888 DreadNecromancer_GreaterDisruptUndead **** **** **** **** **** **** **** **** +7889 DreadNecromancer_HaltUndead **** **** **** **** **** **** **** **** +7890 DreadNecromancer_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +7891 DreadNecromancer_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +7892 DreadNecromancer_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +7893 DreadNecromancer_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +7894 DreadNecromancer_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +7895 DreadNecromancer_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +7896 DreadNecromancer_Necrotic_Bloat **** **** **** **** **** **** **** **** +7897 DreadNecromancer_Negative_Energy_Burst **** **** **** **** **** **** **** **** +7898 DreadNecromancer_RayofExhaustion **** **** **** **** **** **** **** **** +7899 DreadNecromancer_Slashing_Darkness **** **** **** **** **** **** **** **** +7900 DreadNecromancer_SummonUndeadIII **** **** **** **** **** **** **** **** +7901 DreadNecromancer_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +7902 DreadNecromancer_Vampiric_Touch **** **** **** **** **** **** **** **** +7903 DreadNecromancer_WRACK **** **** **** **** **** **** **** **** +7904 DreadNecromancer_Bestow_Curse **** **** **** **** **** **** **** **** +7905 DreadNecromancer_BloodOfTheMartyr **** **** **** **** **** **** **** **** +7906 DreadNecromancer_Contagion **** **** **** **** **** **** **** **** +7907 DreadNecromancer_Death_Ward **** **** **** **** **** **** **** **** +7908 DreadNecromancer_Dispel_Magic **** **** **** **** **** **** **** **** +7909 DreadNecromancer_Doom_Scarabs **** **** **** **** **** **** **** **** +7910 DreadNecromancer_Enervation **** **** **** **** **** **** **** **** +7911 DreadNecromancer_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +7912 DreadNecromancer_Fear **** **** **** **** **** **** **** **** +7913 DreadNecromancer_GRIM_REVENGE **** **** **** **** **** **** **** **** +7914 DreadNecromancer_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +7915 DreadNecromancer_LIQUID_PAIN **** **** **** **** **** **** **** **** +7916 DreadNecromancer_Necrotic_Domination **** **** **** **** **** **** **** **** +7917 DreadNecromancer_Phantasmal_Killer **** **** **** **** **** **** **** **** +7918 DreadNecromancer_Poison **** **** **** **** **** **** **** **** +7919 DreadNecromancer_Sinsaburs_Baleful_Bolt **** **** **** **** **** **** **** **** +7920 DreadNecromancer_STOP_HEART **** **** **** **** **** **** **** **** +7921 DreadNecromancer_SummonUndeadIV **** **** **** **** **** **** **** **** +7922 DreadNecromancer_Beltyns_Burning_Blood **** **** **** **** **** **** **** **** +7923 DreadNecromancer_Circle_of_Doom **** **** **** **** **** **** **** **** +7924 DreadNecromancer_Cloudkill **** **** **** **** **** **** **** **** +7925 DreadNecromancer_FireInTheBlood **** **** **** **** **** **** **** **** +7926 DreadNecromancer_Greater_Dispelling **** **** **** **** **** **** **** **** +7927 DreadNecromancer_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +7928 DreadNecromancer_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +7929 DreadNecromancer_Mass_Contagion **** **** **** **** **** **** **** **** +7930 DreadNecromancer_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +7931 DreadNecromancer_Necrotic_Burst **** **** **** **** **** **** **** **** +7932 DreadNecromancer_Nights_Caress **** **** **** **** **** **** **** **** +7933 DreadNecromancer_Slay_Living **** **** **** **** **** **** **** **** +7934 DreadNecromancer_Soulscour **** **** **** **** **** **** **** **** +7935 DreadNecromancer_SummonUndeadV **** **** **** **** **** **** **** **** +7936 DreadNecromancer_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +7937 DreadNecromancer_Undeath_to_Death **** **** **** **** **** **** **** **** +7938 DreadNecromancer_WavesofFatigue **** **** **** **** **** **** **** **** +7939 DreadNecromancer_Acid_Fog **** **** **** **** **** **** **** **** +7940 DreadNecromancer_Circle_of_Death **** **** **** **** **** **** **** **** +7941 DreadNecromancer_Create_Undead **** **** **** **** **** **** **** **** +7942 DreadNecromancer_ECTOPLASMIC_ENCHANCEMENT **** **** **** **** **** **** **** **** +7943 DreadNecromancer_Eyebite **** **** **** **** **** **** **** **** +7944 DreadNecromancer_Ghoul_Gauntlet **** **** **** **** **** **** **** **** +7945 DreadNecromancer_Harm **** **** **** **** **** **** **** **** +7946 DreadNecromancer_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +7947 DreadNecromancer_Necrotic_Eruption **** **** **** **** **** **** **** **** +7948 DreadNecromancer_Planar_Binding **** **** **** **** **** **** **** **** +7949 DreadNecromancer_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +7950 DreadNecromancer_WavesOfExhaustion **** **** **** **** **** **** **** **** +7951 DreadNecromancer_ArrowOfBone **** **** **** **** **** **** **** **** +7952 DreadNecromancer_Avasculate **** **** **** **** **** **** **** **** +7953 DreadNecromancer_Control_Undead **** **** **** **** **** **** **** **** +7954 DreadNecromancer_Destruction **** **** **** **** **** **** **** **** +7955 DreadNecromancer_Energy_Ebb **** **** **** **** **** **** **** **** +7956 DreadNecromancer_Finger_of_Death **** **** **** **** **** **** **** **** +7957 DreadNecromancer_Greater_Harm **** **** **** **** **** **** **** **** +7958 DreadNecromancer_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +7959 DreadNecromancer_SongOfDiscord **** **** **** **** **** **** **** **** +7960 DreadNecromancer_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +7961 DreadNecromancer_VileDeath **** **** **** **** **** **** **** **** +7962 DreadNecromancer_Avascular_Mass **** **** **** **** **** **** **** **** +7963 DreadNecromancer_Create_Greater_Undead **** **** **** **** **** **** **** **** +7964 DreadNecromancer_GUTWRENCH **** **** **** **** **** **** **** **** +7965 DreadNecromancer_Horrid_Wilting **** **** **** **** **** **** **** **** +7966 DreadNecromancer_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +7967 DreadNecromancer_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +7968 DreadNecromancer_Necrotic_Empowerment **** **** **** **** **** **** **** **** +7969 DreadNecromancer_Pestilence **** **** **** **** **** **** **** **** +7970 DreadNecromancer_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +7971 DreadNecromancer_Energy_Drain **** **** **** **** **** **** **** **** +7972 DreadNecromancer_Mass_Harm **** **** **** **** **** **** **** **** +7973 DreadNecromancer_Necrotic_Termination **** **** **** **** **** **** **** **** +7974 DreadNecromancer_PlagueOfUndead **** **** **** **** **** **** **** **** +7975 DreadNecromancer_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +7976 ****_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +7977 ****_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +7978 ****_Light **** **** **** **** **** **** **** **** +7979 ****_Read_Magic **** **** **** **** **** **** **** **** +7980 ****_Resistance **** **** **** **** **** **** **** **** +7981 ****_Virtue **** **** **** **** **** **** **** **** +7982 ****_ANGRY_ACHE **** **** **** **** **** **** **** **** +7983 ****_Bane **** **** **** **** **** **** **** **** +7984 ****_Blade_of_Blood **** **** **** **** **** **** **** **** +7985 ****_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +7986 ****_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +7987 ****_Bless **** **** **** **** **** **** **** **** +7988 ****_Bless_Water **** **** **** **** **** **** **** **** +7989 ****_Cause_Fear **** **** **** **** **** **** **** **** +7990 ****_Command_RadialMaster **** **** **** **** **** **** **** **** +7991 ****_Command_Approach **** **** **** **** **** **** **** **** +7992 ****_Command_Drop **** **** **** **** **** **** **** **** +7993 ****_Command_Fall **** **** **** **** **** **** **** **** +7994 ****_Command_Flee **** **** **** **** **** **** **** **** +7995 ****_Command_Halt **** **** **** **** **** **** **** **** +7996 ****_Conviction **** **** **** **** **** **** **** **** +7997 ****_Crafters_Blessing **** **** **** **** **** **** **** **** +7998 ****_Crafters_Curse **** **** **** **** **** **** **** **** +7999 ****_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8000 ****_Curse_Water **** **** **** **** **** **** **** **** +8001 ****_Detect_Chaos **** **** **** **** **** **** **** **** +8002 ****_Detect_Evil **** **** **** **** **** **** **** **** +8003 ****_Detect_Good **** **** **** **** **** **** **** **** +8004 ****_Detect_Law **** **** **** **** **** **** **** **** +8005 ****_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8006 ****_Divine_Favor **** **** **** **** **** **** **** **** +8007 ****_Doom **** **** **** **** **** **** **** **** +8008 ****_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +8009 ****_Endure_Elements **** **** **** **** **** **** **** **** +8010 ****_Entropic_Shield **** **** **** **** **** **** **** **** +8011 ****_EXTRACT_DRUG **** **** **** **** **** **** **** **** +8012 ****_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +8013 ****_EXTRACT_VODARE **** **** **** **** **** **** **** **** +8014 ****_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +8015 ****_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8016 ****_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +8017 ****_HEARTACHE **** **** **** **** **** **** **** **** +8018 ****_HideFromUndead **** **** **** **** **** **** **** **** +8019 ****_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8020 ****_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8021 ****_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8022 ****_Lesser_Vigor **** **** **** **** **** **** **** **** +8023 ****_Magic_Stone **** **** **** **** **** **** **** **** +8024 ****_Magic_Weapon **** **** **** **** **** **** **** **** +8025 ****_Necrotic_Awareness **** **** **** **** **** **** **** **** +8026 ****_Obscuring_Mist **** **** **** **** **** **** **** **** +8027 ****_Protection_from_Chaos **** **** **** **** **** **** **** **** +8028 ****_Protection_from_Evil **** **** **** **** **** **** **** **** +8029 ****_Protection_from_Good **** **** **** **** **** **** **** **** +8030 ****_Protection_from_Law **** **** **** **** **** **** **** **** +8031 ****_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8032 ****_Remove_Fear **** **** **** **** **** **** **** **** +8033 ****_Sanctuary **** **** **** **** **** **** **** **** +8034 ****_Shield_of_Faith **** **** **** **** **** **** **** **** +8035 ****_SORROW **** **** **** **** **** **** **** **** +8036 ****_Summon_Creature_I **** **** **** **** **** **** **** **** +8037 ****_SummonUndeadI **** **** **** **** **** **** **** **** +8038 ****_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8039 ****_VisionOfHeaven **** **** **** **** **** **** **** **** +8040 ****_ADDICTION **** **** **** **** **** **** **** **** +8041 ****_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +8042 ****_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8043 ****_ADDICTION_VODARE **** **** **** **** **** **** **** **** +8044 ****_ADDICTION_AGONY **** **** **** **** **** **** **** **** +8045 ****_Aid **** **** **** **** **** **** **** **** +8046 ****_Animalistic_Power **** **** **** **** **** **** **** **** +8047 ****_BONEBLAST **** **** **** **** **** **** **** **** +8048 ****_Bulls_Strength **** **** **** **** **** **** **** **** +8049 ****_Calm_Emotions **** **** **** **** **** **** **** **** +8050 ****_Consecrated_Aura **** **** **** **** **** **** **** **** +8051 ****_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8052 ****_Darkness **** **** **** **** **** **** **** **** +8053 ****_Death_Knell **** **** **** **** **** **** **** **** +8054 ****_Divine_Protection **** **** **** **** **** **** **** **** +8055 ****_Eagle_Splendor **** **** **** **** **** **** **** **** +8056 ****_ELATION **** **** **** **** **** **** **** **** +8057 ****_Endurance **** **** **** **** **** **** **** **** +8058 ****_Find_Traps **** **** **** **** **** **** **** **** +8059 ****_Foxs_Cunning **** **** **** **** **** **** **** **** +8060 ****_Hold_Person **** **** **** **** **** **** **** **** +8061 ****_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +8062 ****_Lesser_Dispel **** **** **** **** **** **** **** **** +8063 ****_Lesser_Restoration **** **** **** **** **** **** **** **** +8064 ****_Living_Undeath **** **** **** **** **** **** **** **** +8065 ****_Necrotic_Cyst **** **** **** **** **** **** **** **** +8066 ****_Negative_Energy_Ray **** **** **** **** **** **** **** **** +8067 ****_Owls_Wisdom **** **** **** **** **** **** **** **** +8068 ****_Remove_Paralysis **** **** **** **** **** **** **** **** +8069 ****_Resist_Elements **** **** **** **** **** **** **** **** +8070 ****_ShieldOther **** **** **** **** **** **** **** **** +8071 ****_Silence **** **** **** **** **** **** **** **** +8072 ****_Sound_Burst **** **** **** **** **** **** **** **** +8073 ****_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +8074 ****_Stone_Bones **** **** **** **** **** **** **** **** +8075 ****_Summon_Creature_II **** **** **** **** **** **** **** **** +8076 ****_SummonUndeadII **** **** **** **** **** **** **** **** +8077 ****_Ultravision **** **** **** **** **** **** **** **** +8078 ****_UndetectableAlignment **** **** **** **** **** **** **** **** +8079 ****_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +8080 ****_Animate_Dead **** **** **** **** **** **** **** **** +8081 ****_Bestow_Curse **** **** **** **** **** **** **** **** +8082 ****_Blindness_and_Deafness **** **** **** **** **** **** **** **** +8083 ****_BONEBLADE **** **** **** **** **** **** **** **** +8084 ****_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +8085 ****_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +8086 ****_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +8087 ****_Clarity **** **** **** **** **** **** **** **** +8088 ****_Close_Wounds **** **** **** **** **** **** **** **** +8089 ****_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +8090 ****_Contagion **** **** **** **** **** **** **** **** +8091 ****_Continual_Flame **** **** **** **** **** **** **** **** +8092 ****_Crown_Might **** **** **** **** **** **** **** **** +8093 ****_Crown_Protection **** **** **** **** **** **** **** **** +8094 ****_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +8095 ****_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +8096 ****_Darkfire **** **** **** **** **** **** **** **** +8097 ****_Daylight **** **** **** **** **** **** **** **** +8098 ****_DeeperDarkness **** **** **** **** **** **** **** **** +8099 ****_DEVILS_EYE **** **** **** **** **** **** **** **** +8100 ****_Dispel_Magic **** **** **** **** **** **** **** **** +8101 ****_ENERGIZE_POTION **** **** **** **** **** **** **** **** +8102 ****_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +8103 ****_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +8104 ****_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +8105 ****_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +8106 ****_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +8107 ****_Energy_Aegis **** **** **** **** **** **** **** **** +8108 ****_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +8109 ****_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +8110 ****_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +8111 ****_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +8112 ****_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +8113 ****_FLESH_RIPPER **** **** **** **** **** **** **** **** +8114 ****_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +8115 ****_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +8116 ****_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +8117 ****_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +8118 ****_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +8119 ****_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +8120 ****_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +8121 ****_Invisibility_Purge **** **** **** **** **** **** **** **** +8122 ****_Legions_Conviction **** **** **** **** **** **** **** **** +8123 ****_LocateObject **** **** **** **** **** **** **** **** +8124 ****_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +8125 ****_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +8126 ****_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +8127 ****_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +8128 ****_Magic_Vestment **** **** **** **** **** **** **** **** +8129 ****_MASOCHISM **** **** **** **** **** **** **** **** +8130 ****_Mass_Aid **** **** **** **** **** **** **** **** +8131 ****_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +8132 ****_Necrotic_Bloat **** **** **** **** **** **** **** **** +8133 ****_Negative_Energy_Protection **** **** **** **** **** **** **** **** +8134 ****_ObscureObject **** **** **** **** **** **** **** **** +8135 ****_Prayer **** **** **** **** **** **** **** **** +8136 ****_Protection_from_Elements **** **** **** **** **** **** **** **** +8137 ****_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +8138 ****_Remove_Curse **** **** **** **** **** **** **** **** +8139 ****_Remove_Disease **** **** **** **** **** **** **** **** +8140 ****_RingOfBlades **** **** **** **** **** **** **** **** +8141 ****_Searing_Light **** **** **** **** **** **** **** **** +8142 ****_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8143 ****_SHRIVELING **** **** **** **** **** **** **** **** +8144 ****_Slashing_Darkness **** **** **** **** **** **** **** **** +8145 ****_Summon_Creature_III **** **** **** **** **** **** **** **** +8146 ****_SummonUndeadIII **** **** **** **** **** **** **** **** +8147 ****_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +8148 ****_Vigor **** **** **** **** **** **** **** **** +8149 ****_WaterBreathing **** **** **** **** **** **** **** **** +8150 ****_WRACK **** **** **** **** **** **** **** **** +8151 ****_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +8152 ****_BloodOfTheMartyr **** **** **** **** **** **** **** **** +8153 ****_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +8154 ****_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +8155 ****_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +8156 ****_Death_Ward **** **** **** **** **** **** **** **** +8157 ****_Dimensional_Anchor **** **** **** **** **** **** **** **** +8158 ****_Dismissal **** **** **** **** **** **** **** **** +8159 ****_Divine_Power **** **** **** **** **** **** **** **** +8160 ****_Freedom_of_Movement **** **** **** **** **** **** **** **** +8161 ****_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +8162 ****_Greater_Resistance **** **** **** **** **** **** **** **** +8163 ****_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +8164 ****_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +8165 ****_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +8166 ****_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +8167 ****_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +8168 ****_Mass_Ultravision **** **** **** **** **** **** **** **** +8169 ****_Necrotic_Domination **** **** **** **** **** **** **** **** +8170 ****_Neutralize_Poison **** **** **** **** **** **** **** **** +8171 ****_Panacea **** **** **** **** **** **** **** **** +8172 ****_Poison **** **** **** **** **** **** **** **** +8173 ****_Recitation **** **** **** **** **** **** **** **** +8174 ****_RepelVermin **** **** **** **** **** **** **** **** +8175 ****_Restoration **** **** **** **** **** **** **** **** +8176 ****_STOP_HEART **** **** **** **** **** **** **** **** +8177 ****_Summon_Creature_IV **** **** **** **** **** **** **** **** +8178 ****_SummonUndeadIV **** **** **** **** **** **** **** **** +8179 ****_SwordOfConscience **** **** **** **** **** **** **** **** +8180 ****_Battletide **** **** **** **** **** **** **** **** +8181 ****_BreakEnchantment **** **** **** **** **** **** **** **** +8182 ****_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +8183 ****_Circle_of_Doom **** **** **** **** **** **** **** **** +8184 ****_CONVERT_WAND **** **** **** **** **** **** **** **** +8185 ****_DANCING_WEB **** **** **** **** **** **** **** **** +8186 ****_FireInTheBlood **** **** **** **** **** **** **** **** +8187 ****_Flame_Strike **** **** **** **** **** **** **** **** +8188 ****_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +8189 ****_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +8190 ****_GreaterCommand_Approach **** **** **** **** **** **** **** **** +8191 ****_GreaterCommand_Drop **** **** **** **** **** **** **** **** +8192 ****_GreaterCommand_Fall **** **** **** **** **** **** **** **** +8193 ****_GreaterCommand_Flee **** **** **** **** **** **** **** **** +8194 ****_GreaterCommand_Halt **** **** **** **** **** **** **** **** +8195 ****_Healing_Circle **** **** **** **** **** **** **** **** +8196 ****_HEARTCLUTCH **** **** **** **** **** **** **** **** +8197 ****_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +8198 ****_Mass_Contagion **** **** **** **** **** **** **** **** +8199 ****_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8200 ****_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8201 ****_MORALITY_UNDONE **** **** **** **** **** **** **** **** +8202 ****_Necrotic_Burst **** **** **** **** **** **** **** **** +8203 ****_Raise_Dead **** **** **** **** **** **** **** **** +8204 ****_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +8205 ****_Revivify **** **** **** **** **** **** **** **** +8206 ****_Righteous_Might **** **** **** **** **** **** **** **** +8207 ****_Scrying **** **** **** **** **** **** **** **** +8208 ****_Slay_Living **** **** **** **** **** **** **** **** +8209 ****_Soulscour **** **** **** **** **** **** **** **** +8210 ****_Spell_Resistance **** **** **** **** **** **** **** **** +8211 ****_Summon_Creature_V **** **** **** **** **** **** **** **** +8212 ****_SummonUndeadV **** **** **** **** **** **** **** **** +8213 ****_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +8214 ****_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +8215 ****_True_Seeing **** **** **** **** **** **** **** **** +8216 ****_Animate_Object **** **** **** **** **** **** **** **** +8217 ****_Banishment **** **** **** **** **** **** **** **** +8218 ****_Blade_Barrier **** **** **** **** **** **** **** **** +8219 ****_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +8220 ****_CELESTIAL_BLOOD **** **** **** **** **** **** **** **** +8221 ****_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +8222 ****_Control_Undead **** **** **** **** **** **** **** **** +8223 ****_Create_Undead **** **** **** **** **** **** **** **** +8224 ****_Energy_Immunity **** **** **** **** **** **** **** **** +8225 ****_EI_Acid **** **** **** **** **** **** **** **** +8226 ****_EI_Cold **** **** **** **** **** **** **** **** +8227 ****_EI_Elec **** **** **** **** **** **** **** **** +8228 ****_EI_Fire **** **** **** **** **** **** **** **** +8229 ****_EI_Sonic **** **** **** **** **** **** **** **** +8230 ****_Etherealness **** **** **** **** **** **** **** **** +8231 ****_Greater_Dispelling **** **** **** **** **** **** **** **** +8232 ****_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +8233 ****_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +8234 ****_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +8235 ****_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +8236 ****_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +8237 ****_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +8238 ****_Harm **** **** **** **** **** **** **** **** +8239 ****_Heal **** **** **** **** **** **** **** **** +8240 ****_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +8241 ****_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8242 ****_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +8243 ****_Mass_Endurance **** **** **** **** **** **** **** **** +8244 ****_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +8245 ****_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +8246 ****_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +8247 ****_Necrotic_Eruption **** **** **** **** **** **** **** **** +8248 ****_Planar_Ally **** **** **** **** **** **** **** **** +8249 ****_SarcophagusOfStone **** **** **** **** **** **** **** **** +8250 ****_Summon_Creature_VI **** **** **** **** **** **** **** **** +8251 ****_Superior_Resistance **** **** **** **** **** **** **** **** +8252 ****_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +8253 ****_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +8254 ****_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +8255 ****_Undeath_to_Death **** **** **** **** **** **** **** **** +8256 ****_Vigorous_Circle **** **** **** **** **** **** **** **** +8257 ****_WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +8258 ****_WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +8259 ****_WordOfRecall_Party **** **** **** **** **** **** **** **** +8260 ****_Blasphemy **** **** **** **** **** **** **** **** +8261 ****_Control_Weather **** **** **** **** **** **** **** **** +8262 ****_CW_Rain **** **** **** **** **** **** **** **** +8263 ****_CW_Snow **** **** **** **** **** **** **** **** +8264 ****_CW_Clear **** **** **** **** **** **** **** **** +8265 ****_Destruction **** **** **** **** **** **** **** **** +8266 ****_Dictum **** **** **** **** **** **** **** **** +8267 ****_Energy_Ebb **** **** **** **** **** **** **** **** +8268 ****_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +8269 ****_Greater_Harm **** **** **** **** **** **** **** **** +8270 ****_Greater_Restoration **** **** **** **** **** **** **** **** +8271 ****_GreaterScrying **** **** **** **** **** **** **** **** +8272 ****_Holy_Word **** **** **** **** **** **** **** **** +8273 ****_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +8274 ****_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +8275 ****_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +8276 ****_Regenerate **** **** **** **** **** **** **** **** +8277 ****_Repulsion **** **** **** **** **** **** **** **** +8278 ****_Resurrection **** **** **** **** **** **** **** **** +8279 ****_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +8280 ****_Summon_Creature_VII **** **** **** **** **** **** **** **** +8281 ****_Summon7Air **** **** **** **** **** **** **** **** +8282 ****_Summon7Earth **** **** **** **** **** **** **** **** +8283 ****_Summon7Fire **** **** **** **** **** **** **** **** +8284 ****_Summon7Water **** **** **** **** **** **** **** **** +8285 ****_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +8286 ****_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +8287 ****_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +8288 ****_Word_of_Chaos **** **** **** **** **** **** **** **** +8289 ****_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +8290 ****_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +8291 ****_Aura_versus_Alignment **** **** **** **** **** **** **** **** +8292 ****_Unholy_Aura **** **** **** **** **** **** **** **** +8293 ****_Holy_Aura **** **** **** **** **** **** **** **** +8294 ****_BODAK_BIRTH **** **** **** **** **** **** **** **** +8295 ****_Create_Greater_Undead **** **** **** **** **** **** **** **** +8296 ****_Dimensional_Lock **** **** **** **** **** **** **** **** +8297 ****_DiscernLocation **** **** **** **** **** **** **** **** +8298 ****_Earthquake **** **** **** **** **** **** **** **** +8299 ****_Fire_Storm **** **** **** **** **** **** **** **** +8300 ****_Greater_Planar_Ally **** **** **** **** **** **** **** **** +8301 ****_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +8302 ****_Holy_Aura **** **** **** **** **** **** **** **** +8303 ****_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +8304 ****_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +8305 ****_Mass_Heal **** **** **** **** **** **** **** **** +8306 ****_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +8307 ****_Necrotic_Empowerment **** **** **** **** **** **** **** **** +8308 ****_Pestilence **** **** **** **** **** **** **** **** +8309 ****_Summon_Creature_VIII **** **** **** **** **** **** **** **** +8310 ****_Summon8Air **** **** **** **** **** **** **** **** +8311 ****_Summon8Earth **** **** **** **** **** **** **** **** +8312 ****_Summon8Fire **** **** **** **** **** **** **** **** +8313 ****_Summon8Water **** **** **** **** **** **** **** **** +8314 ****_Sunbeam **** **** **** **** **** **** **** **** +8315 ****_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +8316 ****_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +8317 ****_DESPOIL **** **** **** **** **** **** **** **** +8318 ****_Elder_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +8319 ****_Elder_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +8320 ****_Elder_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +8321 ****_Elder_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +8322 ****_Elder_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +8323 ****_Elder_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +8324 ****_Energy_Drain **** **** **** **** **** **** **** **** +8325 ****_Gate **** **** **** **** **** **** **** **** +8326 ****_Implosion **** **** **** **** **** **** **** **** +8327 ****_Mass_Harm **** **** **** **** **** **** **** **** +8328 ****_Necrotic_Termination **** **** **** **** **** **** **** **** +8329 ****_PlagueOfUndead **** **** **** **** **** **** **** **** +8330 ****_Storm_of_Vengeance **** **** **** **** **** **** **** **** +8331 ****_Summon_Creature_IX **** **** **** **** **** **** **** **** +8332 ****_Summon9Air **** **** **** **** **** **** **** **** +8333 ****_Summon9Earth **** **** **** **** **** **** **** **** +8334 ****_Summon9Fire **** **** **** **** **** **** **** **** +8335 ****_Summon9Water **** **** **** **** **** **** **** **** +8336 ****_True_Resurrection **** **** **** **** **** **** **** **** +8337 ****_Undeaths_Eternal_Foe **** **** **** **** **** **** **** **** +8338 ****_VileDeath **** **** **** **** **** **** **** **** +8339 Archivist_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +8340 Archivist_Quickened_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +8341 Archivist_Silent_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +8342 Archivist_Still_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +8343 Archivist_Flare **** **** **** **** **** **** **** **** +8344 Archivist_Exteneded_Flare **** **** **** **** **** **** **** **** +8345 Archivist_Quickened_Flare **** **** **** **** **** **** **** **** +8346 Archivist_Silent_Flare **** **** **** **** **** **** **** **** +8347 Archivist_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +8348 Archivist_Quickened_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +8349 Archivist_Silent_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +8350 Archivist_Still_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +8351 Archivist_Light **** **** **** **** **** **** **** **** +8352 Archivist_Exteneded_Light **** **** **** **** **** **** **** **** +8353 Archivist_Quickened_Light **** **** **** **** **** **** **** **** +8354 Archivist_Silent_Light **** **** **** **** **** **** **** **** +8355 Archivist_Read_Magic **** **** **** **** **** **** **** **** +8356 Archivist_Quickened_Read_Magic **** **** **** **** **** **** **** **** +8357 Archivist_Silent_Read_Magic **** **** **** **** **** **** **** **** +8358 Archivist_Still_Read_Magic **** **** **** **** **** **** **** **** +8359 Archivist_Resistance **** **** **** **** **** **** **** **** +8360 Archivist_Exteneded_Resistance **** **** **** **** **** **** **** **** +8361 Archivist_Quickened_Resistance **** **** **** **** **** **** **** **** +8362 Archivist_Silent_Resistance **** **** **** **** **** **** **** **** +8363 Archivist_Still_Resistance **** **** **** **** **** **** **** **** +8364 Archivist_Virtue **** **** **** **** **** **** **** **** +8365 Archivist_Exteneded_Virtue **** **** **** **** **** **** **** **** +8366 Archivist_Quickened_Virtue **** **** **** **** **** **** **** **** +8367 Archivist_Silent_Virtue **** **** **** **** **** **** **** **** +8368 Archivist_Still_Virtue **** **** **** **** **** **** **** **** +8369 Archivist_ANGRY_ACHE **** **** **** **** **** **** **** **** +8370 Archivist_Exteneded_ANGRY_ACHE **** **** **** **** **** **** **** **** +8371 Archivist_Quickened_ANGRY_ACHE **** **** **** **** **** **** **** **** +8372 Archivist_Silent_ANGRY_ACHE **** **** **** **** **** **** **** **** +8373 Archivist_Still_ANGRY_ACHE **** **** **** **** **** **** **** **** +8374 Archivist_Bane **** **** **** **** **** **** **** **** +8375 Archivist_Exteneded_Bane **** **** **** **** **** **** **** **** +8376 Archivist_Quickened_Bane **** **** **** **** **** **** **** **** +8377 Archivist_Silent_Bane **** **** **** **** **** **** **** **** +8378 Archivist_Still_Bane **** **** **** **** **** **** **** **** +8379 Archivist_Blade_of_Blood **** **** **** **** **** **** **** **** +8380 Archivist_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8381 Archivist_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8382 Archivist_Empowered_Blade_of_Blood **** **** **** **** **** **** **** **** +8383 Archivist_Empowered_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8384 Archivist_Empowered_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8385 Archivist_Exteneded_Blade_of_Blood **** **** **** **** **** **** **** **** +8386 Archivist_Exteneded_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8387 Archivist_Exteneded_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8388 Archivist_Maximized_Blade_of_Blood **** **** **** **** **** **** **** **** +8389 Archivist_Maximized_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8390 Archivist_Maximized_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8391 Archivist_Quickened_Blade_of_Blood **** **** **** **** **** **** **** **** +8392 Archivist_Quickened_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8393 Archivist_Quickened_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8394 Archivist_Silent_Blade_of_Blood **** **** **** **** **** **** **** **** +8395 Archivist_Silent_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8396 Archivist_Silent_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8397 Archivist_Still_Blade_of_Blood **** **** **** **** **** **** **** **** +8398 Archivist_Still_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +8399 Archivist_Still_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +8400 Archivist_Bless **** **** **** **** **** **** **** **** +8401 Archivist_Exteneded_Bless **** **** **** **** **** **** **** **** +8402 Archivist_Quickened_Bless **** **** **** **** **** **** **** **** +8403 Archivist_Silent_Bless **** **** **** **** **** **** **** **** +8404 Archivist_Still_Bless **** **** **** **** **** **** **** **** +8405 Archivist_Bless_Water **** **** **** **** **** **** **** **** +8406 Archivist_Quickened_Bless_Water **** **** **** **** **** **** **** **** +8407 Archivist_Silent_Bless_Water **** **** **** **** **** **** **** **** +8408 Archivist_Still_Bless_Water **** **** **** **** **** **** **** **** +8409 Archivist_Bless_Weapon **** **** **** **** **** **** **** **** +8410 Archivist_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +8411 Archivist_Quickened_Bless_Weapon **** **** **** **** **** **** **** **** +8412 Archivist_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +8413 Archivist_Still_Bless_Weapon **** **** **** **** **** **** **** **** +8414 Archivist_Camoflage **** **** **** **** **** **** **** **** +8415 Archivist_Exteneded_Camoflage **** **** **** **** **** **** **** **** +8416 Archivist_Quickened_Camoflage **** **** **** **** **** **** **** **** +8417 Archivist_Silent_Camoflage **** **** **** **** **** **** **** **** +8418 Archivist_Still_Camoflage **** **** **** **** **** **** **** **** +8419 Archivist_Cause_Fear **** **** **** **** **** **** **** **** +8420 Archivist_Exteneded_Cause_Fear **** **** **** **** **** **** **** **** +8421 Archivist_Quickened_Cause_Fear **** **** **** **** **** **** **** **** +8422 Archivist_Still_Cause_Fear **** **** **** **** **** **** **** **** +8423 Archivist_Charm_Person **** **** **** **** **** **** **** **** +8424 Archivist_Exteneded_Charm_Person **** **** **** **** **** **** **** **** +8425 Archivist_Quickened_Charm_Person **** **** **** **** **** **** **** **** +8426 Archivist_Silent_Charm_Person **** **** **** **** **** **** **** **** +8427 Archivist_Still_Charm_Person **** **** **** **** **** **** **** **** +8428 Archivist_Color_Spray **** **** **** **** **** **** **** **** +8429 Archivist_Empowered_Color_Spray **** **** **** **** **** **** **** **** +8430 Archivist_Maximized_Color_Spray **** **** **** **** **** **** **** **** +8431 Archivist_Quickened_Color_Spray **** **** **** **** **** **** **** **** +8432 Archivist_Silent_Color_Spray **** **** **** **** **** **** **** **** +8433 Archivist_Still_Color_Spray **** **** **** **** **** **** **** **** +8434 Archivist_Command_RadialMaster **** **** **** **** **** **** **** **** +8435 Archivist_Command_Approach **** **** **** **** **** **** **** **** +8436 Archivist_Command_Drop **** **** **** **** **** **** **** **** +8437 Archivist_Command_Fall **** **** **** **** **** **** **** **** +8438 Archivist_Command_Flee **** **** **** **** **** **** **** **** +8439 Archivist_Command_Halt **** **** **** **** **** **** **** **** +8440 Archivist_Exteneded_Command_RadialMaster **** **** **** **** **** **** **** **** +8441 Archivist_Exteneded_Command_Approach **** **** **** **** **** **** **** **** +8442 Archivist_Exteneded_Command_Drop **** **** **** **** **** **** **** **** +8443 Archivist_Exteneded_Command_Fall **** **** **** **** **** **** **** **** +8444 Archivist_Exteneded_Command_Flee **** **** **** **** **** **** **** **** +8445 Archivist_Exteneded_Command_Halt **** **** **** **** **** **** **** **** +8446 Archivist_Quickened_Command_RadialMaster **** **** **** **** **** **** **** **** +8447 Archivist_Quickened_Command_Approach **** **** **** **** **** **** **** **** +8448 Archivist_Quickened_Command_Drop **** **** **** **** **** **** **** **** +8449 Archivist_Quickened_Command_Fall **** **** **** **** **** **** **** **** +8450 Archivist_Quickened_Command_Flee **** **** **** **** **** **** **** **** +8451 Archivist_Quickened_Command_Halt **** **** **** **** **** **** **** **** +8452 Archivist_Silent_Command_RadialMaster **** **** **** **** **** **** **** **** +8453 Archivist_Silent_Command_Approach **** **** **** **** **** **** **** **** +8454 Archivist_Silent_Command_Drop **** **** **** **** **** **** **** **** +8455 Archivist_Silent_Command_Fall **** **** **** **** **** **** **** **** +8456 Archivist_Silent_Command_Flee **** **** **** **** **** **** **** **** +8457 Archivist_Silent_Command_Halt **** **** **** **** **** **** **** **** +8458 Archivist_Still_Command_RadialMaster **** **** **** **** **** **** **** **** +8459 Archivist_Still_Command_Approach **** **** **** **** **** **** **** **** +8460 Archivist_Still_Command_Drop **** **** **** **** **** **** **** **** +8461 Archivist_Still_Command_Fall **** **** **** **** **** **** **** **** +8462 Archivist_Still_Command_Flee **** **** **** **** **** **** **** **** +8463 Archivist_Still_Command_Halt **** **** **** **** **** **** **** **** +8464 Archivist_Conviction **** **** **** **** **** **** **** **** +8465 Archivist_Exteneded_Conviction **** **** **** **** **** **** **** **** +8466 Archivist_Quickened_Conviction **** **** **** **** **** **** **** **** +8467 Archivist_Silent_Conviction **** **** **** **** **** **** **** **** +8468 Archivist_Still_Conviction **** **** **** **** **** **** **** **** +8469 Archivist_Crafters_Blessing **** **** **** **** **** **** **** **** +8470 Archivist_Exteneded_Crafters_Blessing **** **** **** **** **** **** **** **** +8471 Archivist_Quickened_Crafters_Blessing **** **** **** **** **** **** **** **** +8472 Archivist_Silent_Crafters_Blessing **** **** **** **** **** **** **** **** +8473 Archivist_Still_Crafters_Blessing **** **** **** **** **** **** **** **** +8474 Archivist_Crafters_Curse **** **** **** **** **** **** **** **** +8475 Archivist_Exteneded_Crafters_Curse **** **** **** **** **** **** **** **** +8476 Archivist_Quickened_Crafters_Curse **** **** **** **** **** **** **** **** +8477 Archivist_Silent_Crafters_Curse **** **** **** **** **** **** **** **** +8478 Archivist_Still_Crafters_Curse **** **** **** **** **** **** **** **** +8479 Archivist_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8480 Archivist_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8481 Archivist_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8482 Archivist_Quickened_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8483 Archivist_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8484 Archivist_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +8485 Archivist_Curse_Water **** **** **** **** **** **** **** **** +8486 Archivist_Quickened_Curse_Water **** **** **** **** **** **** **** **** +8487 Archivist_Silent_Curse_Water **** **** **** **** **** **** **** **** +8488 Archivist_Still_Curse_Water **** **** **** **** **** **** **** **** +8489 Archivist_Deafening_Clang **** **** **** **** **** **** **** **** +8490 Archivist_Exteneded_Deafening_Clang **** **** **** **** **** **** **** **** +8491 Archivist_Quickened_Deafening_Clang **** **** **** **** **** **** **** **** +8492 Archivist_Silent_Deafening_Clang **** **** **** **** **** **** **** **** +8493 Archivist_Still_Deafening_Clang **** **** **** **** **** **** **** **** +8494 Archivist_DEMONFLESH **** **** **** **** **** **** **** **** +8495 Archivist_Exteneded_DEMONFLESH **** **** **** **** **** **** **** **** +8496 Archivist_Quickened_DEMONFLESH **** **** **** **** **** **** **** **** +8497 Archivist_Silent_DEMONFLESH **** **** **** **** **** **** **** **** +8498 Archivist_Still_DEMONFLESH **** **** **** **** **** **** **** **** +8499 Archivist_Detect_Chaos **** **** **** **** **** **** **** **** +8500 Archivist_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +8501 Archivist_Quickened_Detect_Chaos **** **** **** **** **** **** **** **** +8502 Archivist_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +8503 Archivist_Still_Detect_Chaos **** **** **** **** **** **** **** **** +8504 Archivist_Detect_Evil **** **** **** **** **** **** **** **** +8505 Archivist_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +8506 Archivist_Quickened_Detect_Evil **** **** **** **** **** **** **** **** +8507 Archivist_Silent_Detect_Evil **** **** **** **** **** **** **** **** +8508 Archivist_Still_Detect_Evil **** **** **** **** **** **** **** **** +8509 Archivist_Detect_Good **** **** **** **** **** **** **** **** +8510 Archivist_Exteneded_Detect_Good **** **** **** **** **** **** **** **** +8511 Archivist_Quickened_Detect_Good **** **** **** **** **** **** **** **** +8512 Archivist_Silent_Detect_Good **** **** **** **** **** **** **** **** +8513 Archivist_Still_Detect_Good **** **** **** **** **** **** **** **** +8514 Archivist_Detect_Law **** **** **** **** **** **** **** **** +8515 Archivist_Exteneded_Detect_Law **** **** **** **** **** **** **** **** +8516 Archivist_Quickened_Detect_Law **** **** **** **** **** **** **** **** +8517 Archivist_Silent_Detect_Law **** **** **** **** **** **** **** **** +8518 Archivist_Still_Detect_Law **** **** **** **** **** **** **** **** +8519 Archivist_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8520 Archivist_Exteneded_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8521 Archivist_Quickened_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8522 Archivist_Silent_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8523 Archivist_Still_DETECT_UNDEAD **** **** **** **** **** **** **** **** +8524 Archivist_DetectFavoredEnemies **** **** **** **** **** **** **** **** +8525 Archivist_Quickened_DetectFavoredEnemies **** **** **** **** **** **** **** **** +8526 Archivist_Silent_DetectFavoredEnemies **** **** **** **** **** **** **** **** +8527 Archivist_Still_DetectFavoredEnemies **** **** **** **** **** **** **** **** +8528 Archivist_Divine_Favor **** **** **** **** **** **** **** **** +8529 Archivist_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +8530 Archivist_Quickened_Divine_Favor **** **** **** **** **** **** **** **** +8531 Archivist_Silent_Divine_Favor **** **** **** **** **** **** **** **** +8532 Archivist_Still_Divine_Favor **** **** **** **** **** **** **** **** +8533 Archivist_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +8534 Archivist_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +8535 Archivist_Quickened_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +8536 Archivist_DIVINE_SACRIFICE **** **** **** **** **** **** **** **** +8537 Archivist_SPELL_DIVINE_SACRIFICE_2 **** **** **** **** **** **** **** **** +8538 Archivist_SPELL_DIVINE_SACRIFICE_4 **** **** **** **** **** **** **** **** +8539 Archivist_SPELL_DIVINE_SACRIFICE_6 **** **** **** **** **** **** **** **** +8540 Archivist_SPELL_DIVINE_SACRIFICE_8 **** **** **** **** **** **** **** **** +8541 Archivist_SPELL_DIVINE_SACRIFICE_10 **** **** **** **** **** **** **** **** +8542 Archivist_Doom **** **** **** **** **** **** **** **** +8543 Archivist_Exteneded_Doom **** **** **** **** **** **** **** **** +8544 Archivist_Quickened_Doom **** **** **** **** **** **** **** **** +8545 Archivist_Silent_Doom **** **** **** **** **** **** **** **** +8546 Archivist_Still_Doom **** **** **** **** **** **** **** **** +8547 Archivist_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +8548 Archivist_Quickened_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +8549 Archivist_Silent_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +8550 Archivist_Endure_Elements **** **** **** **** **** **** **** **** +8551 Archivist_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +8552 Archivist_Quickened_Endure_Elements **** **** **** **** **** **** **** **** +8553 Archivist_Silent_Endure_Elements **** **** **** **** **** **** **** **** +8554 Archivist_Still_Endure_Elements **** **** **** **** **** **** **** **** +8555 Archivist_Entangle **** **** **** **** **** **** **** **** +8556 Archivist_Exteneded_Entangle **** **** **** **** **** **** **** **** +8557 Archivist_Quickened_Entangle **** **** **** **** **** **** **** **** +8558 Archivist_Silent_Entangle **** **** **** **** **** **** **** **** +8559 Archivist_Still_Entangle **** **** **** **** **** **** **** **** +8560 Archivist_Entropic_Shield **** **** **** **** **** **** **** **** +8561 Archivist_Exteneded_Entropic_Shield **** **** **** **** **** **** **** **** +8562 Archivist_Quickened_Entropic_Shield **** **** **** **** **** **** **** **** +8563 Archivist_Silent_Entropic_Shield **** **** **** **** **** **** **** **** +8564 Archivist_Still_Entropic_Shield **** **** **** **** **** **** **** **** +8565 Archivist_Expeditious_Retreat **** **** **** **** **** **** **** **** +8566 Archivist_Exteneded_Expeditious_Retreat **** **** **** **** **** **** **** **** +8567 Archivist_Quickened_Expeditious_Retreat **** **** **** **** **** **** **** **** +8568 Archivist_Silent_Expeditious_Retreat **** **** **** **** **** **** **** **** +8569 Archivist_Still_Expeditious_Retreat **** **** **** **** **** **** **** **** +8570 Archivist_EXTRACT_DRUG **** **** **** **** **** **** **** **** +8571 Archivist_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +8572 Archivist_EXTRACT_VODARE **** **** **** **** **** **** **** **** +8573 Archivist_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +8574 Archivist_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8575 Archivist_Quickened_EXTRACT_DRUG **** **** **** **** **** **** **** **** +8576 Archivist_Quickened_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +8577 Archivist_Quickened_EXTRACT_VODARE **** **** **** **** **** **** **** **** +8578 Archivist_Quickened_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +8579 Archivist_Quickened_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8580 Archivist_Silent_EXTRACT_DRUG **** **** **** **** **** **** **** **** +8581 Archivist_Silent_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +8582 Archivist_Silent_EXTRACT_VODARE **** **** **** **** **** **** **** **** +8583 Archivist_Silent_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +8584 Archivist_Silent_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8585 Archivist_Still_EXTRACT_DRUG **** **** **** **** **** **** **** **** +8586 Archivist_Still_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +8587 Archivist_Still_EXTRACT_VODARE **** **** **** **** **** **** **** **** +8588 Archivist_Still_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +8589 Archivist_Still_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8590 Archivist_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +8591 Archivist_Exteneded_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +8592 Archivist_Quickened_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +8593 Archivist_Still_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +8594 Archivist_Faerie_Fire **** **** **** **** **** **** **** **** +8595 Archivist_Exteneded_Faerie_Fire **** **** **** **** **** **** **** **** +8596 Archivist_Quickened_Faerie_Fire **** **** **** **** **** **** **** **** +8597 Archivist_Silent_Faerie_Fire **** **** **** **** **** **** **** **** +8598 Archivist_Still_Faerie_Fire **** **** **** **** **** **** **** **** +8599 Archivist_Grease **** **** **** **** **** **** **** **** +8600 Archivist_Exteneded_Grease **** **** **** **** **** **** **** **** +8601 Archivist_Quickened_Grease **** **** **** **** **** **** **** **** +8602 Archivist_Silent_Grease **** **** **** **** **** **** **** **** +8603 Archivist_Still_Grease **** **** **** **** **** **** **** **** +8604 Archivist_HEARTACHE **** **** **** **** **** **** **** **** +8605 Archivist_Exteneded_HEARTACHE **** **** **** **** **** **** **** **** +8606 Archivist_Quickened_HEARTACHE **** **** **** **** **** **** **** **** +8607 Archivist_Silent_HEARTACHE **** **** **** **** **** **** **** **** +8608 Archivist_Still_HEARTACHE **** **** **** **** **** **** **** **** +8609 Archivist_HideFromAnimals **** **** **** **** **** **** **** **** +8610 Archivist_Exteneded_HideFromAnimals **** **** **** **** **** **** **** **** +8611 Archivist_Quickened_HideFromAnimals **** **** **** **** **** **** **** **** +8612 Archivist_Still_HideFromAnimals **** **** **** **** **** **** **** **** +8613 Archivist_HideFromUndead **** **** **** **** **** **** **** **** +8614 Archivist_Exteneded_HideFromUndead **** **** **** **** **** **** **** **** +8615 Archivist_Quickened_HideFromUndead **** **** **** **** **** **** **** **** +8616 Archivist_Still_HideFromUndead **** **** **** **** **** **** **** **** +8617 Archivist_Identify **** **** **** **** **** **** **** **** +8618 Archivist_Exteneded_Identify **** **** **** **** **** **** **** **** +8619 Archivist_Quickened_Identify **** **** **** **** **** **** **** **** +8620 Archivist_Silent_Identify **** **** **** **** **** **** **** **** +8621 Archivist_Still_Identify **** **** **** **** **** **** **** **** +8622 Archivist_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8623 Archivist_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8624 Archivist_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8625 Archivist_Quickened_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8626 Archivist_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8627 Archivist_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +8628 Archivist_Spell_Jump **** **** **** **** **** **** **** **** +8629 Archivist_Exteneded_Spell_Jump **** **** **** **** **** **** **** **** +8630 Archivist_Quickened_Spell_Jump **** **** **** **** **** **** **** **** +8631 Archivist_Silent_Spell_Jump **** **** **** **** **** **** **** **** +8632 Archivist_Still_Spell_Jump **** **** **** **** **** **** **** **** +8633 Archivist_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8634 Archivist_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8635 Archivist_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8636 Archivist_Quickened_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8637 Archivist_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +8638 Archivist_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8639 Archivist_Empowered_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8640 Archivist_Exteneded_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8641 Archivist_Maximized_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8642 Archivist_Quickened_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8643 Archivist_Silent_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8644 Archivist_Still_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +8645 Archivist_Lesser_Vigor **** **** **** **** **** **** **** **** +8646 Archivist_Exteneded_Lesser_Vigor **** **** **** **** **** **** **** **** +8647 Archivist_Quickened_Lesser_Vigor **** **** **** **** **** **** **** **** +8648 Archivist_Silent_Lesser_Vigor **** **** **** **** **** **** **** **** +8649 Archivist_Still_Lesser_Vigor **** **** **** **** **** **** **** **** +8650 Archivist_Lionheart **** **** **** **** **** **** **** **** +8651 Archivist_Exteneded_Lionheart **** **** **** **** **** **** **** **** +8652 Archivist_Quickened_Lionheart **** **** **** **** **** **** **** **** +8653 Archivist_Silent_Lionheart **** **** **** **** **** **** **** **** +8654 Archivist_Still_Lionheart **** **** **** **** **** **** **** **** +8655 Archivist_Longstrider **** **** **** **** **** **** **** **** +8656 Archivist_Exteneded_Longstrider **** **** **** **** **** **** **** **** +8657 Archivist_Quickened_Longstrider **** **** **** **** **** **** **** **** +8658 Archivist_Silent_Longstrider **** **** **** **** **** **** **** **** +8659 Archivist_Still_Longstrider **** **** **** **** **** **** **** **** +8660 Archivist_Mage_Armor **** **** **** **** **** **** **** **** +8661 Archivist_Exteneded_Mage_Armor **** **** **** **** **** **** **** **** +8662 Archivist_Quickened_Mage_Armor **** **** **** **** **** **** **** **** +8663 Archivist_Silent_Mage_Armor **** **** **** **** **** **** **** **** +8664 Archivist_Still_Mage_Armor **** **** **** **** **** **** **** **** +8665 Archivist_Magic_Fang **** **** **** **** **** **** **** **** +8666 Archivist_Exteneded_Magic_Fang **** **** **** **** **** **** **** **** +8667 Archivist_Quickened_Magic_Fang **** **** **** **** **** **** **** **** +8668 Archivist_Silent_Magic_Fang **** **** **** **** **** **** **** **** +8669 Archivist_Still_Magic_Fang **** **** **** **** **** **** **** **** +8670 Archivist_Magic_Stone **** **** **** **** **** **** **** **** +8671 Archivist_Exteneded_Magic_Stone **** **** **** **** **** **** **** **** +8672 Archivist_Quickened_Magic_Stone **** **** **** **** **** **** **** **** +8673 Archivist_Silent_Magic_Stone **** **** **** **** **** **** **** **** +8674 Archivist_Still_Magic_Stone **** **** **** **** **** **** **** **** +8675 Archivist_Magic_Weapon **** **** **** **** **** **** **** **** +8676 Archivist_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +8677 Archivist_Quickened_Magic_Weapon **** **** **** **** **** **** **** **** +8678 Archivist_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +8679 Archivist_Still_Magic_Weapon **** **** **** **** **** **** **** **** +8680 Archivist_Necrotic_Awareness **** **** **** **** **** **** **** **** +8681 Archivist_Quickened_Necrotic_Awareness **** **** **** **** **** **** **** **** +8682 Archivist_Silent_Necrotic_Awareness **** **** **** **** **** **** **** **** +8683 Archivist_Still_Necrotic_Awareness **** **** **** **** **** **** **** **** +8684 Archivist_Obscuring_Mist **** **** **** **** **** **** **** **** +8685 Archivist_Exteneded_Obscuring_Mist **** **** **** **** **** **** **** **** +8686 Archivist_Quickened_Obscuring_Mist **** **** **** **** **** **** **** **** +8687 Archivist_Silent_Obscuring_Mist **** **** **** **** **** **** **** **** +8688 Archivist_Still_Obscuring_Mist **** **** **** **** **** **** **** **** +8689 Archivist_Protection_from_Chaos **** **** **** **** **** **** **** **** +8690 Archivist_Exteneded_Protection_from_Chaos **** **** **** **** **** **** **** **** +8691 Archivist_Quickened_Protection_from_Chaos **** **** **** **** **** **** **** **** +8692 Archivist_Silent_Protection_from_Chaos **** **** **** **** **** **** **** **** +8693 Archivist_Still_Protection_from_Chaos **** **** **** **** **** **** **** **** +8694 Archivist_Protection_from_Evil **** **** **** **** **** **** **** **** +8695 Archivist_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +8696 Archivist_Quickened_Protection_from_Evil **** **** **** **** **** **** **** **** +8697 Archivist_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +8698 Archivist_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +8699 Archivist_Protection_from_Good **** **** **** **** **** **** **** **** +8700 Archivist_Exteneded_Protection_from_Good **** **** **** **** **** **** **** **** +8701 Archivist_Quickened_Protection_from_Good **** **** **** **** **** **** **** **** +8702 Archivist_Silent_Protection_from_Good **** **** **** **** **** **** **** **** +8703 Archivist_Still_Protection_from_Good **** **** **** **** **** **** **** **** +8704 Archivist_Protection_from_Law **** **** **** **** **** **** **** **** +8705 Archivist_Exteneded_Protection_from_Law **** **** **** **** **** **** **** **** +8706 Archivist_Quickened_Protection_from_Law **** **** **** **** **** **** **** **** +8707 Archivist_Silent_Protection_from_Law **** **** **** **** **** **** **** **** +8708 Archivist_Still_Protection_from_Law **** **** **** **** **** **** **** **** +8709 Archivist_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8710 Archivist_Exteneded_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8711 Archivist_Quickened_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8712 Archivist_Silent_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8713 Archivist_Still_RAY_OF_HOPE **** **** **** **** **** **** **** **** +8714 Archivist_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8715 Archivist_Empowered_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8716 Archivist_Exteneded_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8717 Archivist_Maximized_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8718 Archivist_Quickened_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8719 Archivist_Silent_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8720 Archivist_Still_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +8721 Archivist_Remove_Fear **** **** **** **** **** **** **** **** +8722 Archivist_Exteneded_Remove_Fear **** **** **** **** **** **** **** **** +8723 Archivist_Quickened_Remove_Fear **** **** **** **** **** **** **** **** +8724 Archivist_Silent_Remove_Fear **** **** **** **** **** **** **** **** +8725 Archivist_Still_Remove_Fear **** **** **** **** **** **** **** **** +8726 Archivist_Sanctuary **** **** **** **** **** **** **** **** +8727 Archivist_Exteneded_Sanctuary **** **** **** **** **** **** **** **** +8728 Archivist_Quickened_Sanctuary **** **** **** **** **** **** **** **** +8729 Archivist_Silent_Sanctuary **** **** **** **** **** **** **** **** +8730 Archivist_Still_Sanctuary **** **** **** **** **** **** **** **** +8731 Archivist_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +8732 Archivist_Quickened_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +8733 Archivist_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +8734 Archivist_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +8735 Archivist_Shield **** **** **** **** **** **** **** **** +8736 Archivist_Exteneded_Shield **** **** **** **** **** **** **** **** +8737 Archivist_Quickened_Shield **** **** **** **** **** **** **** **** +8738 Archivist_Silent_Shield **** **** **** **** **** **** **** **** +8739 Archivist_Still_Shield **** **** **** **** **** **** **** **** +8740 Archivist_Shield_of_Faith **** **** **** **** **** **** **** **** +8741 Archivist_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +8742 Archivist_Quickened_Shield_of_Faith **** **** **** **** **** **** **** **** +8743 Archivist_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +8744 Archivist_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +8745 Archivist_Shillelagh **** **** **** **** **** **** **** **** +8746 Archivist_Exteneded_Shillelagh **** **** **** **** **** **** **** **** +8747 Archivist_Quickened_Shillelagh **** **** **** **** **** **** **** **** +8748 Archivist_Silent_Shillelagh **** **** **** **** **** **** **** **** +8749 Archivist_Still_Shillelagh **** **** **** **** **** **** **** **** +8750 Archivist_Sleep **** **** **** **** **** **** **** **** +8751 Archivist_Empowered_Sleep **** **** **** **** **** **** **** **** +8752 Archivist_Exteneded_Sleep **** **** **** **** **** **** **** **** +8753 Archivist_Maximized_Sleep **** **** **** **** **** **** **** **** +8754 Archivist_Quickened_Sleep **** **** **** **** **** **** **** **** +8755 Archivist_Silent_Sleep **** **** **** **** **** **** **** **** +8756 Archivist_Still_Sleep **** **** **** **** **** **** **** **** +8757 Archivist_Snillocs_Snowball **** **** **** **** **** **** **** **** +8758 Archivist_Empowered_Snillocs_Snowball **** **** **** **** **** **** **** **** +8759 Archivist_Maximized_Snillocs_Snowball **** **** **** **** **** **** **** **** +8760 Archivist_Quickened_Snillocs_Snowball **** **** **** **** **** **** **** **** +8761 Archivist_Silent_Snillocs_Snowball **** **** **** **** **** **** **** **** +8762 Archivist_Still_Snillocs_Snowball **** **** **** **** **** **** **** **** +8763 Archivist_SORROW **** **** **** **** **** **** **** **** +8764 Archivist_Quickened_SORROW **** **** **** **** **** **** **** **** +8765 Archivist_Silent_SORROW **** **** **** **** **** **** **** **** +8766 Archivist_Still_SORROW **** **** **** **** **** **** **** **** +8767 Archivist_Summon_Creature_I **** **** **** **** **** **** **** **** +8768 Archivist_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +8769 Archivist_Quickened_Summon_Creature_I **** **** **** **** **** **** **** **** +8770 Archivist_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +8771 Archivist_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +8772 Archivist_SummonUndeadI **** **** **** **** **** **** **** **** +8773 Archivist_Exteneded_SummonUndeadI **** **** **** **** **** **** **** **** +8774 Archivist_Quickened_SummonUndeadI **** **** **** **** **** **** **** **** +8775 Archivist_Silent_SummonUndeadI **** **** **** **** **** **** **** **** +8776 Archivist_Still_SummonUndeadI **** **** **** **** **** **** **** **** +8777 Archivist_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8778 Archivist_Exteneded_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8779 Archivist_Quickened_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8780 Archivist_Silent_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8781 Archivist_Still_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +8782 Archivist_ToweringOak **** **** **** **** **** **** **** **** +8783 Archivist_Exteneded_ToweringOak **** **** **** **** **** **** **** **** +8784 Archivist_Quickened_ToweringOak **** **** **** **** **** **** **** **** +8785 Archivist_Silent_ToweringOak **** **** **** **** **** **** **** **** +8786 Archivist_Still_ToweringOak **** **** **** **** **** **** **** **** +8787 Archivist_True_Strike **** **** **** **** **** **** **** **** +8788 Archivist_Quickened_True_Strike **** **** **** **** **** **** **** **** +8789 Archivist_Silent_True_Strike **** **** **** **** **** **** **** **** +8790 Archivist_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +8791 Archivist_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +8792 Archivist_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +8793 Archivist_VisionOfHeaven **** **** **** **** **** **** **** **** +8794 Archivist_Exteneded_VisionOfHeaven **** **** **** **** **** **** **** **** +8795 Archivist_Quickened_VisionOfHeaven **** **** **** **** **** **** **** **** +8796 Archivist_Silent_VisionOfHeaven **** **** **** **** **** **** **** **** +8797 Archivist_ADDICTION **** **** **** **** **** **** **** **** +8798 Archivist_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +8799 Archivist_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8800 Archivist_ADDICTION_VODARE **** **** **** **** **** **** **** **** +8801 Archivist_ADDICTION_AGONY **** **** **** **** **** **** **** **** +8802 Archivist_Quickened_ADDICTION **** **** **** **** **** **** **** **** +8803 Archivist_Quickened_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +8804 Archivist_Quickened_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8805 Archivist_Quickened_ADDICTION_VODARE **** **** **** **** **** **** **** **** +8806 Archivist_Quickened_ADDICTION_AGONY **** **** **** **** **** **** **** **** +8807 Archivist_Silent_ADDICTION **** **** **** **** **** **** **** **** +8808 Archivist_Silent_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +8809 Archivist_Silent_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8810 Archivist_Silent_ADDICTION_VODARE **** **** **** **** **** **** **** **** +8811 Archivist_Silent_ADDICTION_AGONY **** **** **** **** **** **** **** **** +8812 Archivist_Still_ADDICTION **** **** **** **** **** **** **** **** +8813 Archivist_Still_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +8814 Archivist_Still_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +8815 Archivist_Still_ADDICTION_VODARE **** **** **** **** **** **** **** **** +8816 Archivist_Still_ADDICTION_AGONY **** **** **** **** **** **** **** **** +8817 Archivist_Aid **** **** **** **** **** **** **** **** +8818 Archivist_Empowered_Aid **** **** **** **** **** **** **** **** +8819 Archivist_Exteneded_Aid **** **** **** **** **** **** **** **** +8820 Archivist_Maximized_Aid **** **** **** **** **** **** **** **** +8821 Archivist_Quickened_Aid **** **** **** **** **** **** **** **** +8822 Archivist_Silent_Aid **** **** **** **** **** **** **** **** +8823 Archivist_Still_Aid **** **** **** **** **** **** **** **** +8824 Archivist_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +8825 Archivist_Alter_Self_Learn **** **** **** **** **** **** **** **** +8826 Archivist_Alter_Self_Options **** **** **** **** **** **** **** **** +8827 Archivist_Alter_Self_QS1 **** **** **** **** **** **** **** **** +8828 Archivist_Alter_Self_QS2 **** **** **** **** **** **** **** **** +8829 Archivist_Alter_Self_QS3 **** **** **** **** **** **** **** **** +8830 Archivist_Exteneded_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +8831 Archivist_Exteneded_Alter_Self_Learn **** **** **** **** **** **** **** **** +8832 Archivist_Exteneded_Alter_Self_Options **** **** **** **** **** **** **** **** +8833 Archivist_Exteneded_Alter_Self_QS1 **** **** **** **** **** **** **** **** +8834 Archivist_Exteneded_Alter_Self_QS2 **** **** **** **** **** **** **** **** +8835 Archivist_Exteneded_Alter_Self_QS3 **** **** **** **** **** **** **** **** +8836 Archivist_Quickened_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +8837 Archivist_Quickened_Alter_Self_Learn **** **** **** **** **** **** **** **** +8838 Archivist_Quickened_Alter_Self_Options **** **** **** **** **** **** **** **** +8839 Archivist_Quickened_Alter_Self_QS1 **** **** **** **** **** **** **** **** +8840 Archivist_Quickened_Alter_Self_QS2 **** **** **** **** **** **** **** **** +8841 Archivist_Quickened_Alter_Self_QS3 **** **** **** **** **** **** **** **** +8842 Archivist_Silent_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +8843 Archivist_Silent_Alter_Self_Learn **** **** **** **** **** **** **** **** +8844 Archivist_Silent_Alter_Self_Options **** **** **** **** **** **** **** **** +8845 Archivist_Silent_Alter_Self_QS1 **** **** **** **** **** **** **** **** +8846 Archivist_Silent_Alter_Self_QS2 **** **** **** **** **** **** **** **** +8847 Archivist_Silent_Alter_Self_QS3 **** **** **** **** **** **** **** **** +8848 Archivist_Still_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +8849 Archivist_Still_Alter_Self_Learn **** **** **** **** **** **** **** **** +8850 Archivist_Still_Alter_Self_Options **** **** **** **** **** **** **** **** +8851 Archivist_Still_Alter_Self_QS1 **** **** **** **** **** **** **** **** +8852 Archivist_Still_Alter_Self_QS2 **** **** **** **** **** **** **** **** +8853 Archivist_Still_Alter_Self_QS3 **** **** **** **** **** **** **** **** +8854 Archivist_Animalistic_Power **** **** **** **** **** **** **** **** +8855 Archivist_Exteneded_Animalistic_Power **** **** **** **** **** **** **** **** +8856 Archivist_AuraOfGlory **** **** **** **** **** **** **** **** +8857 Archivist_Exteneded_AuraOfGlory **** **** **** **** **** **** **** **** +8858 Archivist_Quickened_AuraOfGlory **** **** **** **** **** **** **** **** +8859 Archivist_Silent_AuraOfGlory **** **** **** **** **** **** **** **** +8860 Archivist_Still_AuraOfGlory **** **** **** **** **** **** **** **** +8861 Archivist_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8862 Archivist_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8863 Archivist_Maximized_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8864 Archivist_Quickened_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8865 Archivist_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8866 Archivist_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +8867 Archivist_Barkskin **** **** **** **** **** **** **** **** +8868 Archivist_Exteneded_Barkskin **** **** **** **** **** **** **** **** +8869 Archivist_Quickened_Barkskin **** **** **** **** **** **** **** **** +8870 Archivist_Silent_Barkskin **** **** **** **** **** **** **** **** +8871 Archivist_Still_Barkskin **** **** **** **** **** **** **** **** +8872 Archivist_Benign_Transposition **** **** **** **** **** **** **** **** +8873 Archivist_Quickened_Benign_Transposition **** **** **** **** **** **** **** **** +8874 Archivist_Silent_Benign_Transposition **** **** **** **** **** **** **** **** +8875 Archivist_BladesOfFire **** **** **** **** **** **** **** **** +8876 Archivist_Exteneded_BladesOfFire **** **** **** **** **** **** **** **** +8877 Archivist_Quickened_BladesOfFire **** **** **** **** **** **** **** **** +8878 Archivist_Silent_BladesOfFire **** **** **** **** **** **** **** **** +8879 Archivist_Blood_Frenzy **** **** **** **** **** **** **** **** +8880 Archivist_Exteneded_Blood_Frenzy **** **** **** **** **** **** **** **** +8881 Archivist_Quickened_Blood_Frenzy **** **** **** **** **** **** **** **** +8882 Archivist_Silent_Blood_Frenzy **** **** **** **** **** **** **** **** +8883 Archivist_Still_Blood_Frenzy **** **** **** **** **** **** **** **** +8884 Archivist_Blur **** **** **** **** **** **** **** **** +8885 Archivist_Exteneded_Blur **** **** **** **** **** **** **** **** +8886 Archivist_Quickened_Blur **** **** **** **** **** **** **** **** +8887 Archivist_Silent_Blur **** **** **** **** **** **** **** **** +8888 Archivist_BONEBLAST **** **** **** **** **** **** **** **** +8889 Archivist_Quickened_BONEBLAST **** **** **** **** **** **** **** **** +8890 Archivist_Silent_BONEBLAST **** **** **** **** **** **** **** **** +8891 Archivist_Still_BONEBLAST **** **** **** **** **** **** **** **** +8892 Archivist_BrilliantEnergyArrows **** **** **** **** **** **** **** **** +8893 Archivist_Quickened_BrilliantEnergyArrows **** **** **** **** **** **** **** **** +8894 Archivist_Silent_BrilliantEnergyArrows **** **** **** **** **** **** **** **** +8895 Archivist_Bulls_Strength **** **** **** **** **** **** **** **** +8896 Archivist_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +8897 Archivist_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +8898 Archivist_Maximized_Bulls_Strength **** **** **** **** **** **** **** **** +8899 Archivist_Quickened_Bulls_Strength **** **** **** **** **** **** **** **** +8900 Archivist_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +8901 Archivist_Still_Bulls_Strength **** **** **** **** **** **** **** **** +8902 Archivist_Burning_Bolt **** **** **** **** **** **** **** **** +8903 Archivist_Empowered_Burning_Bolt **** **** **** **** **** **** **** **** +8904 Archivist_Maximized_Burning_Bolt **** **** **** **** **** **** **** **** +8905 Archivist_Quickened_Burning_Bolt **** **** **** **** **** **** **** **** +8906 Archivist_Silent_Burning_Bolt **** **** **** **** **** **** **** **** +8907 Archivist_Still_Burning_Bolt **** **** **** **** **** **** **** **** +8908 Archivist_Calm_Emotions **** **** **** **** **** **** **** **** +8909 Archivist_Exteneded_Calm_Emotions **** **** **** **** **** **** **** **** +8910 Archivist_Quickened_Calm_Emotions **** **** **** **** **** **** **** **** +8911 Archivist_Silent_Calm_Emotions **** **** **** **** **** **** **** **** +8912 Archivist_Still_Calm_Emotions **** **** **** **** **** **** **** **** +8913 Archivist_Cats_Grace **** **** **** **** **** **** **** **** +8914 Archivist_Empowered_Cats_Grace **** **** **** **** **** **** **** **** +8915 Archivist_Exteneded_Cats_Grace **** **** **** **** **** **** **** **** +8916 Archivist_Maximized_Cats_Grace **** **** **** **** **** **** **** **** +8917 Archivist_Quickened_Cats_Grace **** **** **** **** **** **** **** **** +8918 Archivist_Silent_Cats_Grace **** **** **** **** **** **** **** **** +8919 Archivist_Still_Cats_Grace **** **** **** **** **** **** **** **** +8920 Archivist_Charm_Person_or_Animal **** **** **** **** **** **** **** **** +8921 Archivist_Exteneded_Charm_Person_or_Animal **** **** **** **** **** **** **** **** +8922 Archivist_Quickened_Charm_Person_or_Animal **** **** **** **** **** **** **** **** +8923 Archivist_Silent_Charm_Person_or_Animal **** **** **** **** **** **** **** **** +8924 Archivist_Still_Charm_Person_or_Animal **** **** **** **** **** **** **** **** +8925 Archivist_Clarity_of_Mind **** **** **** **** **** **** **** **** +8926 Archivist_Exteneded_Clarity_of_Mind **** **** **** **** **** **** **** **** +8927 Archivist_Quickened_Clarity_of_Mind **** **** **** **** **** **** **** **** +8928 Archivist_Silent_Clarity_of_Mind **** **** **** **** **** **** **** **** +8929 Archivist_Still_Clarity_of_Mind **** **** **** **** **** **** **** **** +8930 Archivist_Consecrated_Aura **** **** **** **** **** **** **** **** +8931 Archivist_Exteneded_Consecrated_Aura **** **** **** **** **** **** **** **** +8932 Archivist_Quickened_Consecrated_Aura **** **** **** **** **** **** **** **** +8933 Archivist_Silent_Consecrated_Aura **** **** **** **** **** **** **** **** +8934 Archivist_Still_Consecrated_Aura **** **** **** **** **** **** **** **** +8935 Archivist_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8936 Archivist_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8937 Archivist_Maximized_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8938 Archivist_Quickened_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8939 Archivist_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8940 Archivist_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +8941 Archivist_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +8942 Archivist_Exteneded_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +8943 Archivist_Quickened_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +8944 Archivist_Silent_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +8945 Archivist_Still_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +8946 Archivist_Darkness **** **** **** **** **** **** **** **** +8947 Archivist_Exteneded_Darkness **** **** **** **** **** **** **** **** +8948 Archivist_Quickened_Darkness **** **** **** **** **** **** **** **** +8949 Archivist_Silent_Darkness **** **** **** **** **** **** **** **** +8950 Archivist_Death_Armor **** **** **** **** **** **** **** **** +8951 Archivist_Exteneded_Death_Armor **** **** **** **** **** **** **** **** +8952 Archivist_Quickened_Death_Armor **** **** **** **** **** **** **** **** +8953 Archivist_Silent_Death_Armor **** **** **** **** **** **** **** **** +8954 Archivist_Still_Death_Armor **** **** **** **** **** **** **** **** +8955 Archivist_Death_Knell **** **** **** **** **** **** **** **** +8956 Archivist_Empowered_Death_Knell **** **** **** **** **** **** **** **** +8957 Archivist_Exteneded_Death_Knell **** **** **** **** **** **** **** **** +8958 Archivist_Maximized_Death_Knell **** **** **** **** **** **** **** **** +8959 Archivist_Quickened_Death_Knell **** **** **** **** **** **** **** **** +8960 Archivist_Silent_Death_Knell **** **** **** **** **** **** **** **** +8961 Archivist_Still_Death_Knell **** **** **** **** **** **** **** **** +8962 Archivist_DEMONCALL **** **** **** **** **** **** **** **** +8963 Archivist_Quickened_DEMONCALL **** **** **** **** **** **** **** **** +8964 Archivist_Silent_DEMONCALL **** **** **** **** **** **** **** **** +8965 Archivist_Still_DEMONCALL **** **** **** **** **** **** **** **** +8966 Archivist_Divine_Protection **** **** **** **** **** **** **** **** +8967 Archivist_Exteneded_Divine_Protection **** **** **** **** **** **** **** **** +8968 Archivist_Quickened_Divine_Protection **** **** **** **** **** **** **** **** +8969 Archivist_Silent_Divine_Protection **** **** **** **** **** **** **** **** +8970 Archivist_Still_Divine_Protection **** **** **** **** **** **** **** **** +8971 Archivist_Eagle_Splendor **** **** **** **** **** **** **** **** +8972 Archivist_Empowered_Eagle_Splendor **** **** **** **** **** **** **** **** +8973 Archivist_Exteneded_Eagle_Splendor **** **** **** **** **** **** **** **** +8974 Archivist_Maximized_Eagle_Splendor **** **** **** **** **** **** **** **** +8975 Archivist_Quickened_Eagle_Splendor **** **** **** **** **** **** **** **** +8976 Archivist_Silent_Eagle_Splendor **** **** **** **** **** **** **** **** +8977 Archivist_Still_Eagle_Splendor **** **** **** **** **** **** **** **** +8978 Archivist_ELATION **** **** **** **** **** **** **** **** +8979 Archivist_Exteneded_ELATION **** **** **** **** **** **** **** **** +8980 Archivist_Quickened_ELATION **** **** **** **** **** **** **** **** +8981 Archivist_Silent_ELATION **** **** **** **** **** **** **** **** +8982 Archivist_Still_ELATION **** **** **** **** **** **** **** **** +8983 Archivist_Endurance **** **** **** **** **** **** **** **** +8984 Archivist_Empowered_Endurance **** **** **** **** **** **** **** **** +8985 Archivist_Exteneded_Endurance **** **** **** **** **** **** **** **** +8986 Archivist_Maximized_Endurance **** **** **** **** **** **** **** **** +8987 Archivist_Quickened_Endurance **** **** **** **** **** **** **** **** +8988 Archivist_Silent_Endurance **** **** **** **** **** **** **** **** +8989 Archivist_Still_Endurance **** **** **** **** **** **** **** **** +8990 Archivist_Find_Traps **** **** **** **** **** **** **** **** +8991 Archivist_Exteneded_Find_Traps **** **** **** **** **** **** **** **** +8992 Archivist_Quickened_Find_Traps **** **** **** **** **** **** **** **** +8993 Archivist_Silent_Find_Traps **** **** **** **** **** **** **** **** +8994 Archivist_Still_Find_Traps **** **** **** **** **** **** **** **** +8995 Archivist_FireTrap **** **** **** **** **** **** **** **** +8996 Archivist_Empowered_FireTrap **** **** **** **** **** **** **** **** +8997 Archivist_Maximized_FireTrap **** **** **** **** **** **** **** **** +8998 Archivist_Quickened_FireTrap **** **** **** **** **** **** **** **** +8999 Archivist_Silent_FireTrap **** **** **** **** **** **** **** **** +9000 Archivist_Still_FireTrap **** **** **** **** **** **** **** **** +9001 Archivist_Flame_Lash **** **** **** **** **** **** **** **** +9002 Archivist_Empowered_Flame_Lash **** **** **** **** **** **** **** **** +9003 Archivist_Maximized_Flame_Lash **** **** **** **** **** **** **** **** +9004 Archivist_Quickened_Flame_Lash **** **** **** **** **** **** **** **** +9005 Archivist_Silent_Flame_Lash **** **** **** **** **** **** **** **** +9006 Archivist_Still_Flame_Lash **** **** **** **** **** **** **** **** +9007 Archivist_FogCloud **** **** **** **** **** **** **** **** +9008 Archivist_Exteneded_FogCloud **** **** **** **** **** **** **** **** +9009 Archivist_Quickened_FogCloud **** **** **** **** **** **** **** **** +9010 Archivist_Silent_FogCloud **** **** **** **** **** **** **** **** +9011 Archivist_Foxs_Cunning **** **** **** **** **** **** **** **** +9012 Archivist_Empowered_Foxs_Cunning **** **** **** **** **** **** **** **** +9013 Archivist_Exteneded_Foxs_Cunning **** **** **** **** **** **** **** **** +9014 Archivist_Maximized_Foxs_Cunning **** **** **** **** **** **** **** **** +9015 Archivist_Quickened_Foxs_Cunning **** **** **** **** **** **** **** **** +9016 Archivist_Silent_Foxs_Cunning **** **** **** **** **** **** **** **** +9017 Archivist_Still_Foxs_Cunning **** **** **** **** **** **** **** **** +9018 Archivist_Ghoul_Touch **** **** **** **** **** **** **** **** +9019 Archivist_Exteneded_Ghoul_Touch **** **** **** **** **** **** **** **** +9020 Archivist_Quickened_Ghoul_Touch **** **** **** **** **** **** **** **** +9021 Archivist_Silent_Ghoul_Touch **** **** **** **** **** **** **** **** +9022 Archivist_Still_Ghoul_Touch **** **** **** **** **** **** **** **** +9023 Archivist_Hold_Animal **** **** **** **** **** **** **** **** +9024 Archivist_Exteneded_Hold_Animal **** **** **** **** **** **** **** **** +9025 Archivist_Quickened_Hold_Animal **** **** **** **** **** **** **** **** +9026 Archivist_Silent_Hold_Animal **** **** **** **** **** **** **** **** +9027 Archivist_Still_Hold_Animal **** **** **** **** **** **** **** **** +9028 Archivist_Hold_Person **** **** **** **** **** **** **** **** +9029 Archivist_Exteneded_Hold_Person **** **** **** **** **** **** **** **** +9030 Archivist_Quickened_Hold_Person **** **** **** **** **** **** **** **** +9031 Archivist_Silent_Hold_Person **** **** **** **** **** **** **** **** +9032 Archivist_Still_Hold_Person **** **** **** **** **** **** **** **** +9033 Archivist_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9034 Archivist_Empowered_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9035 Archivist_Maximized_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9036 Archivist_Quickened_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9037 Archivist_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9038 Archivist_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +9039 Archivist_Knock **** **** **** **** **** **** **** **** +9040 Archivist_Quickened_Knock **** **** **** **** **** **** **** **** +9041 Archivist_Still_Knock **** **** **** **** **** **** **** **** +9042 Archivist_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +9043 Archivist_Quickened_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +9044 Archivist_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +9045 Archivist_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +9046 Archivist_Lesser_Dispel **** **** **** **** **** **** **** **** +9047 Archivist_Silent_Lesser_Dispel **** **** **** **** **** **** **** **** +9048 Archivist_Still_Lesser_Dispel **** **** **** **** **** **** **** **** +9049 Archivist_Lesser_Restoration **** **** **** **** **** **** **** **** +9050 Archivist_Quickened_Lesser_Restoration **** **** **** **** **** **** **** **** +9051 Archivist_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +9052 Archivist_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +9053 Archivist_Living_Undeath **** **** **** **** **** **** **** **** +9054 Archivist_Exteneded_Living_Undeath **** **** **** **** **** **** **** **** +9055 Archivist_Quickened_Living_Undeath **** **** **** **** **** **** **** **** +9056 Archivist_Silent_Living_Undeath **** **** **** **** **** **** **** **** +9057 Archivist_Still_Living_Undeath **** **** **** **** **** **** **** **** +9058 Archivist_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9059 Archivist_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9060 Archivist_Quickened_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9061 Archivist_Magic_Missile **** **** **** **** **** **** **** **** +9062 Archivist_Empowered_Magic_Missile **** **** **** **** **** **** **** **** +9063 Archivist_Maximized_Magic_Missile **** **** **** **** **** **** **** **** +9064 Archivist_Quickened_Magic_Missile **** **** **** **** **** **** **** **** +9065 Archivist_Silent_Magic_Missile **** **** **** **** **** **** **** **** +9066 Archivist_Still_Magic_Missile **** **** **** **** **** **** **** **** +9067 Archivist_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9068 Archivist_Empowered_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9069 Archivist_Maximized_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9070 Archivist_Quickened_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9071 Archivist_Silent_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9072 Archivist_Still_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +9073 Archivist_Necrotic_Cyst **** **** **** **** **** **** **** **** +9074 Archivist_Quickened_Necrotic_Cyst **** **** **** **** **** **** **** **** +9075 Archivist_Silent_Necrotic_Cyst **** **** **** **** **** **** **** **** +9076 Archivist_Still_Necrotic_Cyst **** **** **** **** **** **** **** **** +9077 Archivist_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9078 Archivist_Empowered_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9079 Archivist_Maximized_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9080 Archivist_Quickened_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9081 Archivist_Silent_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9082 Archivist_Still_Negative_Energy_Ray **** **** **** **** **** **** **** **** +9083 Archivist_One_With_The_Land **** **** **** **** **** **** **** **** +9084 Archivist_Exteneded_One_With_The_Land **** **** **** **** **** **** **** **** +9085 Archivist_Quickened_One_With_The_Land **** **** **** **** **** **** **** **** +9086 Archivist_Silent_One_With_The_Land **** **** **** **** **** **** **** **** +9087 Archivist_Still_One_With_The_Land **** **** **** **** **** **** **** **** +9088 Archivist_Owls_Wisdom **** **** **** **** **** **** **** **** +9089 Archivist_Empowered_Owls_Wisdom **** **** **** **** **** **** **** **** +9090 Archivist_Exteneded_Owls_Wisdom **** **** **** **** **** **** **** **** +9091 Archivist_Maximized_Owls_Wisdom **** **** **** **** **** **** **** **** +9092 Archivist_Quickened_Owls_Wisdom **** **** **** **** **** **** **** **** +9093 Archivist_Silent_Owls_Wisdom **** **** **** **** **** **** **** **** +9094 Archivist_Still_Owls_Wisdom **** **** **** **** **** **** **** **** +9095 Archivist_Remove_Paralysis **** **** **** **** **** **** **** **** +9096 Archivist_Quickened_Remove_Paralysis **** **** **** **** **** **** **** **** +9097 Archivist_Silent_Remove_Paralysis **** **** **** **** **** **** **** **** +9098 Archivist_Still_Remove_Paralysis **** **** **** **** **** **** **** **** +9099 Archivist_Resist_Elements **** **** **** **** **** **** **** **** +9100 Archivist_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +9101 Archivist_Quickened_Resist_Elements **** **** **** **** **** **** **** **** +9102 Archivist_Silent_Resist_Elements **** **** **** **** **** **** **** **** +9103 Archivist_Still_Resist_Elements **** **** **** **** **** **** **** **** +9104 Archivist_ShieldOther **** **** **** **** **** **** **** **** +9105 Archivist_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +9106 Archivist_Quickened_ShieldOther **** **** **** **** **** **** **** **** +9107 Archivist_Silent_ShieldOther **** **** **** **** **** **** **** **** +9108 Archivist_Still_ShieldOther **** **** **** **** **** **** **** **** +9109 Archivist_Silence **** **** **** **** **** **** **** **** +9110 Archivist_Exteneded_Silence **** **** **** **** **** **** **** **** +9111 Archivist_Quickened_Silence **** **** **** **** **** **** **** **** +9112 Archivist_Silent_Silence **** **** **** **** **** **** **** **** +9113 Archivist_Still_Silence **** **** **** **** **** **** **** **** +9114 Archivist_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9115 Archivist_Empowered_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9116 Archivist_Maximized_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9117 Archivist_Quickened_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9118 Archivist_Silent_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9119 Archivist_Still_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +9120 Archivist_Sound_Burst **** **** **** **** **** **** **** **** +9121 Archivist_Maximized_Sound_Burst **** **** **** **** **** **** **** **** +9122 Archivist_Quickened_Sound_Burst **** **** **** **** **** **** **** **** +9123 Archivist_Silent_Sound_Burst **** **** **** **** **** **** **** **** +9124 Archivist_Still_Sound_Burst **** **** **** **** **** **** **** **** +9125 Archivist_SpellslayerArrow **** **** **** **** **** **** **** **** +9126 Archivist_Silent_SpellslayerArrow **** **** **** **** **** **** **** **** +9127 Archivist_Still_SpellslayerArrow **** **** **** **** **** **** **** **** +9128 Archivist_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9129 Archivist_Empowered_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9130 Archivist_Maximized_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9131 Archivist_Quickened_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9132 Archivist_Silent_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9133 Archivist_Still_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +9134 Archivist_Stone_Bones **** **** **** **** **** **** **** **** +9135 Archivist_Exteneded_Stone_Bones **** **** **** **** **** **** **** **** +9136 Archivist_Quickened_Stone_Bones **** **** **** **** **** **** **** **** +9137 Archivist_Silent_Stone_Bones **** **** **** **** **** **** **** **** +9138 Archivist_Still_Stone_Bones **** **** **** **** **** **** **** **** +9139 Archivist_Summon_Creature_II **** **** **** **** **** **** **** **** +9140 Archivist_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +9141 Archivist_Quickened_Summon_Creature_II **** **** **** **** **** **** **** **** +9142 Archivist_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +9143 Archivist_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +9144 Archivist_SummonUndeadII **** **** **** **** **** **** **** **** +9145 Archivist_Exteneded_SummonUndeadII **** **** **** **** **** **** **** **** +9146 Archivist_Quickened_SummonUndeadII **** **** **** **** **** **** **** **** +9147 Archivist_Silent_SummonUndeadII **** **** **** **** **** **** **** **** +9148 Archivist_Still_SummonUndeadII **** **** **** **** **** **** **** **** +9149 Archivist_Treeshape **** **** **** **** **** **** **** **** +9150 Archivist_Exteneded_Treeshape **** **** **** **** **** **** **** **** +9151 Archivist_Quickened_Treeshape **** **** **** **** **** **** **** **** +9152 Archivist_Silent_Treeshape **** **** **** **** **** **** **** **** +9153 Archivist_Still_Treeshape **** **** **** **** **** **** **** **** +9154 Archivist_Ultravision **** **** **** **** **** **** **** **** +9155 Archivist_Exteneded_Ultravision **** **** **** **** **** **** **** **** +9156 Archivist_Silent_Ultravision **** **** **** **** **** **** **** **** +9157 Archivist_Still_Ultravision **** **** **** **** **** **** **** **** +9158 Archivist_UndetectableAlignment **** **** **** **** **** **** **** **** +9159 Archivist_Exteneded_UndetectableAlignment **** **** **** **** **** **** **** **** +9160 Archivist_Quickened_UndetectableAlignment **** **** **** **** **** **** **** **** +9161 Archivist_Silent_UndetectableAlignment **** **** **** **** **** **** **** **** +9162 Archivist_Still_UndetectableAlignment **** **** **** **** **** **** **** **** +9163 Archivist_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +9164 Archivist_Exteneded_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +9165 Archivist_Quickened_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +9166 Archivist_Still_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +9167 Archivist_Web **** **** **** **** **** **** **** **** +9168 Archivist_Exteneded_Web **** **** **** **** **** **** **** **** +9169 Archivist_Quickened_Web **** **** **** **** **** **** **** **** +9170 Archivist_Silent_Web **** **** **** **** **** **** **** **** +9171 Archivist_Still_Web **** **** **** **** **** **** **** **** +9172 Archivist_Wolfskin **** **** **** **** **** **** **** **** +9173 Archivist_Exteneded_Wolfskin **** **** **** **** **** **** **** **** +9174 Archivist_Quickened_Wolfskin **** **** **** **** **** **** **** **** +9175 Archivist_Silent_Wolfskin **** **** **** **** **** **** **** **** +9176 Archivist_Still_Wolfskin **** **** **** **** **** **** **** **** +9177 Archivist_Animate_Dead **** **** **** **** **** **** **** **** +9178 Archivist_Exteneded_Animate_Dead **** **** **** **** **** **** **** **** +9179 Archivist_Quickened_Animate_Dead **** **** **** **** **** **** **** **** +9180 Archivist_Silent_Animate_Dead **** **** **** **** **** **** **** **** +9181 Archivist_Still_Animate_Dead **** **** **** **** **** **** **** **** +9182 Archivist_ArrowSplit **** **** **** **** **** **** **** **** +9183 Archivist_Silent_ArrowSplit **** **** **** **** **** **** **** **** +9184 Archivist_ArrowStorm **** **** **** **** **** **** **** **** +9185 Archivist_Silent_ArrowStorm **** **** **** **** **** **** **** **** +9186 Archivist_Bestow_Curse **** **** **** **** **** **** **** **** +9187 Archivist_Quickened_Bestow_Curse **** **** **** **** **** **** **** **** +9188 Archivist_Silent_Bestow_Curse **** **** **** **** **** **** **** **** +9189 Archivist_Still_Bestow_Curse **** **** **** **** **** **** **** **** +9190 Archivist_Blacklight **** **** **** **** **** **** **** **** +9191 Archivist_Exteneded_Blacklight **** **** **** **** **** **** **** **** +9192 Archivist_Quickened_Blacklight **** **** **** **** **** **** **** **** +9193 Archivist_Silent_Blacklight **** **** **** **** **** **** **** **** +9194 Archivist_Still_Blacklight **** **** **** **** **** **** **** **** +9195 Archivist_Blade_Thirst **** **** **** **** **** **** **** **** +9196 Archivist_Exteneded_Blade_Thirst **** **** **** **** **** **** **** **** +9197 Archivist_Quickened_Blade_Thirst **** **** **** **** **** **** **** **** +9198 Archivist_Silent_Blade_Thirst **** **** **** **** **** **** **** **** +9199 Archivist_Still_Blade_Thirst **** **** **** **** **** **** **** **** +9200 Archivist_Blessing_of_bahamut **** **** **** **** **** **** **** **** +9201 Archivist_Exteneded_Blessing_of_bahamut **** **** **** **** **** **** **** **** +9202 Archivist_Quickened_Blessing_of_bahamut **** **** **** **** **** **** **** **** +9203 Archivist_Silent_Blessing_of_bahamut **** **** **** **** **** **** **** **** +9204 Archivist_Still_Blessing_of_bahamut **** **** **** **** **** **** **** **** +9205 Archivist_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9206 Archivist_Exteneded_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9207 Archivist_Quickened_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9208 Archivist_Silent_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9209 Archivist_BONEBLADE **** **** **** **** **** **** **** **** +9210 Archivist_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +9211 Archivist_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +9212 Archivist_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +9213 Archivist_Exteneded_BONEBLADE **** **** **** **** **** **** **** **** +9214 Archivist_Exteneded_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +9215 Archivist_Exteneded_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +9216 Archivist_Exteneded_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +9217 Archivist_Quickened_BONEBLADE **** **** **** **** **** **** **** **** +9218 Archivist_Quickened_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +9219 Archivist_Quickened_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +9220 Archivist_Quickened_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +9221 Archivist_Silent_BONEBLADE **** **** **** **** **** **** **** **** +9222 Archivist_Silent_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +9223 Archivist_Silent_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +9224 Archivist_Silent_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +9225 Archivist_Still_BONEBLADE **** **** **** **** **** **** **** **** +9226 Archivist_Still_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +9227 Archivist_Still_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +9228 Archivist_Still_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +9229 Archivist_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +9230 Archivist_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +9231 Archivist_Quickened_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +9232 Archivist_Call_Lightning **** **** **** **** **** **** **** **** +9233 Archivist_Empowered_Call_Lightning **** **** **** **** **** **** **** **** +9234 Archivist_Maximized_Call_Lightning **** **** **** **** **** **** **** **** +9235 Archivist_Quickened_Call_Lightning **** **** **** **** **** **** **** **** +9236 Archivist_Silent_Call_Lightning **** **** **** **** **** **** **** **** +9237 Archivist_Still_Call_Lightning **** **** **** **** **** **** **** **** +9238 Archivist_Charm_Monster **** **** **** **** **** **** **** **** +9239 Archivist_Exteneded_Charm_Monster **** **** **** **** **** **** **** **** +9240 Archivist_Quickened_Charm_Monster **** **** **** **** **** **** **** **** +9241 Archivist_Silent_Charm_Monster **** **** **** **** **** **** **** **** +9242 Archivist_Still_Charm_Monster **** **** **** **** **** **** **** **** +9243 Archivist_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +9244 Archivist_Exteneded_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +9245 Archivist_Quickened_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +9246 Archivist_Silent_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +9247 Archivist_Still_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +9248 Archivist_Clarity **** **** **** **** **** **** **** **** +9249 Archivist_Exteneded_Clarity **** **** **** **** **** **** **** **** +9250 Archivist_Quickened_Clarity **** **** **** **** **** **** **** **** +9251 Archivist_Still_Clarity **** **** **** **** **** **** **** **** +9252 Archivist_Close_Wounds **** **** **** **** **** **** **** **** +9253 Archivist_Empowered_Close_Wounds **** **** **** **** **** **** **** **** +9254 Archivist_Maximized_Close_Wounds **** **** **** **** **** **** **** **** +9255 Archivist_Quickened_Close_Wounds **** **** **** **** **** **** **** **** +9256 Archivist_Silent_Close_Wounds **** **** **** **** **** **** **** **** +9257 Archivist_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +9258 Archivist_Quickened_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +9259 Archivist_Silent_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +9260 Archivist_Still_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +9261 Archivist_Contagion **** **** **** **** **** **** **** **** +9262 Archivist_Quickened_Contagion **** **** **** **** **** **** **** **** +9263 Archivist_Silent_Contagion **** **** **** **** **** **** **** **** +9264 Archivist_Still_Contagion **** **** **** **** **** **** **** **** +9265 Archivist_Continual_Flame **** **** **** **** **** **** **** **** +9266 Archivist_Quickened_Continual_Flame **** **** **** **** **** **** **** **** +9267 Archivist_Silent_Continual_Flame **** **** **** **** **** **** **** **** +9268 Archivist_Still_Continual_Flame **** **** **** **** **** **** **** **** +9269 Archivist_Crown_Might **** **** **** **** **** **** **** **** +9270 Archivist_Exteneded_Crown_Might **** **** **** **** **** **** **** **** +9271 Archivist_Quickened_Crown_Might **** **** **** **** **** **** **** **** +9272 Archivist_Silent_Crown_Might **** **** **** **** **** **** **** **** +9273 Archivist_Still_Crown_Might **** **** **** **** **** **** **** **** +9274 Archivist_Crown_Protection **** **** **** **** **** **** **** **** +9275 Archivist_Exteneded_Crown_Protection **** **** **** **** **** **** **** **** +9276 Archivist_Quickened_Crown_Protection **** **** **** **** **** **** **** **** +9277 Archivist_Silent_Crown_Protection **** **** **** **** **** **** **** **** +9278 Archivist_Still_Crown_Protection **** **** **** **** **** **** **** **** +9279 Archivist_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9280 Archivist_Empowered_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9281 Archivist_Maximized_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9282 Archivist_Quickened_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9283 Archivist_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9284 Archivist_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +9285 Archivist_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +9286 Archivist_Exteneded_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +9287 Archivist_Quickened_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +9288 Archivist_Silent_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +9289 Archivist_Still_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +9290 Archivist_Darkfire **** **** **** **** **** **** **** **** +9291 Archivist_Exteneded_Darkfire **** **** **** **** **** **** **** **** +9292 Archivist_Quickened_Darkfire **** **** **** **** **** **** **** **** +9293 Archivist_Silent_Darkfire **** **** **** **** **** **** **** **** +9294 Archivist_Still_Darkfire **** **** **** **** **** **** **** **** +9295 Archivist_DarkflameArrow **** **** **** **** **** **** **** **** +9296 Archivist_Silent_DarkflameArrow **** **** **** **** **** **** **** **** +9297 Archivist_Daylight **** **** **** **** **** **** **** **** +9298 Archivist_Exteneded_Daylight **** **** **** **** **** **** **** **** +9299 Archivist_Quickened_Daylight **** **** **** **** **** **** **** **** +9300 Archivist_Silent_Daylight **** **** **** **** **** **** **** **** +9301 Archivist_Still_Daylight **** **** **** **** **** **** **** **** +9302 Archivist_DeeperDarkness **** **** **** **** **** **** **** **** +9303 Archivist_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +9304 Archivist_Quickened_DeeperDarkness **** **** **** **** **** **** **** **** +9305 Archivist_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +9306 Archivist_DEVILS_EYE **** **** **** **** **** **** **** **** +9307 Archivist_Quickened_DEVILS_EYE **** **** **** **** **** **** **** **** +9308 Archivist_Silent_DEVILS_EYE **** **** **** **** **** **** **** **** +9309 Archivist_Still_DEVILS_EYE **** **** **** **** **** **** **** **** +9310 Archivist_Dispel_Magic **** **** **** **** **** **** **** **** +9311 Archivist_Quickened_Dispel_Magic **** **** **** **** **** **** **** **** +9312 Archivist_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +9313 Archivist_Still_Dispel_Magic **** **** **** **** **** **** **** **** +9314 Archivist_Dominate_Animal **** **** **** **** **** **** **** **** +9315 Archivist_Exteneded_Dominate_Animal **** **** **** **** **** **** **** **** +9316 Archivist_Quickened_Dominate_Animal **** **** **** **** **** **** **** **** +9317 Archivist_Silent_Dominate_Animal **** **** **** **** **** **** **** **** +9318 Archivist_Still_Dominate_Animal **** **** **** **** **** **** **** **** +9319 Archivist_ENERGIZE_POTION **** **** **** **** **** **** **** **** +9320 Archivist_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +9321 Archivist_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +9322 Archivist_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +9323 Archivist_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +9324 Archivist_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +9325 Archivist_Quickened_ENERGIZE_POTION **** **** **** **** **** **** **** **** +9326 Archivist_Quickened_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +9327 Archivist_Quickened_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +9328 Archivist_Quickened_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +9329 Archivist_Quickened_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +9330 Archivist_Quickened_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +9331 Archivist_Silent_ENERGIZE_POTION **** **** **** **** **** **** **** **** +9332 Archivist_Silent_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +9333 Archivist_Silent_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +9334 Archivist_Silent_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +9335 Archivist_Silent_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +9336 Archivist_Silent_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +9337 Archivist_Still_ENERGIZE_POTION **** **** **** **** **** **** **** **** +9338 Archivist_Still_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +9339 Archivist_Still_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +9340 Archivist_Still_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +9341 Archivist_Still_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +9342 Archivist_Still_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +9343 Archivist_Energy_Aegis **** **** **** **** **** **** **** **** +9344 Archivist_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +9345 Archivist_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +9346 Archivist_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +9347 Archivist_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +9348 Archivist_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +9349 Archivist_Exteneded_Energy_Aegis **** **** **** **** **** **** **** **** +9350 Archivist_Exteneded_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +9351 Archivist_Exteneded_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +9352 Archivist_Exteneded_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +9353 Archivist_Exteneded_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +9354 Archivist_Exteneded_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +9355 Archivist_Quickened_Energy_Aegis **** **** **** **** **** **** **** **** +9356 Archivist_Quickened_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +9357 Archivist_Quickened_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +9358 Archivist_Quickened_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +9359 Archivist_Quickened_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +9360 Archivist_Quickened_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +9361 Archivist_Silent_Energy_Aegis **** **** **** **** **** **** **** **** +9362 Archivist_Silent_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +9363 Archivist_Silent_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +9364 Archivist_Silent_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +9365 Archivist_Silent_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +9366 Archivist_Silent_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +9367 Archivist_Still_Energy_Aegis **** **** **** **** **** **** **** **** +9368 Archivist_Still_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +9369 Archivist_Still_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +9370 Archivist_Still_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +9371 Archivist_Still_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +9372 Archivist_Still_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +9373 Archivist_FLESH_RIPPER **** **** **** **** **** **** **** **** +9374 Archivist_Empowered_FLESH_RIPPER **** **** **** **** **** **** **** **** +9375 Archivist_Maximized_FLESH_RIPPER **** **** **** **** **** **** **** **** +9376 Archivist_Quickened_FLESH_RIPPER **** **** **** **** **** **** **** **** +9377 Archivist_Silent_FLESH_RIPPER **** **** **** **** **** **** **** **** +9378 Archivist_Still_FLESH_RIPPER **** **** **** **** **** **** **** **** +9379 Archivist_Forceblast **** **** **** **** **** **** **** **** +9380 Archivist_Empowered_Forceblast **** **** **** **** **** **** **** **** +9381 Archivist_Maximized_Forceblast **** **** **** **** **** **** **** **** +9382 Archivist_Quickened_Forceblast **** **** **** **** **** **** **** **** +9383 Archivist_Silent_Forceblast **** **** **** **** **** **** **** **** +9384 Archivist_Still_Forceblast **** **** **** **** **** **** **** **** +9385 Archivist_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9386 Archivist_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9387 Archivist_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9388 Archivist_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9389 Archivist_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9390 Archivist_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9391 Archivist_Empowered_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9392 Archivist_Empowered_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9393 Archivist_Empowered_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9394 Archivist_Empowered_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9395 Archivist_Empowered_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9396 Archivist_Empowered_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9397 Archivist_Exteneded_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9398 Archivist_Exteneded_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9399 Archivist_Exteneded_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9400 Archivist_Exteneded_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9401 Archivist_Exteneded_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9402 Archivist_Exteneded_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9403 Archivist_Maximized_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9404 Archivist_Maximized_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9405 Archivist_Maximized_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9406 Archivist_Maximized_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9407 Archivist_Maximized_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9408 Archivist_Maximized_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9409 Archivist_Quickened_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9410 Archivist_Quickened_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9411 Archivist_Quickened_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9412 Archivist_Quickened_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9413 Archivist_Quickened_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9414 Archivist_Quickened_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9415 Archivist_Silent_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9416 Archivist_Silent_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9417 Archivist_Silent_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9418 Archivist_Silent_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9419 Archivist_Silent_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9420 Archivist_Silent_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9421 Archivist_Still_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +9422 Archivist_Still_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +9423 Archivist_Still_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +9424 Archivist_Still_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +9425 Archivist_Still_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +9426 Archivist_Still_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +9427 Archivist_Greater_Magic_Fang **** **** **** **** **** **** **** **** +9428 Archivist_Exteneded_Greater_Magic_Fang **** **** **** **** **** **** **** **** +9429 Archivist_Quickened_Greater_Magic_Fang **** **** **** **** **** **** **** **** +9430 Archivist_Silent_Greater_Magic_Fang **** **** **** **** **** **** **** **** +9431 Archivist_Still_Greater_Magic_Fang **** **** **** **** **** **** **** **** +9432 Archivist_Greenfire **** **** **** **** **** **** **** **** +9433 Archivist_Empowered_Greenfire **** **** **** **** **** **** **** **** +9434 Archivist_Exteneded_Greenfire **** **** **** **** **** **** **** **** +9435 Archivist_Maximized_Greenfire **** **** **** **** **** **** **** **** +9436 Archivist_Quickened_Greenfire **** **** **** **** **** **** **** **** +9437 Archivist_Silent_Greenfire **** **** **** **** **** **** **** **** +9438 Archivist_Still_Greenfire **** **** **** **** **** **** **** **** +9439 Archivist_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9440 Archivist_Empowered_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9441 Archivist_Maximized_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9442 Archivist_Quickened_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9443 Archivist_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9444 Archivist_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +9445 Archivist_Healing_Sting **** **** **** **** **** **** **** **** +9446 Archivist_Empowered_Healing_Sting **** **** **** **** **** **** **** **** +9447 Archivist_Maximized_Healing_Sting **** **** **** **** **** **** **** **** +9448 Archivist_Quickened_Healing_Sting **** **** **** **** **** **** **** **** +9449 Archivist_Silent_Healing_Sting **** **** **** **** **** **** **** **** +9450 Archivist_Still_Healing_Sting **** **** **** **** **** **** **** **** +9451 Archivist_Heroism **** **** **** **** **** **** **** **** +9452 Archivist_Exteneded_Heroism **** **** **** **** **** **** **** **** +9453 Archivist_Quickened_Heroism **** **** **** **** **** **** **** **** +9454 Archivist_Silent_Heroism **** **** **** **** **** **** **** **** +9455 Archivist_Still_Heroism **** **** **** **** **** **** **** **** +9456 Archivist_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9457 Archivist_Empowered_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9458 Archivist_Exteneded_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9459 Archivist_Maximized_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9460 Archivist_Quickened_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9461 Archivist_Silent_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9462 Archivist_Still_Infestation_of_Maggots **** **** **** **** **** **** **** **** +9463 Archivist_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9464 Archivist_Empowered_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9465 Archivist_Maximized_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9466 Archivist_Quickened_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9467 Archivist_Silent_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9468 Archivist_Still_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +9469 Archivist_Invisibility **** **** **** **** **** **** **** **** +9470 Archivist_Exteneded_Invisibility **** **** **** **** **** **** **** **** +9471 Archivist_Quickened_Invisibility **** **** **** **** **** **** **** **** +9472 Archivist_Silent_Invisibility **** **** **** **** **** **** **** **** +9473 Archivist_Still_Invisibility **** **** **** **** **** **** **** **** +9474 Archivist_Invisibility_Purge **** **** **** **** **** **** **** **** +9475 Archivist_Exteneded_Invisibility_Purge **** **** **** **** **** **** **** **** +9476 Archivist_Quickened_Invisibility_Purge **** **** **** **** **** **** **** **** +9477 Archivist_Silent_Invisibility_Purge **** **** **** **** **** **** **** **** +9478 Archivist_Still_Invisibility_Purge **** **** **** **** **** **** **** **** +9479 Archivist_Invisibility_Sphere **** **** **** **** **** **** **** **** +9480 Archivist_Exteneded_Invisibility_Sphere **** **** **** **** **** **** **** **** +9481 Archivist_Quickened_Invisibility_Sphere **** **** **** **** **** **** **** **** +9482 Archivist_Silent_Invisibility_Sphere **** **** **** **** **** **** **** **** +9483 Archivist_Still_Invisibility_Sphere **** **** **** **** **** **** **** **** +9484 Archivist_Keen_Edge **** **** **** **** **** **** **** **** +9485 Archivist_Exteneded_Keen_Edge **** **** **** **** **** **** **** **** +9486 Archivist_Quickened_Keen_Edge **** **** **** **** **** **** **** **** +9487 Archivist_Silent_Keen_Edge **** **** **** **** **** **** **** **** +9488 Archivist_Still_Keen_Edge **** **** **** **** **** **** **** **** +9489 Archivist_Legions_Conviction **** **** **** **** **** **** **** **** +9490 Archivist_Exteneded_Legions_Conviction **** **** **** **** **** **** **** **** +9491 Archivist_Quickened_Legions_Conviction **** **** **** **** **** **** **** **** +9492 Archivist_Silent_Legions_Conviction **** **** **** **** **** **** **** **** +9493 Archivist_Still_Legions_Conviction **** **** **** **** **** **** **** **** +9494 Archivist_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +9495 Archivist_Exteneded_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +9496 Archivist_Quickened_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +9497 Archivist_Silent_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +9498 Archivist_Still_Legions_Curse_of_Impending_Blades **** **** **** **** **** **** **** **** +9499 Archivist_Lightning_Bolt **** **** **** **** **** **** **** **** +9500 Archivist_Empowered_Lightning_Bolt **** **** **** **** **** **** **** **** +9501 Archivist_Maximized_Lightning_Bolt **** **** **** **** **** **** **** **** +9502 Archivist_Quickened_Lightning_Bolt **** **** **** **** **** **** **** **** +9503 Archivist_Silent_Lightning_Bolt **** **** **** **** **** **** **** **** +9504 Archivist_Still_Lightning_Bolt **** **** **** **** **** **** **** **** +9505 Archivist_LocateObject **** **** **** **** **** **** **** **** +9506 Archivist_Exteneded_LocateObject **** **** **** **** **** **** **** **** +9507 Archivist_Quickened_LocateObject **** **** **** **** **** **** **** **** +9508 Archivist_Silent_LocateObject **** **** **** **** **** **** **** **** +9509 Archivist_Still_LocateObject **** **** **** **** **** **** **** **** +9510 Archivist_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +9511 Archivist_Exteneded_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +9512 Archivist_Quickened_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +9513 Archivist_Silent_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +9514 Archivist_Still_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +9515 Archivist_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +9516 Archivist_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +9517 Archivist_Quickened_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +9518 Archivist_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +9519 Archivist_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +9520 Archivist_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +9521 Archivist_Exteneded_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +9522 Archivist_Quickened_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +9523 Archivist_Silent_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +9524 Archivist_Still_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +9525 Archivist_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +9526 Archivist_Exteneded_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +9527 Archivist_Quickened_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +9528 Archivist_Silent_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +9529 Archivist_Still_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +9530 Archivist_Magic_Vestment **** **** **** **** **** **** **** **** +9531 Archivist_Exteneded_Magic_Vestment **** **** **** **** **** **** **** **** +9532 Archivist_Quickened_Magic_Vestment **** **** **** **** **** **** **** **** +9533 Archivist_Silent_Magic_Vestment **** **** **** **** **** **** **** **** +9534 Archivist_Still_Magic_Vestment **** **** **** **** **** **** **** **** +9535 Archivist_MASOCHISM **** **** **** **** **** **** **** **** +9536 Archivist_Exteneded_MASOCHISM **** **** **** **** **** **** **** **** +9537 Archivist_Mass_Aid **** **** **** **** **** **** **** **** +9538 Archivist_Empowered_Mass_Aid **** **** **** **** **** **** **** **** +9539 Archivist_Exteneded_Mass_Aid **** **** **** **** **** **** **** **** +9540 Archivist_Maximized_Mass_Aid **** **** **** **** **** **** **** **** +9541 Archivist_Quickened_Mass_Aid **** **** **** **** **** **** **** **** +9542 Archivist_Silent_Mass_Aid **** **** **** **** **** **** **** **** +9543 Archivist_Still_Mass_Aid **** **** **** **** **** **** **** **** +9544 Archivist_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +9545 Archivist_Exteneded_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +9546 Archivist_Quickened_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +9547 Archivist_Silent_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +9548 Archivist_Still_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +9549 Archivist_MirrorImage **** **** **** **** **** **** **** **** +9550 Archivist_Exteneded_MirrorImage **** **** **** **** **** **** **** **** +9551 Archivist_Quickened_MirrorImage **** **** **** **** **** **** **** **** +9552 Archivist_Silent_MirrorImage **** **** **** **** **** **** **** **** +9553 Archivist_Still_MirrorImage **** **** **** **** **** **** **** **** +9554 Archivist_Necrotic_Bloat **** **** **** **** **** **** **** **** +9555 Archivist_Empowered_Necrotic_Bloat **** **** **** **** **** **** **** **** +9556 Archivist_Maximized_Necrotic_Bloat **** **** **** **** **** **** **** **** +9557 Archivist_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9558 Archivist_Empowered_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9559 Archivist_Maximized_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9560 Archivist_Quickened_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9561 Archivist_Silent_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9562 Archivist_Still_Negative_Energy_Burst **** **** **** **** **** **** **** **** +9563 Archivist_Negative_Energy_Protection **** **** **** **** **** **** **** **** +9564 Archivist_Exteneded_Negative_Energy_Protection **** **** **** **** **** **** **** **** +9565 Archivist_Quickened_Negative_Energy_Protection **** **** **** **** **** **** **** **** +9566 Archivist_Silent_Negative_Energy_Protection **** **** **** **** **** **** **** **** +9567 Archivist_Still_Negative_Energy_Protection **** **** **** **** **** **** **** **** +9568 Archivist_ObscureObject **** **** **** **** **** **** **** **** +9569 Archivist_Exteneded_ObscureObject **** **** **** **** **** **** **** **** +9570 Archivist_Quickened_ObscureObject **** **** **** **** **** **** **** **** +9571 Archivist_Silent_ObscureObject **** **** **** **** **** **** **** **** +9572 Archivist_Still_ObscureObject **** **** **** **** **** **** **** **** +9573 Archivist_Prayer **** **** **** **** **** **** **** **** +9574 Archivist_Exteneded_Prayer **** **** **** **** **** **** **** **** +9575 Archivist_Quickened_Prayer **** **** **** **** **** **** **** **** +9576 Archivist_Silent_Prayer **** **** **** **** **** **** **** **** +9577 Archivist_Still_Prayer **** **** **** **** **** **** **** **** +9578 Archivist_Protection_from_Elements **** **** **** **** **** **** **** **** +9579 Archivist_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +9580 Archivist_Quickened_Protection_from_Elements **** **** **** **** **** **** **** **** +9581 Archivist_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +9582 Archivist_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +9583 Archivist_Quillfire **** **** **** **** **** **** **** **** +9584 Archivist_Empowered_Quillfire **** **** **** **** **** **** **** **** +9585 Archivist_Maximized_Quillfire **** **** **** **** **** **** **** **** +9586 Archivist_Quickened_Quillfire **** **** **** **** **** **** **** **** +9587 Archivist_Silent_Quillfire **** **** **** **** **** **** **** **** +9588 Archivist_Still_Quillfire **** **** **** **** **** **** **** **** +9589 Archivist_RED_FESTER **** **** **** **** **** **** **** **** +9590 Archivist_Quickened_RED_FESTER **** **** **** **** **** **** **** **** +9591 Archivist_Silent_RED_FESTER **** **** **** **** **** **** **** **** +9592 Archivist_Still_RED_FESTER **** **** **** **** **** **** **** **** +9593 Archivist_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9594 Archivist_Quickened_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9595 Archivist_Silent_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9596 Archivist_Still_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +9597 Archivist_Remove_Curse **** **** **** **** **** **** **** **** +9598 Archivist_Quickened_Remove_Curse **** **** **** **** **** **** **** **** +9599 Archivist_Silent_Remove_Curse **** **** **** **** **** **** **** **** +9600 Archivist_Still_Remove_Curse **** **** **** **** **** **** **** **** +9601 Archivist_Remove_Disease **** **** **** **** **** **** **** **** +9602 Archivist_Quickened_Remove_Disease **** **** **** **** **** **** **** **** +9603 Archivist_Silent_Remove_Disease **** **** **** **** **** **** **** **** +9604 Archivist_Still_Remove_Disease **** **** **** **** **** **** **** **** +9605 Archivist_RingOfBlades **** **** **** **** **** **** **** **** +9606 Archivist_Exteneded_RingOfBlades **** **** **** **** **** **** **** **** +9607 Archivist_Quickened_RingOfBlades **** **** **** **** **** **** **** **** +9608 Archivist_Silent_RingOfBlades **** **** **** **** **** **** **** **** +9609 Archivist_Still_RingOfBlades **** **** **** **** **** **** **** **** +9610 Archivist_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9611 Archivist_Empowered_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9612 Archivist_Maximized_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9613 Archivist_Quickened_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9614 Archivist_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9615 Archivist_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +9616 Archivist_Searing_Light **** **** **** **** **** **** **** **** +9617 Archivist_Empowered_Searing_Light **** **** **** **** **** **** **** **** +9618 Archivist_Maximized_Searing_Light **** **** **** **** **** **** **** **** +9619 Archivist_Quickened_Searing_Light **** **** **** **** **** **** **** **** +9620 Archivist_Silent_Searing_Light **** **** **** **** **** **** **** **** +9621 Archivist_Still_Searing_Light **** **** **** **** **** **** **** **** +9622 Archivist_SerpentArrows **** **** **** **** **** **** **** **** +9623 Archivist_Quickened_SerpentArrows **** **** **** **** **** **** **** **** +9624 Archivist_Silent_SerpentArrows **** **** **** **** **** **** **** **** +9625 Archivist_Still_SerpentArrows **** **** **** **** **** **** **** **** +9626 Archivist_Serpents_Sigh **** **** **** **** **** **** **** **** +9627 Archivist_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9628 Archivist_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9629 Archivist_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9630 Archivist_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9631 Archivist_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9632 Archivist_Empowered_Serpents_Sigh **** **** **** **** **** **** **** **** +9633 Archivist_Empowered_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9634 Archivist_Empowered_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9635 Archivist_Empowered_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9636 Archivist_Empowered_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9637 Archivist_Empowered_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9638 Archivist_Maximized_Serpents_Sigh **** **** **** **** **** **** **** **** +9639 Archivist_Maximized_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9640 Archivist_Maximized_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9641 Archivist_Maximized_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9642 Archivist_Maximized_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9643 Archivist_Maximized_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9644 Archivist_Quickened_Serpents_Sigh **** **** **** **** **** **** **** **** +9645 Archivist_Quickened_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9646 Archivist_Quickened_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9647 Archivist_Quickened_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9648 Archivist_Quickened_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9649 Archivist_Quickened_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9650 Archivist_Silent_Serpents_Sigh **** **** **** **** **** **** **** **** +9651 Archivist_Silent_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9652 Archivist_Silent_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9653 Archivist_Silent_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9654 Archivist_Silent_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9655 Archivist_Silent_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9656 Archivist_Still_Serpents_Sigh **** **** **** **** **** **** **** **** +9657 Archivist_Still_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +9658 Archivist_Still_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +9659 Archivist_Still_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +9660 Archivist_Still_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +9661 Archivist_Still_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +9662 Archivist_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9663 Archivist_Empowered_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9664 Archivist_Exteneded_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9665 Archivist_Maximized_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9666 Archivist_Quickened_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9667 Archivist_Silent_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9668 Archivist_Still_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +9669 Archivist_Shout **** **** **** **** **** **** **** **** +9670 Archivist_Empowered_Shout **** **** **** **** **** **** **** **** +9671 Archivist_Maximized_Shout **** **** **** **** **** **** **** **** +9672 Archivist_Quickened_Shout **** **** **** **** **** **** **** **** +9673 Archivist_Silent_Shout **** **** **** **** **** **** **** **** +9674 Archivist_SHRIVELING **** **** **** **** **** **** **** **** +9675 Archivist_Empowered_SHRIVELING **** **** **** **** **** **** **** **** +9676 Archivist_Maximized_SHRIVELING **** **** **** **** **** **** **** **** +9677 Archivist_Quickened_SHRIVELING **** **** **** **** **** **** **** **** +9678 Archivist_Silent_SHRIVELING **** **** **** **** **** **** **** **** +9679 Archivist_Still_SHRIVELING **** **** **** **** **** **** **** **** +9680 Archivist_Slashing_Darkness **** **** **** **** **** **** **** **** +9681 Archivist_Empowered_Slashing_Darkness **** **** **** **** **** **** **** **** +9682 Archivist_Maximized_Slashing_Darkness **** **** **** **** **** **** **** **** +9683 Archivist_Quickened_Slashing_Darkness **** **** **** **** **** **** **** **** +9684 Archivist_Silent_Slashing_Darkness **** **** **** **** **** **** **** **** +9685 Archivist_Still_Slashing_Darkness **** **** **** **** **** **** **** **** +9686 Archivist_SleetStorm **** **** **** **** **** **** **** **** +9687 Archivist_Exteneded_SleetStorm **** **** **** **** **** **** **** **** +9688 Archivist_Quickened_SleetStorm **** **** **** **** **** **** **** **** +9689 Archivist_Silent_SleetStorm **** **** **** **** **** **** **** **** +9690 Archivist_Still_SleetStorm **** **** **** **** **** **** **** **** +9691 Archivist_Snare **** **** **** **** **** **** **** **** +9692 Archivist_Quickened_Snare **** **** **** **** **** **** **** **** +9693 Archivist_Silent_Snare **** **** **** **** **** **** **** **** +9694 Archivist_Still_Snare **** **** **** **** **** **** **** **** +9695 Archivist_Spiderskin **** **** **** **** **** **** **** **** +9696 Archivist_Exteneded_Spiderskin **** **** **** **** **** **** **** **** +9697 Archivist_Quickened_Spiderskin **** **** **** **** **** **** **** **** +9698 Archivist_Silent_Spiderskin **** **** **** **** **** **** **** **** +9699 Archivist_Still_Spiderskin **** **** **** **** **** **** **** **** +9700 Archivist_Spike_Growth **** **** **** **** **** **** **** **** +9701 Archivist_Exteneded_Spike_Growth **** **** **** **** **** **** **** **** +9702 Archivist_Quickened_Spike_Growth **** **** **** **** **** **** **** **** +9703 Archivist_Silent_Spike_Growth **** **** **** **** **** **** **** **** +9704 Archivist_Still_Spike_Growth **** **** **** **** **** **** **** **** +9705 Archivist_Summon_Creature_III **** **** **** **** **** **** **** **** +9706 Archivist_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +9707 Archivist_Quickened_Summon_Creature_III **** **** **** **** **** **** **** **** +9708 Archivist_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +9709 Archivist_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +9710 Archivist_SummonUndeadIII **** **** **** **** **** **** **** **** +9711 Archivist_Exteneded_SummonUndeadIII **** **** **** **** **** **** **** **** +9712 Archivist_Quickened_SummonUndeadIII **** **** **** **** **** **** **** **** +9713 Archivist_Silent_SummonUndeadIII **** **** **** **** **** **** **** **** +9714 Archivist_Still_SummonUndeadIII **** **** **** **** **** **** **** **** +9715 Archivist_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +9716 Archivist_Quickened_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +9717 Archivist_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +9718 Archivist_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +9719 Archivist_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9720 Archivist_Empowered_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9721 Archivist_Maximized_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9722 Archivist_Quickened_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9723 Archivist_Silent_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9724 Archivist_Still_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +9725 Archivist_Vigor **** **** **** **** **** **** **** **** +9726 Archivist_Exteneded_Vigor **** **** **** **** **** **** **** **** +9727 Archivist_Quickened_Vigor **** **** **** **** **** **** **** **** +9728 Archivist_Silent_Vigor **** **** **** **** **** **** **** **** +9729 Archivist_Still_Vigor **** **** **** **** **** **** **** **** +9730 Archivist_WaterBreathing **** **** **** **** **** **** **** **** +9731 Archivist_Exteneded_WaterBreathing **** **** **** **** **** **** **** **** +9732 Archivist_Quickened_WaterBreathing **** **** **** **** **** **** **** **** +9733 Archivist_Silent_WaterBreathing **** **** **** **** **** **** **** **** +9734 Archivist_Still_WaterBreathing **** **** **** **** **** **** **** **** +9735 Archivist_WRACK **** **** **** **** **** **** **** **** +9736 Archivist_Exteneded_WRACK **** **** **** **** **** **** **** **** +9737 Archivist_Quickened_WRACK **** **** **** **** **** **** **** **** +9738 Archivist_Silent_WRACK **** **** **** **** **** **** **** **** +9739 Archivist_Still_WRACK **** **** **** **** **** **** **** **** +9740 Archivist_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +9741 Archivist_Exteneded_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +9742 Archivist_Quickened_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +9743 Archivist_Silent_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +9744 Archivist_Still_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +9745 Archivist_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9746 Archivist_Empowered_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9747 Archivist_Exteneded_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9748 Archivist_Quickened_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9749 Archivist_Silent_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9750 Archivist_Still_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +9751 Archivist_BloodfreezeArrow **** **** **** **** **** **** **** **** +9752 Archivist_Silent_BloodfreezeArrow **** **** **** **** **** **** **** **** +9753 Archivist_BloodOfTheMartyr **** **** **** **** **** **** **** **** +9754 Archivist_Quickened_BloodOfTheMartyr **** **** **** **** **** **** **** **** +9755 Archivist_Silent_BloodOfTheMartyr **** **** **** **** **** **** **** **** +9756 Archivist_Still_BloodOfTheMartyr **** **** **** **** **** **** **** **** +9757 Archivist_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9758 Archivist_Empowered_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9759 Archivist_Exteneded_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9760 Archivist_Quickened_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9761 Archivist_Silent_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9762 Archivist_Still_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +9763 Archivist_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9764 Archivist_Empowered_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9765 Archivist_Maximized_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9766 Archivist_Quickened_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9767 Archivist_Silent_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9768 Archivist_Still_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +9769 Archivist_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +9770 Archivist_Exteneded_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +9771 Archivist_Quickened_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +9772 Archivist_Silent_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +9773 Archivist_Darkness_Armor **** **** **** **** **** **** **** **** +9774 Archivist_Exteneded_Darkness_Armor **** **** **** **** **** **** **** **** +9775 Archivist_Quickened_Darkness_Armor **** **** **** **** **** **** **** **** +9776 Archivist_Silent_Darkness_Armor **** **** **** **** **** **** **** **** +9777 Archivist_Still_Darkness_Armor **** **** **** **** **** **** **** **** +9778 Archivist_Death_Ward **** **** **** **** **** **** **** **** +9779 Archivist_Exteneded_Death_Ward **** **** **** **** **** **** **** **** +9780 Archivist_Quickened_Death_Ward **** **** **** **** **** **** **** **** +9781 Archivist_Silent_Death_Ward **** **** **** **** **** **** **** **** +9782 Archivist_Still_Death_Ward **** **** **** **** **** **** **** **** +9783 Archivist_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9784 Archivist_Empowered_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9785 Archivist_Exteneded_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9786 Archivist_Maximized_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9787 Archivist_Quickened_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9788 Archivist_Silent_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9789 Archivist_Still_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +9790 Archivist_Dimensional_Anchor **** **** **** **** **** **** **** **** +9791 Archivist_Exteneded_Dimensional_Anchor **** **** **** **** **** **** **** **** +9792 Archivist_Quickened_Dimensional_Anchor **** **** **** **** **** **** **** **** +9793 Archivist_Silent_Dimensional_Anchor **** **** **** **** **** **** **** **** +9794 Archivist_Still_Dimensional_Anchor **** **** **** **** **** **** **** **** +9795 Archivist_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +9796 Archivist_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +9797 Archivist_DimensionDoor_Party **** **** **** **** **** **** **** **** +9798 Archivist_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +9799 Archivist_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +9800 Archivist_Quickened_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +9801 Archivist_Quickened_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +9802 Archivist_Quickened_DimensionDoor_Party **** **** **** **** **** **** **** **** +9803 Archivist_Quickened_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +9804 Archivist_Quickened_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +9805 Archivist_Silent_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +9806 Archivist_Silent_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +9807 Archivist_Silent_DimensionDoor_Party **** **** **** **** **** **** **** **** +9808 Archivist_Silent_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +9809 Archivist_Silent_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +9810 Archivist_Dismissal **** **** **** **** **** **** **** **** +9811 Archivist_Quickened_Dismissal **** **** **** **** **** **** **** **** +9812 Archivist_Silent_Dismissal **** **** **** **** **** **** **** **** +9813 Archivist_Still_Dismissal **** **** **** **** **** **** **** **** +9814 Archivist_Divine_Power **** **** **** **** **** **** **** **** +9815 Archivist_Exteneded_Divine_Power **** **** **** **** **** **** **** **** +9816 Archivist_Quickened_Divine_Power **** **** **** **** **** **** **** **** +9817 Archivist_Silent_Divine_Power **** **** **** **** **** **** **** **** +9818 Archivist_Still_Divine_Power **** **** **** **** **** **** **** **** +9819 Archivist_Dominate_Person **** **** **** **** **** **** **** **** +9820 Archivist_Exteneded_Dominate_Person **** **** **** **** **** **** **** **** +9821 Archivist_Quickened_Dominate_Person **** **** **** **** **** **** **** **** +9822 Archivist_Silent_Dominate_Person **** **** **** **** **** **** **** **** +9823 Archivist_Still_Dominate_Person **** **** **** **** **** **** **** **** +9824 Archivist_DoublestrikeArrow **** **** **** **** **** **** **** **** +9825 Archivist_Quickened_DoublestrikeArrow **** **** **** **** **** **** **** **** +9826 Archivist_Silent_DoublestrikeArrow **** **** **** **** **** **** **** **** +9827 Archivist_Still_DoublestrikeArrow **** **** **** **** **** **** **** **** +9828 Archivist_DraconicMight **** **** **** **** **** **** **** **** +9829 Archivist_Exteneded_DraconicMight **** **** **** **** **** **** **** **** +9830 Archivist_Quickened_DraconicMight **** **** **** **** **** **** **** **** +9831 Archivist_Silent_DraconicMight **** **** **** **** **** **** **** **** +9832 Archivist_Still_DraconicMight **** **** **** **** **** **** **** **** +9833 Archivist_Elemental_Shield **** **** **** **** **** **** **** **** +9834 Archivist_Exteneded_Elemental_Shield **** **** **** **** **** **** **** **** +9835 Archivist_Quickened_Elemental_Shield **** **** **** **** **** **** **** **** +9836 Archivist_Silent_Elemental_Shield **** **** **** **** **** **** **** **** +9837 Archivist_Still_Elemental_Shield **** **** **** **** **** **** **** **** +9838 Archivist_Enervation **** **** **** **** **** **** **** **** +9839 Archivist_Empowered_Enervation **** **** **** **** **** **** **** **** +9840 Archivist_Maximized_Enervation **** **** **** **** **** **** **** **** +9841 Archivist_Quickened_Enervation **** **** **** **** **** **** **** **** +9842 Archivist_Silent_Enervation **** **** **** **** **** **** **** **** +9843 Archivist_Still_Enervation **** **** **** **** **** **** **** **** +9844 Archivist_Fear **** **** **** **** **** **** **** **** +9845 Archivist_Exteneded_Fear **** **** **** **** **** **** **** **** +9846 Archivist_Quickened_Fear **** **** **** **** **** **** **** **** +9847 Archivist_Silent_Fear **** **** **** **** **** **** **** **** +9848 Archivist_Still_Fear **** **** **** **** **** **** **** **** +9849 Archivist_Fireball **** **** **** **** **** **** **** **** +9850 Archivist_Empowered_Fireball **** **** **** **** **** **** **** **** +9851 Archivist_Maximized_Fireball **** **** **** **** **** **** **** **** +9852 Archivist_Quickened_Fireball **** **** **** **** **** **** **** **** +9853 Archivist_Silent_Fireball **** **** **** **** **** **** **** **** +9854 Archivist_Still_Fireball **** **** **** **** **** **** **** **** +9855 Archivist_Freedom_of_Movement **** **** **** **** **** **** **** **** +9856 Archivist_Exteneded_Freedom_of_Movement **** **** **** **** **** **** **** **** +9857 Archivist_Quickened_Freedom_of_Movement **** **** **** **** **** **** **** **** +9858 Archivist_Silent_Freedom_of_Movement **** **** **** **** **** **** **** **** +9859 Archivist_Still_Freedom_of_Movement **** **** **** **** **** **** **** **** +9860 Archivist_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9861 Archivist_Exteneded_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9862 Archivist_Quickened_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +9863 Archivist_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +9864 Archivist_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +9865 Archivist_Quickened_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +9866 Archivist_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +9867 Archivist_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +9868 Archivist_Greater_Resistance **** **** **** **** **** **** **** **** +9869 Archivist_Exteneded_Greater_Resistance **** **** **** **** **** **** **** **** +9870 Archivist_Quickened_Greater_Resistance **** **** **** **** **** **** **** **** +9871 Archivist_Silent_Greater_Resistance **** **** **** **** **** **** **** **** +9872 Archivist_Still_Greater_Resistance **** **** **** **** **** **** **** **** +9873 Archivist_Gust_of_Wind **** **** **** **** **** **** **** **** +9874 Archivist_Quickened_Gust_of_Wind **** **** **** **** **** **** **** **** +9875 Archivist_Silent_Gust_of_Wind **** **** **** **** **** **** **** **** +9876 Archivist_Still_Gust_of_Wind **** **** **** **** **** **** **** **** +9877 Archivist_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9878 Archivist_Empowered_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9879 Archivist_Maximized_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9880 Archivist_Quickened_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9881 Archivist_Silent_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9882 Archivist_Still_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +9883 Archivist_Haste **** **** **** **** **** **** **** **** +9884 Archivist_Exteneded_Haste **** **** **** **** **** **** **** **** +9885 Archivist_Quickened_Haste **** **** **** **** **** **** **** **** +9886 Archivist_Silent_Haste **** **** **** **** **** **** **** **** +9887 Archivist_Still_Haste **** **** **** **** **** **** **** **** +9888 Archivist_Hold_Monster **** **** **** **** **** **** **** **** +9889 Archivist_Exteneded_Hold_Monster **** **** **** **** **** **** **** **** +9890 Archivist_Quickened_Hold_Monster **** **** **** **** **** **** **** **** +9891 Archivist_Silent_Hold_Monster **** **** **** **** **** **** **** **** +9892 Archivist_Still_Hold_Monster **** **** **** **** **** **** **** **** +9893 Archivist_Holy_Sword **** **** **** **** **** **** **** **** +9894 Archivist_Exteneded_Holy_Sword **** **** **** **** **** **** **** **** +9895 Archivist_Quickened_Holy_Sword **** **** **** **** **** **** **** **** +9896 Archivist_Silent_Holy_Sword **** **** **** **** **** **** **** **** +9897 Archivist_Still_Holy_Sword **** **** **** **** **** **** **** **** +9898 Archivist_Improved_Invisibility **** **** **** **** **** **** **** **** +9899 Archivist_Exteneded_Improved_Invisibility **** **** **** **** **** **** **** **** +9900 Archivist_Quickened_Improved_Invisibility **** **** **** **** **** **** **** **** +9901 Archivist_Silent_Improved_Invisibility **** **** **** **** **** **** **** **** +9902 Archivist_Still_Improved_Invisibility **** **** **** **** **** **** **** **** +9903 Archivist_Improved_Mage_Armor **** **** **** **** **** **** **** **** +9904 Archivist_Exteneded_Improved_Mage_Armor **** **** **** **** **** **** **** **** +9905 Archivist_Quickened_Improved_Mage_Armor **** **** **** **** **** **** **** **** +9906 Archivist_Silent_Improved_Mage_Armor **** **** **** **** **** **** **** **** +9907 Archivist_Still_Improved_Mage_Armor **** **** **** **** **** **** **** **** +9908 Archivist_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9909 Archivist_Empowered_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9910 Archivist_Maximized_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9911 Archivist_Quickened_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9912 Archivist_Silent_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9913 Archivist_Still_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +9914 Archivist_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +9915 Archivist_Exteneded_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +9916 Archivist_Quickened_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +9917 Archivist_Silent_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +9918 Archivist_Still_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +9919 Archivist_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +9920 Archivist_Exteneded_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +9921 Archivist_Quickened_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +9922 Archivist_Silent_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +9923 Archivist_Still_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +9924 Archivist_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +9925 Archivist_Exteneded_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +9926 Archivist_Quickened_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +9927 Archivist_Silent_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +9928 Archivist_Still_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +9929 Archivist_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +9930 Archivist_Quickened_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +9931 Archivist_Silent_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +9932 Archivist_Still_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +9933 Archivist_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +9934 Archivist_Exteneded_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +9935 Archivist_Silent_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +9936 Archivist_Still_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +9937 Archivist_Mass_Camoflage **** **** **** **** **** **** **** **** +9938 Archivist_Exteneded_Mass_Camoflage **** **** **** **** **** **** **** **** +9939 Archivist_Quickened_Mass_Camoflage **** **** **** **** **** **** **** **** +9940 Archivist_Silent_Mass_Camoflage **** **** **** **** **** **** **** **** +9941 Archivist_Still_Mass_Camoflage **** **** **** **** **** **** **** **** +9942 Archivist_Mass_Ultravision **** **** **** **** **** **** **** **** +9943 Archivist_Exteneded_Mass_Ultravision **** **** **** **** **** **** **** **** +9944 Archivist_Silent_Mass_Ultravision **** **** **** **** **** **** **** **** +9945 Archivist_Still_Mass_Ultravision **** **** **** **** **** **** **** **** +9946 Archivist_Necrotic_Domination **** **** **** **** **** **** **** **** +9947 Archivist_Exteneded_Necrotic_Domination **** **** **** **** **** **** **** **** +9948 Archivist_Quickened_Necrotic_Domination **** **** **** **** **** **** **** **** +9949 Archivist_Silent_Necrotic_Domination **** **** **** **** **** **** **** **** +9950 Archivist_Still_Necrotic_Domination **** **** **** **** **** **** **** **** +9951 Archivist_Neutralize_Poison **** **** **** **** **** **** **** **** +9952 Archivist_Quickened_Neutralize_Poison **** **** **** **** **** **** **** **** +9953 Archivist_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +9954 Archivist_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +9955 Archivist_NONDETECTION **** **** **** **** **** **** **** **** +9956 Archivist_Exteneded_NONDETECTION **** **** **** **** **** **** **** **** +9957 Archivist_Quickened_NONDETECTION **** **** **** **** **** **** **** **** +9958 Archivist_Silent_NONDETECTION **** **** **** **** **** **** **** **** +9959 Archivist_Still_NONDETECTION **** **** **** **** **** **** **** **** +9960 Archivist_Panacea **** **** **** **** **** **** **** **** +9961 Archivist_Empowered_Panacea **** **** **** **** **** **** **** **** +9962 Archivist_Maximized_Panacea **** **** **** **** **** **** **** **** +9963 Archivist_Quickened_Panacea **** **** **** **** **** **** **** **** +9964 Archivist_Silent_Panacea **** **** **** **** **** **** **** **** +9965 Archivist_Still_Panacea **** **** **** **** **** **** **** **** +9966 Archivist_Phantasmal_Killer **** **** **** **** **** **** **** **** +9967 Archivist_Empowered_Phantasmal_Killer **** **** **** **** **** **** **** **** +9968 Archivist_Maximized_Phantasmal_Killer **** **** **** **** **** **** **** **** +9969 Archivist_Quickened_Phantasmal_Killer **** **** **** **** **** **** **** **** +9970 Archivist_Silent_Phantasmal_Killer **** **** **** **** **** **** **** **** +9971 Archivist_Still_Phantasmal_Killer **** **** **** **** **** **** **** **** +9972 Archivist_Poison **** **** **** **** **** **** **** **** +9973 Archivist_Empowered_Poison **** **** **** **** **** **** **** **** +9974 Archivist_Maximized_Poison **** **** **** **** **** **** **** **** +9975 Archivist_Quickened_Poison **** **** **** **** **** **** **** **** +9976 Archivist_Silent_Poison **** **** **** **** **** **** **** **** +9977 Archivist_Still_Poison **** **** **** **** **** **** **** **** +9978 Archivist_Polymorph_Self **** **** **** **** **** **** **** **** +9979 Archivist_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +9980 Archivist_Polymorph_TROLL **** **** **** **** **** **** **** **** +9981 Archivist_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +9982 Archivist_Polymorph_PIXIE **** **** **** **** **** **** **** **** +9983 Archivist_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +9984 Archivist_Exteneded_Polymorph_Self **** **** **** **** **** **** **** **** +9985 Archivist_Exteneded_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +9986 Archivist_Exteneded_Polymorph_TROLL **** **** **** **** **** **** **** **** +9987 Archivist_Exteneded_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +9988 Archivist_Exteneded_Polymorph_PIXIE **** **** **** **** **** **** **** **** +9989 Archivist_Exteneded_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +9990 Archivist_Quickened_Polymorph_Self **** **** **** **** **** **** **** **** +9991 Archivist_Quickened_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +9992 Archivist_Quickened_Polymorph_TROLL **** **** **** **** **** **** **** **** +9993 Archivist_Quickened_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +9994 Archivist_Quickened_Polymorph_PIXIE **** **** **** **** **** **** **** **** +9995 Archivist_Quickened_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +9996 Archivist_Silent_Polymorph_Self **** **** **** **** **** **** **** **** +9997 Archivist_Silent_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +9998 Archivist_Silent_Polymorph_TROLL **** **** **** **** **** **** **** **** +9999 Archivist_Silent_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +10000 Archivist_Silent_Polymorph_PIXIE **** **** **** **** **** **** **** **** +10001 Archivist_Silent_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +10002 Archivist_Recitation **** **** **** **** **** **** **** **** +10003 Archivist_Exteneded_Recitation **** **** **** **** **** **** **** **** +10004 Archivist_Quickened_Recitation **** **** **** **** **** **** **** **** +10005 Archivist_Silent_Recitation **** **** **** **** **** **** **** **** +10006 Archivist_Still_Recitation **** **** **** **** **** **** **** **** +10007 Archivist_RepelVermin **** **** **** **** **** **** **** **** +10008 Archivist_Exteneded_RepelVermin **** **** **** **** **** **** **** **** +10009 Archivist_Quickened_RepelVermin **** **** **** **** **** **** **** **** +10010 Archivist_Silent_RepelVermin **** **** **** **** **** **** **** **** +10011 Archivist_Still_RepelVermin **** **** **** **** **** **** **** **** +10012 Archivist_Restoration **** **** **** **** **** **** **** **** +10013 Archivist_Quickened_Restoration **** **** **** **** **** **** **** **** +10014 Archivist_Silent_Restoration **** **** **** **** **** **** **** **** +10015 Archivist_Still_Restoration **** **** **** **** **** **** **** **** +10016 Archivist_ShadowArrow **** **** **** **** **** **** **** **** +10017 Archivist_Silent_ShadowArrow **** **** **** **** **** **** **** **** +10018 Archivist_Stoneskin **** **** **** **** **** **** **** **** +10019 Archivist_Exteneded_Stoneskin **** **** **** **** **** **** **** **** +10020 Archivist_Quickened_Stoneskin **** **** **** **** **** **** **** **** +10021 Archivist_Silent_Stoneskin **** **** **** **** **** **** **** **** +10022 Archivist_Still_Stoneskin **** **** **** **** **** **** **** **** +10023 Archivist_STOP_HEART **** **** **** **** **** **** **** **** +10024 Archivist_Quickened_STOP_HEART **** **** **** **** **** **** **** **** +10025 Archivist_Still_STOP_HEART **** **** **** **** **** **** **** **** +10026 Archivist_Summon_Creature_IV **** **** **** **** **** **** **** **** +10027 Archivist_Exteneded_Summon_Creature_IV **** **** **** **** **** **** **** **** +10028 Archivist_Quickened_Summon_Creature_IV **** **** **** **** **** **** **** **** +10029 Archivist_Silent_Summon_Creature_IV **** **** **** **** **** **** **** **** +10030 Archivist_Still_Summon_Creature_IV **** **** **** **** **** **** **** **** +10031 Archivist_SummonUndeadIV **** **** **** **** **** **** **** **** +10032 Archivist_Exteneded_SummonUndeadIV **** **** **** **** **** **** **** **** +10033 Archivist_Quickened_SummonUndeadIV **** **** **** **** **** **** **** **** +10034 Archivist_Silent_SummonUndeadIV **** **** **** **** **** **** **** **** +10035 Archivist_Still_SummonUndeadIV **** **** **** **** **** **** **** **** +10036 Archivist_SUNMANTLE **** **** **** **** **** **** **** **** +10037 Archivist_Exteneded_SUNMANTLE **** **** **** **** **** **** **** **** +10038 Archivist_Quickened_SUNMANTLE **** **** **** **** **** **** **** **** +10039 Archivist_Still_SUNMANTLE **** **** **** **** **** **** **** **** +10040 Archivist_SwordOfConscience **** **** **** **** **** **** **** **** +10041 Archivist_Quickened_SwordOfConscience **** **** **** **** **** **** **** **** +10042 Archivist_Silent_SwordOfConscience **** **** **** **** **** **** **** **** +10043 Archivist_Unholy_Sword **** **** **** **** **** **** **** **** +10044 Archivist_Exteneded_Unholy_Sword **** **** **** **** **** **** **** **** +10045 Archivist_Quickened_Unholy_Sword **** **** **** **** **** **** **** **** +10046 Archivist_Silent_Unholy_Sword **** **** **** **** **** **** **** **** +10047 Archivist_Still_Unholy_Sword **** **** **** **** **** **** **** **** +10048 Archivist_Awaken **** **** **** **** **** **** **** **** +10049 Archivist_Empowered_Awaken **** **** **** **** **** **** **** **** +10050 Archivist_Maximized_Awaken **** **** **** **** **** **** **** **** +10051 Archivist_Quickened_Awaken **** **** **** **** **** **** **** **** +10052 Archivist_Silent_Awaken **** **** **** **** **** **** **** **** +10053 Archivist_Still_Awaken **** **** **** **** **** **** **** **** +10054 Archivist_BalefulPolymorph **** **** **** **** **** **** **** **** +10055 Archivist_Quickened_BalefulPolymorph **** **** **** **** **** **** **** **** +10056 Archivist_Silent_BalefulPolymorph **** **** **** **** **** **** **** **** +10057 Archivist_Still_BalefulPolymorph **** **** **** **** **** **** **** **** +10058 Archivist_Battletide **** **** **** **** **** **** **** **** +10059 Archivist_Exteneded_Battletide **** **** **** **** **** **** **** **** +10060 Archivist_Quickened_Battletide **** **** **** **** **** **** **** **** +10061 Archivist_Silent_Battletide **** **** **** **** **** **** **** **** +10062 Archivist_Still_Battletide **** **** **** **** **** **** **** **** +10063 Archivist_BreakEnchantment **** **** **** **** **** **** **** **** +10064 Archivist_Quickened_BreakEnchantment **** **** **** **** **** **** **** **** +10065 Archivist_Silent_BreakEnchantment **** **** **** **** **** **** **** **** +10066 Archivist_Still_BreakEnchantment **** **** **** **** **** **** **** **** +10067 Archivist_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +10068 Archivist_Exteneded_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +10069 Archivist_Quickened_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +10070 Archivist_Silent_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +10071 Archivist_Circle_of_Doom **** **** **** **** **** **** **** **** +10072 Archivist_Empowered_Circle_of_Doom **** **** **** **** **** **** **** **** +10073 Archivist_Maximized_Circle_of_Doom **** **** **** **** **** **** **** **** +10074 Archivist_Quickened_Circle_of_Doom **** **** **** **** **** **** **** **** +10075 Archivist_Silent_Circle_of_Doom **** **** **** **** **** **** **** **** +10076 Archivist_Still_Circle_of_Doom **** **** **** **** **** **** **** **** +10077 Archivist_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +10078 Archivist_Exteneded_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +10079 Archivist_Quickened_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +10080 Archivist_Silent_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +10081 Archivist_Still_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +10082 Archivist_Cone_of_Cold **** **** **** **** **** **** **** **** +10083 Archivist_Empowered_Cone_of_Cold **** **** **** **** **** **** **** **** +10084 Archivist_Maximized_Cone_of_Cold **** **** **** **** **** **** **** **** +10085 Archivist_Quickened_Cone_of_Cold **** **** **** **** **** **** **** **** +10086 Archivist_Silent_Cone_of_Cold **** **** **** **** **** **** **** **** +10087 Archivist_Still_Cone_of_Cold **** **** **** **** **** **** **** **** +10088 Archivist_CONVERT_WAND **** **** **** **** **** **** **** **** +10089 Archivist_Exteneded_CONVERT_WAND **** **** **** **** **** **** **** **** +10090 Archivist_Quickened_CONVERT_WAND **** **** **** **** **** **** **** **** +10091 Archivist_Silent_CONVERT_WAND **** **** **** **** **** **** **** **** +10092 Archivist_Still_CONVERT_WAND **** **** **** **** **** **** **** **** +10093 Archivist_DANCING_WEB **** **** **** **** **** **** **** **** +10094 Archivist_Empowered_DANCING_WEB **** **** **** **** **** **** **** **** +10095 Archivist_Exteneded_DANCING_WEB **** **** **** **** **** **** **** **** +10096 Archivist_Maximized_DANCING_WEB **** **** **** **** **** **** **** **** +10097 Archivist_Quickened_DANCING_WEB **** **** **** **** **** **** **** **** +10098 Archivist_Silent_DANCING_WEB **** **** **** **** **** **** **** **** +10099 Archivist_Still_DANCING_WEB **** **** **** **** **** **** **** **** +10100 Archivist_DarkBolt **** **** **** **** **** **** **** **** +10101 Archivist_DarkBolt_all **** **** **** **** **** **** **** **** +10102 Archivist_DarkBolt_1 **** **** **** **** **** **** **** **** +10103 Archivist_Empowered_DarkBolt **** **** **** **** **** **** **** **** +10104 Archivist_Empowered_DarkBolt_all **** **** **** **** **** **** **** **** +10105 Archivist_Empowered_DarkBolt_1 **** **** **** **** **** **** **** **** +10106 Archivist_Maximized_DarkBolt **** **** **** **** **** **** **** **** +10107 Archivist_Maximized_DarkBolt_all **** **** **** **** **** **** **** **** +10108 Archivist_Maximized_DarkBolt_1 **** **** **** **** **** **** **** **** +10109 Archivist_Quickened_DarkBolt **** **** **** **** **** **** **** **** +10110 Archivist_Quickened_DarkBolt_all **** **** **** **** **** **** **** **** +10111 Archivist_Quickened_DarkBolt_1 **** **** **** **** **** **** **** **** +10112 Archivist_Silent_DarkBolt **** **** **** **** **** **** **** **** +10113 Archivist_Silent_DarkBolt_all **** **** **** **** **** **** **** **** +10114 Archivist_Silent_DarkBolt_1 **** **** **** **** **** **** **** **** +10115 Archivist_Still_DarkBolt **** **** **** **** **** **** **** **** +10116 Archivist_Still_DarkBolt_all **** **** **** **** **** **** **** **** +10117 Archivist_Still_DarkBolt_1 **** **** **** **** **** **** **** **** +10118 Archivist_Elemental_Strike **** **** **** **** **** **** **** **** +10119 Archivist_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10120 Archivist_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10121 Archivist_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10122 Archivist_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10123 Archivist_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10124 Archivist_Empowered_Elemental_Strike **** **** **** **** **** **** **** **** +10125 Archivist_Empowered_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10126 Archivist_Empowered_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10127 Archivist_Empowered_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10128 Archivist_Empowered_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10129 Archivist_Empowered_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10130 Archivist_Maximized_Elemental_Strike **** **** **** **** **** **** **** **** +10131 Archivist_Maximized_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10132 Archivist_Maximized_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10133 Archivist_Maximized_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10134 Archivist_Maximized_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10135 Archivist_Maximized_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10136 Archivist_Quickened_Elemental_Strike **** **** **** **** **** **** **** **** +10137 Archivist_Quickened_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10138 Archivist_Quickened_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10139 Archivist_Quickened_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10140 Archivist_Quickened_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10141 Archivist_Quickened_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10142 Archivist_Silent_Elemental_Strike **** **** **** **** **** **** **** **** +10143 Archivist_Silent_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10144 Archivist_Silent_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10145 Archivist_Silent_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10146 Archivist_Silent_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10147 Archivist_Silent_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10148 Archivist_Still_Elemental_Strike **** **** **** **** **** **** **** **** +10149 Archivist_Still_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +10150 Archivist_Still_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +10151 Archivist_Still_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +10152 Archivist_Still_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +10153 Archivist_Still_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +10154 Archivist_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10155 Archivist_Empowered_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10156 Archivist_Exteneded_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10157 Archivist_Maximized_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10158 Archivist_Quickened_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10159 Archivist_Silent_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10160 Archivist_Still_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +10161 Archivist_FireInTheBlood **** **** **** **** **** **** **** **** +10162 Archivist_Exteneded_FireInTheBlood **** **** **** **** **** **** **** **** +10163 Archivist_Quickened_FireInTheBlood **** **** **** **** **** **** **** **** +10164 Archivist_Silent_FireInTheBlood **** **** **** **** **** **** **** **** +10165 Archivist_Still_FireInTheBlood **** **** **** **** **** **** **** **** +10166 Archivist_Flame_Strike **** **** **** **** **** **** **** **** +10167 Archivist_Empowered_Flame_Strike **** **** **** **** **** **** **** **** +10168 Archivist_Maximized_Flame_Strike **** **** **** **** **** **** **** **** +10169 Archivist_Quickened_Flame_Strike **** **** **** **** **** **** **** **** +10170 Archivist_Silent_Flame_Strike **** **** **** **** **** **** **** **** +10171 Archivist_Still_Flame_Strike **** **** **** **** **** **** **** **** +10172 Archivist_Greater_Heroism **** **** **** **** **** **** **** **** +10173 Archivist_Exteneded_Greater_Heroism **** **** **** **** **** **** **** **** +10174 Archivist_Silent_Greater_Heroism **** **** **** **** **** **** **** **** +10175 Archivist_Still_Greater_Heroism **** **** **** **** **** **** **** **** +10176 Archivist_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +10177 Archivist_Exteneded_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +10178 Archivist_Quickened_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +10179 Archivist_Silent_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +10180 Archivist_Still_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +10181 Archivist_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +10182 Archivist_GreaterCommand_Approach **** **** **** **** **** **** **** **** +10183 Archivist_GreaterCommand_Drop **** **** **** **** **** **** **** **** +10184 Archivist_GreaterCommand_Fall **** **** **** **** **** **** **** **** +10185 Archivist_GreaterCommand_Flee **** **** **** **** **** **** **** **** +10186 Archivist_GreaterCommand_Halt **** **** **** **** **** **** **** **** +10187 Archivist_Exteneded_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +10188 Archivist_Exteneded_GreaterCommand_Approach **** **** **** **** **** **** **** **** +10189 Archivist_Exteneded_GreaterCommand_Drop **** **** **** **** **** **** **** **** +10190 Archivist_Exteneded_GreaterCommand_Fall **** **** **** **** **** **** **** **** +10191 Archivist_Exteneded_GreaterCommand_Flee **** **** **** **** **** **** **** **** +10192 Archivist_Exteneded_GreaterCommand_Halt **** **** **** **** **** **** **** **** +10193 Archivist_Quickened_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +10194 Archivist_Quickened_GreaterCommand_Approach **** **** **** **** **** **** **** **** +10195 Archivist_Quickened_GreaterCommand_Drop **** **** **** **** **** **** **** **** +10196 Archivist_Quickened_GreaterCommand_Fall **** **** **** **** **** **** **** **** +10197 Archivist_Quickened_GreaterCommand_Flee **** **** **** **** **** **** **** **** +10198 Archivist_Quickened_GreaterCommand_Halt **** **** **** **** **** **** **** **** +10199 Archivist_Silent_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +10200 Archivist_Silent_GreaterCommand_Approach **** **** **** **** **** **** **** **** +10201 Archivist_Silent_GreaterCommand_Drop **** **** **** **** **** **** **** **** +10202 Archivist_Silent_GreaterCommand_Fall **** **** **** **** **** **** **** **** +10203 Archivist_Silent_GreaterCommand_Flee **** **** **** **** **** **** **** **** +10204 Archivist_Silent_GreaterCommand_Halt **** **** **** **** **** **** **** **** +10205 Archivist_Still_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +10206 Archivist_Still_GreaterCommand_Approach **** **** **** **** **** **** **** **** +10207 Archivist_Still_GreaterCommand_Drop **** **** **** **** **** **** **** **** +10208 Archivist_Still_GreaterCommand_Fall **** **** **** **** **** **** **** **** +10209 Archivist_Still_GreaterCommand_Flee **** **** **** **** **** **** **** **** +10210 Archivist_Still_GreaterCommand_Halt **** **** **** **** **** **** **** **** +10211 Archivist_HealAnimalCompanion **** **** **** **** **** **** **** **** +10212 Archivist_Quickened_HealAnimalCompanion **** **** **** **** **** **** **** **** +10213 Archivist_Silent_HealAnimalCompanion **** **** **** **** **** **** **** **** +10214 Archivist_Still_HealAnimalCompanion **** **** **** **** **** **** **** **** +10215 Archivist_Healing_Circle **** **** **** **** **** **** **** **** +10216 Archivist_Empowered_Healing_Circle **** **** **** **** **** **** **** **** +10217 Archivist_Maximized_Healing_Circle **** **** **** **** **** **** **** **** +10218 Archivist_Quickened_Healing_Circle **** **** **** **** **** **** **** **** +10219 Archivist_Silent_Healing_Circle **** **** **** **** **** **** **** **** +10220 Archivist_Still_Healing_Circle **** **** **** **** **** **** **** **** +10221 Archivist_HEARTCLUTCH **** **** **** **** **** **** **** **** +10222 Archivist_Quickened_HEARTCLUTCH **** **** **** **** **** **** **** **** +10223 Archivist_Silent_HEARTCLUTCH **** **** **** **** **** **** **** **** +10224 Archivist_Still_HEARTCLUTCH **** **** **** **** **** **** **** **** +10225 Archivist_Ice_Storm **** **** **** **** **** **** **** **** +10226 Archivist_Empowered_Ice_Storm **** **** **** **** **** **** **** **** +10227 Archivist_Maximized_Ice_Storm **** **** **** **** **** **** **** **** +10228 Archivist_Quickened_Ice_Storm **** **** **** **** **** **** **** **** +10229 Archivist_Silent_Ice_Storm **** **** **** **** **** **** **** **** +10230 Archivist_Still_Ice_Storm **** **** **** **** **** **** **** **** +10231 Archivist_Inferno **** **** **** **** **** **** **** **** +10232 Archivist_Empowered_Inferno **** **** **** **** **** **** **** **** +10233 Archivist_Exteneded_Inferno **** **** **** **** **** **** **** **** +10234 Archivist_Maximized_Inferno **** **** **** **** **** **** **** **** +10235 Archivist_Quickened_Inferno **** **** **** **** **** **** **** **** +10236 Archivist_Silent_Inferno **** **** **** **** **** **** **** **** +10237 Archivist_Still_Inferno **** **** **** **** **** **** **** **** +10238 Archivist_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +10239 Archivist_Exteneded_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +10240 Archivist_Quickened_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +10241 Archivist_Silent_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +10242 Archivist_Still_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +10243 Archivist_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10244 Archivist_Empowered_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10245 Archivist_Exteneded_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10246 Archivist_Maximized_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10247 Archivist_Quickened_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10248 Archivist_Silent_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10249 Archivist_Still_Mass_Cats_Grace **** **** **** **** **** **** **** **** +10250 Archivist_Mass_Contagion **** **** **** **** **** **** **** **** +10251 Archivist_Quickened_Mass_Contagion **** **** **** **** **** **** **** **** +10252 Archivist_Silent_Mass_Contagion **** **** **** **** **** **** **** **** +10253 Archivist_Still_Mass_Contagion **** **** **** **** **** **** **** **** +10254 Archivist_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10255 Archivist_Empowered_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10256 Archivist_Maximized_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10257 Archivist_Quickened_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10258 Archivist_Silent_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10259 Archivist_Still_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +10260 Archivist_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10261 Archivist_Empowered_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10262 Archivist_Maximized_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10263 Archivist_Quickened_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10264 Archivist_Silent_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10265 Archivist_Still_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +10266 Archivist_MORALITY_UNDONE **** **** **** **** **** **** **** **** +10267 Archivist_Quickened_MORALITY_UNDONE **** **** **** **** **** **** **** **** +10268 Archivist_Silent_MORALITY_UNDONE **** **** **** **** **** **** **** **** +10269 Archivist_Still_MORALITY_UNDONE **** **** **** **** **** **** **** **** +10270 Archivist_Necrotic_Burst **** **** **** **** **** **** **** **** +10271 Archivist_Empowered_Necrotic_Burst **** **** **** **** **** **** **** **** +10272 Archivist_Maximized_Necrotic_Burst **** **** **** **** **** **** **** **** +10273 Archivist_Quickened_Necrotic_Burst **** **** **** **** **** **** **** **** +10274 Archivist_Silent_Necrotic_Burst **** **** **** **** **** **** **** **** +10275 Archivist_Still_Necrotic_Burst **** **** **** **** **** **** **** **** +10276 Archivist_Owls_Insight **** **** **** **** **** **** **** **** +10277 Archivist_Exteneded_Owls_Insight **** **** **** **** **** **** **** **** +10278 Archivist_Quickened_Owls_Insight **** **** **** **** **** **** **** **** +10279 Archivist_Silent_Owls_Insight **** **** **** **** **** **** **** **** +10280 Archivist_Still_Owls_Insight **** **** **** **** **** **** **** **** +10281 Archivist_POWER_LEECH **** **** **** **** **** **** **** **** +10282 Archivist_Exteneded_POWER_LEECH **** **** **** **** **** **** **** **** +10283 Archivist_Quickened_POWER_LEECH **** **** **** **** **** **** **** **** +10284 Archivist_Silent_POWER_LEECH **** **** **** **** **** **** **** **** +10285 Archivist_Still_POWER_LEECH **** **** **** **** **** **** **** **** +10286 Archivist_Raise_Dead **** **** **** **** **** **** **** **** +10287 Archivist_Quickened_Raise_Dead **** **** **** **** **** **** **** **** +10288 Archivist_Silent_Raise_Dead **** **** **** **** **** **** **** **** +10289 Archivist_Still_Raise_Dead **** **** **** **** **** **** **** **** +10290 Archivist_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +10291 Archivist_Exteneded_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +10292 Archivist_Quickened_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +10293 Archivist_Silent_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +10294 Archivist_Revivify **** **** **** **** **** **** **** **** +10295 Archivist_Quickened_Revivify **** **** **** **** **** **** **** **** +10296 Archivist_Silent_Revivify **** **** **** **** **** **** **** **** +10297 Archivist_Still_Revivify **** **** **** **** **** **** **** **** +10298 Archivist_Righteous_Might **** **** **** **** **** **** **** **** +10299 Archivist_Exteneded_Righteous_Might **** **** **** **** **** **** **** **** +10300 Archivist_Quickened_Righteous_Might **** **** **** **** **** **** **** **** +10301 Archivist_Silent_Righteous_Might **** **** **** **** **** **** **** **** +10302 Archivist_Still_Righteous_Might **** **** **** **** **** **** **** **** +10303 Archivist_Scrying **** **** **** **** **** **** **** **** +10304 Archivist_Exteneded_Scrying **** **** **** **** **** **** **** **** +10305 Archivist_Quickened_Scrying **** **** **** **** **** **** **** **** +10306 Archivist_Silent_Scrying **** **** **** **** **** **** **** **** +10307 Archivist_Still_Scrying **** **** **** **** **** **** **** **** +10308 Archivist_SICKEN_EVIL **** **** **** **** **** **** **** **** +10309 Archivist_Exteneded_SICKEN_EVIL **** **** **** **** **** **** **** **** +10310 Archivist_Quickened_SICKEN_EVIL **** **** **** **** **** **** **** **** +10311 Archivist_Silent_SICKEN_EVIL **** **** **** **** **** **** **** **** +10312 Archivist_Still_SICKEN_EVIL **** **** **** **** **** **** **** **** +10313 Archivist_Slay_Living **** **** **** **** **** **** **** **** +10314 Archivist_Empowered_Slay_Living **** **** **** **** **** **** **** **** +10315 Archivist_Maximized_Slay_Living **** **** **** **** **** **** **** **** +10316 Archivist_Quickened_Slay_Living **** **** **** **** **** **** **** **** +10317 Archivist_Silent_Slay_Living **** **** **** **** **** **** **** **** +10318 Archivist_Still_Slay_Living **** **** **** **** **** **** **** **** +10319 Archivist_Soulscour **** **** **** **** **** **** **** **** +10320 Archivist_Empowered_Soulscour **** **** **** **** **** **** **** **** +10321 Archivist_Maximized_Soulscour **** **** **** **** **** **** **** **** +10322 Archivist_Quickened_Soulscour **** **** **** **** **** **** **** **** +10323 Archivist_Silent_Soulscour **** **** **** **** **** **** **** **** +10324 Archivist_Still_Soulscour **** **** **** **** **** **** **** **** +10325 Archivist_Spell_Mantle **** **** **** **** **** **** **** **** +10326 Archivist_Empowered_Spell_Mantle **** **** **** **** **** **** **** **** +10327 Archivist_Exteneded_Spell_Mantle **** **** **** **** **** **** **** **** +10328 Archivist_Maximized_Spell_Mantle **** **** **** **** **** **** **** **** +10329 Archivist_Quickened_Spell_Mantle **** **** **** **** **** **** **** **** +10330 Archivist_Silent_Spell_Mantle **** **** **** **** **** **** **** **** +10331 Archivist_Still_Spell_Mantle **** **** **** **** **** **** **** **** +10332 Archivist_Spell_Resistance **** **** **** **** **** **** **** **** +10333 Archivist_Exteneded_Spell_Resistance **** **** **** **** **** **** **** **** +10334 Archivist_Quickened_Spell_Resistance **** **** **** **** **** **** **** **** +10335 Archivist_Silent_Spell_Resistance **** **** **** **** **** **** **** **** +10336 Archivist_Still_Spell_Resistance **** **** **** **** **** **** **** **** +10337 Archivist_Stone_to_flesh **** **** **** **** **** **** **** **** +10338 Archivist_Exteneded_Stone_to_flesh **** **** **** **** **** **** **** **** +10339 Archivist_Quickened_Stone_to_flesh **** **** **** **** **** **** **** **** +10340 Archivist_Silent_Stone_to_flesh **** **** **** **** **** **** **** **** +10341 Archivist_Still_Stone_to_flesh **** **** **** **** **** **** **** **** +10342 Archivist_Summon_Creature_V **** **** **** **** **** **** **** **** +10343 Archivist_Exteneded_Summon_Creature_V **** **** **** **** **** **** **** **** +10344 Archivist_Quickened_Summon_Creature_V **** **** **** **** **** **** **** **** +10345 Archivist_Silent_Summon_Creature_V **** **** **** **** **** **** **** **** +10346 Archivist_Still_Summon_Creature_V **** **** **** **** **** **** **** **** +10347 Archivist_SummonUndeadV **** **** **** **** **** **** **** **** +10348 Archivist_Exteneded_SummonUndeadV **** **** **** **** **** **** **** **** +10349 Archivist_Quickened_SummonUndeadV **** **** **** **** **** **** **** **** +10350 Archivist_Silent_SummonUndeadV **** **** **** **** **** **** **** **** +10351 Archivist_Still_SummonUndeadV **** **** **** **** **** **** **** **** +10352 Archivist_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10353 Archivist_Empowered_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10354 Archivist_Exteneded_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10355 Archivist_Maximized_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10356 Archivist_Quickened_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10357 Archivist_Silent_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10358 Archivist_Still_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +10359 Archivist_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10360 Archivist_Empowered_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10361 Archivist_Exteneded_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10362 Archivist_Maximized_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10363 Archivist_Quickened_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10364 Archivist_Silent_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10365 Archivist_Still_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +10366 Archivist_Teleport_RadialMaster **** **** **** **** **** **** **** **** +10367 Archivist_Teleport_SelfOnly **** **** **** **** **** **** **** **** +10368 Archivist_Teleport_Party **** **** **** **** **** **** **** **** +10369 Archivist_Quickened_Teleport_RadialMaster **** **** **** **** **** **** **** **** +10370 Archivist_Quickened_Teleport_SelfOnly **** **** **** **** **** **** **** **** +10371 Archivist_Quickened_Teleport_Party **** **** **** **** **** **** **** **** +10372 Archivist_Silent_Teleport_RadialMaster **** **** **** **** **** **** **** **** +10373 Archivist_Silent_Teleport_SelfOnly **** **** **** **** **** **** **** **** +10374 Archivist_Silent_Teleport_Party **** **** **** **** **** **** **** **** +10375 Archivist_True_Seeing **** **** **** **** **** **** **** **** +10376 Archivist_Exteneded_True_Seeing **** **** **** **** **** **** **** **** +10377 Archivist_Quickened_True_Seeing **** **** **** **** **** **** **** **** +10378 Archivist_Silent_True_Seeing **** **** **** **** **** **** **** **** +10379 Archivist_Still_True_Seeing **** **** **** **** **** **** **** **** +10380 Archivist_Vine_Mine **** **** **** **** **** **** **** **** +10381 Archivist_Vine_Mine_Entangle **** **** **** **** **** **** **** **** +10382 Archivist_Vine_Mine_Hamper_Movement **** **** **** **** **** **** **** **** +10383 Archivist_Vine_Mine_Camouflage **** **** **** **** **** **** **** **** +10384 Archivist_Exteneded_Vine_Mine **** **** **** **** **** **** **** **** +10385 Archivist_Exteneded_Vine_Mine_Entangle **** **** **** **** **** **** **** **** +10386 Archivist_Exteneded_Vine_Mine_Hamper_Movement **** **** **** **** **** **** **** **** +10387 Archivist_Exteneded_Vine_Mine_Camouflage **** **** **** **** **** **** **** **** +10388 Archivist_Quickened_Vine_Mine **** **** **** **** **** **** **** **** +10389 Archivist_Quickened_Vine_Mine_Entangle **** **** **** **** **** **** **** **** +10390 Archivist_Quickened_Vine_Mine_Hamper_Movement **** **** **** **** **** **** **** **** +10391 Archivist_Quickened_Vine_Mine_Camouflage **** **** **** **** **** **** **** **** +10392 Archivist_Silent_Vine_Mine **** **** **** **** **** **** **** **** +10393 Archivist_Silent_Vine_Mine_Entangle **** **** **** **** **** **** **** **** +10394 Archivist_Silent_Vine_Mine_Hamper_Movement **** **** **** **** **** **** **** **** +10395 Archivist_Silent_Vine_Mine_Camouflage **** **** **** **** **** **** **** **** +10396 Archivist_Still_Vine_Mine **** **** **** **** **** **** **** **** +10397 Archivist_Still_Vine_Mine_Entangle **** **** **** **** **** **** **** **** +10398 Archivist_Still_Vine_Mine_Hamper_Movement **** **** **** **** **** **** **** **** +10399 Archivist_Still_Vine_Mine_Camouflage **** **** **** **** **** **** **** **** +10400 Archivist_Viscid_Glob **** **** **** **** **** **** **** **** +10401 Archivist_Exteneded_Viscid_Glob **** **** **** **** **** **** **** **** +10402 Archivist_Quickened_Viscid_Glob **** **** **** **** **** **** **** **** +10403 Archivist_Silent_Viscid_Glob **** **** **** **** **** **** **** **** +10404 Archivist_Still_Viscid_Glob **** **** **** **** **** **** **** **** +10405 Archivist_Wall_of_Fire **** **** **** **** **** **** **** **** +10406 Archivist_Empowered_Wall_of_Fire **** **** **** **** **** **** **** **** +10407 Archivist_Exteneded_Wall_of_Fire **** **** **** **** **** **** **** **** +10408 Archivist_Maximized_Wall_of_Fire **** **** **** **** **** **** **** **** +10409 Archivist_Quickened_Wall_of_Fire **** **** **** **** **** **** **** **** +10410 Archivist_Silent_Wall_of_Fire **** **** **** **** **** **** **** **** +10411 Archivist_Still_Wall_of_Fire **** **** **** **** **** **** **** **** +10412 Archivist_Acid_Storm **** **** **** **** **** **** **** **** +10413 Archivist_Empowered_Acid_Storm **** **** **** **** **** **** **** **** +10414 Archivist_Maximized_Acid_Storm **** **** **** **** **** **** **** **** +10415 Archivist_Silent_Acid_Storm **** **** **** **** **** **** **** **** +10416 Archivist_Still_Acid_Storm **** **** **** **** **** **** **** **** +10417 Archivist_Animate_Object **** **** **** **** **** **** **** **** +10418 Archivist_Exteneded_Animate_Object **** **** **** **** **** **** **** **** +10419 Archivist_Banishment **** **** **** **** **** **** **** **** +10420 Archivist_Silent_Banishment **** **** **** **** **** **** **** **** +10421 Archivist_Still_Banishment **** **** **** **** **** **** **** **** +10422 Archivist_Blade_Barrier **** **** **** **** **** **** **** **** +10423 Archivist_Empowered_Blade_Barrier **** **** **** **** **** **** **** **** +10424 Archivist_Exteneded_Blade_Barrier **** **** **** **** **** **** **** **** +10425 Archivist_Maximized_Blade_Barrier **** **** **** **** **** **** **** **** +10426 Archivist_Silent_Blade_Barrier **** **** **** **** **** **** **** **** +10427 Archivist_Still_Blade_Barrier **** **** **** **** **** **** **** **** +10428 Archivist_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +10429 Archivist_Empowered_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +10430 Archivist_Maximized_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +10431 Archivist_Silent_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +10432 Archivist_Still_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +10433 Archivist_CELESTIAL_BLOOD **** **** **** **** **** **** **** **** +10434 Archivist_Silent_CELESTIAL_BLOOD **** **** **** **** **** **** **** **** +10435 Archivist_Still_CELESTIAL_BLOOD **** **** **** **** **** **** **** **** +10436 Archivist_Chain_Lightning **** **** **** **** **** **** **** **** +10437 Archivist_Empowered_Chain_Lightning **** **** **** **** **** **** **** **** +10438 Archivist_Maximized_Chain_Lightning **** **** **** **** **** **** **** **** +10439 Archivist_Silent_Chain_Lightning **** **** **** **** **** **** **** **** +10440 Archivist_Still_Chain_Lightning **** **** **** **** **** **** **** **** +10441 Archivist_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +10442 Archivist_Exteneded_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +10443 Archivist_Silent_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +10444 Archivist_Still_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +10445 Archivist_Control_Undead **** **** **** **** **** **** **** **** +10446 Archivist_Exteneded_Control_Undead **** **** **** **** **** **** **** **** +10447 Archivist_Silent_Control_Undead **** **** **** **** **** **** **** **** +10448 Archivist_Still_Control_Undead **** **** **** **** **** **** **** **** +10449 Archivist_Create_Undead **** **** **** **** **** **** **** **** +10450 Archivist_Exteneded_Create_Undead **** **** **** **** **** **** **** **** +10451 Archivist_Silent_Create_Undead **** **** **** **** **** **** **** **** +10452 Archivist_Still_Create_Undead **** **** **** **** **** **** **** **** +10453 Archivist_Crumble **** **** **** **** **** **** **** **** +10454 Archivist_Empowered_Crumble **** **** **** **** **** **** **** **** +10455 Archivist_Maximized_Crumble **** **** **** **** **** **** **** **** +10456 Archivist_Silent_Crumble **** **** **** **** **** **** **** **** +10457 Archivist_Still_Crumble **** **** **** **** **** **** **** **** +10458 Archivist_Drown **** **** **** **** **** **** **** **** +10459 Archivist_Silent_Drown **** **** **** **** **** **** **** **** +10460 Archivist_Still_Drown **** **** **** **** **** **** **** **** +10461 Archivist_Energy_Buffer **** **** **** **** **** **** **** **** +10462 Archivist_Exteneded_Energy_Buffer **** **** **** **** **** **** **** **** +10463 Archivist_Silent_Energy_Buffer **** **** **** **** **** **** **** **** +10464 Archivist_Still_Energy_Buffer **** **** **** **** **** **** **** **** +10465 Archivist_Energy_Immunity **** **** **** **** **** **** **** **** +10466 Archivist_EI_Acid **** **** **** **** **** **** **** **** +10467 Archivist_EI_Cold **** **** **** **** **** **** **** **** +10468 Archivist_EI_Elec **** **** **** **** **** **** **** **** +10469 Archivist_EI_Fire **** **** **** **** **** **** **** **** +10470 Archivist_EI_Sonic **** **** **** **** **** **** **** **** +10471 Archivist_Exteneded_Energy_Immunity **** **** **** **** **** **** **** **** +10472 Archivist_Exteneded_EI_Acid **** **** **** **** **** **** **** **** +10473 Archivist_Exteneded_EI_Cold **** **** **** **** **** **** **** **** +10474 Archivist_Exteneded_EI_Elec **** **** **** **** **** **** **** **** +10475 Archivist_Exteneded_EI_Fire **** **** **** **** **** **** **** **** +10476 Archivist_Exteneded_EI_Sonic **** **** **** **** **** **** **** **** +10477 Archivist_Silent_Energy_Immunity **** **** **** **** **** **** **** **** +10478 Archivist_Silent_EI_Acid **** **** **** **** **** **** **** **** +10479 Archivist_Silent_EI_Cold **** **** **** **** **** **** **** **** +10480 Archivist_Silent_EI_Elec **** **** **** **** **** **** **** **** +10481 Archivist_Silent_EI_Fire **** **** **** **** **** **** **** **** +10482 Archivist_Silent_EI_Sonic **** **** **** **** **** **** **** **** +10483 Archivist_Still_Energy_Immunity **** **** **** **** **** **** **** **** +10484 Archivist_Still_EI_Acid **** **** **** **** **** **** **** **** +10485 Archivist_Still_EI_Cold **** **** **** **** **** **** **** **** +10486 Archivist_Still_EI_Elec **** **** **** **** **** **** **** **** +10487 Archivist_Still_EI_Fire **** **** **** **** **** **** **** **** +10488 Archivist_Still_EI_Sonic **** **** **** **** **** **** **** **** +10489 Archivist_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +10490 Archivist_Exteneded_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +10491 Archivist_Silent_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +10492 Archivist_ExtractWaterElemental **** **** **** **** **** **** **** **** +10493 Archivist_Empowered_ExtractWaterElemental **** **** **** **** **** **** **** **** +10494 Archivist_Maximized_ExtractWaterElemental **** **** **** **** **** **** **** **** +10495 Archivist_Silent_ExtractWaterElemental **** **** **** **** **** **** **** **** +10496 Archivist_Still_ExtractWaterElemental **** **** **** **** **** **** **** **** +10497 Archivist_Greater_Dispelling **** **** **** **** **** **** **** **** +10498 Archivist_Silent_Greater_Dispelling **** **** **** **** **** **** **** **** +10499 Archivist_Still_Greater_Dispelling **** **** **** **** **** **** **** **** +10500 Archivist_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10501 Archivist_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10502 Archivist_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10503 Archivist_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10504 Archivist_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10505 Archivist_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10506 Archivist_Empowered_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10507 Archivist_Empowered_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10508 Archivist_Empowered_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10509 Archivist_Empowered_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10510 Archivist_Empowered_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10511 Archivist_Empowered_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10512 Archivist_Exteneded_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10513 Archivist_Exteneded_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10514 Archivist_Exteneded_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10515 Archivist_Exteneded_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10516 Archivist_Exteneded_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10517 Archivist_Exteneded_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10518 Archivist_Maximized_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10519 Archivist_Maximized_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10520 Archivist_Maximized_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10521 Archivist_Maximized_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10522 Archivist_Maximized_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10523 Archivist_Maximized_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10524 Archivist_Silent_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10525 Archivist_Silent_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10526 Archivist_Silent_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10527 Archivist_Silent_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10528 Archivist_Silent_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10529 Archivist_Silent_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10530 Archivist_Still_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +10531 Archivist_Still_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +10532 Archivist_Still_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +10533 Archivist_Still_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +10534 Archivist_Still_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +10535 Archivist_Still_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +10536 Archivist_Etherealness **** **** **** **** **** **** **** **** +10537 Archivist_Exteneded_Etherealness **** **** **** **** **** **** **** **** +10538 Archivist_Silent_Etherealness **** **** **** **** **** **** **** **** +10539 Archivist_Still_Etherealness **** **** **** **** **** **** **** **** +10540 Archivist_Greater_Stoneskin **** **** **** **** **** **** **** **** +10541 Archivist_Exteneded_Greater_Stoneskin **** **** **** **** **** **** **** **** +10542 Archivist_Silent_Greater_Stoneskin **** **** **** **** **** **** **** **** +10543 Archivist_Still_Greater_Stoneskin **** **** **** **** **** **** **** **** +10544 Archivist_Harm **** **** **** **** **** **** **** **** +10545 Archivist_Silent_Harm **** **** **** **** **** **** **** **** +10546 Archivist_Still_Harm **** **** **** **** **** **** **** **** +10547 Archivist_Heal **** **** **** **** **** **** **** **** +10548 Archivist_Silent_Heal **** **** **** **** **** **** **** **** +10549 Archivist_Still_Heal **** **** **** **** **** **** **** **** +10550 Archivist_Legend_Lore **** **** **** **** **** **** **** **** +10551 Archivist_Exteneded_Legend_Lore **** **** **** **** **** **** **** **** +10552 Archivist_Silent_Legend_Lore **** **** **** **** **** **** **** **** +10553 Archivist_Still_Legend_Lore **** **** **** **** **** **** **** **** +10554 Archivist_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10555 Archivist_Empowered_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10556 Archivist_Exteneded_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10557 Archivist_Maximized_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10558 Archivist_Silent_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10559 Archivist_Still_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +10560 Archivist_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +10561 Archivist_Empowered_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +10562 Archivist_Maximized_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +10563 Archivist_Silent_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +10564 Archivist_Still_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +10565 Archivist_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10566 Archivist_Empowered_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10567 Archivist_Exteneded_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10568 Archivist_Maximized_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10569 Archivist_Silent_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10570 Archivist_Still_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +10571 Archivist_Mass_Endurance **** **** **** **** **** **** **** **** +10572 Archivist_Empowered_Mass_Endurance **** **** **** **** **** **** **** **** +10573 Archivist_Exteneded_Mass_Endurance **** **** **** **** **** **** **** **** +10574 Archivist_Maximized_Mass_Endurance **** **** **** **** **** **** **** **** +10575 Archivist_Silent_Mass_Endurance **** **** **** **** **** **** **** **** +10576 Archivist_Still_Mass_Endurance **** **** **** **** **** **** **** **** +10577 Archivist_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10578 Archivist_Empowered_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10579 Archivist_Exteneded_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10580 Archivist_Maximized_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10581 Archivist_Silent_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10582 Archivist_Still_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +10583 Archivist_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +10584 Archivist_Empowered_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +10585 Archivist_Maximized_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +10586 Archivist_Silent_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +10587 Archivist_Still_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +10588 Archivist_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10589 Archivist_Empowered_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10590 Archivist_Exteneded_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10591 Archivist_Maximized_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10592 Archivist_Silent_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10593 Archivist_Still_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +10594 Archivist_Necrotic_Eruption **** **** **** **** **** **** **** **** +10595 Archivist_Empowered_Necrotic_Eruption **** **** **** **** **** **** **** **** +10596 Archivist_Maximized_Necrotic_Eruption **** **** **** **** **** **** **** **** +10597 Archivist_Silent_Necrotic_Eruption **** **** **** **** **** **** **** **** +10598 Archivist_Still_Necrotic_Eruption **** **** **** **** **** **** **** **** +10599 Archivist_Planar_Ally **** **** **** **** **** **** **** **** +10600 Archivist_Exteneded_Planar_Ally **** **** **** **** **** **** **** **** +10601 Archivist_Silent_Planar_Ally **** **** **** **** **** **** **** **** +10602 Archivist_Still_Planar_Ally **** **** **** **** **** **** **** **** +10603 Archivist_Planar_Binding **** **** **** **** **** **** **** **** +10604 Archivist_Exteneded_Planar_Binding **** **** **** **** **** **** **** **** +10605 Archivist_Silent_Planar_Binding **** **** **** **** **** **** **** **** +10606 Archivist_Still_Planar_Binding **** **** **** **** **** **** **** **** +10607 Archivist_Pox **** **** **** **** **** **** **** **** +10608 Archivist_Empowered_Pox **** **** **** **** **** **** **** **** +10609 Archivist_Maximized_Pox **** **** **** **** **** **** **** **** +10610 Archivist_Silent_Pox **** **** **** **** **** **** **** **** +10611 Archivist_Still_Pox **** **** **** **** **** **** **** **** +10612 Archivist_SarcophagusOfStone **** **** **** **** **** **** **** **** +10613 Archivist_Silent_SarcophagusOfStone **** **** **** **** **** **** **** **** +10614 Archivist_Still_SarcophagusOfStone **** **** **** **** **** **** **** **** +10615 Archivist_Stonehold **** **** **** **** **** **** **** **** +10616 Archivist_Empowered_Stonehold **** **** **** **** **** **** **** **** +10617 Archivist_Exteneded_Stonehold **** **** **** **** **** **** **** **** +10618 Archivist_Maximized_Stonehold **** **** **** **** **** **** **** **** +10619 Archivist_Silent_Stonehold **** **** **** **** **** **** **** **** +10620 Archivist_Still_Stonehold **** **** **** **** **** **** **** **** +10621 Archivist_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +10622 Archivist_Empowered_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +10623 Archivist_Maximized_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +10624 Archivist_Silent_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +10625 Archivist_Still_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +10626 Archivist_Summon_Creature_VI **** **** **** **** **** **** **** **** +10627 Archivist_Exteneded_Summon_Creature_VI **** **** **** **** **** **** **** **** +10628 Archivist_Silent_Summon_Creature_VI **** **** **** **** **** **** **** **** +10629 Archivist_Still_Summon_Creature_VI **** **** **** **** **** **** **** **** +10630 Archivist_Superior_Resistance **** **** **** **** **** **** **** **** +10631 Archivist_Exteneded_Superior_Resistance **** **** **** **** **** **** **** **** +10632 Archivist_Silent_Superior_Resistance **** **** **** **** **** **** **** **** +10633 Archivist_Still_Superior_Resistance **** **** **** **** **** **** **** **** +10634 Archivist_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10635 Archivist_Empowered_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10636 Archivist_Exteneded_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10637 Archivist_Maximized_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10638 Archivist_Silent_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10639 Archivist_Still_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +10640 Archivist_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10641 Archivist_Empowered_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10642 Archivist_Exteneded_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10643 Archivist_Maximized_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10644 Archivist_Silent_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10645 Archivist_Still_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +10646 Archivist_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10647 Archivist_Empowered_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10648 Archivist_Exteneded_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10649 Archivist_Maximized_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10650 Archivist_Silent_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10651 Archivist_Still_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +10652 Archivist_TransportViaPlants_RadialMaster **** **** **** **** **** **** **** **** +10653 Archivist_TransportViaPlants_SelfOnly **** **** **** **** **** **** **** **** +10654 Archivist_TransportViaPlants_Party **** **** **** **** **** **** **** **** +10655 Archivist_Silent_TransportViaPlants_RadialMaster **** **** **** **** **** **** **** **** +10656 Archivist_Silent_TransportViaPlants_SelfOnly **** **** **** **** **** **** **** **** +10657 Archivist_Silent_TransportViaPlants_Party **** **** **** **** **** **** **** **** +10658 Archivist_Undeath_to_Death **** **** **** **** **** **** **** **** +10659 Archivist_Empowered_Undeath_to_Death **** **** **** **** **** **** **** **** +10660 Archivist_Maximized_Undeath_to_Death **** **** **** **** **** **** **** **** +10661 Archivist_Silent_Undeath_to_Death **** **** **** **** **** **** **** **** +10662 Archivist_Still_Undeath_to_Death **** **** **** **** **** **** **** **** +10663 Archivist_Vigorous_Circle **** **** **** **** **** **** **** **** +10664 Archivist_Exteneded_Vigorous_Circle **** **** **** **** **** **** **** **** +10665 Archivist_Silent_Vigorous_Circle **** **** **** **** **** **** **** **** +10666 Archivist_Still_Vigorous_Circle **** **** **** **** **** **** **** **** +10667 Archivist_WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +10668 Archivist_WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +10669 Archivist_WordOfRecall_Party **** **** **** **** **** **** **** **** +10670 Archivist_Silent_WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +10671 Archivist_Silent_WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +10672 Archivist_Silent_WordOfRecall_Party **** **** **** **** **** **** **** **** +10673 Archivist_Aura_of_Vitality **** **** **** **** **** **** **** **** +10674 Archivist_Exteneded_Aura_of_Vitality **** **** **** **** **** **** **** **** +10675 Archivist_Silent_Aura_of_Vitality **** **** **** **** **** **** **** **** +10676 Archivist_Still_Aura_of_Vitality **** **** **** **** **** **** **** **** +10677 Archivist_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +10678 Archivist_Exteneded_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +10679 Archivist_Silent_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +10680 Archivist_Still_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +10681 Archivist_Blasphemy **** **** **** **** **** **** **** **** +10682 Archivist_Silent_Blasphemy **** **** **** **** **** **** **** **** +10683 Archivist_Still_Blasphemy **** **** **** **** **** **** **** **** +10684 Archivist_Control_Weather **** **** **** **** **** **** **** **** +10685 Archivist_CW_Rain **** **** **** **** **** **** **** **** +10686 Archivist_CW_Snow **** **** **** **** **** **** **** **** +10687 Archivist_CW_Clear **** **** **** **** **** **** **** **** +10688 Archivist_Exteneded_Control_Weather **** **** **** **** **** **** **** **** +10689 Archivist_Exteneded_CW_Rain **** **** **** **** **** **** **** **** +10690 Archivist_Exteneded_CW_Snow **** **** **** **** **** **** **** **** +10691 Archivist_Exteneded_CW_Clear **** **** **** **** **** **** **** **** +10692 Archivist_Silent_Control_Weather **** **** **** **** **** **** **** **** +10693 Archivist_Silent_CW_Rain **** **** **** **** **** **** **** **** +10694 Archivist_Silent_CW_Snow **** **** **** **** **** **** **** **** +10695 Archivist_Silent_CW_Clear **** **** **** **** **** **** **** **** +10696 Archivist_Still_Control_Weather **** **** **** **** **** **** **** **** +10697 Archivist_Still_CW_Rain **** **** **** **** **** **** **** **** +10698 Archivist_Still_CW_Snow **** **** **** **** **** **** **** **** +10699 Archivist_Still_CW_Clear **** **** **** **** **** **** **** **** +10700 Archivist_Creeping_Doom **** **** **** **** **** **** **** **** +10701 Archivist_Exteneded_Creeping_Doom **** **** **** **** **** **** **** **** +10702 Archivist_Silent_Creeping_Doom **** **** **** **** **** **** **** **** +10703 Archivist_Still_Creeping_Doom **** **** **** **** **** **** **** **** +10704 Archivist_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +10705 Archivist_Silent_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +10706 Archivist_Still_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +10707 Archivist_Destruction **** **** **** **** **** **** **** **** +10708 Archivist_Silent_Destruction **** **** **** **** **** **** **** **** +10709 Archivist_Still_Destruction **** **** **** **** **** **** **** **** +10710 Archivist_Dictum **** **** **** **** **** **** **** **** +10711 Archivist_Silent_Dictum **** **** **** **** **** **** **** **** +10712 Archivist_Still_Dictum **** **** **** **** **** **** **** **** +10713 Archivist_Disintegrate **** **** **** **** **** **** **** **** +10714 Archivist_Empowered_Disintegrate **** **** **** **** **** **** **** **** +10715 Archivist_Silent_Disintegrate **** **** **** **** **** **** **** **** +10716 Archivist_Still_Disintegrate **** **** **** **** **** **** **** **** +10717 Archivist_DRAGON_ALLY **** **** **** **** **** **** **** **** +10718 Archivist_Exteneded_DRAGON_ALLY **** **** **** **** **** **** **** **** +10719 Archivist_Silent_DRAGON_ALLY **** **** **** **** **** **** **** **** +10720 Archivist_Energy_Ebb **** **** **** **** **** **** **** **** +10721 Archivist_Exteneded_Energy_Ebb **** **** **** **** **** **** **** **** +10722 Archivist_Silent_Energy_Ebb **** **** **** **** **** **** **** **** +10723 Archivist_Still_Energy_Ebb **** **** **** **** **** **** **** **** +10724 Archivist_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +10725 Archivist_Silent_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +10726 Archivist_Still_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +10727 Archivist_Great_Thunderclap **** **** **** **** **** **** **** **** +10728 Archivist_Silent_Great_Thunderclap **** **** **** **** **** **** **** **** +10729 Archivist_Still_Great_Thunderclap **** **** **** **** **** **** **** **** +10730 Archivist_Greater_Harm **** **** **** **** **** **** **** **** +10731 Archivist_Silent_Greater_Harm **** **** **** **** **** **** **** **** +10732 Archivist_Still_Greater_Harm **** **** **** **** **** **** **** **** +10733 Archivist_Greater_Restoration **** **** **** **** **** **** **** **** +10734 Archivist_Silent_Greater_Restoration **** **** **** **** **** **** **** **** +10735 Archivist_Still_Greater_Restoration **** **** **** **** **** **** **** **** +10736 Archivist_GreaterScrying **** **** **** **** **** **** **** **** +10737 Archivist_Exteneded_GreaterScrying **** **** **** **** **** **** **** **** +10738 Archivist_Silent_GreaterScrying **** **** **** **** **** **** **** **** +10739 Archivist_Still_GreaterScrying **** **** **** **** **** **** **** **** +10740 Archivist_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +10741 Archivist_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +10742 Archivist_GreaterTeleport_Party **** **** **** **** **** **** **** **** +10743 Archivist_Silent_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +10744 Archivist_Silent_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +10745 Archivist_Silent_GreaterTeleport_Party **** **** **** **** **** **** **** **** +10746 Archivist_Holy_Word **** **** **** **** **** **** **** **** +10747 Archivist_Silent_Holy_Word **** **** **** **** **** **** **** **** +10748 Archivist_Still_Holy_Word **** **** **** **** **** **** **** **** +10749 Archivist_Mass_Charm **** **** **** **** **** **** **** **** +10750 Archivist_Exteneded_Mass_Charm **** **** **** **** **** **** **** **** +10751 Archivist_Silent_Mass_Charm **** **** **** **** **** **** **** **** +10752 Archivist_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +10753 Archivist_Empowered_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +10754 Archivist_Silent_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +10755 Archivist_Still_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +10756 Archivist_Mass_Haste **** **** **** **** **** **** **** **** +10757 Archivist_Exteneded_Mass_Haste **** **** **** **** **** **** **** **** +10758 Archivist_Silent_Mass_Haste **** **** **** **** **** **** **** **** +10759 Archivist_Still_Mass_Haste **** **** **** **** **** **** **** **** +10760 Archivist_Mass_Hold_Person **** **** **** **** **** **** **** **** +10761 Archivist_Exteneded_Mass_Hold_Person **** **** **** **** **** **** **** **** +10762 Archivist_Silent_Mass_Hold_Person **** **** **** **** **** **** **** **** +10763 Archivist_Still_Mass_Hold_Person **** **** **** **** **** **** **** **** +10764 Archivist_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +10765 Archivist_Empowered_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +10766 Archivist_Silent_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +10767 Archivist_Still_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +10768 Archivist_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +10769 Archivist_Exteneded_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +10770 Archivist_Silent_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +10771 Archivist_Still_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +10772 Archivist_PHOENIX_FIRE **** **** **** **** **** **** **** **** +10773 Archivist_Empowered_PHOENIX_FIRE **** **** **** **** **** **** **** **** +10774 Archivist_Silent_PHOENIX_FIRE **** **** **** **** **** **** **** **** +10775 Archivist_Still_PHOENIX_FIRE **** **** **** **** **** **** **** **** +10776 Archivist_Prismatic_Spray **** **** **** **** **** **** **** **** +10777 Archivist_Silent_Prismatic_Spray **** **** **** **** **** **** **** **** +10778 Archivist_Still_Prismatic_Spray **** **** **** **** **** **** **** **** +10779 Archivist_Protection_from_Spells **** **** **** **** **** **** **** **** +10780 Archivist_Exteneded_Protection_from_Spells **** **** **** **** **** **** **** **** +10781 Archivist_Silent_Protection_from_Spells **** **** **** **** **** **** **** **** +10782 Archivist_Still_Protection_from_Spells **** **** **** **** **** **** **** **** +10783 Archivist_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +10784 Archivist_Empowered_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +10785 Archivist_Exteneded_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +10786 Archivist_Silent_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +10787 Archivist_Still_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +10788 Archivist_RAIN_OF_ROSES **** **** **** **** **** **** **** **** +10789 Archivist_Exteneded_RAIN_OF_ROSES **** **** **** **** **** **** **** **** +10790 Archivist_Silent_RAIN_OF_ROSES **** **** **** **** **** **** **** **** +10791 Archivist_Still_RAIN_OF_ROSES **** **** **** **** **** **** **** **** +10792 Archivist_RAPTURE_OF_RUPTURE **** **** **** **** **** **** **** **** +10793 Archivist_Empowered_RAPTURE_OF_RUPTURE **** **** **** **** **** **** **** **** +10794 Archivist_Regenerate **** **** **** **** **** **** **** **** +10795 Archivist_Exteneded_Regenerate **** **** **** **** **** **** **** **** +10796 Archivist_Silent_Regenerate **** **** **** **** **** **** **** **** +10797 Archivist_Still_Regenerate **** **** **** **** **** **** **** **** +10798 Archivist_Repulsion **** **** **** **** **** **** **** **** +10799 Archivist_Exteneded_Repulsion **** **** **** **** **** **** **** **** +10800 Archivist_Silent_Repulsion **** **** **** **** **** **** **** **** +10801 Archivist_Still_Repulsion **** **** **** **** **** **** **** **** +10802 Archivist_Resurrection **** **** **** **** **** **** **** **** +10803 Archivist_Silent_Resurrection **** **** **** **** **** **** **** **** +10804 Archivist_Still_Resurrection **** **** **** **** **** **** **** **** +10805 Archivist_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +10806 Archivist_Empowered_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +10807 Archivist_Silent_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +10808 Archivist_Still_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +10809 Archivist_Spell_Turning **** **** **** **** **** **** **** **** +10810 Archivist_Empowered_Spell_Turning **** **** **** **** **** **** **** **** +10811 Archivist_Exteneded_Spell_Turning **** **** **** **** **** **** **** **** +10812 Archivist_Silent_Spell_Turning **** **** **** **** **** **** **** **** +10813 Archivist_Still_Spell_Turning **** **** **** **** **** **** **** **** +10814 Archivist_Summon_Creature_VII **** **** **** **** **** **** **** **** +10815 Archivist_Summon7Air **** **** **** **** **** **** **** **** +10816 Archivist_Summon7Earth **** **** **** **** **** **** **** **** +10817 Archivist_Summon7Fire **** **** **** **** **** **** **** **** +10818 Archivist_Summon7Water **** **** **** **** **** **** **** **** +10819 Archivist_Exteneded_Summon_Creature_VII **** **** **** **** **** **** **** **** +10820 Archivist_Exteneded_Summon7Air **** **** **** **** **** **** **** **** +10821 Archivist_Exteneded_Summon7Earth **** **** **** **** **** **** **** **** +10822 Archivist_Exteneded_Summon7Fire **** **** **** **** **** **** **** **** +10823 Archivist_Exteneded_Summon7Water **** **** **** **** **** **** **** **** +10824 Archivist_Silent_Summon_Creature_VII **** **** **** **** **** **** **** **** +10825 Archivist_Silent_Summon7Air **** **** **** **** **** **** **** **** +10826 Archivist_Silent_Summon7Earth **** **** **** **** **** **** **** **** +10827 Archivist_Silent_Summon7Fire **** **** **** **** **** **** **** **** +10828 Archivist_Silent_Summon7Water **** **** **** **** **** **** **** **** +10829 Archivist_Still_Summon_Creature_VII **** **** **** **** **** **** **** **** +10830 Archivist_Still_Summon7Air **** **** **** **** **** **** **** **** +10831 Archivist_Still_Summon7Earth **** **** **** **** **** **** **** **** +10832 Archivist_Still_Summon7Fire **** **** **** **** **** **** **** **** +10833 Archivist_Still_Summon7Water **** **** **** **** **** **** **** **** +10834 Archivist_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +10835 Archivist_Empowered_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +10836 Archivist_Exteneded_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +10837 Archivist_Silent_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +10838 Archivist_Still_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +10839 Archivist_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +10840 Archivist_Empowered_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +10841 Archivist_Exteneded_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +10842 Archivist_Silent_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +10843 Archivist_Still_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +10844 Archivist_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +10845 Archivist_Silent_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +10846 Archivist_Still_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +10847 Archivist_Word_of_Balance **** **** **** **** **** **** **** **** +10848 Archivist_Empowered_Word_of_Balance **** **** **** **** **** **** **** **** +10849 Archivist_Silent_Word_of_Balance **** **** **** **** **** **** **** **** +10850 Archivist_Word_of_Chaos **** **** **** **** **** **** **** **** +10851 Archivist_Silent_Word_of_Chaos **** **** **** **** **** **** **** **** +10852 Archivist_Still_Word_of_Chaos **** **** **** **** **** **** **** **** +10853 Archivist_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +10854 Archivist_Empowered_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +10855 Archivist_Silent_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +10856 Archivist_Still_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +10857 Archivist_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +10858 Archivist_Exteneded_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +10859 Archivist_Silent_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +10860 Archivist_Still_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +10861 Archivist_Aura_versus_Alignment **** **** **** **** **** **** **** **** +10862 Archivist_Unholy_Aura **** **** **** **** **** **** **** **** +10863 Archivist_Holy_Aura **** **** **** **** **** **** **** **** +10864 Archivist_Exteneded_Aura_versus_Alignment **** **** **** **** **** **** **** **** +10865 Archivist_Exteneded_Unholy_Aura **** **** **** **** **** **** **** **** +10866 Archivist_Exteneded_Holy_Aura **** **** **** **** **** **** **** **** +10867 Archivist_Silent_Aura_versus_Alignment **** **** **** **** **** **** **** **** +10868 Archivist_Silent_Unholy_Aura **** **** **** **** **** **** **** **** +10869 Archivist_Silent_Holy_Aura **** **** **** **** **** **** **** **** +10870 Archivist_Still_Aura_versus_Alignment **** **** **** **** **** **** **** **** +10871 Archivist_Still_Unholy_Aura **** **** **** **** **** **** **** **** +10872 Archivist_Still_Holy_Aura **** **** **** **** **** **** **** **** +10873 Archivist_Blackstaff **** **** **** **** **** **** **** **** +10874 Archivist_Exteneded_Blackstaff **** **** **** **** **** **** **** **** +10875 Archivist_Silent_Blackstaff **** **** **** **** **** **** **** **** +10876 Archivist_Still_Blackstaff **** **** **** **** **** **** **** **** +10877 Archivist_BODAK_BIRTH **** **** **** **** **** **** **** **** +10878 Archivist_Silent_BODAK_BIRTH **** **** **** **** **** **** **** **** +10879 Archivist_Still_BODAK_BIRTH **** **** **** **** **** **** **** **** +10880 Archivist_Bombardment **** **** **** **** **** **** **** **** +10881 Archivist_Silent_Bombardment **** **** **** **** **** **** **** **** +10882 Archivist_Still_Bombardment **** **** **** **** **** **** **** **** +10883 Archivist_Create_Greater_Undead **** **** **** **** **** **** **** **** +10884 Archivist_Exteneded_Create_Greater_Undead **** **** **** **** **** **** **** **** +10885 Archivist_Silent_Create_Greater_Undead **** **** **** **** **** **** **** **** +10886 Archivist_Still_Create_Greater_Undead **** **** **** **** **** **** **** **** +10887 Archivist_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +10888 Archivist_Exteneded_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +10889 Archivist_Silent_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +10890 Archivist_Still_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +10891 Archivist_Dimensional_Lock **** **** **** **** **** **** **** **** +10892 Archivist_Exteneded_Dimensional_Lock **** **** **** **** **** **** **** **** +10893 Archivist_Silent_Dimensional_Lock **** **** **** **** **** **** **** **** +10894 Archivist_Still_Dimensional_Lock **** **** **** **** **** **** **** **** +10895 Archivist_DiscernLocation **** **** **** **** **** **** **** **** +10896 Archivist_Exteneded_DiscernLocation **** **** **** **** **** **** **** **** +10897 Archivist_Silent_DiscernLocation **** **** **** **** **** **** **** **** +10898 Archivist_Still_DiscernLocation **** **** **** **** **** **** **** **** +10899 Archivist_Dominate_Monster **** **** **** **** **** **** **** **** +10900 Archivist_Exteneded_Dominate_Monster **** **** **** **** **** **** **** **** +10901 Archivist_Silent_Dominate_Monster **** **** **** **** **** **** **** **** +10902 Archivist_Still_Dominate_Monster **** **** **** **** **** **** **** **** +10903 Archivist_DRAGON_CLOUD **** **** **** **** **** **** **** **** +10904 Archivist_Silent_DRAGON_CLOUD **** **** **** **** **** **** **** **** +10905 Archivist_Still_DRAGON_CLOUD **** **** **** **** **** **** **** **** +10906 Archivist_Earthquake **** **** **** **** **** **** **** **** +10907 Archivist_Exteneded_Earthquake **** **** **** **** **** **** **** **** +10908 Archivist_Silent_Earthquake **** **** **** **** **** **** **** **** +10909 Archivist_Still_Earthquake **** **** **** **** **** **** **** **** +10910 Archivist_EVIL_WEATHER **** **** **** **** **** **** **** **** +10911 Archivist_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +10912 Archivist_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +10913 Archivist_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +10914 Archivist_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +10915 Archivist_Silent_EVIL_WEATHER **** **** **** **** **** **** **** **** +10916 Archivist_Silent_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +10917 Archivist_Silent_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +10918 Archivist_Silent_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +10919 Archivist_Silent_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +10920 Archivist_Still_EVIL_WEATHER **** **** **** **** **** **** **** **** +10921 Archivist_Still_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +10922 Archivist_Still_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +10923 Archivist_Still_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +10924 Archivist_Still_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +10925 Archivist_Finger_of_Death **** **** **** **** **** **** **** **** +10926 Archivist_Silent_Finger_of_Death **** **** **** **** **** **** **** **** +10927 Archivist_Still_Finger_of_Death **** **** **** **** **** **** **** **** +10928 Archivist_Fire_Storm **** **** **** **** **** **** **** **** +10929 Archivist_Silent_Fire_Storm **** **** **** **** **** **** **** **** +10930 Archivist_Still_Fire_Storm **** **** **** **** **** **** **** **** +10931 Archivist_Greater_Planar_Ally **** **** **** **** **** **** **** **** +10932 Archivist_Exteneded_Greater_Planar_Ally **** **** **** **** **** **** **** **** +10933 Archivist_Silent_Greater_Planar_Ally **** **** **** **** **** **** **** **** +10934 Archivist_Still_Greater_Planar_Ally **** **** **** **** **** **** **** **** +10935 Archivist_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +10936 Archivist_Exteneded_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +10937 Archivist_Silent_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +10938 Archivist_Still_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +10939 Archivist_Holy_Aura **** **** **** **** **** **** **** **** +10940 Archivist_Exteneded_Holy_Aura **** **** **** **** **** **** **** **** +10941 Archivist_Silent_Holy_Aura **** **** **** **** **** **** **** **** +10942 Archivist_Still_Holy_Aura **** **** **** **** **** **** **** **** +10943 Archivist_Horrid_Wilting **** **** **** **** **** **** **** **** +10944 Archivist_Silent_Horrid_Wilting **** **** **** **** **** **** **** **** +10945 Archivist_Still_Horrid_Wilting **** **** **** **** **** **** **** **** +10946 Archivist_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +10947 Archivist_Silent_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +10948 Archivist_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +10949 Archivist_Silent_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +10950 Archivist_Still_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +10951 Archivist_Mass_Heal **** **** **** **** **** **** **** **** +10952 Archivist_Silent_Mass_Heal **** **** **** **** **** **** **** **** +10953 Archivist_Still_Mass_Heal **** **** **** **** **** **** **** **** +10954 Archivist_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +10955 Archivist_Silent_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +10956 Archivist_Still_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +10957 Archivist_Natures_Balance **** **** **** **** **** **** **** **** +10958 Archivist_Silent_Natures_Balance **** **** **** **** **** **** **** **** +10959 Archivist_Still_Natures_Balance **** **** **** **** **** **** **** **** +10960 Archivist_Necrotic_Empowerment **** **** **** **** **** **** **** **** +10961 Archivist_Exteneded_Necrotic_Empowerment **** **** **** **** **** **** **** **** +10962 Archivist_Silent_Necrotic_Empowerment **** **** **** **** **** **** **** **** +10963 Archivist_Still_Necrotic_Empowerment **** **** **** **** **** **** **** **** +10964 Archivist_Pestilence **** **** **** **** **** **** **** **** +10965 Archivist_Silent_Pestilence **** **** **** **** **** **** **** **** +10966 Archivist_Still_Pestilence **** **** **** **** **** **** **** **** +10967 Archivist_Power_Word_Stun **** **** **** **** **** **** **** **** +10968 Archivist_Silent_Power_Word_Stun **** **** **** **** **** **** **** **** +10969 Archivist_Premonition **** **** **** **** **** **** **** **** +10970 Archivist_Exteneded_Premonition **** **** **** **** **** **** **** **** +10971 Archivist_Silent_Premonition **** **** **** **** **** **** **** **** +10972 Archivist_Still_Premonition **** **** **** **** **** **** **** **** +10973 Archivist_Shadow_Shield **** **** **** **** **** **** **** **** +10974 Archivist_Exteneded_Shadow_Shield **** **** **** **** **** **** **** **** +10975 Archivist_Silent_Shadow_Shield **** **** **** **** **** **** **** **** +10976 Archivist_Still_Shadow_Shield **** **** **** **** **** **** **** **** +10977 Archivist_Summon_Creature_VIII **** **** **** **** **** **** **** **** +10978 Archivist_Summon8Air **** **** **** **** **** **** **** **** +10979 Archivist_Summon8Earth **** **** **** **** **** **** **** **** +10980 Archivist_Summon8Fire **** **** **** **** **** **** **** **** +10981 Archivist_Summon8Water **** **** **** **** **** **** **** **** +10982 Archivist_Exteneded_Summon_Creature_VIII **** **** **** **** **** **** **** **** +10983 Archivist_Exteneded_Summon8Air **** **** **** **** **** **** **** **** +10984 Archivist_Exteneded_Summon8Earth **** **** **** **** **** **** **** **** +10985 Archivist_Exteneded_Summon8Fire **** **** **** **** **** **** **** **** +10986 Archivist_Exteneded_Summon8Water **** **** **** **** **** **** **** **** +10987 Archivist_Silent_Summon_Creature_VIII **** **** **** **** **** **** **** **** +10988 Archivist_Silent_Summon8Air **** **** **** **** **** **** **** **** +10989 Archivist_Silent_Summon8Earth **** **** **** **** **** **** **** **** +10990 Archivist_Silent_Summon8Fire **** **** **** **** **** **** **** **** +10991 Archivist_Silent_Summon8Water **** **** **** **** **** **** **** **** +10992 Archivist_Still_Summon_Creature_VIII **** **** **** **** **** **** **** **** +10993 Archivist_Still_Summon8Air **** **** **** **** **** **** **** **** +10994 Archivist_Still_Summon8Earth **** **** **** **** **** **** **** **** +10995 Archivist_Still_Summon8Fire **** **** **** **** **** **** **** **** +10996 Archivist_Still_Summon8Water **** **** **** **** **** **** **** **** +10997 Archivist_Sunbeam **** **** **** **** **** **** **** **** +10998 Archivist_Silent_Sunbeam **** **** **** **** **** **** **** **** +10999 Archivist_Still_Sunbeam **** **** **** **** **** **** **** **** +11000 Archivist_Sunburst **** **** **** **** **** **** **** **** +11001 Archivist_Silent_Sunburst **** **** **** **** **** **** **** **** +11002 Archivist_Still_Sunburst **** **** **** **** **** **** **** **** +11003 Archivist_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +11004 Archivist_Exteneded_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +11005 Archivist_Silent_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +11006 Archivist_Still_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +11007 Archivist_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +11008 Archivist_Exteneded_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +11009 Archivist_Silent_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +11010 Archivist_Still_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +11011 Archivist_APOCALYPSE_FROM_THE_SKY **** **** **** **** **** **** **** **** +11012 Archivist_APOCALYPSE_FROM_THE_SKY_FIRE **** **** **** **** **** **** **** **** +11013 Archivist_APOCALYPSE_FROM_THE_SKY_ACID **** **** **** **** **** **** **** **** +11014 Archivist_APOCALYPSE_FROM_THE_SKY_SONIC **** **** **** **** **** **** **** **** +11015 Archivist_DESPOIL **** **** **** **** **** **** **** **** +11016 Archivist_Elder_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +11017 Archivist_Elder_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +11018 Archivist_Elder_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +11019 Archivist_Elder_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +11020 Archivist_Elder_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +11021 Archivist_Elder_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +11022 Archivist_Elemental_Swarm **** **** **** **** **** **** **** **** +11023 Archivist_Energy_Drain **** **** **** **** **** **** **** **** +11024 Archivist_EXALTED_FURY **** **** **** **** **** **** **** **** +11025 Archivist_Foresight **** **** **** **** **** **** **** **** +11026 Archivist_Gate **** **** **** **** **** **** **** **** +11027 Archivist_Greater_Planar_Binding **** **** **** **** **** **** **** **** +11028 Archivist_Greater_Spell_Mantle **** **** **** **** **** **** **** **** +11029 Archivist_Implosion **** **** **** **** **** **** **** **** +11030 Archivist_Mantle_of_Eg_Might **** **** **** **** **** **** **** **** +11031 Archivist_Mass_Drown **** **** **** **** **** **** **** **** +11032 Archivist_Mass_Harm **** **** **** **** **** **** **** **** +11033 Archivist_Mass_Hold_Monster **** **** **** **** **** **** **** **** +11034 Archivist_Nature_Avatar **** **** **** **** **** **** **** **** +11035 Archivist_Necrotic_Termination **** **** **** **** **** **** **** **** +11036 Archivist_PlagueOfUndead **** **** **** **** **** **** **** **** +11037 Archivist_Power_Word_Kill **** **** **** **** **** **** **** **** +11038 Archivist_Power_Word_Blind **** **** **** **** **** **** **** **** +11039 Archivist_RAIN_OF_BLACK_TULIPS **** **** **** **** **** **** **** **** +11040 Archivist_Shapechange **** **** **** **** **** **** **** **** +11041 Archivist_Shapechange_RED_DRAGON **** **** **** **** **** **** **** **** +11042 Archivist_Shapechange_FIRE_GIANT **** **** **** **** **** **** **** **** +11043 Archivist_Shapechange_BALOR **** **** **** **** **** **** **** **** +11044 Archivist_Shapechange_DEATH_SLAAD **** **** **** **** **** **** **** **** +11045 Archivist_Shapechange_IRON_GOLEM **** **** **** **** **** **** **** **** +11046 Archivist_Sphere_of_Ultimate_Destruction **** **** **** **** **** **** **** **** +11047 Archivist_Storm_of_Vengeance **** **** **** **** **** **** **** **** +11048 Archivist_Summon_Creature_IX **** **** **** **** **** **** **** **** +11049 Archivist_Summon9Air **** **** **** **** **** **** **** **** +11050 Archivist_Summon9Earth **** **** **** **** **** **** **** **** +11051 Archivist_Summon9Fire **** **** **** **** **** **** **** **** +11052 Archivist_Summon9Water **** **** **** **** **** **** **** **** +11053 Archivist_True_Resurrection **** **** **** **** **** **** **** **** +11054 Archivist_Undeaths_Eternal_Foe **** **** **** **** **** **** **** **** +11055 Archivist_Unyielding_Roots **** **** **** **** **** **** **** **** +11056 Archivist_VileDeath **** **** **** **** **** **** **** **** +11057 Archivist_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +11058 Archivist_Weird **** **** **** **** **** **** **** **** +11059 ****_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11060 ****_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +11061 ****_Light **** **** **** **** **** **** **** **** +11062 ****_Read_Magic **** **** **** **** **** **** **** **** +11063 ****_Resistance **** **** **** **** **** **** **** **** +11064 ****_Virtue **** **** **** **** **** **** **** **** +11065 ****_Command_RadialMaster **** **** **** **** **** **** **** **** +11066 ****_Command_Approach **** **** **** **** **** **** **** **** +11067 ****_Command_Drop **** **** **** **** **** **** **** **** +11068 ****_Command_Fall **** **** **** **** **** **** **** **** +11069 ****_Command_Flee **** **** **** **** **** **** **** **** +11070 ****_Command_Halt **** **** **** **** **** **** **** **** +11071 ****_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11072 ****_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11073 ****_Divine_Favor **** **** **** **** **** **** **** **** +11074 ****_Doom **** **** **** **** **** **** **** **** +11075 ****_Endure_Elements **** **** **** **** **** **** **** **** +11076 ****_HideFromUndead **** **** **** **** **** **** **** **** +11077 ****_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11078 ****_Remove_Fear **** **** **** **** **** **** **** **** +11079 ****_Protection_from_Evil **** **** **** **** **** **** **** **** +11080 ****_Protection_from_Good **** **** **** **** **** **** **** **** +11081 ****_Shield_of_Faith **** **** **** **** **** **** **** **** +11082 ****_Endurance **** **** **** **** **** **** **** **** +11083 ****_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11084 ****_Hold_Person **** **** **** **** **** **** **** **** +11085 ****_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11086 ****_Remove_Paralysis **** **** **** **** **** **** **** **** +11087 ****_Resist_Elements **** **** **** **** **** **** **** **** +11088 ****_Lesser_Restoration **** **** **** **** **** **** **** **** +11089 ****_Silence **** **** **** **** **** **** **** **** +11090 ****_UndetectableAlignment **** **** **** **** **** **** **** **** +11091 ****_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11092 ****_Dispel_Magic **** **** **** **** **** **** **** **** +11093 ****_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +11094 ****_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +11095 ****_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +11096 ****_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +11097 ****_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +11098 ****_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +11099 ****_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11100 ****_Lightning_Bolt **** **** **** **** **** **** **** **** +11101 ****_LocateObject **** **** **** **** **** **** **** **** +11102 ****_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11103 ****_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11104 ****_Magic_Vestment **** **** **** **** **** **** **** **** +11105 ****_Protection_from_Elements **** **** **** **** **** **** **** **** +11106 ****_Remove_Disease **** **** **** **** **** **** **** **** +11107 ****_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +11108 ****_GreaterCommand_Approach **** **** **** **** **** **** **** **** +11109 ****_GreaterCommand_Drop **** **** **** **** **** **** **** **** +11110 ****_GreaterCommand_Fall **** **** **** **** **** **** **** **** +11111 ****_GreaterCommand_Flee **** **** **** **** **** **** **** **** +11112 ****_GreaterCommand_Halt **** **** **** **** **** **** **** **** +11113 ****_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11114 ****_Dimensional_Anchor **** **** **** **** **** **** **** **** +11115 ****_Freedom_of_Movement **** **** **** **** **** **** **** **** +11116 ****_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11117 ****_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +11118 ****_Neutralize_Poison **** **** **** **** **** **** **** **** +11119 ****_BreakEnchantment **** **** **** **** **** **** **** **** +11120 ****_Elemental_Strike **** **** **** **** **** **** **** **** +11121 ****_Elemental_Strike_Acid **** **** **** **** **** **** **** **** +11122 ****_Elemental_Strike_Cold **** **** **** **** **** **** **** **** +11123 ****_Elemental_Strike_Electricity **** **** **** **** **** **** **** **** +11124 ****_Elemental_Strike_Fire **** **** **** **** **** **** **** **** +11125 ****_Elemental_Strike_Sonic **** **** **** **** **** **** **** **** +11126 ****_Scrying **** **** **** **** **** **** **** **** +11127 ****_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +11128 ****_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +11129 ****_True_Seeing **** **** **** **** **** **** **** **** +11130 ****_Create_Undead **** **** **** **** **** **** **** **** +11131 ****_Greater_Dispelling **** **** **** **** **** **** **** **** +11132 ****_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +11133 ****_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +11134 ****_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +11135 ****_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +11136 ****_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +11137 ****_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +11138 ****_Raise_Dead **** **** **** **** **** **** **** **** +11139 ****_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +11140 ****_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +11141 ****_WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +11142 ****_WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +11143 ****_WordOfRecall_Party **** **** **** **** **** **** **** **** +11144 ****_GreaterScrying **** **** **** **** **** **** **** **** +11145 ****_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +11146 ****_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +11147 ****_Create_Greater_Undead **** **** **** **** **** **** **** **** +11148 ****_DiscernLocation **** **** **** **** **** **** **** **** +11149 ****_Finger_of_Death **** **** **** **** **** **** **** **** +11150 ****_Regenerate **** **** **** **** **** **** **** **** +11151 ****_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +11152 ****_Energy_Drain **** **** **** **** **** **** **** **** +11153 ****_Power_Word_Blind **** **** **** **** **** **** **** **** +11154 ****_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11155 ****_Dancing_Lights **** **** **** **** **** **** **** **** +11156 ****_Daze **** **** **** **** **** **** **** **** +11157 ****_Flare **** **** **** **** **** **** **** **** +11158 ****_Light **** **** **** **** **** **** **** **** +11159 ****_MAGE_HAND **** **** **** **** **** **** **** **** +11160 ****_Read_Magic **** **** **** **** **** **** **** **** +11161 ****_Resistance **** **** **** **** **** **** **** **** +11162 ****_Sobriety **** **** **** **** **** **** **** **** +11163 ****_Virtue **** **** **** **** **** **** **** **** +11164 ****_Cause_Fear **** **** **** **** **** **** **** **** +11165 ****_Charm_Person **** **** **** **** **** **** **** **** +11166 ****_Command_RadialMaster **** **** **** **** **** **** **** **** +11167 ****_Command_Approach **** **** **** **** **** **** **** **** +11168 ****_Command_Drop **** **** **** **** **** **** **** **** +11169 ****_Command_Fall **** **** **** **** **** **** **** **** +11170 ****_Command_Flee **** **** **** **** **** **** **** **** +11171 ****_Command_Halt **** **** **** **** **** **** **** **** +11172 ****_Crafters_Blessing **** **** **** **** **** **** **** **** +11173 ****_Crafters_Curse **** **** **** **** **** **** **** **** +11174 ****_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11175 ****_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +11176 ****_Disguise_Self_Learn **** **** **** **** **** **** **** **** +11177 ****_Disguise_Self_Options **** **** **** **** **** **** **** **** +11178 ****_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +11179 ****_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +11180 ****_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +11181 ****_Doom **** **** **** **** **** **** **** **** +11182 ****_Endure_Elements **** **** **** **** **** **** **** **** +11183 ****_Grease **** **** **** **** **** **** **** **** +11184 ****_Expeditious_Retreat **** **** **** **** **** **** **** **** +11185 ****_Faerie_Fire **** **** **** **** **** **** **** **** +11186 ****_Tashas_Hideous_Laughter **** **** **** **** **** **** **** **** +11187 ****_Identify **** **** **** **** **** **** **** **** +11188 ****_Spell_Jump **** **** **** **** **** **** **** **** +11189 ****_ObscureObject **** **** **** **** **** **** **** **** +11190 ****_Obscuring_Mist **** **** **** **** **** **** **** **** +11191 ****_Protection_from_Chaos **** **** **** **** **** **** **** **** +11192 ****_Protection_from_Evil **** **** **** **** **** **** **** **** +11193 ****_Protection_from_Good **** **** **** **** **** **** **** **** +11194 ****_Protection_from_Law **** **** **** **** **** **** **** **** +11195 ****_Remove_Fear **** **** **** **** **** **** **** **** +11196 ****_Sleep **** **** **** **** **** **** **** **** +11197 ****_Summon_Creature_I **** **** **** **** **** **** **** **** +11198 ****_UndetectableAlignment **** **** **** **** **** **** **** **** +11199 ****_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +11200 ****_Alter_Self_Learn **** **** **** **** **** **** **** **** +11201 ****_Alter_Self_Options **** **** **** **** **** **** **** **** +11202 ****_Alter_Self_QS1 **** **** **** **** **** **** **** **** +11203 ****_Alter_Self_QS2 **** **** **** **** **** **** **** **** +11204 ****_Alter_Self_QS3 **** **** **** **** **** **** **** **** +11205 ****_Endurance **** **** **** **** **** **** **** **** +11206 ****_Bulls_Strength **** **** **** **** **** **** **** **** +11207 ****_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11208 ****_Blur **** **** **** **** **** **** **** **** +11209 ****_Calm_Emotions **** **** **** **** **** **** **** **** +11210 ****_Cats_Grace **** **** **** **** **** **** **** **** +11211 ****_Continual_Flame **** **** **** **** **** **** **** **** +11212 ****_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11213 ****_Darkness **** **** **** **** **** **** **** **** +11214 ****_Daze_Monster **** **** **** **** **** **** **** **** +11215 ****_Eagle_Splendor **** **** **** **** **** **** **** **** +11216 ****_FogCloud **** **** **** **** **** **** **** **** +11217 ****_Foxs_Cunning **** **** **** **** **** **** **** **** +11218 ****_Heroism **** **** **** **** **** **** **** **** +11219 ****_Hold_Person **** **** **** **** **** **** **** **** +11220 ****_Invisibility **** **** **** **** **** **** **** **** +11221 ****_Lesser_Dispel **** **** **** **** **** **** **** **** +11222 ****_LocateObject **** **** **** **** **** **** **** **** +11223 ****_MirrorImage **** **** **** **** **** **** **** **** +11224 ****_Owls_Wisdom **** **** **** **** **** **** **** **** +11225 ****_ProtectionArrows **** **** **** **** **** **** **** **** +11226 ****_Pyrotechnics **** **** **** **** **** **** **** **** +11227 ****_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +11228 ****_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +11229 ****_Resist_Elements **** **** **** **** **** **** **** **** +11230 ****_Scare **** **** **** **** **** **** **** **** +11231 ****_Silence **** **** **** **** **** **** **** **** +11232 ****_Summon_Creature_II **** **** **** **** **** **** **** **** +11233 ****_TouchIdiocy **** **** **** **** **** **** **** **** +11234 ****_Ultravision **** **** **** **** **** **** **** **** +11235 ****_Bestow_Curse **** **** **** **** **** **** **** **** +11236 ****_Charm_Monster **** **** **** **** **** **** **** **** +11237 ****_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +11238 ****_Confusion **** **** **** **** **** **** **** **** +11239 ****_CrushingDespair **** **** **** **** **** **** **** **** +11240 ****_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11241 ****_Daylight **** **** **** **** **** **** **** **** +11242 ****_DeepSlumber **** **** **** **** **** **** **** **** +11243 ****_Dispel_Magic **** **** **** **** **** **** **** **** +11244 ****_Displacement **** **** **** **** **** **** **** **** +11245 ****_Fear **** **** **** **** **** **** **** **** +11246 ****_GLIBNESS **** **** **** **** **** **** **** **** +11247 ****_Haste **** **** **** **** **** **** **** **** +11248 ****_Invisibility_Sphere **** **** **** **** **** **** **** **** +11249 ****_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11250 ****_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11251 ****_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11252 ****_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11253 ****_Protection_from_Elements **** **** **** **** **** **** **** **** +11254 ****_RayofExhaustion **** **** **** **** **** **** **** **** +11255 ****_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11256 ****_Remove_Curse **** **** **** **** **** **** **** **** +11257 ****_Remove_Disease **** **** **** **** **** **** **** **** +11258 ****_Scrying **** **** **** **** **** **** **** **** +11259 ****_See_Invisibility **** **** **** **** **** **** **** **** +11260 ****_Slow **** **** **** **** **** **** **** **** +11261 ****_Spiderskin **** **** **** **** **** **** **** **** +11262 ****_Summon_Creature_III **** **** **** **** **** **** **** **** +11263 ****_WaterBreathing **** **** **** **** **** **** **** **** +11264 ****_Animate_Dead **** **** **** **** **** **** **** **** +11265 ****_ArcaneEye **** **** **** **** **** **** **** **** +11266 ****_BreakEnchantment **** **** **** **** **** **** **** **** +11267 ****_Contagion **** **** **** **** **** **** **** **** +11268 ****_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11269 ****_DetectScrying **** **** **** **** **** **** **** **** +11270 ****_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +11271 ****_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +11272 ****_DimensionDoor_Party **** **** **** **** **** **** **** **** +11273 ****_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +11274 ****_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +11275 ****_Dominate_Person **** **** **** **** **** **** **** **** +11276 ****_Freedom_of_Movement **** **** **** **** **** **** **** **** +11277 ****_Hold_Monster **** **** **** **** **** **** **** **** +11278 ****_Improved_Invisibility **** **** **** **** **** **** **** **** +11279 ****_Greater_Resistance **** **** **** **** **** **** **** **** +11280 ****_LocateCreature **** **** **** **** **** **** **** **** +11281 ****_Mass_Ultravision **** **** **** **** **** **** **** **** +11282 ****_Neutralize_Poison **** **** **** **** **** **** **** **** +11283 ****_Polymorph_Self **** **** **** **** **** **** **** **** +11284 ****_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +11285 ****_Polymorph_TROLL **** **** **** **** **** **** **** **** +11286 ****_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +11287 ****_Polymorph_PIXIE **** **** **** **** **** **** **** **** +11288 ****_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +11289 ****_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +11290 ****_RepelVermin **** **** **** **** **** **** **** **** +11291 ****_Shadow_Conjuration **** **** **** **** **** **** **** **** +11292 ****_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +11293 ****_SHADOW_CON_Darkness **** **** **** **** **** **** **** **** +11294 ****_SHADOW_CON_Inivsibility **** **** **** **** **** **** **** **** +11295 ****_SHADOW_CON_Mage_Armor **** **** **** **** **** **** **** **** +11296 ****_SHADOW_CON_Magic_Missile **** **** **** **** **** **** **** **** +11297 ****_Stoneskin **** **** **** **** **** **** **** **** +11298 ****_Summon_Creature_IV **** **** **** **** **** **** **** **** +11299 ****_BalefulPolymorph **** **** **** **** **** **** **** **** +11300 ****_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +11301 ****_GreaterCommand_Approach **** **** **** **** **** **** **** **** +11302 ****_GreaterCommand_Drop **** **** **** **** **** **** **** **** +11303 ****_GreaterCommand_Fall **** **** **** **** **** **** **** **** +11304 ****_GreaterCommand_Flee **** **** **** **** **** **** **** **** +11305 ****_GreaterCommand_Halt **** **** **** **** **** **** **** **** +11306 ****_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11307 ****_Greater_Dispelling **** **** **** **** **** **** **** **** +11308 ****_Energy_Buffer **** **** **** **** **** **** **** **** +11309 ****_Eternal_Charm_Person **** **** **** **** **** **** **** **** +11310 ****_Feeblemind **** **** **** **** **** **** **** **** +11311 ****_Greater_Heroism **** **** **** **** **** **** **** **** +11312 ****_Lesser_Planar_Binding **** **** **** **** **** **** **** **** +11313 ****_Mind_Fog **** **** **** **** **** **** **** **** +11314 ****_Mislead **** **** **** **** **** **** **** **** +11315 ****_Panacea **** **** **** **** **** **** **** **** +11316 ****_GreaterScrying **** **** **** **** **** **** **** **** +11317 ****_Summon_Creature_V **** **** **** **** **** **** **** **** +11318 ****_WavesofFatigue **** **** **** **** **** **** **** **** +11319 ****_Animate_Object **** **** **** **** **** **** **** **** +11320 ****_Mass_Endurance **** **** **** **** **** **** **** **** +11321 ****_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +11322 ****_Mass_Cats_Grace **** **** **** **** **** **** **** **** +11323 ****_Mass_Charm **** **** **** **** **** **** **** **** +11324 ****_Control_Weather **** **** **** **** **** **** **** **** +11325 ****_CW_Rain **** **** **** **** **** **** **** **** +11326 ****_CW_Snow **** **** **** **** **** **** **** **** +11327 ****_CW_Clear **** **** **** **** **** **** **** **** +11328 ****_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11329 ****_Mass_Contagion **** **** **** **** **** **** **** **** +11330 ****_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +11331 ****_Energy_Immunity **** **** **** **** **** **** **** **** +11332 ****_EI_Acid **** **** **** **** **** **** **** **** +11333 ****_EI_Cold **** **** **** **** **** **** **** **** +11334 ****_EI_Elec **** **** **** **** **** **** **** **** +11335 ****_EI_Fire **** **** **** **** **** **** **** **** +11336 ****_EI_Sonic **** **** **** **** **** **** **** **** +11337 ****_Eyebite **** **** **** **** **** **** **** **** +11338 ****_Flesh_to_stone **** **** **** **** **** **** **** **** +11339 ****_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +11340 ****_Greater_Stoneskin **** **** **** **** **** **** **** **** +11341 ****_Legend_Lore **** **** **** **** **** **** **** **** +11342 ****_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +11343 ****_Planar_Binding **** **** **** **** **** **** **** **** +11344 ****_Summon_Creature_VI **** **** **** **** **** **** **** **** +11345 ****_True_Seeing **** **** **** **** **** **** **** **** +11346 ****_Repulsion **** **** **** **** **** **** **** **** +11347 ****_Superior_Resistance **** **** **** **** **** **** **** **** +11348 ****_Tensers_Transformation **** **** **** **** **** **** **** **** +11349 ****_Creeping_Doom **** **** **** **** **** **** **** **** +11350 ****_Eternal_Charm_Monster **** **** **** **** **** **** **** **** +11351 ****_Finger_of_Death **** **** **** **** **** **** **** **** +11352 ****_Insanity **** **** **** **** **** **** **** **** +11353 ****_Sequester **** **** **** **** **** **** **** **** +11354 ****_Summon_Creature_VII **** **** **** **** **** **** **** **** +11355 ****_Summon7Air **** **** **** **** **** **** **** **** +11356 ****_Summon7Earth **** **** **** **** **** **** **** **** +11357 ****_Summon7Fire **** **** **** **** **** **** **** **** +11358 ****_Summon7Water **** **** **** **** **** **** **** **** +11359 ****_TransportViaPlants_RadialMaster **** **** **** **** **** **** **** **** +11360 ****_TransportViaPlants_SelfOnly **** **** **** **** **** **** **** **** +11361 ****_TransportViaPlants_Party **** **** **** **** **** **** **** **** +11362 ****_DiscernLocation **** **** **** **** **** **** **** **** +11363 ****_Horrid_Wilting **** **** **** **** **** **** **** **** +11364 ****_Protection_from_Spells **** **** **** **** **** **** **** **** +11365 ****_Greater_Planar_Binding **** **** **** **** **** **** **** **** +11366 ****_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +11367 ****_Shadow_Shield **** **** **** **** **** **** **** **** +11368 ****_Summon_Creature_VIII **** **** **** **** **** **** **** **** +11369 ****_Summon8Air **** **** **** **** **** **** **** **** +11370 ****_Summon8Earth **** **** **** **** **** **** **** **** +11371 ****_Summon8Fire **** **** **** **** **** **** **** **** +11372 ****_Summon8Water **** **** **** **** **** **** **** **** +11373 ****_Earthquake **** **** **** **** **** **** **** **** +11374 ****_Foresight **** **** **** **** **** **** **** **** +11375 ****_Gate **** **** **** **** **** **** **** **** +11376 ****_Mystic_Barrier **** **** **** **** **** **** **** **** +11377 ****_Shapechange **** **** **** **** **** **** **** **** +11378 ****_Shapechange_RED_DRAGON **** **** **** **** **** **** **** **** +11379 ****_Shapechange_FIRE_GIANT **** **** **** **** **** **** **** **** +11380 ****_Shapechange_BALOR **** **** **** **** **** **** **** **** +11381 ****_Shapechange_DEATH_SLAAD **** **** **** **** **** **** **** **** +11382 ****_Shapechange_IRON_GOLEM **** **** **** **** **** **** **** **** +11383 ****_Summon_Creature_IX **** **** **** **** **** **** **** **** +11384 ****_Summon9Air **** **** **** **** **** **** **** **** +11385 ****_Summon9Earth **** **** **** **** **** **** **** **** +11386 ****_Summon9Fire **** **** **** **** **** **** **** **** +11387 ****_Summon9Water **** **** **** **** **** **** **** **** +11388 ****_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +11389 ****_Weird **** **** **** **** **** **** **** **** +11390 OAShaman_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11391 OAShaman_Quickened_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11392 OAShaman_Silent_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11393 OAShaman_Still_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +11394 OAShaman_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +11395 OAShaman_Quickened_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +11396 OAShaman_Silent_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +11397 OAShaman_Still_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +11398 OAShaman_Light **** **** **** **** **** **** **** **** +11399 OAShaman_Exteneded_Light **** **** **** **** **** **** **** **** +11400 OAShaman_Quickened_Light **** **** **** **** **** **** **** **** +11401 OAShaman_Silent_Light **** **** **** **** **** **** **** **** +11402 OAShaman_Read_Magic **** **** **** **** **** **** **** **** +11403 OAShaman_Quickened_Read_Magic **** **** **** **** **** **** **** **** +11404 OAShaman_Silent_Read_Magic **** **** **** **** **** **** **** **** +11405 OAShaman_Still_Read_Magic **** **** **** **** **** **** **** **** +11406 OAShaman_Resistance **** **** **** **** **** **** **** **** +11407 OAShaman_Exteneded_Resistance **** **** **** **** **** **** **** **** +11408 OAShaman_Quickened_Resistance **** **** **** **** **** **** **** **** +11409 OAShaman_Silent_Resistance **** **** **** **** **** **** **** **** +11410 OAShaman_Still_Resistance **** **** **** **** **** **** **** **** +11411 OAShaman_Virtue **** **** **** **** **** **** **** **** +11412 OAShaman_Exteneded_Virtue **** **** **** **** **** **** **** **** +11413 OAShaman_Quickened_Virtue **** **** **** **** **** **** **** **** +11414 OAShaman_Silent_Virtue **** **** **** **** **** **** **** **** +11415 OAShaman_Still_Virtue **** **** **** **** **** **** **** **** +11416 OAShaman_Bane **** **** **** **** **** **** **** **** +11417 OAShaman_Exteneded_Bane **** **** **** **** **** **** **** **** +11418 OAShaman_Quickened_Bane **** **** **** **** **** **** **** **** +11419 OAShaman_Silent_Bane **** **** **** **** **** **** **** **** +11420 OAShaman_Still_Bane **** **** **** **** **** **** **** **** +11421 OAShaman_Bless **** **** **** **** **** **** **** **** +11422 OAShaman_Exteneded_Bless **** **** **** **** **** **** **** **** +11423 OAShaman_Quickened_Bless **** **** **** **** **** **** **** **** +11424 OAShaman_Silent_Bless **** **** **** **** **** **** **** **** +11425 OAShaman_Still_Bless **** **** **** **** **** **** **** **** +11426 OAShaman_Bless_Water **** **** **** **** **** **** **** **** +11427 OAShaman_Quickened_Bless_Water **** **** **** **** **** **** **** **** +11428 OAShaman_Silent_Bless_Water **** **** **** **** **** **** **** **** +11429 OAShaman_Still_Bless_Water **** **** **** **** **** **** **** **** +11430 OAShaman_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11431 OAShaman_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11432 OAShaman_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11433 OAShaman_Quickened_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11434 OAShaman_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11435 OAShaman_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +11436 OAShaman_Curse_Water **** **** **** **** **** **** **** **** +11437 OAShaman_Quickened_Curse_Water **** **** **** **** **** **** **** **** +11438 OAShaman_Silent_Curse_Water **** **** **** **** **** **** **** **** +11439 OAShaman_Still_Curse_Water **** **** **** **** **** **** **** **** +11440 OAShaman_Detect_Chaos **** **** **** **** **** **** **** **** +11441 OAShaman_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +11442 OAShaman_Quickened_Detect_Chaos **** **** **** **** **** **** **** **** +11443 OAShaman_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +11444 OAShaman_Still_Detect_Chaos **** **** **** **** **** **** **** **** +11445 OAShaman_Detect_Evil **** **** **** **** **** **** **** **** +11446 OAShaman_Exteneded_Detect_Evil **** **** **** **** **** **** **** **** +11447 OAShaman_Quickened_Detect_Evil **** **** **** **** **** **** **** **** +11448 OAShaman_Silent_Detect_Evil **** **** **** **** **** **** **** **** +11449 OAShaman_Still_Detect_Evil **** **** **** **** **** **** **** **** +11450 OAShaman_Detect_Good **** **** **** **** **** **** **** **** +11451 OAShaman_Exteneded_Detect_Good **** **** **** **** **** **** **** **** +11452 OAShaman_Quickened_Detect_Good **** **** **** **** **** **** **** **** +11453 OAShaman_Silent_Detect_Good **** **** **** **** **** **** **** **** +11454 OAShaman_Still_Detect_Good **** **** **** **** **** **** **** **** +11455 OAShaman_Detect_Law **** **** **** **** **** **** **** **** +11456 OAShaman_Exteneded_Detect_Law **** **** **** **** **** **** **** **** +11457 OAShaman_Quickened_Detect_Law **** **** **** **** **** **** **** **** +11458 OAShaman_Silent_Detect_Law **** **** **** **** **** **** **** **** +11459 OAShaman_Still_Detect_Law **** **** **** **** **** **** **** **** +11460 OAShaman_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11461 OAShaman_Exteneded_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11462 OAShaman_Quickened_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11463 OAShaman_Silent_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11464 OAShaman_Still_DETECT_UNDEAD **** **** **** **** **** **** **** **** +11465 OAShaman_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +11466 OAShaman_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +11467 OAShaman_Quickened_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +11468 OAShaman_Doom **** **** **** **** **** **** **** **** +11469 OAShaman_Exteneded_Doom **** **** **** **** **** **** **** **** +11470 OAShaman_Quickened_Doom **** **** **** **** **** **** **** **** +11471 OAShaman_Silent_Doom **** **** **** **** **** **** **** **** +11472 OAShaman_Still_Doom **** **** **** **** **** **** **** **** +11473 OAShaman_Endure_Elements **** **** **** **** **** **** **** **** +11474 OAShaman_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +11475 OAShaman_Quickened_Endure_Elements **** **** **** **** **** **** **** **** +11476 OAShaman_Silent_Endure_Elements **** **** **** **** **** **** **** **** +11477 OAShaman_Still_Endure_Elements **** **** **** **** **** **** **** **** +11478 OAShaman_Entropic_Shield **** **** **** **** **** **** **** **** +11479 OAShaman_Exteneded_Entropic_Shield **** **** **** **** **** **** **** **** +11480 OAShaman_Quickened_Entropic_Shield **** **** **** **** **** **** **** **** +11481 OAShaman_Silent_Entropic_Shield **** **** **** **** **** **** **** **** +11482 OAShaman_Still_Entropic_Shield **** **** **** **** **** **** **** **** +11483 OAShaman_HideFromUndead **** **** **** **** **** **** **** **** +11484 OAShaman_Exteneded_HideFromUndead **** **** **** **** **** **** **** **** +11485 OAShaman_Quickened_HideFromUndead **** **** **** **** **** **** **** **** +11486 OAShaman_Still_HideFromUndead **** **** **** **** **** **** **** **** +11487 OAShaman_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11488 OAShaman_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11489 OAShaman_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11490 OAShaman_Quickened_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11491 OAShaman_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11492 OAShaman_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +11493 OAShaman_Obscuring_Mist **** **** **** **** **** **** **** **** +11494 OAShaman_Exteneded_Obscuring_Mist **** **** **** **** **** **** **** **** +11495 OAShaman_Quickened_Obscuring_Mist **** **** **** **** **** **** **** **** +11496 OAShaman_Silent_Obscuring_Mist **** **** **** **** **** **** **** **** +11497 OAShaman_Still_Obscuring_Mist **** **** **** **** **** **** **** **** +11498 OAShaman_Protection_from_Chaos **** **** **** **** **** **** **** **** +11499 OAShaman_Exteneded_Protection_from_Chaos **** **** **** **** **** **** **** **** +11500 OAShaman_Quickened_Protection_from_Chaos **** **** **** **** **** **** **** **** +11501 OAShaman_Silent_Protection_from_Chaos **** **** **** **** **** **** **** **** +11502 OAShaman_Still_Protection_from_Chaos **** **** **** **** **** **** **** **** +11503 OAShaman_Protection_from_Evil **** **** **** **** **** **** **** **** +11504 OAShaman_Exteneded_Protection_from_Evil **** **** **** **** **** **** **** **** +11505 OAShaman_Quickened_Protection_from_Evil **** **** **** **** **** **** **** **** +11506 OAShaman_Silent_Protection_from_Evil **** **** **** **** **** **** **** **** +11507 OAShaman_Still_Protection_from_Evil **** **** **** **** **** **** **** **** +11508 OAShaman_Protection_from_Good **** **** **** **** **** **** **** **** +11509 OAShaman_Exteneded_Protection_from_Good **** **** **** **** **** **** **** **** +11510 OAShaman_Quickened_Protection_from_Good **** **** **** **** **** **** **** **** +11511 OAShaman_Silent_Protection_from_Good **** **** **** **** **** **** **** **** +11512 OAShaman_Still_Protection_from_Good **** **** **** **** **** **** **** **** +11513 OAShaman_Protection_from_Law **** **** **** **** **** **** **** **** +11514 OAShaman_Exteneded_Protection_from_Law **** **** **** **** **** **** **** **** +11515 OAShaman_Quickened_Protection_from_Law **** **** **** **** **** **** **** **** +11516 OAShaman_Silent_Protection_from_Law **** **** **** **** **** **** **** **** +11517 OAShaman_Still_Protection_from_Law **** **** **** **** **** **** **** **** +11518 OAShaman_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +11519 OAShaman_Quickened_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +11520 OAShaman_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +11521 OAShaman_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +11522 OAShaman_Shield_of_Faith **** **** **** **** **** **** **** **** +11523 OAShaman_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +11524 OAShaman_Quickened_Shield_of_Faith **** **** **** **** **** **** **** **** +11525 OAShaman_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +11526 OAShaman_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +11527 OAShaman_Summon_Creature_I **** **** **** **** **** **** **** **** +11528 OAShaman_Exteneded_Summon_Creature_I **** **** **** **** **** **** **** **** +11529 OAShaman_Quickened_Summon_Creature_I **** **** **** **** **** **** **** **** +11530 OAShaman_Silent_Summon_Creature_I **** **** **** **** **** **** **** **** +11531 OAShaman_Still_Summon_Creature_I **** **** **** **** **** **** **** **** +11532 OAShaman_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +11533 OAShaman_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +11534 OAShaman_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +11535 OAShaman_Aid **** **** **** **** **** **** **** **** +11536 OAShaman_Empowered_Aid **** **** **** **** **** **** **** **** +11537 OAShaman_Exteneded_Aid **** **** **** **** **** **** **** **** +11538 OAShaman_Maximized_Aid **** **** **** **** **** **** **** **** +11539 OAShaman_Quickened_Aid **** **** **** **** **** **** **** **** +11540 OAShaman_Silent_Aid **** **** **** **** **** **** **** **** +11541 OAShaman_Still_Aid **** **** **** **** **** **** **** **** +11542 OAShaman_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11543 OAShaman_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11544 OAShaman_Maximized_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11545 OAShaman_Quickened_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11546 OAShaman_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11547 OAShaman_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +11548 OAShaman_Bulls_Strength **** **** **** **** **** **** **** **** +11549 OAShaman_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +11550 OAShaman_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +11551 OAShaman_Maximized_Bulls_Strength **** **** **** **** **** **** **** **** +11552 OAShaman_Quickened_Bulls_Strength **** **** **** **** **** **** **** **** +11553 OAShaman_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +11554 OAShaman_Still_Bulls_Strength **** **** **** **** **** **** **** **** +11555 OAShaman_Calm_Emotions **** **** **** **** **** **** **** **** +11556 OAShaman_Exteneded_Calm_Emotions **** **** **** **** **** **** **** **** +11557 OAShaman_Quickened_Calm_Emotions **** **** **** **** **** **** **** **** +11558 OAShaman_Silent_Calm_Emotions **** **** **** **** **** **** **** **** +11559 OAShaman_Still_Calm_Emotions **** **** **** **** **** **** **** **** +11560 OAShaman_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11561 OAShaman_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11562 OAShaman_Maximized_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11563 OAShaman_Quickened_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11564 OAShaman_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11565 OAShaman_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +11566 OAShaman_Ghoul_Touch **** **** **** **** **** **** **** **** +11567 OAShaman_Exteneded_Ghoul_Touch **** **** **** **** **** **** **** **** +11568 OAShaman_Quickened_Ghoul_Touch **** **** **** **** **** **** **** **** +11569 OAShaman_Silent_Ghoul_Touch **** **** **** **** **** **** **** **** +11570 OAShaman_Still_Ghoul_Touch **** **** **** **** **** **** **** **** +11571 OAShaman_Hold_Person **** **** **** **** **** **** **** **** +11572 OAShaman_Exteneded_Hold_Person **** **** **** **** **** **** **** **** +11573 OAShaman_Quickened_Hold_Person **** **** **** **** **** **** **** **** +11574 OAShaman_Silent_Hold_Person **** **** **** **** **** **** **** **** +11575 OAShaman_Still_Hold_Person **** **** **** **** **** **** **** **** +11576 OAShaman_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11577 OAShaman_Empowered_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11578 OAShaman_Maximized_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11579 OAShaman_Quickened_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11580 OAShaman_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11581 OAShaman_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +11582 OAShaman_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +11583 OAShaman_Quickened_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +11584 OAShaman_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +11585 OAShaman_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +11586 OAShaman_Lesser_Restoration **** **** **** **** **** **** **** **** +11587 OAShaman_Quickened_Lesser_Restoration **** **** **** **** **** **** **** **** +11588 OAShaman_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +11589 OAShaman_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +11590 OAShaman_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11591 OAShaman_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11592 OAShaman_Quickened_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11593 OAShaman_Remove_Paralysis **** **** **** **** **** **** **** **** +11594 OAShaman_Quickened_Remove_Paralysis **** **** **** **** **** **** **** **** +11595 OAShaman_Silent_Remove_Paralysis **** **** **** **** **** **** **** **** +11596 OAShaman_Still_Remove_Paralysis **** **** **** **** **** **** **** **** +11597 OAShaman_Summon_Creature_II **** **** **** **** **** **** **** **** +11598 OAShaman_Exteneded_Summon_Creature_II **** **** **** **** **** **** **** **** +11599 OAShaman_Quickened_Summon_Creature_II **** **** **** **** **** **** **** **** +11600 OAShaman_Silent_Summon_Creature_II **** **** **** **** **** **** **** **** +11601 OAShaman_Still_Summon_Creature_II **** **** **** **** **** **** **** **** +11602 OAShaman_Bestow_Curse **** **** **** **** **** **** **** **** +11603 OAShaman_Quickened_Bestow_Curse **** **** **** **** **** **** **** **** +11604 OAShaman_Silent_Bestow_Curse **** **** **** **** **** **** **** **** +11605 OAShaman_Still_Bestow_Curse **** **** **** **** **** **** **** **** +11606 OAShaman_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11607 OAShaman_Exteneded_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11608 OAShaman_Quickened_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11609 OAShaman_Silent_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11610 OAShaman_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +11611 OAShaman_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +11612 OAShaman_Quickened_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +11613 OAShaman_Contagion **** **** **** **** **** **** **** **** +11614 OAShaman_Quickened_Contagion **** **** **** **** **** **** **** **** +11615 OAShaman_Silent_Contagion **** **** **** **** **** **** **** **** +11616 OAShaman_Still_Contagion **** **** **** **** **** **** **** **** +11617 OAShaman_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11618 OAShaman_Empowered_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11619 OAShaman_Maximized_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11620 OAShaman_Quickened_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11621 OAShaman_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11622 OAShaman_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +11623 OAShaman_Dispel_Magic **** **** **** **** **** **** **** **** +11624 OAShaman_Quickened_Dispel_Magic **** **** **** **** **** **** **** **** +11625 OAShaman_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +11626 OAShaman_Still_Dispel_Magic **** **** **** **** **** **** **** **** +11627 OAShaman_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11628 OAShaman_Empowered_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11629 OAShaman_Maximized_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11630 OAShaman_Quickened_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11631 OAShaman_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11632 OAShaman_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +11633 OAShaman_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11634 OAShaman_Empowered_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11635 OAShaman_Maximized_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11636 OAShaman_Quickened_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11637 OAShaman_Silent_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11638 OAShaman_Still_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +11639 OAShaman_LocateObject **** **** **** **** **** **** **** **** +11640 OAShaman_Exteneded_LocateObject **** **** **** **** **** **** **** **** +11641 OAShaman_Quickened_LocateObject **** **** **** **** **** **** **** **** +11642 OAShaman_Silent_LocateObject **** **** **** **** **** **** **** **** +11643 OAShaman_Still_LocateObject **** **** **** **** **** **** **** **** +11644 OAShaman_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11645 OAShaman_Exteneded_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11646 OAShaman_Quickened_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11647 OAShaman_Silent_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11648 OAShaman_Still_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +11649 OAShaman_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11650 OAShaman_Exteneded_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11651 OAShaman_Quickened_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11652 OAShaman_Silent_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11653 OAShaman_Still_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +11654 OAShaman_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11655 OAShaman_Exteneded_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11656 OAShaman_Quickened_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11657 OAShaman_Silent_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11658 OAShaman_Still_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +11659 OAShaman_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11660 OAShaman_Exteneded_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11661 OAShaman_Quickened_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11662 OAShaman_Silent_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11663 OAShaman_Still_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +11664 OAShaman_Magic_Vestment **** **** **** **** **** **** **** **** +11665 OAShaman_Exteneded_Magic_Vestment **** **** **** **** **** **** **** **** +11666 OAShaman_Quickened_Magic_Vestment **** **** **** **** **** **** **** **** +11667 OAShaman_Silent_Magic_Vestment **** **** **** **** **** **** **** **** +11668 OAShaman_Still_Magic_Vestment **** **** **** **** **** **** **** **** +11669 OAShaman_Prayer **** **** **** **** **** **** **** **** +11670 OAShaman_Exteneded_Prayer **** **** **** **** **** **** **** **** +11671 OAShaman_Quickened_Prayer **** **** **** **** **** **** **** **** +11672 OAShaman_Silent_Prayer **** **** **** **** **** **** **** **** +11673 OAShaman_Still_Prayer **** **** **** **** **** **** **** **** +11674 OAShaman_Protection_from_Elements **** **** **** **** **** **** **** **** +11675 OAShaman_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +11676 OAShaman_Quickened_Protection_from_Elements **** **** **** **** **** **** **** **** +11677 OAShaman_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +11678 OAShaman_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +11679 OAShaman_RED_FESTER **** **** **** **** **** **** **** **** +11680 OAShaman_Quickened_RED_FESTER **** **** **** **** **** **** **** **** +11681 OAShaman_Silent_RED_FESTER **** **** **** **** **** **** **** **** +11682 OAShaman_Still_RED_FESTER **** **** **** **** **** **** **** **** +11683 OAShaman_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11684 OAShaman_Quickened_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11685 OAShaman_Silent_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11686 OAShaman_Still_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +11687 OAShaman_Remove_Curse **** **** **** **** **** **** **** **** +11688 OAShaman_Quickened_Remove_Curse **** **** **** **** **** **** **** **** +11689 OAShaman_Silent_Remove_Curse **** **** **** **** **** **** **** **** +11690 OAShaman_Still_Remove_Curse **** **** **** **** **** **** **** **** +11691 OAShaman_Remove_Disease **** **** **** **** **** **** **** **** +11692 OAShaman_Quickened_Remove_Disease **** **** **** **** **** **** **** **** +11693 OAShaman_Silent_Remove_Disease **** **** **** **** **** **** **** **** +11694 OAShaman_Still_Remove_Disease **** **** **** **** **** **** **** **** +11695 OAShaman_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11696 OAShaman_Empowered_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11697 OAShaman_Maximized_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11698 OAShaman_Quickened_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11699 OAShaman_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11700 OAShaman_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +11701 OAShaman_Summon_Creature_III **** **** **** **** **** **** **** **** +11702 OAShaman_Exteneded_Summon_Creature_III **** **** **** **** **** **** **** **** +11703 OAShaman_Quickened_Summon_Creature_III **** **** **** **** **** **** **** **** +11704 OAShaman_Silent_Summon_Creature_III **** **** **** **** **** **** **** **** +11705 OAShaman_Still_Summon_Creature_III **** **** **** **** **** **** **** **** +11706 OAShaman_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +11707 OAShaman_Quickened_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +11708 OAShaman_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +11709 OAShaman_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +11710 OAShaman_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +11711 OAShaman_Exteneded_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +11712 OAShaman_Quickened_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +11713 OAShaman_Silent_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +11714 OAShaman_Still_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +11715 OAShaman_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11716 OAShaman_Empowered_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11717 OAShaman_Maximized_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11718 OAShaman_Quickened_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11719 OAShaman_Silent_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11720 OAShaman_Still_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +11721 OAShaman_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11722 OAShaman_Empowered_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11723 OAShaman_Maximized_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11724 OAShaman_Quickened_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11725 OAShaman_Silent_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11726 OAShaman_Still_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +11727 OAShaman_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11728 OAShaman_Empowered_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11729 OAShaman_Exteneded_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11730 OAShaman_Maximized_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11731 OAShaman_Quickened_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11732 OAShaman_Silent_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11733 OAShaman_Still_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +11734 OAShaman_Dismissal **** **** **** **** **** **** **** **** +11735 OAShaman_Quickened_Dismissal **** **** **** **** **** **** **** **** +11736 OAShaman_Silent_Dismissal **** **** **** **** **** **** **** **** +11737 OAShaman_Still_Dismissal **** **** **** **** **** **** **** **** +11738 OAShaman_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11739 OAShaman_Exteneded_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11740 OAShaman_Quickened_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +11741 OAShaman_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11742 OAShaman_Empowered_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11743 OAShaman_Maximized_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11744 OAShaman_Quickened_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11745 OAShaman_Silent_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11746 OAShaman_Still_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +11747 OAShaman_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +11748 OAShaman_Exteneded_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +11749 OAShaman_Quickened_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +11750 OAShaman_Silent_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +11751 OAShaman_Still_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +11752 OAShaman_Neutralize_Poison **** **** **** **** **** **** **** **** +11753 OAShaman_Quickened_Neutralize_Poison **** **** **** **** **** **** **** **** +11754 OAShaman_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +11755 OAShaman_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +11756 OAShaman_Polymorph_Self **** **** **** **** **** **** **** **** +11757 OAShaman_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +11758 OAShaman_Polymorph_TROLL **** **** **** **** **** **** **** **** +11759 OAShaman_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +11760 OAShaman_Polymorph_PIXIE **** **** **** **** **** **** **** **** +11761 OAShaman_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +11762 OAShaman_Exteneded_Polymorph_Self **** **** **** **** **** **** **** **** +11763 OAShaman_Exteneded_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +11764 OAShaman_Exteneded_Polymorph_TROLL **** **** **** **** **** **** **** **** +11765 OAShaman_Exteneded_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +11766 OAShaman_Exteneded_Polymorph_PIXIE **** **** **** **** **** **** **** **** +11767 OAShaman_Exteneded_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +11768 OAShaman_Quickened_Polymorph_Self **** **** **** **** **** **** **** **** +11769 OAShaman_Quickened_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +11770 OAShaman_Quickened_Polymorph_TROLL **** **** **** **** **** **** **** **** +11771 OAShaman_Quickened_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +11772 OAShaman_Quickened_Polymorph_PIXIE **** **** **** **** **** **** **** **** +11773 OAShaman_Quickened_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +11774 OAShaman_Silent_Polymorph_Self **** **** **** **** **** **** **** **** +11775 OAShaman_Silent_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +11776 OAShaman_Silent_Polymorph_TROLL **** **** **** **** **** **** **** **** +11777 OAShaman_Silent_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +11778 OAShaman_Silent_Polymorph_PIXIE **** **** **** **** **** **** **** **** +11779 OAShaman_Silent_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +11780 OAShaman_Restoration **** **** **** **** **** **** **** **** +11781 OAShaman_Quickened_Restoration **** **** **** **** **** **** **** **** +11782 OAShaman_Silent_Restoration **** **** **** **** **** **** **** **** +11783 OAShaman_Still_Restoration **** **** **** **** **** **** **** **** +11784 OAShaman_Summon_Creature_IV **** **** **** **** **** **** **** **** +11785 OAShaman_Exteneded_Summon_Creature_IV **** **** **** **** **** **** **** **** +11786 OAShaman_Quickened_Summon_Creature_IV **** **** **** **** **** **** **** **** +11787 OAShaman_Silent_Summon_Creature_IV **** **** **** **** **** **** **** **** +11788 OAShaman_Still_Summon_Creature_IV **** **** **** **** **** **** **** **** +11789 OAShaman_SUNMANTLE **** **** **** **** **** **** **** **** +11790 OAShaman_Exteneded_SUNMANTLE **** **** **** **** **** **** **** **** +11791 OAShaman_Quickened_SUNMANTLE **** **** **** **** **** **** **** **** +11792 OAShaman_Still_SUNMANTLE **** **** **** **** **** **** **** **** +11793 OAShaman_BreakEnchantment **** **** **** **** **** **** **** **** +11794 OAShaman_Quickened_BreakEnchantment **** **** **** **** **** **** **** **** +11795 OAShaman_Silent_BreakEnchantment **** **** **** **** **** **** **** **** +11796 OAShaman_Still_BreakEnchantment **** **** **** **** **** **** **** **** +11797 OAShaman_Circle_of_Doom **** **** **** **** **** **** **** **** +11798 OAShaman_Empowered_Circle_of_Doom **** **** **** **** **** **** **** **** +11799 OAShaman_Maximized_Circle_of_Doom **** **** **** **** **** **** **** **** +11800 OAShaman_Quickened_Circle_of_Doom **** **** **** **** **** **** **** **** +11801 OAShaman_Silent_Circle_of_Doom **** **** **** **** **** **** **** **** +11802 OAShaman_Still_Circle_of_Doom **** **** **** **** **** **** **** **** +11803 OAShaman_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +11804 OAShaman_Exteneded_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +11805 OAShaman_Quickened_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +11806 OAShaman_Silent_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +11807 OAShaman_Still_CLAWS_OF_THE_BEBILITH **** **** **** **** **** **** **** **** +11808 OAShaman_Etherealness **** **** **** **** **** **** **** **** +11809 OAShaman_Exteneded_Etherealness **** **** **** **** **** **** **** **** +11810 OAShaman_Quickened_Etherealness **** **** **** **** **** **** **** **** +11811 OAShaman_Silent_Etherealness **** **** **** **** **** **** **** **** +11812 OAShaman_Still_Etherealness **** **** **** **** **** **** **** **** +11813 OAShaman_Healing_Circle **** **** **** **** **** **** **** **** +11814 OAShaman_Empowered_Healing_Circle **** **** **** **** **** **** **** **** +11815 OAShaman_Maximized_Healing_Circle **** **** **** **** **** **** **** **** +11816 OAShaman_Quickened_Healing_Circle **** **** **** **** **** **** **** **** +11817 OAShaman_Silent_Healing_Circle **** **** **** **** **** **** **** **** +11818 OAShaman_Still_Healing_Circle **** **** **** **** **** **** **** **** +11819 OAShaman_POWER_LEECH **** **** **** **** **** **** **** **** +11820 OAShaman_Exteneded_POWER_LEECH **** **** **** **** **** **** **** **** +11821 OAShaman_Quickened_POWER_LEECH **** **** **** **** **** **** **** **** +11822 OAShaman_Silent_POWER_LEECH **** **** **** **** **** **** **** **** +11823 OAShaman_Still_POWER_LEECH **** **** **** **** **** **** **** **** +11824 OAShaman_Raise_Dead **** **** **** **** **** **** **** **** +11825 OAShaman_Quickened_Raise_Dead **** **** **** **** **** **** **** **** +11826 OAShaman_Silent_Raise_Dead **** **** **** **** **** **** **** **** +11827 OAShaman_Still_Raise_Dead **** **** **** **** **** **** **** **** +11828 OAShaman_Scrying **** **** **** **** **** **** **** **** +11829 OAShaman_Exteneded_Scrying **** **** **** **** **** **** **** **** +11830 OAShaman_Quickened_Scrying **** **** **** **** **** **** **** **** +11831 OAShaman_Silent_Scrying **** **** **** **** **** **** **** **** +11832 OAShaman_Still_Scrying **** **** **** **** **** **** **** **** +11833 OAShaman_SICKEN_EVIL **** **** **** **** **** **** **** **** +11834 OAShaman_Exteneded_SICKEN_EVIL **** **** **** **** **** **** **** **** +11835 OAShaman_Quickened_SICKEN_EVIL **** **** **** **** **** **** **** **** +11836 OAShaman_Silent_SICKEN_EVIL **** **** **** **** **** **** **** **** +11837 OAShaman_Still_SICKEN_EVIL **** **** **** **** **** **** **** **** +11838 OAShaman_Slay_Living **** **** **** **** **** **** **** **** +11839 OAShaman_Empowered_Slay_Living **** **** **** **** **** **** **** **** +11840 OAShaman_Maximized_Slay_Living **** **** **** **** **** **** **** **** +11841 OAShaman_Quickened_Slay_Living **** **** **** **** **** **** **** **** +11842 OAShaman_Silent_Slay_Living **** **** **** **** **** **** **** **** +11843 OAShaman_Still_Slay_Living **** **** **** **** **** **** **** **** +11844 OAShaman_Summon_Creature_V **** **** **** **** **** **** **** **** +11845 OAShaman_Exteneded_Summon_Creature_V **** **** **** **** **** **** **** **** +11846 OAShaman_Quickened_Summon_Creature_V **** **** **** **** **** **** **** **** +11847 OAShaman_Silent_Summon_Creature_V **** **** **** **** **** **** **** **** +11848 OAShaman_Still_Summon_Creature_V **** **** **** **** **** **** **** **** +11849 OAShaman_True_Seeing **** **** **** **** **** **** **** **** +11850 OAShaman_Exteneded_True_Seeing **** **** **** **** **** **** **** **** +11851 OAShaman_Quickened_True_Seeing **** **** **** **** **** **** **** **** +11852 OAShaman_Silent_True_Seeing **** **** **** **** **** **** **** **** +11853 OAShaman_Still_True_Seeing **** **** **** **** **** **** **** **** +11854 OAShaman_Animate_Object **** **** **** **** **** **** **** **** +11855 OAShaman_Exteneded_Animate_Object **** **** **** **** **** **** **** **** +11856 OAShaman_Planar_Ally **** **** **** **** **** **** **** **** +11857 OAShaman_Exteneded_Planar_Ally **** **** **** **** **** **** **** **** +11858 OAShaman_Silent_Planar_Ally **** **** **** **** **** **** **** **** +11859 OAShaman_Still_Planar_Ally **** **** **** **** **** **** **** **** +11860 OAShaman_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +11861 OAShaman_Exteneded_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +11862 OAShaman_Silent_EXALTED_RAIMENT **** **** **** **** **** **** **** **** +11863 OAShaman_Greater_Dispelling **** **** **** **** **** **** **** **** +11864 OAShaman_Silent_Greater_Dispelling **** **** **** **** **** **** **** **** +11865 OAShaman_Still_Greater_Dispelling **** **** **** **** **** **** **** **** +11866 OAShaman_Harm **** **** **** **** **** **** **** **** +11867 OAShaman_Silent_Harm **** **** **** **** **** **** **** **** +11868 OAShaman_Still_Harm **** **** **** **** **** **** **** **** +11869 OAShaman_Heal **** **** **** **** **** **** **** **** +11870 OAShaman_Silent_Heal **** **** **** **** **** **** **** **** +11871 OAShaman_Still_Heal **** **** **** **** **** **** **** **** +11872 OAShaman_Planar_Ally **** **** **** **** **** **** **** **** +11873 OAShaman_Exteneded_Planar_Ally **** **** **** **** **** **** **** **** +11874 OAShaman_Silent_Planar_Ally **** **** **** **** **** **** **** **** +11875 OAShaman_Still_Planar_Ally **** **** **** **** **** **** **** **** +11876 OAShaman_Stoneskin **** **** **** **** **** **** **** **** +11877 OAShaman_Exteneded_Stoneskin **** **** **** **** **** **** **** **** +11878 OAShaman_Silent_Stoneskin **** **** **** **** **** **** **** **** +11879 OAShaman_Still_Stoneskin **** **** **** **** **** **** **** **** +11880 OAShaman_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +11881 OAShaman_Empowered_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +11882 OAShaman_Maximized_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +11883 OAShaman_Silent_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +11884 OAShaman_Still_STORM_OF_SHARDS **** **** **** **** **** **** **** **** +11885 OAShaman_Summon_Creature_VI **** **** **** **** **** **** **** **** +11886 OAShaman_Exteneded_Summon_Creature_VI **** **** **** **** **** **** **** **** +11887 OAShaman_Silent_Summon_Creature_VI **** **** **** **** **** **** **** **** +11888 OAShaman_Still_Summon_Creature_VI **** **** **** **** **** **** **** **** +11889 OAShaman_Blasphemy **** **** **** **** **** **** **** **** +11890 OAShaman_Silent_Blasphemy **** **** **** **** **** **** **** **** +11891 OAShaman_Still_Blasphemy **** **** **** **** **** **** **** **** +11892 OAShaman_Control_Weather **** **** **** **** **** **** **** **** +11893 OAShaman_CW_Rain **** **** **** **** **** **** **** **** +11894 OAShaman_CW_Snow **** **** **** **** **** **** **** **** +11895 OAShaman_CW_Clear **** **** **** **** **** **** **** **** +11896 OAShaman_Exteneded_Control_Weather **** **** **** **** **** **** **** **** +11897 OAShaman_Exteneded_CW_Rain **** **** **** **** **** **** **** **** +11898 OAShaman_Exteneded_CW_Snow **** **** **** **** **** **** **** **** +11899 OAShaman_Exteneded_CW_Clear **** **** **** **** **** **** **** **** +11900 OAShaman_Silent_Control_Weather **** **** **** **** **** **** **** **** +11901 OAShaman_Silent_CW_Rain **** **** **** **** **** **** **** **** +11902 OAShaman_Silent_CW_Snow **** **** **** **** **** **** **** **** +11903 OAShaman_Silent_CW_Clear **** **** **** **** **** **** **** **** +11904 OAShaman_Still_Control_Weather **** **** **** **** **** **** **** **** +11905 OAShaman_Still_CW_Rain **** **** **** **** **** **** **** **** +11906 OAShaman_Still_CW_Snow **** **** **** **** **** **** **** **** +11907 OAShaman_Still_CW_Clear **** **** **** **** **** **** **** **** +11908 OAShaman_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +11909 OAShaman_Silent_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +11910 OAShaman_Still_DEATH_BY_THORNS **** **** **** **** **** **** **** **** +11911 OAShaman_Dictum **** **** **** **** **** **** **** **** +11912 OAShaman_Silent_Dictum **** **** **** **** **** **** **** **** +11913 OAShaman_Still_Dictum **** **** **** **** **** **** **** **** +11914 OAShaman_Greater_Restoration **** **** **** **** **** **** **** **** +11915 OAShaman_Silent_Greater_Restoration **** **** **** **** **** **** **** **** +11916 OAShaman_Still_Greater_Restoration **** **** **** **** **** **** **** **** +11917 OAShaman_GreaterScrying **** **** **** **** **** **** **** **** +11918 OAShaman_Exteneded_GreaterScrying **** **** **** **** **** **** **** **** +11919 OAShaman_Silent_GreaterScrying **** **** **** **** **** **** **** **** +11920 OAShaman_Still_GreaterScrying **** **** **** **** **** **** **** **** +11921 OAShaman_Holy_Word **** **** **** **** **** **** **** **** +11922 OAShaman_Silent_Holy_Word **** **** **** **** **** **** **** **** +11923 OAShaman_Still_Holy_Word **** **** **** **** **** **** **** **** +11924 OAShaman_PHOENIX_FIRE **** **** **** **** **** **** **** **** +11925 OAShaman_Empowered_PHOENIX_FIRE **** **** **** **** **** **** **** **** +11926 OAShaman_Silent_PHOENIX_FIRE **** **** **** **** **** **** **** **** +11927 OAShaman_Still_PHOENIX_FIRE **** **** **** **** **** **** **** **** +11928 OAShaman_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +11929 OAShaman_Empowered_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +11930 OAShaman_Exteneded_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +11931 OAShaman_Silent_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +11932 OAShaman_Still_RAIN_OF_EMBERS **** **** **** **** **** **** **** **** +11933 OAShaman_RAPTURE_OF_RUPTURE **** **** **** **** **** **** **** **** +11934 OAShaman_Empowered_RAPTURE_OF_RUPTURE **** **** **** **** **** **** **** **** +11935 OAShaman_Regenerate **** **** **** **** **** **** **** **** +11936 OAShaman_Exteneded_Regenerate **** **** **** **** **** **** **** **** +11937 OAShaman_Silent_Regenerate **** **** **** **** **** **** **** **** +11938 OAShaman_Still_Regenerate **** **** **** **** **** **** **** **** +11939 OAShaman_Repulsion **** **** **** **** **** **** **** **** +11940 OAShaman_Exteneded_Repulsion **** **** **** **** **** **** **** **** +11941 OAShaman_Silent_Repulsion **** **** **** **** **** **** **** **** +11942 OAShaman_Still_Repulsion **** **** **** **** **** **** **** **** +11943 OAShaman_Resurrection **** **** **** **** **** **** **** **** +11944 OAShaman_Silent_Resurrection **** **** **** **** **** **** **** **** +11945 OAShaman_Still_Resurrection **** **** **** **** **** **** **** **** +11946 OAShaman_Summon_Creature_VII **** **** **** **** **** **** **** **** +11947 OAShaman_Summon7Air **** **** **** **** **** **** **** **** +11948 OAShaman_Summon7Earth **** **** **** **** **** **** **** **** +11949 OAShaman_Summon7Fire **** **** **** **** **** **** **** **** +11950 OAShaman_Summon7Water **** **** **** **** **** **** **** **** +11951 OAShaman_Exteneded_Summon_Creature_VII **** **** **** **** **** **** **** **** +11952 OAShaman_Exteneded_Summon7Air **** **** **** **** **** **** **** **** +11953 OAShaman_Exteneded_Summon7Earth **** **** **** **** **** **** **** **** +11954 OAShaman_Exteneded_Summon7Fire **** **** **** **** **** **** **** **** +11955 OAShaman_Exteneded_Summon7Water **** **** **** **** **** **** **** **** +11956 OAShaman_Silent_Summon_Creature_VII **** **** **** **** **** **** **** **** +11957 OAShaman_Silent_Summon7Air **** **** **** **** **** **** **** **** +11958 OAShaman_Silent_Summon7Earth **** **** **** **** **** **** **** **** +11959 OAShaman_Silent_Summon7Fire **** **** **** **** **** **** **** **** +11960 OAShaman_Silent_Summon7Water **** **** **** **** **** **** **** **** +11961 OAShaman_Still_Summon_Creature_VII **** **** **** **** **** **** **** **** +11962 OAShaman_Still_Summon7Air **** **** **** **** **** **** **** **** +11963 OAShaman_Still_Summon7Earth **** **** **** **** **** **** **** **** +11964 OAShaman_Still_Summon7Fire **** **** **** **** **** **** **** **** +11965 OAShaman_Still_Summon7Water **** **** **** **** **** **** **** **** +11966 OAShaman_Sunbeam **** **** **** **** **** **** **** **** +11967 OAShaman_Silent_Sunbeam **** **** **** **** **** **** **** **** +11968 OAShaman_Still_Sunbeam **** **** **** **** **** **** **** **** +11969 OAShaman_Word_of_Chaos **** **** **** **** **** **** **** **** +11970 OAShaman_Silent_Word_of_Chaos **** **** **** **** **** **** **** **** +11971 OAShaman_Still_Word_of_Chaos **** **** **** **** **** **** **** **** +11972 OAShaman_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +11973 OAShaman_Exteneded_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +11974 OAShaman_Silent_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +11975 OAShaman_Still_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +11976 OAShaman_Aura_versus_Alignment **** **** **** **** **** **** **** **** +11977 OAShaman_Unholy_Aura **** **** **** **** **** **** **** **** +11978 OAShaman_Holy_Aura **** **** **** **** **** **** **** **** +11979 OAShaman_Exteneded_Aura_versus_Alignment **** **** **** **** **** **** **** **** +11980 OAShaman_Exteneded_Unholy_Aura **** **** **** **** **** **** **** **** +11981 OAShaman_Exteneded_Holy_Aura **** **** **** **** **** **** **** **** +11982 OAShaman_Silent_Aura_versus_Alignment **** **** **** **** **** **** **** **** +11983 OAShaman_Silent_Unholy_Aura **** **** **** **** **** **** **** **** +11984 OAShaman_Silent_Holy_Aura **** **** **** **** **** **** **** **** +11985 OAShaman_Still_Aura_versus_Alignment **** **** **** **** **** **** **** **** +11986 OAShaman_Still_Unholy_Aura **** **** **** **** **** **** **** **** +11987 OAShaman_Still_Holy_Aura **** **** **** **** **** **** **** **** +11988 OAShaman_DiscernLocation **** **** **** **** **** **** **** **** +11989 OAShaman_Exteneded_DiscernLocation **** **** **** **** **** **** **** **** +11990 OAShaman_Silent_DiscernLocation **** **** **** **** **** **** **** **** +11991 OAShaman_Still_DiscernLocation **** **** **** **** **** **** **** **** +11992 OAShaman_DRAGON_CLOUD **** **** **** **** **** **** **** **** +11993 OAShaman_Silent_DRAGON_CLOUD **** **** **** **** **** **** **** **** +11994 OAShaman_Still_DRAGON_CLOUD **** **** **** **** **** **** **** **** +11995 OAShaman_Earthquake **** **** **** **** **** **** **** **** +11996 OAShaman_Exteneded_Earthquake **** **** **** **** **** **** **** **** +11997 OAShaman_Silent_Earthquake **** **** **** **** **** **** **** **** +11998 OAShaman_Still_Earthquake **** **** **** **** **** **** **** **** +11999 OAShaman_EVIL_WEATHER **** **** **** **** **** **** **** **** +12000 OAShaman_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +12001 OAShaman_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +12002 OAShaman_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +12003 OAShaman_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +12004 OAShaman_Silent_EVIL_WEATHER **** **** **** **** **** **** **** **** +12005 OAShaman_Silent_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +12006 OAShaman_Silent_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +12007 OAShaman_Silent_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +12008 OAShaman_Silent_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +12009 OAShaman_Still_EVIL_WEATHER **** **** **** **** **** **** **** **** +12010 OAShaman_Still_EVIL_WEATHER_RAIN_OF_BLOOD **** **** **** **** **** **** **** **** +12011 OAShaman_Still_EVIL_WEATHER_VIOLET_RAIN **** **** **** **** **** **** **** **** +12012 OAShaman_Still_EVIL_WEATHER_GREEN_FOG **** **** **** **** **** **** **** **** +12013 OAShaman_Still_EVIL_WEATHER_RAIN_OF_FISH **** **** **** **** **** **** **** **** +12014 OAShaman_Greater_Planar_Ally **** **** **** **** **** **** **** **** +12015 OAShaman_Exteneded_Greater_Planar_Ally **** **** **** **** **** **** **** **** +12016 OAShaman_Silent_Greater_Planar_Ally **** **** **** **** **** **** **** **** +12017 OAShaman_Still_Greater_Planar_Ally **** **** **** **** **** **** **** **** +12018 OAShaman_Holy_Aura **** **** **** **** **** **** **** **** +12019 OAShaman_Exteneded_Holy_Aura **** **** **** **** **** **** **** **** +12020 OAShaman_Silent_Holy_Aura **** **** **** **** **** **** **** **** +12021 OAShaman_Still_Holy_Aura **** **** **** **** **** **** **** **** +12022 OAShaman_Mass_Heal **** **** **** **** **** **** **** **** +12023 OAShaman_Silent_Mass_Heal **** **** **** **** **** **** **** **** +12024 OAShaman_Still_Mass_Heal **** **** **** **** **** **** **** **** +12025 OAShaman_Summon_Creature_VIII **** **** **** **** **** **** **** **** +12026 OAShaman_Summon8Air **** **** **** **** **** **** **** **** +12027 OAShaman_Summon8Earth **** **** **** **** **** **** **** **** +12028 OAShaman_Summon8Fire **** **** **** **** **** **** **** **** +12029 OAShaman_Summon8Water **** **** **** **** **** **** **** **** +12030 OAShaman_Exteneded_Summon_Creature_VIII **** **** **** **** **** **** **** **** +12031 OAShaman_Exteneded_Summon8Air **** **** **** **** **** **** **** **** +12032 OAShaman_Exteneded_Summon8Earth **** **** **** **** **** **** **** **** +12033 OAShaman_Exteneded_Summon8Fire **** **** **** **** **** **** **** **** +12034 OAShaman_Exteneded_Summon8Water **** **** **** **** **** **** **** **** +12035 OAShaman_Silent_Summon_Creature_VIII **** **** **** **** **** **** **** **** +12036 OAShaman_Silent_Summon8Air **** **** **** **** **** **** **** **** +12037 OAShaman_Silent_Summon8Earth **** **** **** **** **** **** **** **** +12038 OAShaman_Silent_Summon8Fire **** **** **** **** **** **** **** **** +12039 OAShaman_Silent_Summon8Water **** **** **** **** **** **** **** **** +12040 OAShaman_Still_Summon_Creature_VIII **** **** **** **** **** **** **** **** +12041 OAShaman_Still_Summon8Air **** **** **** **** **** **** **** **** +12042 OAShaman_Still_Summon8Earth **** **** **** **** **** **** **** **** +12043 OAShaman_Still_Summon8Fire **** **** **** **** **** **** **** **** +12044 OAShaman_Still_Summon8Water **** **** **** **** **** **** **** **** +12045 OAShaman_APOCALYPSE_FROM_THE_SKY **** **** **** **** **** **** **** **** +12046 OAShaman_APOCALYPSE_FROM_THE_SKY_FIRE **** **** **** **** **** **** **** **** +12047 OAShaman_APOCALYPSE_FROM_THE_SKY_ACID **** **** **** **** **** **** **** **** +12048 OAShaman_APOCALYPSE_FROM_THE_SKY_SONIC **** **** **** **** **** **** **** **** +12049 OAShaman_EXALTED_FURY **** **** **** **** **** **** **** **** +12050 OAShaman_Gate **** **** **** **** **** **** **** **** +12051 OAShaman_Summon_Creature_IX **** **** **** **** **** **** **** **** +12052 OAShaman_Summon9Air **** **** **** **** **** **** **** **** +12053 OAShaman_Summon9Earth **** **** **** **** **** **** **** **** +12054 OAShaman_Summon9Fire **** **** **** **** **** **** **** **** +12055 OAShaman_Summon9Water **** **** **** **** **** **** **** **** +12056 OAShaman_True_Resurrection **** **** **** **** **** **** **** **** +12057 SlayerOfDomiel_Bless_Weapon **** **** **** **** **** **** **** **** +12058 SlayerOfDomiel_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +12059 SlayerOfDomiel_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +12060 SlayerOfDomiel_Still_Bless_Weapon **** **** **** **** **** **** **** **** +12061 SlayerOfDomiel_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12062 SlayerOfDomiel_Alter_Self_Learn **** **** **** **** **** **** **** **** +12063 SlayerOfDomiel_Alter_Self_Options **** **** **** **** **** **** **** **** +12064 SlayerOfDomiel_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12065 SlayerOfDomiel_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12066 SlayerOfDomiel_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12067 SlayerOfDomiel_Exteneded_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12068 SlayerOfDomiel_Exteneded_Alter_Self_Learn **** **** **** **** **** **** **** **** +12069 SlayerOfDomiel_Exteneded_Alter_Self_Options **** **** **** **** **** **** **** **** +12070 SlayerOfDomiel_Exteneded_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12071 SlayerOfDomiel_Exteneded_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12072 SlayerOfDomiel_Exteneded_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12073 SlayerOfDomiel_Silent_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12074 SlayerOfDomiel_Silent_Alter_Self_Learn **** **** **** **** **** **** **** **** +12075 SlayerOfDomiel_Silent_Alter_Self_Options **** **** **** **** **** **** **** **** +12076 SlayerOfDomiel_Silent_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12077 SlayerOfDomiel_Silent_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12078 SlayerOfDomiel_Silent_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12079 SlayerOfDomiel_Still_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12080 SlayerOfDomiel_Still_Alter_Self_Learn **** **** **** **** **** **** **** **** +12081 SlayerOfDomiel_Still_Alter_Self_Options **** **** **** **** **** **** **** **** +12082 SlayerOfDomiel_Still_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12083 SlayerOfDomiel_Still_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12084 SlayerOfDomiel_Still_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12085 SlayerOfDomiel_Divine_Favor **** **** **** **** **** **** **** **** +12086 SlayerOfDomiel_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +12087 SlayerOfDomiel_Silent_Divine_Favor **** **** **** **** **** **** **** **** +12088 SlayerOfDomiel_Still_Divine_Favor **** **** **** **** **** **** **** **** +12089 SlayerOfDomiel_Obscuring_Mist **** **** **** **** **** **** **** **** +12090 SlayerOfDomiel_Exteneded_Obscuring_Mist **** **** **** **** **** **** **** **** +12091 SlayerOfDomiel_Silent_Obscuring_Mist **** **** **** **** **** **** **** **** +12092 SlayerOfDomiel_Still_Obscuring_Mist **** **** **** **** **** **** **** **** +12093 SlayerOfDomiel_VisionOfHeaven **** **** **** **** **** **** **** **** +12094 SlayerOfDomiel_Exteneded_VisionOfHeaven **** **** **** **** **** **** **** **** +12095 SlayerOfDomiel_Silent_VisionOfHeaven **** **** **** **** **** **** **** **** +12096 SlayerOfDomiel_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +12097 SlayerOfDomiel_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +12098 SlayerOfDomiel_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12099 SlayerOfDomiel_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12100 SlayerOfDomiel_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12101 SlayerOfDomiel_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12102 SlayerOfDomiel_Empowered_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12103 SlayerOfDomiel_Maximized_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12104 SlayerOfDomiel_Still_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12105 SlayerOfDomiel_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12106 SlayerOfDomiel_Alter_Self_Learn **** **** **** **** **** **** **** **** +12107 SlayerOfDomiel_Alter_Self_Options **** **** **** **** **** **** **** **** +12108 SlayerOfDomiel_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12109 SlayerOfDomiel_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12110 SlayerOfDomiel_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12111 SlayerOfDomiel_Exteneded_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12112 SlayerOfDomiel_Exteneded_Alter_Self_Learn **** **** **** **** **** **** **** **** +12113 SlayerOfDomiel_Exteneded_Alter_Self_Options **** **** **** **** **** **** **** **** +12114 SlayerOfDomiel_Exteneded_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12115 SlayerOfDomiel_Exteneded_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12116 SlayerOfDomiel_Exteneded_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12117 SlayerOfDomiel_Silent_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12118 SlayerOfDomiel_Silent_Alter_Self_Learn **** **** **** **** **** **** **** **** +12119 SlayerOfDomiel_Silent_Alter_Self_Options **** **** **** **** **** **** **** **** +12120 SlayerOfDomiel_Silent_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12121 SlayerOfDomiel_Silent_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12122 SlayerOfDomiel_Silent_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12123 SlayerOfDomiel_Still_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12124 SlayerOfDomiel_Still_Alter_Self_Learn **** **** **** **** **** **** **** **** +12125 SlayerOfDomiel_Still_Alter_Self_Options **** **** **** **** **** **** **** **** +12126 SlayerOfDomiel_Still_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12127 SlayerOfDomiel_Still_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12128 SlayerOfDomiel_Still_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12129 SlayerOfDomiel_Darkness **** **** **** **** **** **** **** **** +12130 SlayerOfDomiel_Exteneded_Darkness **** **** **** **** **** **** **** **** +12131 SlayerOfDomiel_Silent_Darkness **** **** **** **** **** **** **** **** +12132 SlayerOfDomiel_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12133 SlayerOfDomiel_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12134 SlayerOfDomiel_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12135 SlayerOfDomiel_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12136 SlayerOfDomiel_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12137 SlayerOfDomiel_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12138 SlayerOfDomiel_DeeperDarkness **** **** **** **** **** **** **** **** +12139 SlayerOfDomiel_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +12140 SlayerOfDomiel_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +12141 SlayerOfDomiel_Invisibility **** **** **** **** **** **** **** **** +12142 SlayerOfDomiel_Exteneded_Invisibility **** **** **** **** **** **** **** **** +12143 SlayerOfDomiel_Silent_Invisibility **** **** **** **** **** **** **** **** +12144 SlayerOfDomiel_Still_Invisibility **** **** **** **** **** **** **** **** +12145 SlayerOfDomiel_NONDETECTION **** **** **** **** **** **** **** **** +12146 SlayerOfDomiel_Exteneded_NONDETECTION **** **** **** **** **** **** **** **** +12147 SlayerOfDomiel_Silent_NONDETECTION **** **** **** **** **** **** **** **** +12148 SlayerOfDomiel_Still_NONDETECTION **** **** **** **** **** **** **** **** +12149 SlayerOfDomiel_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +12150 SlayerOfDomiel_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +12151 SlayerOfDomiel_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12152 SlayerOfDomiel_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12153 SlayerOfDomiel_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12154 SlayerOfDomiel_Death_Ward **** **** **** **** **** **** **** **** +12155 SlayerOfDomiel_DimensionDoor_RadialMaster **** **** **** **** **** **** **** **** +12156 SlayerOfDomiel_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +12157 SlayerOfDomiel_DimensionDoor_Party **** **** **** **** **** **** **** **** +12158 SlayerOfDomiel_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +12159 SlayerOfDomiel_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +12160 SlayerOfDomiel_Freedom_of_Movement **** **** **** **** **** **** **** **** +12161 SlayerOfDomiel_Holy_Sword **** **** **** **** **** **** **** **** +12162 SlayerOfDomiel_Improved_Invisibility **** **** **** **** **** **** **** **** +12163 SlayerOfDomiel_SwordOfConscience **** **** **** **** **** **** **** **** +12164 SlayerOfDomiel_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +12165 SlayerOfDomiel_SUNMANTLE **** **** **** **** **** **** **** **** +12166 SlayerOfDomiel_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12167 Suel_Archanamach_ABERRATE **** **** **** **** **** **** **** **** +12168 Suel_Archanamach_BESTOW_WOUND **** **** **** **** **** **** **** **** +12169 Suel_Archanamach_Burning_Hands **** **** **** **** **** **** **** **** +12170 Suel_Archanamach_Color_Spray **** **** **** **** **** **** **** **** +12171 Suel_Archanamach_DETECT_UNDEAD **** **** **** **** **** **** **** **** +12172 Suel_Archanamach_Disguise_Self_Radial_Master **** **** **** **** **** **** **** **** +12173 Suel_Archanamach_Disguise_Self_Learn **** **** **** **** **** **** **** **** +12174 Suel_Archanamach_Disguise_Self_Options **** **** **** **** **** **** **** **** +12175 Suel_Archanamach_Disguise_Self_QS1 **** **** **** **** **** **** **** **** +12176 Suel_Archanamach_Disguise_Self_QS2 **** **** **** **** **** **** **** **** +12177 Suel_Archanamach_Disguise_Self_QS3 **** **** **** **** **** **** **** **** +12178 Suel_Archanamach_Endure_Elements **** **** **** **** **** **** **** **** +12179 Suel_Archanamach_ENLARGE_PERSON **** **** **** **** **** **** **** **** +12180 Suel_Archanamach_Expeditious_Retreat **** **** **** **** **** **** **** **** +12181 Suel_Archanamach_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +12182 Suel_Archanamach_FistOfStone **** **** **** **** **** **** **** **** +12183 Suel_Archanamach_Identify **** **** **** **** **** **** **** **** +12184 Suel_Archanamach_Ironguts **** **** **** **** **** **** **** **** +12185 Suel_Archanamach_Lesser_Deflect **** **** **** **** **** **** **** **** +12186 Suel_Archanamach_Magic_Weapon **** **** **** **** **** **** **** **** +12187 Suel_Archanamach_Protection_from_Chaos **** **** **** **** **** **** **** **** +12188 Suel_Archanamach_Protection_from_Evil **** **** **** **** **** **** **** **** +12189 Suel_Archanamach_Protection_from_Good **** **** **** **** **** **** **** **** +12190 Suel_Archanamach_Protection_from_Law **** **** **** **** **** **** **** **** +12191 Suel_Archanamach_REDUCE_PERSON **** **** **** **** **** **** **** **** +12192 Suel_Archanamach_Shield **** **** **** **** **** **** **** **** +12193 Suel_Archanamach_Spell_Jump **** **** **** **** **** **** **** **** +12194 Suel_Archanamach_True_Casting **** **** **** **** **** **** **** **** +12195 Suel_Archanamach_True_Strike **** **** **** **** **** **** **** **** +12196 Suel_Archanamach_Alter_Self_Radial_Master **** **** **** **** **** **** **** **** +12197 Suel_Archanamach_Alter_Self_Learn **** **** **** **** **** **** **** **** +12198 Suel_Archanamach_Alter_Self_Options **** **** **** **** **** **** **** **** +12199 Suel_Archanamach_Alter_Self_QS1 **** **** **** **** **** **** **** **** +12200 Suel_Archanamach_Alter_Self_QS2 **** **** **** **** **** **** **** **** +12201 Suel_Archanamach_Alter_Self_QS3 **** **** **** **** **** **** **** **** +12202 Suel_Archanamach_Animalistic_Power **** **** **** **** **** **** **** **** +12203 Suel_Archanamach_AugmentFamiliar **** **** **** **** **** **** **** **** +12204 Suel_Archanamach_BalagarnsIronHorn **** **** **** **** **** **** **** **** +12205 Suel_Archanamach_Blur **** **** **** **** **** **** **** **** +12206 Suel_Archanamach_Bulls_Strength **** **** **** **** **** **** **** **** +12207 Suel_Archanamach_Cats_Grace **** **** **** **** **** **** **** **** +12208 Suel_Archanamach_Continual_Flame **** **** **** **** **** **** **** **** +12209 Suel_Archanamach_Deflect **** **** **** **** **** **** **** **** +12210 Suel_Archanamach_Dispelling_Touch **** **** **** **** **** **** **** **** +12211 Suel_Archanamach_Eagle_Splendor **** **** **** **** **** **** **** **** +12212 Suel_Archanamach_Endurance **** **** **** **** **** **** **** **** +12213 Suel_Archanamach_ENERGIZE_POTION **** **** **** **** **** **** **** **** +12214 Suel_Archanamach_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +12215 Suel_Archanamach_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +12216 Suel_Archanamach_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +12217 Suel_Archanamach_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +12218 Suel_Archanamach_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +12219 Suel_Archanamach_Foxs_Cunning **** **** **** **** **** **** **** **** +12220 Suel_Archanamach_Ghostly_Visage **** **** **** **** **** **** **** **** +12221 Suel_Archanamach_Invisibility **** **** **** **** **** **** **** **** +12222 Suel_Archanamach_Knock **** **** **** **** **** **** **** **** +12223 Suel_Archanamach_Lesser_Dispel **** **** **** **** **** **** **** **** +12224 Suel_Archanamach_LocateObject **** **** **** **** **** **** **** **** +12225 Suel_Archanamach_MirrorImage **** **** **** **** **** **** **** **** +12226 Suel_Archanamach_ObscureObject **** **** **** **** **** **** **** **** +12227 Suel_Archanamach_Owls_Wisdom **** **** **** **** **** **** **** **** +12228 Suel_Archanamach_ProtectionArrows **** **** **** **** **** **** **** **** +12229 Suel_Archanamach_Pyrotechnics **** **** **** **** **** **** **** **** +12230 Suel_Archanamach_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +12231 Suel_Archanamach_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +12232 Suel_Archanamach_Resist_Elements **** **** **** **** **** **** **** **** +12233 Suel_Archanamach_See_Invisibility **** **** **** **** **** **** **** **** +12234 Suel_Archanamach_Shadow_Spray **** **** **** **** **** **** **** **** +12235 Suel_Archanamach_Stone_Bones **** **** **** **** **** **** **** **** +12236 Suel_Archanamach_Sure_Strike **** **** **** **** **** **** **** **** +12237 Suel_Archanamach_Ultravision **** **** **** **** **** **** **** **** +12238 Suel_Archanamach_UNHEAVENED **** **** **** **** **** **** **** **** +12239 Suel_Archanamach_WhirlingBlade **** **** **** **** **** **** **** **** +12240 Suel_Archanamach_Clairaudience_and_Clairvoyance **** **** **** **** **** **** **** **** +12241 Suel_Archanamach_Clarity **** **** **** **** **** **** **** **** +12242 Suel_Archanamach_Crown_Might **** **** **** **** **** **** **** **** +12243 Suel_Archanamach_Crown_Protection **** **** **** **** **** **** **** **** +12244 Suel_Archanamach_CURSE_OF_THE_PUTRID_HUSK **** **** **** **** **** **** **** **** +12245 Suel_Archanamach_DEVILS_EYE **** **** **** **** **** **** **** **** +12246 Suel_Archanamach_Dispel_Magic **** **** **** **** **** **** **** **** +12247 Suel_Archanamach_Displacement **** **** **** **** **** **** **** **** +12248 Suel_Archanamach_Energy_Aegis **** **** **** **** **** **** **** **** +12249 Suel_Archanamach_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +12250 Suel_Archanamach_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +12251 Suel_Archanamach_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +12252 Suel_Archanamach_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +12253 Suel_Archanamach_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +12254 Suel_Archanamach_Energy_Surge **** **** **** **** **** **** **** **** +12255 Suel_Archanamach_Energy_Surge_Acid **** **** **** **** **** **** **** **** +12256 Suel_Archanamach_Energy_Surge_Cold **** **** **** **** **** **** **** **** +12257 Suel_Archanamach_Energy_Surge_Elec **** **** **** **** **** **** **** **** +12258 Suel_Archanamach_Energy_Surge_Fire **** **** **** **** **** **** **** **** +12259 Suel_Archanamach_Energy_Surge_Sonic **** **** **** **** **** **** **** **** +12260 Suel_Archanamach_Find_Traps **** **** **** **** **** **** **** **** +12261 Suel_Archanamach_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12262 Suel_Archanamach_Halt **** **** **** **** **** **** **** **** +12263 Suel_Archanamach_Haste **** **** **** **** **** **** **** **** +12264 Suel_Archanamach_Invisibility_Sphere **** **** **** **** **** **** **** **** +12265 Suel_Archanamach_Keen_Edge **** **** **** **** **** **** **** **** +12266 Suel_Archanamach_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12267 Suel_Archanamach_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +12268 Suel_Archanamach_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +12269 Suel_Archanamach_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +12270 Suel_Archanamach_NONDETECTION **** **** **** **** **** **** **** **** +12271 Suel_Archanamach_Protection_from_Elements **** **** **** **** **** **** **** **** +12272 Suel_Archanamach_REALITY_BLIND **** **** **** **** **** **** **** **** +12273 Suel_Archanamach_Slow **** **** **** **** **** **** **** **** +12274 Suel_Archanamach_Spiderskin **** **** **** **** **** **** **** **** +12275 Suel_Archanamach_WaterBreathing **** **** **** **** **** **** **** **** +12276 Suel_Archanamach_Weapon_of_Impact **** **** **** **** **** **** **** **** +12277 Suel_Archanamach_ArcaneEye **** **** **** **** **** **** **** **** +12278 Suel_Archanamach_Bestow_Curse **** **** **** **** **** **** **** **** +12279 Suel_Archanamach_DetectScrying **** **** **** **** **** **** **** **** +12280 Suel_Archanamach_Dimensional_Anchor **** **** **** **** **** **** **** **** +12281 Suel_Archanamach_FireTrap **** **** **** **** **** **** **** **** +12282 Suel_Archanamach_Greater_Resistance **** **** **** **** **** **** **** **** +12283 Suel_Archanamach_Ilyykurs_Mantle **** **** **** **** **** **** **** **** +12284 Suel_Archanamach_Improved_Invisibility **** **** **** **** **** **** **** **** +12285 Suel_Archanamach_Lesser_Spell_Breach **** **** **** **** **** **** **** **** +12286 Suel_Archanamach_LocateCreature **** **** **** **** **** **** **** **** +12287 Suel_Archanamach_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +12288 Suel_Archanamach_MASS_ENLARGE_PERSON **** **** **** **** **** **** **** **** +12289 Suel_Archanamach_MASS_REDUCE_PERSON **** **** **** **** **** **** **** **** +12290 Suel_Archanamach_Mass_Ultravision **** **** **** **** **** **** **** **** +12291 Suel_Archanamach_Minor_Globe_of_Invulnerability **** **** **** **** **** **** **** **** +12292 Suel_Archanamach_Phantasmal_Killer **** **** **** **** **** **** **** **** +12293 Suel_Archanamach_Polymorph_Self **** **** **** **** **** **** **** **** +12294 Suel_Archanamach_Polymorph_GIANT_SPIDER **** **** **** **** **** **** **** **** +12295 Suel_Archanamach_Polymorph_TROLL **** **** **** **** **** **** **** **** +12296 Suel_Archanamach_Polymorph_UMBER_HULK **** **** **** **** **** **** **** **** +12297 Suel_Archanamach_Polymorph_PIXIE **** **** **** **** **** **** **** **** +12298 Suel_Archanamach_Polymorph_ZOMBIE **** **** **** **** **** **** **** **** +12299 Suel_Archanamach_RAINBOW_PATTERN **** **** **** **** **** **** **** **** +12300 Suel_Archanamach_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +12301 Suel_Archanamach_Remove_Curse **** **** **** **** **** **** **** **** +12302 Suel_Archanamach_Scrying **** **** **** **** **** **** **** **** +12303 Suel_Archanamach_SerpentArrows **** **** **** **** **** **** **** **** +12304 Suel_Archanamach_Shadow_Conjuration **** **** **** **** **** **** **** **** +12305 Suel_Archanamach_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +12306 Suel_Archanamach_SHADOW_CON_Darkness **** **** **** **** **** **** **** **** +12307 Suel_Archanamach_SHADOW_CON_Inivsibility **** **** **** **** **** **** **** **** +12308 Suel_Archanamach_SHADOW_CON_Mage_Armor **** **** **** **** **** **** **** **** +12309 Suel_Archanamach_SHADOW_CON_Magic_Missile **** **** **** **** **** **** **** **** +12310 Suel_Archanamach_Slashing_Dispel **** **** **** **** **** **** **** **** +12311 Suel_Archanamach_Stoneskin **** **** **** **** **** **** **** **** +12312 Suel_Archanamach_BalefulPolymorph **** **** **** **** **** **** **** **** +12313 Suel_Archanamach_BreakEnchantment **** **** **** **** **** **** **** **** +12314 Suel_Archanamach_Dismissal **** **** **** **** **** **** **** **** +12315 Suel_Archanamach_DraconicMight **** **** **** **** **** **** **** **** +12316 Suel_Archanamach_Energy_Buffer **** **** **** **** **** **** **** **** +12317 Suel_Archanamach_Feeblemind **** **** **** **** **** **** **** **** +12318 Suel_Archanamach_Greater_Shadow_Conjuration **** **** **** **** **** **** **** **** +12319 Suel_Archanamach_GR_SHADOW_CON_Summon_Shadow **** **** **** **** **** **** **** **** +12320 Suel_Archanamach_GR_SHADOW_CON_Acid_Arrow **** **** **** **** **** **** **** **** +12321 Suel_Archanamach_GR_SHADOW_CON_Ghostly_Visage **** **** **** **** **** **** **** **** +12322 Suel_Archanamach_GR_SHADOW_CON_Web **** **** **** **** **** **** **** **** +12323 Suel_Archanamach_GR_SHADOW_CON_Minor_Globe **** **** **** **** **** **** **** **** +12324 Suel_Archanamach_Lesser_Mind_Blank **** **** **** **** **** **** **** **** +12325 Suel_Archanamach_Lesser_Spell_Mantle **** **** **** **** **** **** **** **** +12326 Suel_Archanamach_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +12327 Favoured_Soul_Cure_Minor_Wounds **** **** **** **** **** **** **** **** +12328 Favoured_Soul_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +12329 Favoured_Soul_Light **** **** **** **** **** **** **** **** +12330 Favoured_Soul_Read_Magic **** **** **** **** **** **** **** **** +12331 Favoured_Soul_Resistance **** **** **** **** **** **** **** **** +12332 Favoured_Soul_Virtue **** **** **** **** **** **** **** **** +12333 Favoured_Soul_ANGRY_ACHE **** **** **** **** **** **** **** **** +12334 Favoured_Soul_Bane **** **** **** **** **** **** **** **** +12335 Favoured_Soul_Blade_of_Blood **** **** **** **** **** **** **** **** +12336 Favoured_Soul_Blade_of_Blood_1d6 **** **** **** **** **** **** **** **** +12337 Favoured_Soul_Blade_of_Blood_3d6 **** **** **** **** **** **** **** **** +12338 Favoured_Soul_Bless **** **** **** **** **** **** **** **** +12339 Favoured_Soul_Bless_Water **** **** **** **** **** **** **** **** +12340 Favoured_Soul_Cause_Fear **** **** **** **** **** **** **** **** +12341 Favoured_Soul_Command_RadialMaster **** **** **** **** **** **** **** **** +12342 Favoured_Soul_Command_Approach **** **** **** **** **** **** **** **** +12343 Favoured_Soul_Command_Drop **** **** **** **** **** **** **** **** +12344 Favoured_Soul_Command_Fall **** **** **** **** **** **** **** **** +12345 Favoured_Soul_Command_Flee **** **** **** **** **** **** **** **** +12346 Favoured_Soul_Command_Halt **** **** **** **** **** **** **** **** +12347 Favoured_Soul_Conviction **** **** **** **** **** **** **** **** +12348 Favoured_Soul_Crafters_Blessing **** **** **** **** **** **** **** **** +12349 Favoured_Soul_Crafters_Curse **** **** **** **** **** **** **** **** +12350 Favoured_Soul_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12351 Favoured_Soul_Curse_Water **** **** **** **** **** **** **** **** +12352 Favoured_Soul_Detect_Chaos **** **** **** **** **** **** **** **** +12353 Favoured_Soul_Detect_Evil **** **** **** **** **** **** **** **** +12354 Favoured_Soul_Detect_Good **** **** **** **** **** **** **** **** +12355 Favoured_Soul_Detect_Law **** **** **** **** **** **** **** **** +12356 Favoured_Soul_DETECT_UNDEAD **** **** **** **** **** **** **** **** +12357 Favoured_Soul_Divine_Favor **** **** **** **** **** **** **** **** +12358 Favoured_Soul_Doom **** **** **** **** **** **** **** **** +12359 Favoured_Soul_DRUG_RESISTANCE **** **** **** **** **** **** **** **** +12360 Favoured_Soul_Endure_Elements **** **** **** **** **** **** **** **** +12361 Favoured_Soul_Entropic_Shield **** **** **** **** **** **** **** **** +12362 Favoured_Soul_EXTRACT_DRUG **** **** **** **** **** **** **** **** +12363 Favoured_Soul_EXTRACT_BACCARAN **** **** **** **** **** **** **** **** +12364 Favoured_Soul_EXTRACT_VODARE **** **** **** **** **** **** **** **** +12365 Favoured_Soul_EXTRACT_SANNISH **** **** **** **** **** **** **** **** +12366 Favoured_Soul_EXTRACT_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +12367 Favoured_Soul_EYES_OF_THE_AVORAL **** **** **** **** **** **** **** **** +12368 Favoured_Soul_HEARTACHE **** **** **** **** **** **** **** **** +12369 Favoured_Soul_HideFromUndead **** **** **** **** **** **** **** **** +12370 Favoured_Soul_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +12371 Favoured_Soul_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12372 Favoured_Soul_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +12373 Favoured_Soul_Lesser_Vigor **** **** **** **** **** **** **** **** +12374 Favoured_Soul_Magic_Stone **** **** **** **** **** **** **** **** +12375 Favoured_Soul_Magic_Weapon **** **** **** **** **** **** **** **** +12376 Favoured_Soul_Necrotic_Awareness **** **** **** **** **** **** **** **** +12377 Favoured_Soul_Obscuring_Mist **** **** **** **** **** **** **** **** +12378 Favoured_Soul_Protection_from_Chaos **** **** **** **** **** **** **** **** +12379 Favoured_Soul_Protection_from_Evil **** **** **** **** **** **** **** **** +12380 Favoured_Soul_Protection_from_Good **** **** **** **** **** **** **** **** +12381 Favoured_Soul_Protection_from_Law **** **** **** **** **** **** **** **** +12382 Favoured_Soul_RAY_OF_HOPE **** **** **** **** **** **** **** **** +12383 Favoured_Soul_Remove_Fear **** **** **** **** **** **** **** **** +12384 Favoured_Soul_Sanctuary **** **** **** **** **** **** **** **** +12385 Favoured_Soul_Shield_of_Faith **** **** **** **** **** **** **** **** +12386 Favoured_Soul_SORROW **** **** **** **** **** **** **** **** +12387 Favoured_Soul_Summon_Creature_I **** **** **** **** **** **** **** **** +12388 Favoured_Soul_SummonUndeadI **** **** **** **** **** **** **** **** +12389 Favoured_Soul_TONGUE_OF_BAALZEBUL **** **** **** **** **** **** **** **** +12390 Favoured_Soul_VisionOfHeaven **** **** **** **** **** **** **** **** +12391 Favoured_Soul_ADDICTION **** **** **** **** **** **** **** **** +12392 Favoured_Soul_ADDICTION_TERRAN_BRANDY **** **** **** **** **** **** **** **** +12393 Favoured_Soul_ADDICTION_MUSHROOM_POWDER **** **** **** **** **** **** **** **** +12394 Favoured_Soul_ADDICTION_VODARE **** **** **** **** **** **** **** **** +12395 Favoured_Soul_ADDICTION_AGONY **** **** **** **** **** **** **** **** +12396 Favoured_Soul_Aid **** **** **** **** **** **** **** **** +12397 Favoured_Soul_Animalistic_Power **** **** **** **** **** **** **** **** +12398 Favoured_Soul_BONEBLAST **** **** **** **** **** **** **** **** +12399 Favoured_Soul_Bulls_Strength **** **** **** **** **** **** **** **** +12400 Favoured_Soul_Calm_Emotions **** **** **** **** **** **** **** **** +12401 Favoured_Soul_Consecrated_Aura **** **** **** **** **** **** **** **** +12402 Favoured_Soul_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +12403 Favoured_Soul_Darkness **** **** **** **** **** **** **** **** +12404 Favoured_Soul_Death_Knell **** **** **** **** **** **** **** **** +12405 Favoured_Soul_Divine_Protection **** **** **** **** **** **** **** **** +12406 Favoured_Soul_Eagle_Splendor **** **** **** **** **** **** **** **** +12407 Favoured_Soul_ELATION **** **** **** **** **** **** **** **** +12408 Favoured_Soul_Endurance **** **** **** **** **** **** **** **** +12409 Favoured_Soul_Find_Traps **** **** **** **** **** **** **** **** +12410 Favoured_Soul_Foxs_Cunning **** **** **** **** **** **** **** **** +12411 Favoured_Soul_Hold_Person **** **** **** **** **** **** **** **** +12412 Favoured_Soul_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +12413 Favoured_Soul_Lesser_Dispel **** **** **** **** **** **** **** **** +12414 Favoured_Soul_Lesser_Restoration **** **** **** **** **** **** **** **** +12415 Favoured_Soul_Living_Undeath **** **** **** **** **** **** **** **** +12416 Favoured_Soul_Necrotic_Cyst **** **** **** **** **** **** **** **** +12417 Favoured_Soul_Negative_Energy_Ray **** **** **** **** **** **** **** **** +12418 Favoured_Soul_Owls_Wisdom **** **** **** **** **** **** **** **** +12419 Favoured_Soul_Remove_Paralysis **** **** **** **** **** **** **** **** +12420 Favoured_Soul_Resist_Elements **** **** **** **** **** **** **** **** +12421 Favoured_Soul_ShieldOther **** **** **** **** **** **** **** **** +12422 Favoured_Soul_Silence **** **** **** **** **** **** **** **** +12423 Favoured_Soul_Sound_Burst **** **** **** **** **** **** **** **** +12424 Favoured_Soul_SPORES_OF_THE_VROCK **** **** **** **** **** **** **** **** +12425 Favoured_Soul_Stone_Bones **** **** **** **** **** **** **** **** +12426 Favoured_Soul_Summon_Creature_II **** **** **** **** **** **** **** **** +12427 Favoured_Soul_SummonUndeadII **** **** **** **** **** **** **** **** +12428 Favoured_Soul_Ultravision **** **** **** **** **** **** **** **** +12429 Favoured_Soul_UndetectableAlignment **** **** **** **** **** **** **** **** +12430 Favoured_Soul_WAVE_OF_GRIEF **** **** **** **** **** **** **** **** +12431 Favoured_Soul_Animate_Dead **** **** **** **** **** **** **** **** +12432 Favoured_Soul_Bestow_Curse **** **** **** **** **** **** **** **** +12433 Favoured_Soul_Blindness_and_Deafness **** **** **** **** **** **** **** **** +12434 Favoured_Soul_BONEBLADE **** **** **** **** **** **** **** **** +12435 Favoured_Soul_BONEBLADE_GREATSWORD **** **** **** **** **** **** **** **** +12436 Favoured_Soul_BONEBLADE_LONGSWORD **** **** **** **** **** **** **** **** +12437 Favoured_Soul_BONEBLADE_SHORTSWORD **** **** **** **** **** **** **** **** +12438 Favoured_Soul_Clarity **** **** **** **** **** **** **** **** +12439 Favoured_Soul_Close_Wounds **** **** **** **** **** **** **** **** +12440 Favoured_Soul_CLUTCH_OF_ORCUS **** **** **** **** **** **** **** **** +12441 Favoured_Soul_Contagion **** **** **** **** **** **** **** **** +12442 Favoured_Soul_Continual_Flame **** **** **** **** **** **** **** **** +12443 Favoured_Soul_Crown_Might **** **** **** **** **** **** **** **** +12444 Favoured_Soul_Crown_Protection **** **** **** **** **** **** **** **** +12445 Favoured_Soul_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +12446 Favoured_Soul_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +12447 Favoured_Soul_Darkfire **** **** **** **** **** **** **** **** +12448 Favoured_Soul_Daylight **** **** **** **** **** **** **** **** +12449 Favoured_Soul_DeeperDarkness **** **** **** **** **** **** **** **** +12450 Favoured_Soul_DEVILS_EYE **** **** **** **** **** **** **** **** +12451 Favoured_Soul_Dispel_Magic **** **** **** **** **** **** **** **** +12452 Favoured_Soul_ENERGIZE_POTION **** **** **** **** **** **** **** **** +12453 Favoured_Soul_ENERGIZE_POTION_ACID **** **** **** **** **** **** **** **** +12454 Favoured_Soul_ENERGIZE_POTION_COLD **** **** **** **** **** **** **** **** +12455 Favoured_Soul_ENERGIZE_POTION_ELECTRICITY **** **** **** **** **** **** **** **** +12456 Favoured_Soul_ENERGIZE_POTION_FIRE **** **** **** **** **** **** **** **** +12457 Favoured_Soul_ENERGIZE_POTION_SONIC **** **** **** **** **** **** **** **** +12458 Favoured_Soul_Energy_Aegis **** **** **** **** **** **** **** **** +12459 Favoured_Soul_Energy_Aegis_Acid **** **** **** **** **** **** **** **** +12460 Favoured_Soul_Energy_Aegis_Cold **** **** **** **** **** **** **** **** +12461 Favoured_Soul_Energy_Aegis_Elec **** **** **** **** **** **** **** **** +12462 Favoured_Soul_Energy_Aegis_Fire **** **** **** **** **** **** **** **** +12463 Favoured_Soul_Energy_Aegis_Sonic **** **** **** **** **** **** **** **** +12464 Favoured_Soul_FLESH_RIPPER **** **** **** **** **** **** **** **** +12465 Favoured_Soul_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +12466 Favoured_Soul_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +12467 Favoured_Soul_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +12468 Favoured_Soul_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +12469 Favoured_Soul_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +12470 Favoured_Soul_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +12471 Favoured_Soul_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +12472 Favoured_Soul_Invisibility_Purge **** **** **** **** **** **** **** **** +12473 Favoured_Soul_Legions_Conviction **** **** **** **** **** **** **** **** +12474 Favoured_Soul_LocateObject **** **** **** **** **** **** **** **** +12475 Favoured_Soul_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12476 Favoured_Soul_Magic_Circle_against_Evil **** **** **** **** **** **** **** **** +12477 Favoured_Soul_Magic_Circle_against_Good **** **** **** **** **** **** **** **** +12478 Favoured_Soul_Magic_Circle_against_Law **** **** **** **** **** **** **** **** +12479 Favoured_Soul_Magic_Vestment **** **** **** **** **** **** **** **** +12480 Favoured_Soul_MASOCHISM **** **** **** **** **** **** **** **** +12481 Favoured_Soul_Mass_Aid **** **** **** **** **** **** **** **** +12482 Favoured_Soul_Mass_Lesser_Vigor **** **** **** **** **** **** **** **** +12483 Favoured_Soul_Necrotic_Bloat **** **** **** **** **** **** **** **** +12484 Favoured_Soul_Negative_Energy_Protection **** **** **** **** **** **** **** **** +12485 Favoured_Soul_ObscureObject **** **** **** **** **** **** **** **** +12486 Favoured_Soul_Prayer **** **** **** **** **** **** **** **** +12487 Favoured_Soul_Protection_from_Elements **** **** **** **** **** **** **** **** +12488 Favoured_Soul_Remove_Blindness_and_Deafness **** **** **** **** **** **** **** **** +12489 Favoured_Soul_Remove_Curse **** **** **** **** **** **** **** **** +12490 Favoured_Soul_Remove_Disease **** **** **** **** **** **** **** **** +12491 Favoured_Soul_RingOfBlades **** **** **** **** **** **** **** **** +12492 Favoured_Soul_Searing_Light **** **** **** **** **** **** **** **** +12493 Favoured_Soul_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +12494 Favoured_Soul_SHRIVELING **** **** **** **** **** **** **** **** +12495 Favoured_Soul_Slashing_Darkness **** **** **** **** **** **** **** **** +12496 Favoured_Soul_Summon_Creature_III **** **** **** **** **** **** **** **** +12497 Favoured_Soul_SummonUndeadIII **** **** **** **** **** **** **** **** +12498 Favoured_Soul_UNLIVING_WEAPON **** **** **** **** **** **** **** **** +12499 Favoured_Soul_Vigor **** **** **** **** **** **** **** **** +12500 Favoured_Soul_WaterBreathing **** **** **** **** **** **** **** **** +12501 Favoured_Soul_WRACK **** **** **** **** **** **** **** **** +12502 Favoured_Soul_ABYSSAL_MIGHT **** **** **** **** **** **** **** **** +12503 Favoured_Soul_BloodOfTheMartyr **** **** **** **** **** **** **** **** +12504 Favoured_Soul_CLAWS_OF_THE_SAVAGE **** **** **** **** **** **** **** **** +12505 Favoured_Soul_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +12506 Favoured_Soul_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +12507 Favoured_Soul_Death_Ward **** **** **** **** **** **** **** **** +12508 Favoured_Soul_Dimensional_Anchor **** **** **** **** **** **** **** **** +12509 Favoured_Soul_Dismissal **** **** **** **** **** **** **** **** +12510 Favoured_Soul_Divine_Power **** **** **** **** **** **** **** **** +12511 Favoured_Soul_Freedom_of_Movement **** **** **** **** **** **** **** **** +12512 Favoured_Soul_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12513 Favoured_Soul_Greater_Resistance **** **** **** **** **** **** **** **** +12514 Favoured_Soul_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +12515 Favoured_Soul_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +12516 Favoured_Soul_Legions_Shield_of_Faith **** **** **** **** **** **** **** **** +12517 Favoured_Soul_Lesser_Planar_Ally **** **** **** **** **** **** **** **** +12518 Favoured_Soul_Lower_Spell_Resistance **** **** **** **** **** **** **** **** +12519 Favoured_Soul_Mass_Ultravision **** **** **** **** **** **** **** **** +12520 Favoured_Soul_Necrotic_Domination **** **** **** **** **** **** **** **** +12521 Favoured_Soul_Neutralize_Poison **** **** **** **** **** **** **** **** +12522 Favoured_Soul_Panacea **** **** **** **** **** **** **** **** +12523 Favoured_Soul_Poison **** **** **** **** **** **** **** **** +12524 Favoured_Soul_Recitation **** **** **** **** **** **** **** **** +12525 Favoured_Soul_RepelVermin **** **** **** **** **** **** **** **** +12526 Favoured_Soul_Restoration **** **** **** **** **** **** **** **** +12527 Favoured_Soul_STOP_HEART **** **** **** **** **** **** **** **** +12528 Favoured_Soul_Summon_Creature_IV **** **** **** **** **** **** **** **** +12529 Favoured_Soul_SummonUndeadIV **** **** **** **** **** **** **** **** +12530 Favoured_Soul_SwordOfConscience **** **** **** **** **** **** **** **** +12531 Favoured_Soul_Battletide **** **** **** **** **** **** **** **** +12532 Favoured_Soul_BreakEnchantment **** **** **** **** **** **** **** **** +12533 Favoured_Soul_CHAAVS_LAUGH **** **** **** **** **** **** **** **** +12534 Favoured_Soul_Circle_of_Doom **** **** **** **** **** **** **** **** +12535 Favoured_Soul_CONVERT_WAND **** **** **** **** **** **** **** **** +12536 Favoured_Soul_DANCING_WEB **** **** **** **** **** **** **** **** +12537 Favoured_Soul_FireInTheBlood **** **** **** **** **** **** **** **** +12538 Favoured_Soul_Flame_Strike **** **** **** **** **** **** **** **** +12539 Favoured_Soul_Greater_Vigor(Monstrous_Regeneration) **** **** **** **** **** **** **** **** +12540 Favoured_Soul_GreaterCommand_RadialMaster **** **** **** **** **** **** **** **** +12541 Favoured_Soul_GreaterCommand_Approach **** **** **** **** **** **** **** **** +12542 Favoured_Soul_GreaterCommand_Drop **** **** **** **** **** **** **** **** +12543 Favoured_Soul_GreaterCommand_Fall **** **** **** **** **** **** **** **** +12544 Favoured_Soul_GreaterCommand_Flee **** **** **** **** **** **** **** **** +12545 Favoured_Soul_GreaterCommand_Halt **** **** **** **** **** **** **** **** +12546 Favoured_Soul_Healing_Circle **** **** **** **** **** **** **** **** +12547 Favoured_Soul_HEARTCLUTCH **** **** **** **** **** **** **** **** +12548 Favoured_Soul_Legions_Curse_of_Petty_Failing **** **** **** **** **** **** **** **** +12549 Favoured_Soul_Mass_Contagion **** **** **** **** **** **** **** **** +12550 Favoured_Soul_Mass_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12551 Favoured_Soul_Mass_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +12552 Favoured_Soul_MORALITY_UNDONE **** **** **** **** **** **** **** **** +12553 Favoured_Soul_Necrotic_Burst **** **** **** **** **** **** **** **** +12554 Favoured_Soul_Raise_Dead **** **** **** **** **** **** **** **** +12555 Favoured_Soul_RESONATING_RESISTANCE **** **** **** **** **** **** **** **** +12556 Favoured_Soul_Revivify **** **** **** **** **** **** **** **** +12557 Favoured_Soul_Righteous_Might **** **** **** **** **** **** **** **** +12558 Favoured_Soul_Scrying **** **** **** **** **** **** **** **** +12559 Favoured_Soul_Slay_Living **** **** **** **** **** **** **** **** +12560 Favoured_Soul_Soulscour **** **** **** **** **** **** **** **** +12561 Favoured_Soul_Spell_Resistance **** **** **** **** **** **** **** **** +12562 Favoured_Soul_Summon_Creature_V **** **** **** **** **** **** **** **** +12563 Favoured_Soul_SummonUndeadV **** **** **** **** **** **** **** **** +12564 Favoured_Soul_SYMBOL_OF_PAIN **** **** **** **** **** **** **** **** +12565 Favoured_Soul_SYMBOL_OF_SLEEP **** **** **** **** **** **** **** **** +12566 Favoured_Soul_True_Seeing **** **** **** **** **** **** **** **** +12567 Favoured_Soul_Animate_Object **** **** **** **** **** **** **** **** +12568 Favoured_Soul_Banishment **** **** **** **** **** **** **** **** +12569 Favoured_Soul_Blade_Barrier **** **** **** **** **** **** **** **** +12570 Favoured_Soul_CALL_FAITHFUL_SERVANTS **** **** **** **** **** **** **** **** +12571 Favoured_Soul_CELESTIAL_BLOOD **** **** **** **** **** **** **** **** +12572 Favoured_Soul_CLOUD_OF_THE_ACHAIERAI **** **** **** **** **** **** **** **** +12573 Favoured_Soul_Control_Undead **** **** **** **** **** **** **** **** +12574 Favoured_Soul_Create_Undead **** **** **** **** **** **** **** **** +12575 Favoured_Soul_Energy_Immunity **** **** **** **** **** **** **** **** +12576 Favoured_Soul_EI_Acid **** **** **** **** **** **** **** **** +12577 Favoured_Soul_EI_Cold **** **** **** **** **** **** **** **** +12578 Favoured_Soul_EI_Elec **** **** **** **** **** **** **** **** +12579 Favoured_Soul_EI_Fire **** **** **** **** **** **** **** **** +12580 Favoured_Soul_EI_Sonic **** **** **** **** **** **** **** **** +12581 Favoured_Soul_Etherealness **** **** **** **** **** **** **** **** +12582 Favoured_Soul_Greater_Dispelling **** **** **** **** **** **** **** **** +12583 Favoured_Soul_Greater_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +12584 Favoured_Soul_Greater_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +12585 Favoured_Soul_Greater_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +12586 Favoured_Soul_Greater_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +12587 Favoured_Soul_Greater_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +12588 Favoured_Soul_Greater_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +12589 Favoured_Soul_Harm **** **** **** **** **** **** **** **** +12590 Favoured_Soul_Heal **** **** **** **** **** **** **** **** +12591 Favoured_Soul_Mass_Bulls_Strength **** **** **** **** **** **** **** **** +12592 Favoured_Soul_Mass_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +12593 Favoured_Soul_Mass_Eagle_Splendor **** **** **** **** **** **** **** **** +12594 Favoured_Soul_Mass_Endurance **** **** **** **** **** **** **** **** +12595 Favoured_Soul_Mass_Foxs_Cunning **** **** **** **** **** **** **** **** +12596 Favoured_Soul_Mass_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +12597 Favoured_Soul_Mass_Owls_Wisdom **** **** **** **** **** **** **** **** +12598 Favoured_Soul_Necrotic_Eruption **** **** **** **** **** **** **** **** +12599 Favoured_Soul_Planar_Ally **** **** **** **** **** **** **** **** +12600 Favoured_Soul_SarcophagusOfStone **** **** **** **** **** **** **** **** +12601 Favoured_Soul_Summon_Creature_VI **** **** **** **** **** **** **** **** +12602 Favoured_Soul_Superior_Resistance **** **** **** **** **** **** **** **** +12603 Favoured_Soul_SYMBOL_OF_FEAR **** **** **** **** **** **** **** **** +12604 Favoured_Soul_SYMBOL_OF_PERSUASION **** **** **** **** **** **** **** **** +12605 Favoured_Soul_THOUSAND_NEEDLES **** **** **** **** **** **** **** **** +12606 Favoured_Soul_Undeath_to_Death **** **** **** **** **** **** **** **** +12607 Favoured_Soul_Vigorous_Circle **** **** **** **** **** **** **** **** +12608 Favoured_Soul_WordOfRecall_RadialMaster **** **** **** **** **** **** **** **** +12609 Favoured_Soul_WordOfRecall_SelfOnly **** **** **** **** **** **** **** **** +12610 Favoured_Soul_WordOfRecall_Party **** **** **** **** **** **** **** **** +12611 Favoured_Soul_Blasphemy **** **** **** **** **** **** **** **** +12612 Favoured_Soul_Control_Weather **** **** **** **** **** **** **** **** +12613 Favoured_Soul_CW_Rain **** **** **** **** **** **** **** **** +12614 Favoured_Soul_CW_Snow **** **** **** **** **** **** **** **** +12615 Favoured_Soul_CW_Clear **** **** **** **** **** **** **** **** +12616 Favoured_Soul_Destruction **** **** **** **** **** **** **** **** +12617 Favoured_Soul_Dictum **** **** **** **** **** **** **** **** +12618 Favoured_Soul_Energy_Ebb **** **** **** **** **** **** **** **** +12619 Favoured_Soul_FIENDISH_CLARITY **** **** **** **** **** **** **** **** +12620 Favoured_Soul_Greater_Harm **** **** **** **** **** **** **** **** +12621 Favoured_Soul_Greater_Restoration **** **** **** **** **** **** **** **** +12622 Favoured_Soul_GreaterScrying **** **** **** **** **** **** **** **** +12623 Favoured_Soul_Holy_Word **** **** **** **** **** **** **** **** +12624 Favoured_Soul_Mass_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +12625 Favoured_Soul_Mass_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +12626 Favoured_Soul_Mass_Spell_Resistance **** **** **** **** **** **** **** **** +12627 Favoured_Soul_Regenerate **** **** **** **** **** **** **** **** +12628 Favoured_Soul_Repulsion **** **** **** **** **** **** **** **** +12629 Favoured_Soul_Resurrection **** **** **** **** **** **** **** **** +12630 Favoured_Soul_RIGHTEOUS_SMITE **** **** **** **** **** **** **** **** +12631 Favoured_Soul_Summon_Creature_VII **** **** **** **** **** **** **** **** +12632 Favoured_Soul_Summon7Air **** **** **** **** **** **** **** **** +12633 Favoured_Soul_Summon7Earth **** **** **** **** **** **** **** **** +12634 Favoured_Soul_Summon7Fire **** **** **** **** **** **** **** **** +12635 Favoured_Soul_Summon7Water **** **** **** **** **** **** **** **** +12636 Favoured_Soul_SYMBOL_OF_STUNING **** **** **** **** **** **** **** **** +12637 Favoured_Soul_SYMBOL_OF_WEAKNESS **** **** **** **** **** **** **** **** +12638 Favoured_Soul_TOMB_OF_LIGHT **** **** **** **** **** **** **** **** +12639 Favoured_Soul_Word_of_Chaos **** **** **** **** **** **** **** **** +12640 Favoured_Soul_WRETCHED_BLIGHT **** **** **** **** **** **** **** **** +12641 Favoured_Soul_ANTIMAGIC_FIELD **** **** **** **** **** **** **** **** +12642 Favoured_Soul_Aura_versus_Alignment **** **** **** **** **** **** **** **** +12643 Favoured_Soul_Unholy_Aura **** **** **** **** **** **** **** **** +12644 Favoured_Soul_Holy_Aura **** **** **** **** **** **** **** **** +12645 Favoured_Soul_BODAK_BIRTH **** **** **** **** **** **** **** **** +12646 Favoured_Soul_Create_Greater_Undead **** **** **** **** **** **** **** **** +12647 Favoured_Soul_Dimensional_Lock **** **** **** **** **** **** **** **** +12648 Favoured_Soul_DiscernLocation **** **** **** **** **** **** **** **** +12649 Favoured_Soul_Earthquake **** **** **** **** **** **** **** **** +12650 Favoured_Soul_Fire_Storm **** **** **** **** **** **** **** **** +12651 Favoured_Soul_Greater_Planar_Ally **** **** **** **** **** **** **** **** +12652 Favoured_Soul_Greater_Wall_of_Dispel_Magic **** **** **** **** **** **** **** **** +12653 Favoured_Soul_Holy_Aura **** **** **** **** **** **** **** **** +12654 Favoured_Soul_LAST_JUDGEMENT **** **** **** **** **** **** **** **** +12655 Favoured_Soul_Mass_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +12656 Favoured_Soul_Mass_Heal **** **** **** **** **** **** **** **** +12657 Favoured_Soul_Mass_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +12658 Favoured_Soul_Necrotic_Empowerment **** **** **** **** **** **** **** **** +12659 Favoured_Soul_Pestilence **** **** **** **** **** **** **** **** +12660 Favoured_Soul_Summon_Creature_VIII **** **** **** **** **** **** **** **** +12661 Favoured_Soul_Summon8Air **** **** **** **** **** **** **** **** +12662 Favoured_Soul_Summon8Earth **** **** **** **** **** **** **** **** +12663 Favoured_Soul_Summon8Fire **** **** **** **** **** **** **** **** +12664 Favoured_Soul_Summon8Water **** **** **** **** **** **** **** **** +12665 Favoured_Soul_Sunbeam **** **** **** **** **** **** **** **** +12666 Favoured_Soul_SYMBOL_OF_DEATH **** **** **** **** **** **** **** **** +12667 Favoured_Soul_SYMBOL_OF_INSANITY **** **** **** **** **** **** **** **** +12668 Favoured_Soul_DESPOIL **** **** **** **** **** **** **** **** +12669 Favoured_Soul_Elder_Glyph_of_Warding_Master **** **** **** **** **** **** **** **** +12670 Favoured_Soul_Elder_Glyph_of_Warding_Acid **** **** **** **** **** **** **** **** +12671 Favoured_Soul_Elder_Glyph_of_Warding_Cold **** **** **** **** **** **** **** **** +12672 Favoured_Soul_Elder_Glyph_of_Warding_Electricity **** **** **** **** **** **** **** **** +12673 Favoured_Soul_Elder_Glyph_of_Warding_Fire **** **** **** **** **** **** **** **** +12674 Favoured_Soul_Elder_Glyph_of_Warding_Sonic **** **** **** **** **** **** **** **** +12675 Favoured_Soul_Energy_Drain **** **** **** **** **** **** **** **** +12676 Favoured_Soul_Gate **** **** **** **** **** **** **** **** +12677 Favoured_Soul_Implosion **** **** **** **** **** **** **** **** +12678 Favoured_Soul_Mass_Harm **** **** **** **** **** **** **** **** +12679 Favoured_Soul_Necrotic_Termination **** **** **** **** **** **** **** **** +12680 Favoured_Soul_PlagueOfUndead **** **** **** **** **** **** **** **** +12681 Favoured_Soul_Storm_of_Vengeance **** **** **** **** **** **** **** **** +12682 Favoured_Soul_Summon_Creature_IX **** **** **** **** **** **** **** **** +12683 Favoured_Soul_Summon9Air **** **** **** **** **** **** **** **** +12684 Favoured_Soul_Summon9Earth **** **** **** **** **** **** **** **** +12685 Favoured_Soul_Summon9Fire **** **** **** **** **** **** **** **** +12686 Favoured_Soul_Summon9Water **** **** **** **** **** **** **** **** +12687 Favoured_Soul_True_Resurrection **** **** **** **** **** **** **** **** +12688 Favoured_Soul_Undeaths_Eternal_Foe **** **** **** **** **** **** **** **** +12689 Favoured_Soul_VileDeath **** **** **** **** **** **** **** **** +12690 Sohei_Bane **** **** **** **** **** **** **** **** +12691 Sohei_Exteneded_Bane **** **** **** **** **** **** **** **** +12692 Sohei_Silent_Bane **** **** **** **** **** **** **** **** +12693 Sohei_Still_Bane **** **** **** **** **** **** **** **** +12694 Sohei_Bless **** **** **** **** **** **** **** **** +12695 Sohei_Exteneded_Bless **** **** **** **** **** **** **** **** +12696 Sohei_Silent_Bless **** **** **** **** **** **** **** **** +12697 Sohei_Still_Bless **** **** **** **** **** **** **** **** +12698 Sohei_Bless_Weapon **** **** **** **** **** **** **** **** +12699 Sohei_Exteneded_Bless_Weapon **** **** **** **** **** **** **** **** +12700 Sohei_Silent_Bless_Weapon **** **** **** **** **** **** **** **** +12701 Sohei_Still_Bless_Weapon **** **** **** **** **** **** **** **** +12702 Sohei_Detect_Chaos **** **** **** **** **** **** **** **** +12703 Sohei_Exteneded_Detect_Chaos **** **** **** **** **** **** **** **** +12704 Sohei_Silent_Detect_Chaos **** **** **** **** **** **** **** **** +12705 Sohei_Still_Detect_Chaos **** **** **** **** **** **** **** **** +12706 Sohei_Detect_Law **** **** **** **** **** **** **** **** +12707 Sohei_Exteneded_Detect_Law **** **** **** **** **** **** **** **** +12708 Sohei_Silent_Detect_Law **** **** **** **** **** **** **** **** +12709 Sohei_Still_Detect_Law **** **** **** **** **** **** **** **** +12710 Sohei_Divine_Favor **** **** **** **** **** **** **** **** +12711 Sohei_Exteneded_Divine_Favor **** **** **** **** **** **** **** **** +12712 Sohei_Silent_Divine_Favor **** **** **** **** **** **** **** **** +12713 Sohei_Still_Divine_Favor **** **** **** **** **** **** **** **** +12714 Sohei_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +12715 Sohei_Exteneded_DIVINE_INSPIRATION **** **** **** **** **** **** **** **** +12716 Sohei_Doom **** **** **** **** **** **** **** **** +12717 Sohei_Exteneded_Doom **** **** **** **** **** **** **** **** +12718 Sohei_Silent_Doom **** **** **** **** **** **** **** **** +12719 Sohei_Still_Doom **** **** **** **** **** **** **** **** +12720 Sohei_Endure_Elements **** **** **** **** **** **** **** **** +12721 Sohei_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +12722 Sohei_Silent_Endure_Elements **** **** **** **** **** **** **** **** +12723 Sohei_Still_Endure_Elements **** **** **** **** **** **** **** **** +12724 Sohei_Magic_Weapon **** **** **** **** **** **** **** **** +12725 Sohei_Exteneded_Magic_Weapon **** **** **** **** **** **** **** **** +12726 Sohei_Silent_Magic_Weapon **** **** **** **** **** **** **** **** +12727 Sohei_Still_Magic_Weapon **** **** **** **** **** **** **** **** +12728 Sohei_Protection_from_Chaos **** **** **** **** **** **** **** **** +12729 Sohei_Exteneded_Protection_from_Chaos **** **** **** **** **** **** **** **** +12730 Sohei_Silent_Protection_from_Chaos **** **** **** **** **** **** **** **** +12731 Sohei_Still_Protection_from_Chaos **** **** **** **** **** **** **** **** +12732 Sohei_Resistance **** **** **** **** **** **** **** **** +12733 Sohei_Exteneded_Resistance **** **** **** **** **** **** **** **** +12734 Sohei_Silent_Resistance **** **** **** **** **** **** **** **** +12735 Sohei_Still_Resistance **** **** **** **** **** **** **** **** +12736 Sohei_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +12737 Sohei_Silent_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +12738 Sohei_Still_SEETHING_EYEBANE **** **** **** **** **** **** **** **** +12739 Sohei_Shield_of_Faith **** **** **** **** **** **** **** **** +12740 Sohei_Exteneded_Shield_of_Faith **** **** **** **** **** **** **** **** +12741 Sohei_Silent_Shield_of_Faith **** **** **** **** **** **** **** **** +12742 Sohei_Still_Shield_of_Faith **** **** **** **** **** **** **** **** +12743 Sohei_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12744 Sohei_Exteneded_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12745 Sohei_Silent_TWILIGHT_LUCK **** **** **** **** **** **** **** **** +12746 Sohei_Virtue **** **** **** **** **** **** **** **** +12747 Sohei_Exteneded_Virtue **** **** **** **** **** **** **** **** +12748 Sohei_Silent_Virtue **** **** **** **** **** **** **** **** +12749 Sohei_Still_Virtue **** **** **** **** **** **** **** **** +12750 Sohei_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12751 Sohei_Empowered_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12752 Sohei_Silent_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12753 Sohei_Still_AYAILLAS_RADIANT_BURST **** **** **** **** **** **** **** **** +12754 Sohei_Bulls_Strength **** **** **** **** **** **** **** **** +12755 Sohei_Empowered_Bulls_Strength **** **** **** **** **** **** **** **** +12756 Sohei_Exteneded_Bulls_Strength **** **** **** **** **** **** **** **** +12757 Sohei_Silent_Bulls_Strength **** **** **** **** **** **** **** **** +12758 Sohei_Still_Bulls_Strength **** **** **** **** **** **** **** **** +12759 Sohei_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +12760 Sohei_Silent_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +12761 Sohei_Still_LAHMS_FINGER_DARTS **** **** **** **** **** **** **** **** +12762 Sohei_Lesser_Restoration **** **** **** **** **** **** **** **** +12763 Sohei_Silent_Lesser_Restoration **** **** **** **** **** **** **** **** +12764 Sohei_Still_Lesser_Restoration **** **** **** **** **** **** **** **** +12765 Sohei_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12766 Sohei_Exteneded_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12767 Sohei_Remove_Paralysis **** **** **** **** **** **** **** **** +12768 Sohei_Silent_Remove_Paralysis **** **** **** **** **** **** **** **** +12769 Sohei_Still_Remove_Paralysis **** **** **** **** **** **** **** **** +12770 Sohei_Resist_Elements **** **** **** **** **** **** **** **** +12771 Sohei_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +12772 Sohei_Silent_Resist_Elements **** **** **** **** **** **** **** **** +12773 Sohei_Still_Resist_Elements **** **** **** **** **** **** **** **** +12774 Sohei_ShieldOther **** **** **** **** **** **** **** **** +12775 Sohei_Exteneded_ShieldOther **** **** **** **** **** **** **** **** +12776 Sohei_Silent_ShieldOther **** **** **** **** **** **** **** **** +12777 Sohei_Still_ShieldOther **** **** **** **** **** **** **** **** +12778 Sohei_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +12779 Sohei_Exteneded_BRILLIANT_EMANATION **** **** **** **** **** **** **** **** +12780 Sohei_Dispel_Magic **** **** **** **** **** **** **** **** +12781 Sohei_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +12782 Sohei_Still_Dispel_Magic **** **** **** **** **** **** **** **** +12783 Sohei_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12784 Sohei_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12785 Sohei_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12786 Sohei_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +12787 Sohei_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12788 Sohei_Silent_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12789 Sohei_Still_HAMMER_OF_RIGHTEOUSNESS **** **** **** **** **** **** **** **** +12790 Sohei_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12791 Sohei_Exteneded_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12792 Sohei_Silent_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12793 Sohei_Still_Magic_Circle_against_Chaos **** **** **** **** **** **** **** **** +12794 Sohei_Prayer **** **** **** **** **** **** **** **** +12795 Sohei_Exteneded_Prayer **** **** **** **** **** **** **** **** +12796 Sohei_Silent_Prayer **** **** **** **** **** **** **** **** +12797 Sohei_Still_Prayer **** **** **** **** **** **** **** **** +12798 Sohei_Protection_from_Elements **** **** **** **** **** **** **** **** +12799 Sohei_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +12800 Sohei_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +12801 Sohei_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +12802 Sohei_RED_FESTER **** **** **** **** **** **** **** **** +12803 Sohei_Silent_RED_FESTER **** **** **** **** **** **** **** **** +12804 Sohei_Still_RED_FESTER **** **** **** **** **** **** **** **** +12805 Sohei_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +12806 Sohei_Silent_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +12807 Sohei_Still_ROTTING_CURSE_OF_URFESTRA **** **** **** **** **** **** **** **** +12808 Sohei_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +12809 Sohei_Silent_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +12810 Sohei_Still_TOUCH_OF_JUIBLEX **** **** **** **** **** **** **** **** +12811 Sohei_ABSORB_STRENGTH **** **** **** **** **** **** **** **** +12812 Sohei_Death_Ward **** **** **** **** **** **** **** **** +12813 Sohei_DIAMOND_SPRAY **** **** **** **** **** **** **** **** +12814 Sohei_Divine_Power **** **** **** **** **** **** **** **** +12815 Sohei_Freedom_of_Movement **** **** **** **** **** **** **** **** +12816 Sohei_GREATER_LUMINOUS_ARMOR **** **** **** **** **** **** **** **** +12817 Sohei_Hammer_of_the_Gods **** **** **** **** **** **** **** **** +12818 Sohei_Neutralize_Poison **** **** **** **** **** **** **** **** +12819 Sohei_Restoration **** **** **** **** **** **** **** **** +12820 Sohei_SUNMANTLE **** **** **** **** **** **** **** **** +12821 Warmage_Acid_Splash **** **** **** **** **** **** **** **** +12822 Warmage_Dancing_Lights **** **** **** **** **** **** **** **** +12823 Warmage_DisruptUndead **** **** **** **** **** **** **** **** +12824 Warmage_Electric_Jolt **** **** **** **** **** **** **** **** +12825 Warmage_Flare **** **** **** **** **** **** **** **** +12826 Warmage_Light **** **** **** **** **** **** **** **** +12827 Warmage_Ray_of_Frost **** **** **** **** **** **** **** **** +12828 Warmage_Bigbys_Tripping_Hand **** **** **** **** **** **** **** **** +12829 Warmage_Burning_Bolt **** **** **** **** **** **** **** **** +12830 Warmage_Burning_Hands **** **** **** **** **** **** **** **** +12831 Warmage_Chill_Touch **** **** **** **** **** **** **** **** +12832 Warmage_FistOfStone **** **** **** **** **** **** **** **** +12833 Warmage_Hail_of_Stone **** **** **** **** **** **** **** **** +12834 Warmage_Horizikauls_Boom **** **** **** **** **** **** **** **** +12835 Warmage_Ice_Dagger **** **** **** **** **** **** **** **** +12836 Warmage_Kelgores_Fire_Bolt **** **** **** **** **** **** **** **** +12837 Warmage_LANTERN_LIGHT **** **** **** **** **** **** **** **** +12838 Warmage_Lesser_Acid_Orb **** **** **** **** **** **** **** **** +12839 Warmage_Lesser_Cold_Orb **** **** **** **** **** **** **** **** +12840 Warmage_Lesser_Electric_Orb **** **** **** **** **** **** **** **** +12841 Warmage_Lesser_Fire_Orb **** **** **** **** **** **** **** **** +12842 Warmage_LESSER_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +12843 Warmage_Lesser_Sonic_Orb **** **** **** **** **** **** **** **** +12844 Warmage_Magic_Missile **** **** **** **** **** **** **** **** +12845 Warmage_Shelgarns_Persistent_Blade **** **** **** **** **** **** **** **** +12846 Warmage_ShockingGrasp **** **** **** **** **** **** **** **** +12847 Warmage_Snillocs_Snowball **** **** **** **** **** **** **** **** +12848 Warmage_TensersFloatingDisk **** **** **** **** **** **** **** **** +12849 Warmage_True_Strike **** **** **** **** **** **** **** **** +12850 Warmage_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +12851 Warmage_Bigbys_Striking_Fist **** **** **** **** **** **** **** **** +12852 Warmage_BladesOfFire **** **** **** **** **** **** **** **** +12853 Warmage_Cloud_of_Bewilderment **** **** **** **** **** **** **** **** +12854 Warmage_Combust **** **** **** **** **** **** **** **** +12855 Warmage_Continual_Flame **** **** **** **** **** **** **** **** +12856 Warmage_Darkness **** **** **** **** **** **** **** **** +12857 Warmage_Fireburst **** **** **** **** **** **** **** **** +12858 Warmage_FireTrap **** **** **** **** **** **** **** **** +12859 Warmage_Flame_Weapon **** **** **** **** **** **** **** **** +12860 Warmage_Gedlees_Electric_Loop **** **** **** **** **** **** **** **** +12861 Warmage_IceKnife **** **** **** **** **** **** **** **** +12862 Warmage_Melfs_Acid_Arrow **** **** **** **** **** **** **** **** +12863 Warmage_Pyrotechnics **** **** **** **** **** **** **** **** +12864 Warmage_Pyrotechnics_Fireworks **** **** **** **** **** **** **** **** +12865 Warmage_Pyrotechnics_Smoke **** **** **** **** **** **** **** **** +12866 Warmage_ScorchingRay **** **** **** **** **** **** **** **** +12867 Warmage_Seeking_Ray **** **** **** **** **** **** **** **** +12868 Warmage_Snillocs_Snowball_Swarm **** **** **** **** **** **** **** **** +12869 Warmage_WhirlingBlade **** **** **** **** **** **** **** **** +12870 Warmage_Daylight **** **** **** **** **** **** **** **** +12871 Warmage_DREAD_WORD **** **** **** **** **** **** **** **** +12872 Warmage_Elemental_Shield **** **** **** **** **** **** **** **** +12873 Warmage_Fireball **** **** **** **** **** **** **** **** +12874 Warmage_Flame_Arrow **** **** **** **** **** **** **** **** +12875 Warmage_Flashburst **** **** **** **** **** **** **** **** +12876 Warmage_Forceblast **** **** **** **** **** **** **** **** +12877 Warmage_Gust_of_Wind **** **** **** **** **** **** **** **** +12878 Warmage_Ice_Burst **** **** **** **** **** **** **** **** +12879 Warmage_Ice_Storm **** **** **** **** **** **** **** **** +12880 Warmage_Lightning_Bolt **** **** **** **** **** **** **** **** +12881 Warmage_PnP_FireShield **** **** **** **** **** **** **** **** +12882 Warmage_PnP_FireShieldRed **** **** **** **** **** **** **** **** +12883 Warmage_PnPFireShieldBlue **** **** **** **** **** **** **** **** +12884 Warmage_Poison **** **** **** **** **** **** **** **** +12885 Warmage_RainbowBlast **** **** **** **** **** **** **** **** +12886 Warmage_RingOfBlades **** **** **** **** **** **** **** **** +12887 Warmage_Scintillating_Sphere **** **** **** **** **** **** **** **** +12888 Warmage_Serpents_Sigh **** **** **** **** **** **** **** **** +12889 Warmage_SS_Bolt_of_Acid **** **** **** **** **** **** **** **** +12890 Warmage_SS_Bolt_of_Lightning **** **** **** **** **** **** **** **** +12891 Warmage_SS_Cone_of_Acid **** **** **** **** **** **** **** **** +12892 Warmage_SS_Cone_of_Cold **** **** **** **** **** **** **** **** +12893 Warmage_SS_Cone_of_Fire **** **** **** **** **** **** **** **** +12894 Warmage_SHIVERING_TOUCH **** **** **** **** **** **** **** **** +12895 Warmage_SleetStorm **** **** **** **** **** **** **** **** +12896 Warmage_Stinking_Cloud **** **** **** **** **** **** **** **** +12897 Warmage_Acid_Orb **** **** **** **** **** **** **** **** +12898 Warmage_Blast_of_Flame **** **** **** **** **** **** **** **** +12899 Warmage_Channeled_Pyroburst **** **** **** **** **** **** **** **** +12900 Warmage_Channeled_Pyroburst_Swift **** **** **** **** **** **** **** **** +12901 Warmage_Channeled_Pyroburst_Standard **** **** **** **** **** **** **** **** +12902 Warmage_Channeled_Pyroburst_Full **** **** **** **** **** **** **** **** +12903 Warmage_Channeled_Pyroburst_Two **** **** **** **** **** **** **** **** +12904 Warmage_Cold_Orb **** **** **** **** **** **** **** **** +12905 Warmage_Contagion **** **** **** **** **** **** **** **** +12906 Warmage_DAMNING_DARKNESS **** **** **** **** **** **** **** **** +12907 Warmage_DANCING_WEB **** **** **** **** **** **** **** **** +12908 Warmage_Electric_Orb **** **** **** **** **** **** **** **** +12909 Warmage_Evards_Black_Tentacles **** **** **** **** **** **** **** **** +12910 Warmage_Fire_Orb **** **** **** **** **** **** **** **** +12911 Warmage_Isaacs_Lesser_Missile_Storm **** **** **** **** **** **** **** **** +12912 Warmage_OrbOfForce **** **** **** **** **** **** **** **** +12913 Warmage_Otilukes_Resilient_Sphere **** **** **** **** **** **** **** **** +12914 Warmage_Phantasmal_Killer **** **** **** **** **** **** **** **** +12915 Warmage_Shout **** **** **** **** **** **** **** **** +12916 Warmage_Sonic_Orb **** **** **** **** **** **** **** **** +12917 Warmage_Wall_of_Fire **** **** **** **** **** **** **** **** +12918 Warmage_Ball_Lightning **** **** **** **** **** **** **** **** +12919 Warmage_Bigbys_Interposing_Hand **** **** **** **** **** **** **** **** +12920 Warmage_Cloudkill **** **** **** **** **** **** **** **** +12921 Warmage_Cone_of_Cold **** **** **** **** **** **** **** **** +12922 Warmage_Firebrand **** **** **** **** **** **** **** **** +12923 Warmage_Flame_Strike **** **** **** **** **** **** **** **** +12924 Warmage_Greater_Fireburst **** **** **** **** **** **** **** **** +12925 Warmage_Magic_Missile **** **** **** **** **** **** **** **** +12926 Warmage_MassFireShield **** **** **** **** **** **** **** **** +12927 Warmage_MassFireShieldRed **** **** **** **** **** **** **** **** +12928 Warmage_MassFireShieldBlue **** **** **** **** **** **** **** **** +12929 Warmage_PrismaticRay **** **** **** **** **** **** **** **** +12930 Warmage_Sonic_Shield **** **** **** **** **** **** **** **** +12931 Warmage_Acid_Fog **** **** **** **** **** **** **** **** +12932 Warmage_Acid_Storm **** **** **** **** **** **** **** **** +12933 Warmage_Bigbys_Forceful_Hand **** **** **** **** **** **** **** **** +12934 Warmage_Blade_Barrier **** **** **** **** **** **** **** **** +12935 Warmage_Chain_Lightning **** **** **** **** **** **** **** **** +12936 Warmage_Circle_of_Death **** **** **** **** **** **** **** **** +12937 Warmage_Disintegrate **** **** **** **** **** **** **** **** +12938 Warmage_Isaacs_Greater_Missile_Storm **** **** **** **** **** **** **** **** +12939 Warmage_OtilukesFreezingSphere **** **** **** **** **** **** **** **** +12940 Warmage_Tensers_Transformation **** **** **** **** **** **** **** **** +12941 Warmage_AMBER_SARCOPHAGUS **** **** **** **** **** **** **** **** +12942 Warmage_Bigbys_Grasping_Hand **** **** **** **** **** **** **** **** +12943 Warmage_Delayed_Blast_Fireball **** **** **** **** **** **** **** **** +12944 Warmage_Earthquake **** **** **** **** **** **** **** **** +12945 Warmage_Finger_of_Death **** **** **** **** **** **** **** **** +12946 Warmage_Fire_Storm **** **** **** **** **** **** **** **** +12947 Warmage_Great_Thunderclap **** **** **** **** **** **** **** **** +12948 Warmage_Prismatic_Spray **** **** **** **** **** **** **** **** +12949 Warmage_Sunbeam **** **** **** **** **** **** **** **** +12950 Warmage_WavesOfExhaustion **** **** **** **** **** **** **** **** +12951 Warmage_Bigbys_Clenched_Fist **** **** **** **** **** **** **** **** +12952 Warmage_Flensing **** **** **** **** **** **** **** **** +12953 Warmage_Greater_Shout **** **** **** **** **** **** **** **** +12954 Warmage_Horrid_Wilting **** **** **** **** **** **** **** **** +12955 Warmage_Incendiary_Cloud **** **** **** **** **** **** **** **** +12956 Warmage_PolarRay **** **** **** **** **** **** **** **** +12957 Warmage_PrismaticWall **** **** **** **** **** **** **** **** +12958 Warmage_ScintillatingPattern **** **** **** **** **** **** **** **** +12959 Warmage_Sunburst **** **** **** **** **** **** **** **** +12960 Warmage_Bigbys_Crushing_Hand **** **** **** **** **** **** **** **** +12961 Warmage_CRUSHING_FIST_OF_SPITE **** **** **** **** **** **** **** **** +12962 Warmage_Elemental_Swarm **** **** **** **** **** **** **** **** +12963 Warmage_Implosion **** **** **** **** **** **** **** **** +12964 Warmage_Meteor_Swarm **** **** **** **** **** **** **** **** +12965 Warmage_PrismaticSphere **** **** **** **** **** **** **** **** +12966 Warmage_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +12967 Warmage_Weird **** **** **** **** **** **** **** **** +12968 NentyarHunter_Barkskin **** **** **** **** **** **** **** **** +12969 NentyarHunter_Exteneded_Barkskin **** **** **** **** **** **** **** **** +12970 NentyarHunter_Quickened_Barkskin **** **** **** **** **** **** **** **** +12971 NentyarHunter_Silent_Barkskin **** **** **** **** **** **** **** **** +12972 NentyarHunter_Still_Barkskin **** **** **** **** **** **** **** **** +12973 NentyarHunter_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12974 NentyarHunter_Empowered_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12975 NentyarHunter_Maximized_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12976 NentyarHunter_Quickened_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12977 NentyarHunter_Silent_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12978 NentyarHunter_Still_Cure_Light_Wounds **** **** **** **** **** **** **** **** +12979 NentyarHunter_Entangle **** **** **** **** **** **** **** **** +12980 NentyarHunter_Exteneded_Entangle **** **** **** **** **** **** **** **** +12981 NentyarHunter_Quickened_Entangle **** **** **** **** **** **** **** **** +12982 NentyarHunter_Silent_Entangle **** **** **** **** **** **** **** **** +12983 NentyarHunter_Still_Entangle **** **** **** **** **** **** **** **** +12984 NentyarHunter_Spell_Jump **** **** **** **** **** **** **** **** +12985 NentyarHunter_Exteneded_Spell_Jump **** **** **** **** **** **** **** **** +12986 NentyarHunter_Quickened_Spell_Jump **** **** **** **** **** **** **** **** +12987 NentyarHunter_Silent_Spell_Jump **** **** **** **** **** **** **** **** +12988 NentyarHunter_Still_Spell_Jump **** **** **** **** **** **** **** **** +12989 NentyarHunter_Light **** **** **** **** **** **** **** **** +12990 NentyarHunter_Exteneded_Light **** **** **** **** **** **** **** **** +12991 NentyarHunter_Quickened_Light **** **** **** **** **** **** **** **** +12992 NentyarHunter_Silent_Light **** **** **** **** **** **** **** **** +12993 NentyarHunter_Magic_Missile **** **** **** **** **** **** **** **** +12994 NentyarHunter_Empowered_Magic_Missile **** **** **** **** **** **** **** **** +12995 NentyarHunter_Maximized_Magic_Missile **** **** **** **** **** **** **** **** +12996 NentyarHunter_Quickened_Magic_Missile **** **** **** **** **** **** **** **** +12997 NentyarHunter_Silent_Magic_Missile **** **** **** **** **** **** **** **** +12998 NentyarHunter_Still_Magic_Missile **** **** **** **** **** **** **** **** +12999 NentyarHunter_Snare **** **** **** **** **** **** **** **** +13000 NentyarHunter_Quickened_Snare **** **** **** **** **** **** **** **** +13001 NentyarHunter_Silent_Snare **** **** **** **** **** **** **** **** +13002 NentyarHunter_Still_Snare **** **** **** **** **** **** **** **** +13003 NentyarHunter_True_Strike **** **** **** **** **** **** **** **** +13004 NentyarHunter_Quickened_True_Strike **** **** **** **** **** **** **** **** +13005 NentyarHunter_Silent_True_Strike **** **** **** **** **** **** **** **** +13006 NentyarHunter_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +13007 NentyarHunter_Empowered_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +13008 NentyarHunter_Maximized_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +13009 NentyarHunter_Silent_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +13010 NentyarHunter_Still_Agnazzars_Scorcher **** **** **** **** **** **** **** **** +13011 NentyarHunter_Blur **** **** **** **** **** **** **** **** +13012 NentyarHunter_Exteneded_Blur **** **** **** **** **** **** **** **** +13013 NentyarHunter_Silent_Blur **** **** **** **** **** **** **** **** +13014 NentyarHunter_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +13015 NentyarHunter_Empowered_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +13016 NentyarHunter_Maximized_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +13017 NentyarHunter_Silent_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +13018 NentyarHunter_Still_Cure_Moderate_Wounds **** **** **** **** **** **** **** **** +13019 NentyarHunter_Gust_of_Wind **** **** **** **** **** **** **** **** +13020 NentyarHunter_Silent_Gust_of_Wind **** **** **** **** **** **** **** **** +13021 NentyarHunter_Still_Gust_of_Wind **** **** **** **** **** **** **** **** +13022 NentyarHunter_Neutralize_Poison **** **** **** **** **** **** **** **** +13023 NentyarHunter_Silent_Neutralize_Poison **** **** **** **** **** **** **** **** +13024 NentyarHunter_Still_Neutralize_Poison **** **** **** **** **** **** **** **** +13025 NentyarHunter_Remove_Disease **** **** **** **** **** **** **** **** +13026 NentyarHunter_Silent_Remove_Disease **** **** **** **** **** **** **** **** +13027 NentyarHunter_Still_Remove_Disease **** **** **** **** **** **** **** **** +13028 NentyarHunter_Resist_Elements **** **** **** **** **** **** **** **** +13029 NentyarHunter_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +13030 NentyarHunter_Silent_Resist_Elements **** **** **** **** **** **** **** **** +13031 NentyarHunter_Still_Resist_Elements **** **** **** **** **** **** **** **** +13032 NentyarHunter_Treeshape **** **** **** **** **** **** **** **** +13033 NentyarHunter_Exteneded_Treeshape **** **** **** **** **** **** **** **** +13034 NentyarHunter_Silent_Treeshape **** **** **** **** **** **** **** **** +13035 NentyarHunter_Still_Treeshape **** **** **** **** **** **** **** **** +13036 NentyarHunter_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +13037 NentyarHunter_Empowered_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +13038 NentyarHunter_Silent_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +13039 NentyarHunter_Still_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +13040 NentyarHunter_Freedom_of_Movement **** **** **** **** **** **** **** **** +13041 NentyarHunter_Exteneded_Freedom_of_Movement **** **** **** **** **** **** **** **** +13042 NentyarHunter_Silent_Freedom_of_Movement **** **** **** **** **** **** **** **** +13043 NentyarHunter_Still_Freedom_of_Movement **** **** **** **** **** **** **** **** +13044 NentyarHunter_Greenfire **** **** **** **** **** **** **** **** +13045 NentyarHunter_Empowered_Greenfire **** **** **** **** **** **** **** **** +13046 NentyarHunter_Exteneded_Greenfire **** **** **** **** **** **** **** **** +13047 NentyarHunter_Silent_Greenfire **** **** **** **** **** **** **** **** +13048 NentyarHunter_Still_Greenfire **** **** **** **** **** **** **** **** +13049 NentyarHunter_Invisibility **** **** **** **** **** **** **** **** +13050 NentyarHunter_Exteneded_Invisibility **** **** **** **** **** **** **** **** +13051 NentyarHunter_Silent_Invisibility **** **** **** **** **** **** **** **** +13052 NentyarHunter_Still_Invisibility **** **** **** **** **** **** **** **** +13053 NentyarHunter_Keen_Edge **** **** **** **** **** **** **** **** +13054 NentyarHunter_Exteneded_Keen_Edge **** **** **** **** **** **** **** **** +13055 NentyarHunter_Silent_Keen_Edge **** **** **** **** **** **** **** **** +13056 NentyarHunter_Still_Keen_Edge **** **** **** **** **** **** **** **** +13057 NentyarHunter_See_Invisibility **** **** **** **** **** **** **** **** +13058 NentyarHunter_Exteneded_See_Invisibility **** **** **** **** **** **** **** **** +13059 NentyarHunter_Silent_See_Invisibility **** **** **** **** **** **** **** **** +13060 NentyarHunter_Still_See_Invisibility **** **** **** **** **** **** **** **** +13061 NentyarHunter_BreakEnchantment **** **** **** **** **** **** **** **** +13062 NentyarHunter_Silent_BreakEnchantment **** **** **** **** **** **** **** **** +13063 NentyarHunter_Still_BreakEnchantment **** **** **** **** **** **** **** **** +13064 NentyarHunter_OrbOfForce **** **** **** **** **** **** **** **** +13065 NentyarHunter_Silent_OrbOfForce **** **** **** **** **** **** **** **** +13066 NentyarHunter_Still_OrbOfForce **** **** **** **** **** **** **** **** +13067 NentyarHunter_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +13068 NentyarHunter_Exteneded_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +13069 NentyarHunter_Silent_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +13070 NentyarHunter_Still_Greater_Magic_Weapon **** **** **** **** **** **** **** **** +13071 NentyarHunter_Flame_Strike **** **** **** **** **** **** **** **** +13072 NentyarHunter_Healing_Circle **** **** **** **** **** **** **** **** +13073 NentyarHunter_Righteous_Might **** **** **** **** **** **** **** **** +13074 Blighter_Flare **** **** **** **** **** **** **** **** +13075 Blighter_Exteneded_Flare **** **** **** **** **** **** **** **** +13076 Blighter_Quickened_Flare **** **** **** **** **** **** **** **** +13077 Blighter_Silent_Flare **** **** **** **** **** **** **** **** +13078 Blighter_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +13079 Blighter_Quickened_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +13080 Blighter_Silent_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +13081 Blighter_Still_Inflict_Minor_Wounds **** **** **** **** **** **** **** **** +13082 Blighter_Read_Magic **** **** **** **** **** **** **** **** +13083 Blighter_Quickened_Read_Magic **** **** **** **** **** **** **** **** +13084 Blighter_Silent_Read_Magic **** **** **** **** **** **** **** **** +13085 Blighter_Still_Read_Magic **** **** **** **** **** **** **** **** +13086 Blighter_Bane **** **** **** **** **** **** **** **** +13087 Blighter_Exteneded_Bane **** **** **** **** **** **** **** **** +13088 Blighter_Quickened_Bane **** **** **** **** **** **** **** **** +13089 Blighter_Silent_Bane **** **** **** **** **** **** **** **** +13090 Blighter_Still_Bane **** **** **** **** **** **** **** **** +13091 Blighter_Burning_Hands **** **** **** **** **** **** **** **** +13092 Blighter_Empowered_Burning_Hands **** **** **** **** **** **** **** **** +13093 Blighter_Maximized_Burning_Hands **** **** **** **** **** **** **** **** +13094 Blighter_Quickened_Burning_Hands **** **** **** **** **** **** **** **** +13095 Blighter_Silent_Burning_Hands **** **** **** **** **** **** **** **** +13096 Blighter_Still_Burning_Hands **** **** **** **** **** **** **** **** +13097 Blighter_DETECT_UNDEAD **** **** **** **** **** **** **** **** +13098 Blighter_Exteneded_DETECT_UNDEAD **** **** **** **** **** **** **** **** +13099 Blighter_Quickened_DETECT_UNDEAD **** **** **** **** **** **** **** **** +13100 Blighter_Silent_DETECT_UNDEAD **** **** **** **** **** **** **** **** +13101 Blighter_Still_DETECT_UNDEAD **** **** **** **** **** **** **** **** +13102 Blighter_Doom **** **** **** **** **** **** **** **** +13103 Blighter_Exteneded_Doom **** **** **** **** **** **** **** **** +13104 Blighter_Quickened_Doom **** **** **** **** **** **** **** **** +13105 Blighter_Silent_Doom **** **** **** **** **** **** **** **** +13106 Blighter_Still_Doom **** **** **** **** **** **** **** **** +13107 Blighter_Endure_Elements **** **** **** **** **** **** **** **** +13108 Blighter_Exteneded_Endure_Elements **** **** **** **** **** **** **** **** +13109 Blighter_Quickened_Endure_Elements **** **** **** **** **** **** **** **** +13110 Blighter_Silent_Endure_Elements **** **** **** **** **** **** **** **** +13111 Blighter_Still_Endure_Elements **** **** **** **** **** **** **** **** +13112 Blighter_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13113 Blighter_Empowered_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13114 Blighter_Exteneded_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13115 Blighter_Maximized_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13116 Blighter_Quickened_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13117 Blighter_Silent_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13118 Blighter_Still_Ray_of_Enfeeblement **** **** **** **** **** **** **** **** +13119 Blighter_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13120 Blighter_Empowered_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13121 Blighter_Maximized_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13122 Blighter_Quickened_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13123 Blighter_Silent_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13124 Blighter_Still_Inflict_Light_Wounds **** **** **** **** **** **** **** **** +13125 Blighter_Chill_Touch **** **** **** **** **** **** **** **** +13126 Blighter_Empowered_Chill_Touch **** **** **** **** **** **** **** **** +13127 Blighter_Exteneded_Chill_Touch **** **** **** **** **** **** **** **** +13128 Blighter_Maximized_Chill_Touch **** **** **** **** **** **** **** **** +13129 Blighter_Quickened_Chill_Touch **** **** **** **** **** **** **** **** +13130 Blighter_Silent_Chill_Touch **** **** **** **** **** **** **** **** +13131 Blighter_Still_Chill_Touch **** **** **** **** **** **** **** **** +13132 Blighter_Darkness **** **** **** **** **** **** **** **** +13133 Blighter_Exteneded_Darkness **** **** **** **** **** **** **** **** +13134 Blighter_Quickened_Darkness **** **** **** **** **** **** **** **** +13135 Blighter_Silent_Darkness **** **** **** **** **** **** **** **** +13136 Blighter_Death_Knell **** **** **** **** **** **** **** **** +13137 Blighter_Empowered_Death_Knell **** **** **** **** **** **** **** **** +13138 Blighter_Exteneded_Death_Knell **** **** **** **** **** **** **** **** +13139 Blighter_Maximized_Death_Knell **** **** **** **** **** **** **** **** +13140 Blighter_Quickened_Death_Knell **** **** **** **** **** **** **** **** +13141 Blighter_Silent_Death_Knell **** **** **** **** **** **** **** **** +13142 Blighter_Still_Death_Knell **** **** **** **** **** **** **** **** +13143 Blighter_FireTrap **** **** **** **** **** **** **** **** +13144 Blighter_Empowered_FireTrap **** **** **** **** **** **** **** **** +13145 Blighter_Maximized_FireTrap **** **** **** **** **** **** **** **** +13146 Blighter_Quickened_FireTrap **** **** **** **** **** **** **** **** +13147 Blighter_Silent_FireTrap **** **** **** **** **** **** **** **** +13148 Blighter_Still_FireTrap **** **** **** **** **** **** **** **** +13149 Blighter_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13150 Blighter_Empowered_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13151 Blighter_Maximized_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13152 Blighter_Quickened_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13153 Blighter_Silent_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13154 Blighter_Still_Inflict_Moderate_Wounds **** **** **** **** **** **** **** **** +13155 Blighter_Resist_Elements **** **** **** **** **** **** **** **** +13156 Blighter_Exteneded_Resist_Elements **** **** **** **** **** **** **** **** +13157 Blighter_Quickened_Resist_Elements **** **** **** **** **** **** **** **** +13158 Blighter_Silent_Resist_Elements **** **** **** **** **** **** **** **** +13159 Blighter_Still_Resist_Elements **** **** **** **** **** **** **** **** +13160 Blighter_Contagion **** **** **** **** **** **** **** **** +13161 Blighter_Quickened_Contagion **** **** **** **** **** **** **** **** +13162 Blighter_Silent_Contagion **** **** **** **** **** **** **** **** +13163 Blighter_Still_Contagion **** **** **** **** **** **** **** **** +13164 Blighter_DeeperDarkness **** **** **** **** **** **** **** **** +13165 Blighter_Exteneded_DeeperDarkness **** **** **** **** **** **** **** **** +13166 Blighter_Quickened_DeeperDarkness **** **** **** **** **** **** **** **** +13167 Blighter_Silent_DeeperDarkness **** **** **** **** **** **** **** **** +13168 Blighter_Dispel_Magic **** **** **** **** **** **** **** **** +13169 Blighter_Quickened_Dispel_Magic **** **** **** **** **** **** **** **** +13170 Blighter_Silent_Dispel_Magic **** **** **** **** **** **** **** **** +13171 Blighter_Still_Dispel_Magic **** **** **** **** **** **** **** **** +13172 Blighter_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13173 Blighter_Empowered_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13174 Blighter_Maximized_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13175 Blighter_Quickened_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13176 Blighter_Silent_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13177 Blighter_Still_Inflict_Serious_Wounds **** **** **** **** **** **** **** **** +13178 Blighter_Poison **** **** **** **** **** **** **** **** +13179 Blighter_Empowered_Poison **** **** **** **** **** **** **** **** +13180 Blighter_Maximized_Poison **** **** **** **** **** **** **** **** +13181 Blighter_Quickened_Poison **** **** **** **** **** **** **** **** +13182 Blighter_Silent_Poison **** **** **** **** **** **** **** **** +13183 Blighter_Still_Poison **** **** **** **** **** **** **** **** +13184 Blighter_Protection_from_Elements **** **** **** **** **** **** **** **** +13185 Blighter_Exteneded_Protection_from_Elements **** **** **** **** **** **** **** **** +13186 Blighter_Quickened_Protection_from_Elements **** **** **** **** **** **** **** **** +13187 Blighter_Silent_Protection_from_Elements **** **** **** **** **** **** **** **** +13188 Blighter_Still_Protection_from_Elements **** **** **** **** **** **** **** **** +13189 Blighter_Stinking_Cloud **** **** **** **** **** **** **** **** +13190 Blighter_Exteneded_Stinking_Cloud **** **** **** **** **** **** **** **** +13191 Blighter_Quickened_Stinking_Cloud **** **** **** **** **** **** **** **** +13192 Blighter_Silent_Stinking_Cloud **** **** **** **** **** **** **** **** +13193 Blighter_Still_Stinking_Cloud **** **** **** **** **** **** **** **** +13194 Blighter_Vampiric_Touch **** **** **** **** **** **** **** **** +13195 Blighter_Empowered_Vampiric_Touch **** **** **** **** **** **** **** **** +13196 Blighter_Maximized_Vampiric_Touch **** **** **** **** **** **** **** **** +13197 Blighter_Quickened_Vampiric_Touch **** **** **** **** **** **** **** **** +13198 Blighter_Silent_Vampiric_Touch **** **** **** **** **** **** **** **** +13199 Blighter_Still_Vampiric_Touch **** **** **** **** **** **** **** **** +13200 Blighter_Animate_Dead **** **** **** **** **** **** **** **** +13201 Blighter_Exteneded_Animate_Dead **** **** **** **** **** **** **** **** +13202 Blighter_Quickened_Animate_Dead **** **** **** **** **** **** **** **** +13203 Blighter_Silent_Animate_Dead **** **** **** **** **** **** **** **** +13204 Blighter_Still_Animate_Dead **** **** **** **** **** **** **** **** +13205 Blighter_ContagiousTouch **** **** **** **** **** **** **** **** +13206 Blighter_Quickened_ContagiousTouch **** **** **** **** **** **** **** **** +13207 Blighter_Silent_ContagiousTouch **** **** **** **** **** **** **** **** +13208 Blighter_Still_ContagiousTouch **** **** **** **** **** **** **** **** +13209 Blighter_Death_Ward **** **** **** **** **** **** **** **** +13210 Blighter_Exteneded_Death_Ward **** **** **** **** **** **** **** **** +13211 Blighter_Quickened_Death_Ward **** **** **** **** **** **** **** **** +13212 Blighter_Silent_Death_Ward **** **** **** **** **** **** **** **** +13213 Blighter_Still_Death_Ward **** **** **** **** **** **** **** **** +13214 Blighter_Flame_Strike **** **** **** **** **** **** **** **** +13215 Blighter_Empowered_Flame_Strike **** **** **** **** **** **** **** **** +13216 Blighter_Maximized_Flame_Strike **** **** **** **** **** **** **** **** +13217 Blighter_Quickened_Flame_Strike **** **** **** **** **** **** **** **** +13218 Blighter_Silent_Flame_Strike **** **** **** **** **** **** **** **** +13219 Blighter_Still_Flame_Strike **** **** **** **** **** **** **** **** +13220 Blighter_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13221 Blighter_Empowered_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13222 Blighter_Maximized_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13223 Blighter_Quickened_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13224 Blighter_Silent_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13225 Blighter_Still_Inflict_Critical_Wounds **** **** **** **** **** **** **** **** +13226 Blighter_RepelVermin **** **** **** **** **** **** **** **** +13227 Blighter_Exteneded_RepelVermin **** **** **** **** **** **** **** **** +13228 Blighter_Quickened_RepelVermin **** **** **** **** **** **** **** **** +13229 Blighter_Silent_RepelVermin **** **** **** **** **** **** **** **** +13230 Blighter_Still_RepelVermin **** **** **** **** **** **** **** **** +13231 Blighter_Wall_of_Fire **** **** **** **** **** **** **** **** +13232 Blighter_Empowered_Wall_of_Fire **** **** **** **** **** **** **** **** +13233 Blighter_Exteneded_Wall_of_Fire **** **** **** **** **** **** **** **** +13234 Blighter_Maximized_Wall_of_Fire **** **** **** **** **** **** **** **** +13235 Blighter_Quickened_Wall_of_Fire **** **** **** **** **** **** **** **** +13236 Blighter_Silent_Wall_of_Fire **** **** **** **** **** **** **** **** +13237 Blighter_Still_Wall_of_Fire **** **** **** **** **** **** **** **** +13238 Blighter_Create_Undead **** **** **** **** **** **** **** **** +13239 Blighter_Exteneded_Create_Undead **** **** **** **** **** **** **** **** +13240 Blighter_Quickened_Create_Undead **** **** **** **** **** **** **** **** +13241 Blighter_Silent_Create_Undead **** **** **** **** **** **** **** **** +13242 Blighter_Still_Create_Undead **** **** **** **** **** **** **** **** +13243 Blighter_WavesofFatigue **** **** **** **** **** **** **** **** +13244 Blighter_Quickened_WavesofFatigue **** **** **** **** **** **** **** **** +13245 Blighter_Silent_WavesofFatigue **** **** **** **** **** **** **** **** +13246 Blighter_Still_WavesofFatigue **** **** **** **** **** **** **** **** +13247 Blighter_Acid_Fog **** **** **** **** **** **** **** **** +13248 Blighter_Empowered_Acid_Fog **** **** **** **** **** **** **** **** +13249 Blighter_Exteneded_Acid_Fog **** **** **** **** **** **** **** **** +13250 Blighter_Maximized_Acid_Fog **** **** **** **** **** **** **** **** +13251 Blighter_Silent_Acid_Fog **** **** **** **** **** **** **** **** +13252 Blighter_Still_Acid_Fog **** **** **** **** **** **** **** **** +13253 Blighter_Circle_of_Death **** **** **** **** **** **** **** **** +13254 Blighter_Empowered_Circle_of_Death **** **** **** **** **** **** **** **** +13255 Blighter_Maximized_Circle_of_Death **** **** **** **** **** **** **** **** +13256 Blighter_Silent_Circle_of_Death **** **** **** **** **** **** **** **** +13257 Blighter_Still_Circle_of_Death **** **** **** **** **** **** **** **** +13258 Blighter_Finger_of_Death **** **** **** **** **** **** **** **** +13259 Blighter_Empowered_Finger_of_Death **** **** **** **** **** **** **** **** +13260 Blighter_Maximized_Finger_of_Death **** **** **** **** **** **** **** **** +13261 Blighter_Silent_Finger_of_Death **** **** **** **** **** **** **** **** +13262 Blighter_Still_Finger_of_Death **** **** **** **** **** **** **** **** +13263 Blighter_Greater_Dispelling **** **** **** **** **** **** **** **** +13264 Blighter_Silent_Greater_Dispelling **** **** **** **** **** **** **** **** +13265 Blighter_Still_Greater_Dispelling **** **** **** **** **** **** **** **** +13266 Blighter_Harm **** **** **** **** **** **** **** **** +13267 Blighter_Silent_Harm **** **** **** **** **** **** **** **** +13268 Blighter_Still_Harm **** **** **** **** **** **** **** **** +13269 Blighter_Control_Undead **** **** **** **** **** **** **** **** +13270 Blighter_Exteneded_Control_Undead **** **** **** **** **** **** **** **** +13271 Blighter_Silent_Control_Undead **** **** **** **** **** **** **** **** +13272 Blighter_Still_Control_Undead **** **** **** **** **** **** **** **** +13273 Blighter_Control_Weather **** **** **** **** **** **** **** **** +13274 Blighter_CW_Rain **** **** **** **** **** **** **** **** +13275 Blighter_CW_Snow **** **** **** **** **** **** **** **** +13276 Blighter_CW_Clear **** **** **** **** **** **** **** **** +13277 Blighter_Exteneded_Control_Weather **** **** **** **** **** **** **** **** +13278 Blighter_Exteneded_CW_Rain **** **** **** **** **** **** **** **** +13279 Blighter_Exteneded_CW_Snow **** **** **** **** **** **** **** **** +13280 Blighter_Exteneded_CW_Clear **** **** **** **** **** **** **** **** +13281 Blighter_Silent_Control_Weather **** **** **** **** **** **** **** **** +13282 Blighter_Silent_CW_Rain **** **** **** **** **** **** **** **** +13283 Blighter_Silent_CW_Snow **** **** **** **** **** **** **** **** +13284 Blighter_Silent_CW_Clear **** **** **** **** **** **** **** **** +13285 Blighter_Still_Control_Weather **** **** **** **** **** **** **** **** +13286 Blighter_Still_CW_Rain **** **** **** **** **** **** **** **** +13287 Blighter_Still_CW_Snow **** **** **** **** **** **** **** **** +13288 Blighter_Still_CW_Clear **** **** **** **** **** **** **** **** +13289 Blighter_Earthquake **** **** **** **** **** **** **** **** +13290 Blighter_Exteneded_Earthquake **** **** **** **** **** **** **** **** +13291 Blighter_Silent_Earthquake **** **** **** **** **** **** **** **** +13292 Blighter_Still_Earthquake **** **** **** **** **** **** **** **** +13293 Blighter_Fire_Storm **** **** **** **** **** **** **** **** +13294 Blighter_Empowered_Fire_Storm **** **** **** **** **** **** **** **** +13295 Blighter_Silent_Fire_Storm **** **** **** **** **** **** **** **** +13296 Blighter_Still_Fire_Storm **** **** **** **** **** **** **** **** +13297 Blighter_Repulsion **** **** **** **** **** **** **** **** +13298 Blighter_Exteneded_Repulsion **** **** **** **** **** **** **** **** +13299 Blighter_Silent_Repulsion **** **** **** **** **** **** **** **** +13300 Blighter_Still_Repulsion **** **** **** **** **** **** **** **** +13301 Blighter_Horrid_Wilting **** **** **** **** **** **** **** **** +13302 Blighter_Silent_Horrid_Wilting **** **** **** **** **** **** **** **** +13303 Blighter_Still_Horrid_Wilting **** **** **** **** **** **** **** **** +13304 Blighter_Mind_Blank **** **** **** **** **** **** **** **** +13305 Blighter_Exteneded_Mind_Blank **** **** **** **** **** **** **** **** +13306 Blighter_Silent_Mind_Blank **** **** **** **** **** **** **** **** +13307 Blighter_Still_Mind_Blank **** **** **** **** **** **** **** **** +13308 Blighter_WavesOfExhaustion **** **** **** **** **** **** **** **** +13309 Blighter_Silent_WavesOfExhaustion **** **** **** **** **** **** **** **** +13310 Blighter_Still_WavesOfExhaustion **** **** **** **** **** **** **** **** +13311 Blighter_Foresight **** **** **** **** **** **** **** **** +13312 Blighter_Implosion **** **** **** **** **** **** **** **** +13313 Blighter_Incendiary_Cloud **** **** **** **** **** **** **** **** +13314 Blighter_Storm_of_Vengeance **** **** **** **** **** **** **** **** +13315 **** **** **** **** **** **** **** **** **** +13316 **** **** **** **** **** **** **** **** **** +13317 **** **** **** **** **** **** **** **** **** +13318 **** **** **** **** **** **** **** **** **** +13319 **** **** **** **** **** **** **** **** **** +13320 **** **** **** **** **** **** **** **** **** +13321 **** **** **** **** **** **** **** **** **** +13322 **** **** **** **** **** **** **** **** **** +13323 **** **** **** **** **** **** **** **** **** +13324 **** **** **** **** **** **** **** **** **** +13325 **** **** **** **** **** **** **** **** **** +13326 **** **** **** **** **** **** **** **** **** +13327 **** **** **** **** **** **** **** **** **** +13328 **** **** **** **** **** **** **** **** **** +13329 **** **** **** **** **** **** **** **** **** +13330 **** **** **** **** **** **** **** **** **** +13331 **** **** **** **** **** **** **** **** **** +13332 **** **** **** **** **** **** **** **** **** +13333 **** **** **** **** **** **** **** **** **** +13334 **** **** **** **** **** **** **** **** **** +13335 **** **** **** **** **** **** **** **** **** +13336 **** **** **** **** **** **** **** **** **** +13337 **** **** **** **** **** **** **** **** **** +13338 **** **** **** **** **** **** **** **** **** +13339 **** **** **** **** **** **** **** **** **** +13340 **** **** **** **** **** **** **** **** **** +13341 **** **** **** **** **** **** **** **** **** +13342 **** **** **** **** **** **** **** **** **** +13343 **** **** **** **** **** **** **** **** **** +13344 **** **** **** **** **** **** **** **** **** +13345 **** **** **** **** **** **** **** **** **** +13346 **** **** **** **** **** **** **** **** **** +13347 **** **** **** **** **** **** **** **** **** +13348 **** **** **** **** **** **** **** **** **** +13349 **** **** **** **** **** **** **** **** **** +13350 **** **** **** **** **** **** **** **** **** +13351 **** **** **** **** **** **** **** **** **** +13352 **** **** **** **** **** **** **** **** **** +13353 **** **** **** **** **** **** **** **** **** +13354 **** **** **** **** **** **** **** **** **** +13355 **** **** **** **** **** **** **** **** **** +13356 **** **** **** **** **** **** **** **** **** +13357 **** **** **** **** **** **** **** **** **** +13358 **** **** **** **** **** **** **** **** **** +13359 **** **** **** **** **** **** **** **** **** +13360 **** **** **** **** **** **** **** **** **** +13361 **** **** **** **** **** **** **** **** **** +13362 **** **** **** **** **** **** **** **** **** +13363 **** **** **** **** **** **** **** **** **** +13364 **** **** **** **** **** **** **** **** **** +13365 **** **** **** **** **** **** **** **** **** +13366 **** **** **** **** **** **** **** **** **** +13367 **** **** **** **** **** **** **** **** **** +13368 **** **** **** **** **** **** **** **** **** +13369 **** **** **** **** **** **** **** **** **** +13370 **** **** **** **** **** **** **** **** **** +13371 **** **** **** **** **** **** **** **** **** +13372 **** **** **** **** **** **** **** **** **** +13373 **** **** **** **** **** **** **** **** **** +13374 **** **** **** **** **** **** **** **** **** +13375 **** **** **** **** **** **** **** **** **** +13376 **** **** **** **** **** **** **** **** **** +13377 **** **** **** **** **** **** **** **** **** +13378 **** **** **** **** **** **** **** **** **** +13379 **** **** **** **** **** **** **** **** **** +13380 **** **** **** **** **** **** **** **** **** +13381 **** **** **** **** **** **** **** **** **** +13382 **** **** **** **** **** **** **** **** **** +13383 **** **** **** **** **** **** **** **** **** +13384 **** **** **** **** **** **** **** **** **** +13385 **** **** **** **** **** **** **** **** **** +13386 **** **** **** **** **** **** **** **** **** +13387 **** **** **** **** **** **** **** **** **** +13388 **** **** **** **** **** **** **** **** **** +13389 **** **** **** **** **** **** **** **** **** +13390 **** **** **** **** **** **** **** **** **** +13391 **** **** **** **** **** **** **** **** **** +13392 **** **** **** **** **** **** **** **** **** +13393 **** **** **** **** **** **** **** **** **** +13394 **** **** **** **** **** **** **** **** **** +13395 **** **** **** **** **** **** **** **** **** +13396 **** **** **** **** **** **** **** **** **** +13397 **** **** **** **** **** **** **** **** **** +13398 **** **** **** **** **** **** **** **** **** +13399 **** **** **** **** **** **** **** **** **** +13400 **** **** **** **** **** **** **** **** **** +13401 **** **** **** **** **** **** **** **** **** +13402 **** **** **** **** **** **** **** **** **** +13403 **** **** **** **** **** **** **** **** **** +13404 **** **** **** **** **** **** **** **** **** +13405 **** **** **** **** **** **** **** **** **** +13406 **** **** **** **** **** **** **** **** **** +13407 **** **** **** **** **** **** **** **** **** +13408 **** **** **** **** **** **** **** **** **** +13409 **** **** **** **** **** **** **** **** **** +13410 **** **** **** **** **** **** **** **** **** +13411 **** **** **** **** **** **** **** **** **** +13412 **** **** **** **** **** **** **** **** **** +13413 **** **** **** **** **** **** **** **** **** +13414 **** **** **** **** **** **** **** **** **** +13415 **** **** **** **** **** **** **** **** **** +13416 **** **** **** **** **** **** **** **** **** +13417 **** **** **** **** **** **** **** **** **** +13418 **** **** **** **** **** **** **** **** **** +13419 **** **** **** **** **** **** **** **** **** +13420 **** **** **** **** **** **** **** **** **** +13421 **** **** **** **** **** **** **** **** **** +13422 **** **** **** **** **** **** **** **** **** +13423 **** **** **** **** **** **** **** **** **** +13424 **** **** **** **** **** **** **** **** **** +13425 **** **** **** **** **** **** **** **** **** +13426 **** **** **** **** **** **** **** **** **** +13427 **** **** **** **** **** **** **** **** **** +13428 **** **** **** **** **** **** **** **** **** +13429 **** **** **** **** **** **** **** **** **** +13430 **** **** **** **** **** **** **** **** **** +13431 **** **** **** **** **** **** **** **** **** +13432 **** **** **** **** **** **** **** **** **** +13433 **** **** **** **** **** **** **** **** **** +13434 **** **** **** **** **** **** **** **** **** +13435 **** **** **** **** **** **** **** **** **** +13436 **** **** **** **** **** **** **** **** **** +13437 **** **** **** **** **** **** **** **** **** +13438 **** **** **** **** **** **** **** **** **** +13439 **** **** **** **** **** **** **** **** **** +13440 **** **** **** **** **** **** **** **** **** +13441 **** **** **** **** **** **** **** **** **** +13442 **** **** **** **** **** **** **** **** **** +13443 **** **** **** **** **** **** **** **** **** +13444 **** **** **** **** **** **** **** **** **** +13445 **** **** **** **** **** **** **** **** **** +13446 **** **** **** **** **** **** **** **** **** +13447 **** **** **** **** **** **** **** **** **** +13448 **** **** **** **** **** **** **** **** **** +13449 **** **** **** **** **** **** **** **** **** +13450 **** **** **** **** **** **** **** **** **** +13451 **** **** **** **** **** **** **** **** **** +13452 **** **** **** **** **** **** **** **** **** +13453 **** **** **** **** **** **** **** **** **** +13454 **** **** **** **** **** **** **** **** **** +13455 **** **** **** **** **** **** **** **** **** +13456 **** **** **** **** **** **** **** **** **** +13457 **** **** **** **** **** **** **** **** **** +13458 **** **** **** **** **** **** **** **** **** +13459 **** **** **** **** **** **** **** **** **** +13460 **** **** **** **** **** **** **** **** **** +13461 **** **** **** **** **** **** **** **** **** +13462 **** **** **** **** **** **** **** **** **** +13463 **** **** **** **** **** **** **** **** **** +13464 **** **** **** **** **** **** **** **** **** +13465 **** **** **** **** **** **** **** **** **** +13466 **** **** **** **** **** **** **** **** **** +13467 **** **** **** **** **** **** **** **** **** +13468 **** **** **** **** **** **** **** **** **** +13469 **** **** **** **** **** **** **** **** **** +13470 **** **** **** **** **** **** **** **** **** +13471 **** **** **** **** **** **** **** **** **** +13472 **** **** **** **** **** **** **** **** **** +13473 **** **** **** **** **** **** **** **** **** +13474 **** **** **** **** **** **** **** **** **** +13475 **** **** **** **** **** **** **** **** **** +13476 **** **** **** **** **** **** **** **** **** +13477 **** **** **** **** **** **** **** **** **** +13478 **** **** **** **** **** **** **** **** **** +13479 **** **** **** **** **** **** **** **** **** +13480 **** **** **** **** **** **** **** **** **** +13481 **** **** **** **** **** **** **** **** **** +13482 **** **** **** **** **** **** **** **** **** +13483 **** **** **** **** **** **** **** **** **** +13484 **** **** **** **** **** **** **** **** **** +13485 **** **** **** **** **** **** **** **** **** +13486 **** **** **** **** **** **** **** **** **** +13487 **** **** **** **** **** **** **** **** **** +13488 **** **** **** **** **** **** **** **** **** +13489 **** **** **** **** **** **** **** **** **** +13490 **** **** **** **** **** **** **** **** **** +13491 **** **** **** **** **** **** **** **** **** +13492 **** **** **** **** **** **** **** **** **** +13493 **** **** **** **** **** **** **** **** **** +13494 **** **** **** **** **** **** **** **** **** +13495 **** **** **** **** **** **** **** **** **** +13496 **** **** **** **** **** **** **** **** **** +13497 **** **** **** **** **** **** **** **** **** +13498 **** **** **** **** **** **** **** **** **** +13499 **** **** **** **** **** **** **** **** **** +13500 ####END_OF_NEW_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +13501 ###START_ACP_4_RESERVE **** **** **** **** **** **** **** **** +13502 ACP_Fighting_Stance_QUICK **** **** **** **** **** **** **** **** +13503 ACP_Fighting_Stance_KENSAI **** **** **** **** **** **** **** **** +13504 ACP_Fighting_Stance_ASSASSIN **** **** **** **** **** **** **** **** +13505 ACP_Fighting_Stance_ARCANE **** **** **** **** **** **** **** **** +13506 ACP_Fighting_Stance_FENCING **** **** **** **** **** **** **** **** +13507 ACP_Fighting_Stance_NORMAL **** **** **** **** **** **** **** **** +13508 ACP_Fighting_Stance_HEAVY **** **** **** **** **** **** **** **** +13509 ACP_Fighting_Stance_BARBARIAN **** **** **** **** **** **** **** **** +13510 ACP_Fighting_Stance_DEMONBLADE **** **** **** **** **** **** **** **** +13511 ACP_Fighting_Stance_WARRIOR **** **** **** **** **** **** **** **** +13512 ACP_Fighting_Stance_NORMAL **** **** **** **** **** **** **** **** +13513 ACP_Fighting_Stance_UNARMED **** **** **** **** **** **** **** **** +13514 ACP_Fighting_Stance_TIGERFANG **** **** **** **** **** **** **** **** +13515 ACP_Fighting_Stance_SUNFIST **** **** **** **** **** **** **** **** +13516 ACP_Fighting_Stance_DRAGONPALM **** **** **** **** **** **** **** **** +13517 ACP_Fighting_Stance_BEARCLAW **** **** **** **** **** **** **** **** +13518 ACP_Fighting_Stance_NORMAL **** **** **** **** **** **** **** **** +13519 **** **** **** **** **** **** **** **** **** +13520 **** **** **** **** **** **** **** **** **** +13521 **** **** **** **** **** **** **** **** **** +13522 **** **** **** **** **** **** **** **** **** +13523 **** **** **** **** **** **** **** **** **** +13524 **** **** **** **** **** **** **** **** **** +13525 **** **** **** **** **** **** **** **** **** +13526 **** **** **** **** **** **** **** **** **** +13527 **** **** **** **** **** **** **** **** **** +13528 **** **** **** **** **** **** **** **** **** +13529 **** **** **** **** **** **** **** **** **** +13530 **** **** **** **** **** **** **** **** **** +13531 **** **** **** **** **** **** **** **** **** +13532 **** **** **** **** **** **** **** **** **** +13533 **** **** **** **** **** **** **** **** **** +13534 **** **** **** **** **** **** **** **** **** +13535 **** **** **** **** **** **** **** **** **** +13536 **** **** **** **** **** **** **** **** **** +13537 **** **** **** **** **** **** **** **** **** +13538 **** **** **** **** **** **** **** **** **** +13539 **** **** **** **** **** **** **** **** **** +13540 **** **** **** **** **** **** **** **** **** +13541 **** **** **** **** **** **** **** **** **** +13542 **** **** **** **** **** **** **** **** **** +13543 **** **** **** **** **** **** **** **** **** +13544 **** **** **** **** **** **** **** **** **** +13545 **** **** **** **** **** **** **** **** **** +13546 **** **** **** **** **** **** **** **** **** +13547 **** **** **** **** **** **** **** **** **** +13548 **** **** **** **** **** **** **** **** **** +13549 **** **** **** **** **** **** **** **** **** +13550 **** **** **** **** **** **** **** **** **** +13551 **** **** **** **** **** **** **** **** **** +13552 **** **** **** **** **** **** **** **** **** +13553 **** **** **** **** **** **** **** **** **** +13554 **** **** **** **** **** **** **** **** **** +13555 **** **** **** **** **** **** **** **** **** +13556 **** **** **** **** **** **** **** **** **** +13557 **** **** **** **** **** **** **** **** **** +13558 **** **** **** **** **** **** **** **** **** +13559 **** **** **** **** **** **** **** **** **** +13560 **** **** **** **** **** **** **** **** **** +13561 **** **** **** **** **** **** **** **** **** +13562 **** **** **** **** **** **** **** **** **** +13563 **** **** **** **** **** **** **** **** **** +13564 **** **** **** **** **** **** **** **** **** +13565 **** **** **** **** **** **** **** **** **** +13566 **** **** **** **** **** **** **** **** **** +13567 **** **** **** **** **** **** **** **** **** +13568 **** **** **** **** **** **** **** **** **** +13569 **** **** **** **** **** **** **** **** **** +13570 **** **** **** **** **** **** **** **** **** +13571 **** **** **** **** **** **** **** **** **** +13572 **** **** **** **** **** **** **** **** **** +13573 **** **** **** **** **** **** **** **** **** +13574 **** **** **** **** **** **** **** **** **** +13575 **** **** **** **** **** **** **** **** **** +13576 **** **** **** **** **** **** **** **** **** +13577 **** **** **** **** **** **** **** **** **** +13578 **** **** **** **** **** **** **** **** **** +13579 **** **** **** **** **** **** **** **** **** +13580 **** **** **** **** **** **** **** **** **** +13581 **** **** **** **** **** **** **** **** **** +13582 **** **** **** **** **** **** **** **** **** +13583 **** **** **** **** **** **** **** **** **** +13584 **** **** **** **** **** **** **** **** **** +13585 **** **** **** **** **** **** **** **** **** +13586 **** **** **** **** **** **** **** **** **** +13587 **** **** **** **** **** **** **** **** **** +13588 **** **** **** **** **** **** **** **** **** +13589 **** **** **** **** **** **** **** **** **** +13590 **** **** **** **** **** **** **** **** **** +13591 **** **** **** **** **** **** **** **** **** +13592 **** **** **** **** **** **** **** **** **** +13593 **** **** **** **** **** **** **** **** **** +13594 **** **** **** **** **** **** **** **** **** +13595 **** **** **** **** **** **** **** **** **** +13596 **** **** **** **** **** **** **** **** **** +13597 **** **** **** **** **** **** **** **** **** +13598 **** **** **** **** **** **** **** **** **** +13599 **** **** **** **** **** **** **** **** **** +13600 **** **** **** **** **** **** **** **** **** +13601 **** **** **** **** **** **** **** **** **** +13602 **** **** **** **** **** **** **** **** **** +13603 **** **** **** **** **** **** **** **** **** +13604 **** **** **** **** **** **** **** **** **** +13605 **** **** **** **** **** **** **** **** **** +13606 **** **** **** **** **** **** **** **** **** +13607 **** **** **** **** **** **** **** **** **** +13608 **** **** **** **** **** **** **** **** **** +13609 **** **** **** **** **** **** **** **** **** +13610 **** **** **** **** **** **** **** **** **** +13611 **** **** **** **** **** **** **** **** **** +13612 **** **** **** **** **** **** **** **** **** +13613 **** **** **** **** **** **** **** **** **** +13614 **** **** **** **** **** **** **** **** **** +13615 **** **** **** **** **** **** **** **** **** +13616 **** **** **** **** **** **** **** **** **** +13617 **** **** **** **** **** **** **** **** **** +13618 **** **** **** **** **** **** **** **** **** +13619 **** **** **** **** **** **** **** **** **** +13620 **** **** **** **** **** **** **** **** **** +13621 **** **** **** **** **** **** **** **** **** +13622 **** **** **** **** **** **** **** **** **** +13623 **** **** **** **** **** **** **** **** **** +13624 **** **** **** **** **** **** **** **** **** +13625 **** **** **** **** **** **** **** **** **** +13626 **** **** **** **** **** **** **** **** **** +13627 **** **** **** **** **** **** **** **** **** +13628 **** **** **** **** **** **** **** **** **** +13629 **** **** **** **** **** **** **** **** **** +13630 **** **** **** **** **** **** **** **** **** +13631 **** **** **** **** **** **** **** **** **** +13632 **** **** **** **** **** **** **** **** **** +13633 **** **** **** **** **** **** **** **** **** +13634 **** **** **** **** **** **** **** **** **** +13635 **** **** **** **** **** **** **** **** **** +13636 **** **** **** **** **** **** **** **** **** +13637 **** **** **** **** **** **** **** **** **** +13638 **** **** **** **** **** **** **** **** **** +13639 **** **** **** **** **** **** **** **** **** +13640 **** **** **** **** **** **** **** **** **** +13641 **** **** **** **** **** **** **** **** **** +13642 **** **** **** **** **** **** **** **** **** +13643 **** **** **** **** **** **** **** **** **** +13644 **** **** **** **** **** **** **** **** **** +13645 **** **** **** **** **** **** **** **** **** +13646 **** **** **** **** **** **** **** **** **** +13647 **** **** **** **** **** **** **** **** **** +13648 **** **** **** **** **** **** **** **** **** +13649 **** **** **** **** **** **** **** **** **** +13650 **** **** **** **** **** **** **** **** **** +13651 **** **** **** **** **** **** **** **** **** +13652 **** **** **** **** **** **** **** **** **** +13653 **** **** **** **** **** **** **** **** **** +13654 **** **** **** **** **** **** **** **** **** +13655 **** **** **** **** **** **** **** **** **** +13656 **** **** **** **** **** **** **** **** **** +13657 **** **** **** **** **** **** **** **** **** +13658 **** **** **** **** **** **** **** **** **** +13659 **** **** **** **** **** **** **** **** **** +13660 **** **** **** **** **** **** **** **** **** +13661 **** **** **** **** **** **** **** **** **** +13662 **** **** **** **** **** **** **** **** **** +13663 **** **** **** **** **** **** **** **** **** +13664 **** **** **** **** **** **** **** **** **** +13665 **** **** **** **** **** **** **** **** **** +13666 **** **** **** **** **** **** **** **** **** +13667 **** **** **** **** **** **** **** **** **** +13668 **** **** **** **** **** **** **** **** **** +13669 **** **** **** **** **** **** **** **** **** +13670 **** **** **** **** **** **** **** **** **** +13671 **** **** **** **** **** **** **** **** **** +13672 **** **** **** **** **** **** **** **** **** +13673 **** **** **** **** **** **** **** **** **** +13674 **** **** **** **** **** **** **** **** **** +13675 **** **** **** **** **** **** **** **** **** +13676 **** **** **** **** **** **** **** **** **** +13677 **** **** **** **** **** **** **** **** **** +13678 **** **** **** **** **** **** **** **** **** +13679 **** **** **** **** **** **** **** **** **** +13680 **** **** **** **** **** **** **** **** **** +13681 **** **** **** **** **** **** **** **** **** +13682 **** **** **** **** **** **** **** **** **** +13683 **** **** **** **** **** **** **** **** **** +13684 **** **** **** **** **** **** **** **** **** +13685 **** **** **** **** **** **** **** **** **** +13686 **** **** **** **** **** **** **** **** **** +13687 **** **** **** **** **** **** **** **** **** +13688 **** **** **** **** **** **** **** **** **** +13689 **** **** **** **** **** **** **** **** **** +13690 **** **** **** **** **** **** **** **** **** +13691 **** **** **** **** **** **** **** **** **** +13692 **** **** **** **** **** **** **** **** **** +13693 **** **** **** **** **** **** **** **** **** +13694 **** **** **** **** **** **** **** **** **** +13695 **** **** **** **** **** **** **** **** **** +13696 **** **** **** **** **** **** **** **** **** +13697 **** **** **** **** **** **** **** **** **** +13698 **** **** **** **** **** **** **** **** **** +13699 **** **** **** **** **** **** **** **** **** +13700 **** **** **** **** **** **** **** **** **** +13701 **** **** **** **** **** **** **** **** **** +13702 **** **** **** **** **** **** **** **** **** +13703 **** **** **** **** **** **** **** **** **** +13704 **** **** **** **** **** **** **** **** **** +13705 **** **** **** **** **** **** **** **** **** +13706 **** **** **** **** **** **** **** **** **** +13707 **** **** **** **** **** **** **** **** **** +13708 **** **** **** **** **** **** **** **** **** +13709 **** **** **** **** **** **** **** **** **** +13710 **** **** **** **** **** **** **** **** **** +13711 **** **** **** **** **** **** **** **** **** +13712 **** **** **** **** **** **** **** **** **** +13713 **** **** **** **** **** **** **** **** **** +13714 **** **** **** **** **** **** **** **** **** +13715 **** **** **** **** **** **** **** **** **** +13716 **** **** **** **** **** **** **** **** **** +13717 **** **** **** **** **** **** **** **** **** +13718 **** **** **** **** **** **** **** **** **** +13719 **** **** **** **** **** **** **** **** **** +13720 **** **** **** **** **** **** **** **** **** +13721 **** **** **** **** **** **** **** **** **** +13722 **** **** **** **** **** **** **** **** **** +13723 **** **** **** **** **** **** **** **** **** +13724 **** **** **** **** **** **** **** **** **** +13725 **** **** **** **** **** **** **** **** **** +13726 **** **** **** **** **** **** **** **** **** +13727 **** **** **** **** **** **** **** **** **** +13728 **** **** **** **** **** **** **** **** **** +13729 **** **** **** **** **** **** **** **** **** +13730 **** **** **** **** **** **** **** **** **** +13731 **** **** **** **** **** **** **** **** **** +13732 **** **** **** **** **** **** **** **** **** +13733 **** **** **** **** **** **** **** **** **** +13734 **** **** **** **** **** **** **** **** **** +13735 **** **** **** **** **** **** **** **** **** +13736 **** **** **** **** **** **** **** **** **** +13737 **** **** **** **** **** **** **** **** **** +13738 **** **** **** **** **** **** **** **** **** +13739 **** **** **** **** **** **** **** **** **** +13740 **** **** **** **** **** **** **** **** **** +13741 **** **** **** **** **** **** **** **** **** +13742 **** **** **** **** **** **** **** **** **** +13743 **** **** **** **** **** **** **** **** **** +13744 **** **** **** **** **** **** **** **** **** +13745 **** **** **** **** **** **** **** **** **** +13746 **** **** **** **** **** **** **** **** **** +13747 **** **** **** **** **** **** **** **** **** +13748 **** **** **** **** **** **** **** **** **** +13749 **** **** **** **** **** **** **** **** **** +13750 **** **** **** **** **** **** **** **** **** +13751 **** **** **** **** **** **** **** **** **** +13752 **** **** **** **** **** **** **** **** **** +13753 **** **** **** **** **** **** **** **** **** +13754 **** **** **** **** **** **** **** **** **** +13755 **** **** **** **** **** **** **** **** **** +13756 **** **** **** **** **** **** **** **** **** +13757 **** **** **** **** **** **** **** **** **** +13758 **** **** **** **** **** **** **** **** **** +13759 **** **** **** **** **** **** **** **** **** +13760 **** **** **** **** **** **** **** **** **** +13761 **** **** **** **** **** **** **** **** **** +13762 **** **** **** **** **** **** **** **** **** +13763 **** **** **** **** **** **** **** **** **** +13764 **** **** **** **** **** **** **** **** **** +13765 **** **** **** **** **** **** **** **** **** +13766 **** **** **** **** **** **** **** **** **** +13767 **** **** **** **** **** **** **** **** **** +13768 **** **** **** **** **** **** **** **** **** +13769 **** **** **** **** **** **** **** **** **** +13770 **** **** **** **** **** **** **** **** **** +13771 **** **** **** **** **** **** **** **** **** +13772 **** **** **** **** **** **** **** **** **** +13773 **** **** **** **** **** **** **** **** **** +13774 **** **** **** **** **** **** **** **** **** +13775 **** **** **** **** **** **** **** **** **** +13776 **** **** **** **** **** **** **** **** **** +13777 **** **** **** **** **** **** **** **** **** +13778 **** **** **** **** **** **** **** **** **** +13779 **** **** **** **** **** **** **** **** **** +13780 **** **** **** **** **** **** **** **** **** +13781 **** **** **** **** **** **** **** **** **** +13782 **** **** **** **** **** **** **** **** **** +13783 **** **** **** **** **** **** **** **** **** +13784 **** **** **** **** **** **** **** **** **** +13785 **** **** **** **** **** **** **** **** **** +13786 **** **** **** **** **** **** **** **** **** +13787 **** **** **** **** **** **** **** **** **** +13788 **** **** **** **** **** **** **** **** **** +13789 **** **** **** **** **** **** **** **** **** +13790 **** **** **** **** **** **** **** **** **** +13791 **** **** **** **** **** **** **** **** **** +13792 **** **** **** **** **** **** **** **** **** +13793 **** **** **** **** **** **** **** **** **** +13794 **** **** **** **** **** **** **** **** **** +13795 **** **** **** **** **** **** **** **** **** +13796 **** **** **** **** **** **** **** **** **** +13797 **** **** **** **** **** **** **** **** **** +13798 **** **** **** **** **** **** **** **** **** +13799 **** **** **** **** **** **** **** **** **** +13800 **** **** **** **** **** **** **** **** **** +13801 **** **** **** **** **** **** **** **** **** +13802 **** **** **** **** **** **** **** **** **** +13803 **** **** **** **** **** **** **** **** **** +13804 **** **** **** **** **** **** **** **** **** +13805 **** **** **** **** **** **** **** **** **** +13806 **** **** **** **** **** **** **** **** **** +13807 **** **** **** **** **** **** **** **** **** +13808 **** **** **** **** **** **** **** **** **** +13809 **** **** **** **** **** **** **** **** **** +13810 **** **** **** **** **** **** **** **** **** +13811 **** **** **** **** **** **** **** **** **** +13812 **** **** **** **** **** **** **** **** **** +13813 **** **** **** **** **** **** **** **** **** +13814 **** **** **** **** **** **** **** **** **** +13815 **** **** **** **** **** **** **** **** **** +13816 **** **** **** **** **** **** **** **** **** +13817 **** **** **** **** **** **** **** **** **** +13818 **** **** **** **** **** **** **** **** **** +13819 **** **** **** **** **** **** **** **** **** +13820 **** **** **** **** **** **** **** **** **** +13821 **** **** **** **** **** **** **** **** **** +13822 **** **** **** **** **** **** **** **** **** +13823 **** **** **** **** **** **** **** **** **** +13824 **** **** **** **** **** **** **** **** **** +13825 **** **** **** **** **** **** **** **** **** +13826 **** **** **** **** **** **** **** **** **** +13827 **** **** **** **** **** **** **** **** **** +13828 **** **** **** **** **** **** **** **** **** +13829 **** **** **** **** **** **** **** **** **** +13830 **** **** **** **** **** **** **** **** **** +13831 **** **** **** **** **** **** **** **** **** +13832 **** **** **** **** **** **** **** **** **** +13833 **** **** **** **** **** **** **** **** **** +13834 **** **** **** **** **** **** **** **** **** +13835 **** **** **** **** **** **** **** **** **** +13836 **** **** **** **** **** **** **** **** **** +13837 **** **** **** **** **** **** **** **** **** +13838 **** **** **** **** **** **** **** **** **** +13839 **** **** **** **** **** **** **** **** **** +13840 **** **** **** **** **** **** **** **** **** +13841 **** **** **** **** **** **** **** **** **** +13842 **** **** **** **** **** **** **** **** **** +13843 **** **** **** **** **** **** **** **** **** +13844 **** **** **** **** **** **** **** **** **** +13845 **** **** **** **** **** **** **** **** **** +13846 **** **** **** **** **** **** **** **** **** +13847 **** **** **** **** **** **** **** **** **** +13848 **** **** **** **** **** **** **** **** **** +13849 **** **** **** **** **** **** **** **** **** +13850 **** **** **** **** **** **** **** **** **** +13851 **** **** **** **** **** **** **** **** **** +13852 **** **** **** **** **** **** **** **** **** +13853 **** **** **** **** **** **** **** **** **** +13854 **** **** **** **** **** **** **** **** **** +13855 **** **** **** **** **** **** **** **** **** +13856 **** **** **** **** **** **** **** **** **** +13857 **** **** **** **** **** **** **** **** **** +13858 **** **** **** **** **** **** **** **** **** +13859 **** **** **** **** **** **** **** **** **** +13860 **** **** **** **** **** **** **** **** **** +13861 **** **** **** **** **** **** **** **** **** +13862 **** **** **** **** **** **** **** **** **** +13863 **** **** **** **** **** **** **** **** **** +13864 **** **** **** **** **** **** **** **** **** +13865 **** **** **** **** **** **** **** **** **** +13866 **** **** **** **** **** **** **** **** **** +13867 **** **** **** **** **** **** **** **** **** +13868 **** **** **** **** **** **** **** **** **** +13869 **** **** **** **** **** **** **** **** **** +13870 **** **** **** **** **** **** **** **** **** +13871 **** **** **** **** **** **** **** **** **** +13872 **** **** **** **** **** **** **** **** **** +13873 **** **** **** **** **** **** **** **** **** +13874 **** **** **** **** **** **** **** **** **** +13875 **** **** **** **** **** **** **** **** **** +13876 **** **** **** **** **** **** **** **** **** +13877 **** **** **** **** **** **** **** **** **** +13878 **** **** **** **** **** **** **** **** **** +13879 **** **** **** **** **** **** **** **** **** +13880 **** **** **** **** **** **** **** **** **** +13881 **** **** **** **** **** **** **** **** **** +13882 **** **** **** **** **** **** **** **** **** +13883 **** **** **** **** **** **** **** **** **** +13884 **** **** **** **** **** **** **** **** **** +13885 **** **** **** **** **** **** **** **** **** +13886 **** **** **** **** **** **** **** **** **** +13887 **** **** **** **** **** **** **** **** **** +13888 **** **** **** **** **** **** **** **** **** +13889 **** **** **** **** **** **** **** **** **** +13890 **** **** **** **** **** **** **** **** **** +13891 **** **** **** **** **** **** **** **** **** +13892 **** **** **** **** **** **** **** **** **** +13893 **** **** **** **** **** **** **** **** **** +13894 **** **** **** **** **** **** **** **** **** +13895 **** **** **** **** **** **** **** **** **** +13896 **** **** **** **** **** **** **** **** **** +13897 **** **** **** **** **** **** **** **** **** +13898 **** **** **** **** **** **** **** **** **** +13899 **** **** **** **** **** **** **** **** **** +13900 **** **** **** **** **** **** **** **** **** +13901 **** **** **** **** **** **** **** **** **** +13902 **** **** **** **** **** **** **** **** **** +13903 **** **** **** **** **** **** **** **** **** +13904 **** **** **** **** **** **** **** **** **** +13905 **** **** **** **** **** **** **** **** **** +13906 **** **** **** **** **** **** **** **** **** +13907 **** **** **** **** **** **** **** **** **** +13908 **** **** **** **** **** **** **** **** **** +13909 **** **** **** **** **** **** **** **** **** +13910 **** **** **** **** **** **** **** **** **** +13911 **** **** **** **** **** **** **** **** **** +13912 **** **** **** **** **** **** **** **** **** +13913 **** **** **** **** **** **** **** **** **** +13914 **** **** **** **** **** **** **** **** **** +13915 **** **** **** **** **** **** **** **** **** +13916 **** **** **** **** **** **** **** **** **** +13917 **** **** **** **** **** **** **** **** **** +13918 **** **** **** **** **** **** **** **** **** +13919 **** **** **** **** **** **** **** **** **** +13920 **** **** **** **** **** **** **** **** **** +13921 **** **** **** **** **** **** **** **** **** +13922 **** **** **** **** **** **** **** **** **** +13923 **** **** **** **** **** **** **** **** **** +13924 **** **** **** **** **** **** **** **** **** +13925 **** **** **** **** **** **** **** **** **** +13926 **** **** **** **** **** **** **** **** **** +13927 **** **** **** **** **** **** **** **** **** +13928 **** **** **** **** **** **** **** **** **** +13929 **** **** **** **** **** **** **** **** **** +13930 **** **** **** **** **** **** **** **** **** +13931 **** **** **** **** **** **** **** **** **** +13932 **** **** **** **** **** **** **** **** **** +13933 **** **** **** **** **** **** **** **** **** +13934 **** **** **** **** **** **** **** **** **** +13935 **** **** **** **** **** **** **** **** **** +13936 **** **** **** **** **** **** **** **** **** +13937 **** **** **** **** **** **** **** **** **** +13938 **** **** **** **** **** **** **** **** **** +13939 **** **** **** **** **** **** **** **** **** +13940 **** **** **** **** **** **** **** **** **** +13941 **** **** **** **** **** **** **** **** **** +13942 **** **** **** **** **** **** **** **** **** +13943 **** **** **** **** **** **** **** **** **** +13944 **** **** **** **** **** **** **** **** **** +13945 **** **** **** **** **** **** **** **** **** +13946 **** **** **** **** **** **** **** **** **** +13947 **** **** **** **** **** **** **** **** **** +13948 **** **** **** **** **** **** **** **** **** +13949 **** **** **** **** **** **** **** **** **** +13950 **** **** **** **** **** **** **** **** **** +13951 **** **** **** **** **** **** **** **** **** +13952 **** **** **** **** **** **** **** **** **** +13953 **** **** **** **** **** **** **** **** **** +13954 **** **** **** **** **** **** **** **** **** +13955 **** **** **** **** **** **** **** **** **** +13956 **** **** **** **** **** **** **** **** **** +13957 **** **** **** **** **** **** **** **** **** +13958 **** **** **** **** **** **** **** **** **** +13959 **** **** **** **** **** **** **** **** **** +13960 **** **** **** **** **** **** **** **** **** +13961 **** **** **** **** **** **** **** **** **** +13962 **** **** **** **** **** **** **** **** **** +13963 **** **** **** **** **** **** **** **** **** +13964 **** **** **** **** **** **** **** **** **** +13965 **** **** **** **** **** **** **** **** **** +13966 **** **** **** **** **** **** **** **** **** +13967 **** **** **** **** **** **** **** **** **** +13968 **** **** **** **** **** **** **** **** **** +13969 **** **** **** **** **** **** **** **** **** +13970 **** **** **** **** **** **** **** **** **** +13971 **** **** **** **** **** **** **** **** **** +13972 **** **** **** **** **** **** **** **** **** +13973 **** **** **** **** **** **** **** **** **** +13974 **** **** **** **** **** **** **** **** **** +13975 **** **** **** **** **** **** **** **** **** +13976 **** **** **** **** **** **** **** **** **** +13977 **** **** **** **** **** **** **** **** **** +13978 **** **** **** **** **** **** **** **** **** +13979 **** **** **** **** **** **** **** **** **** +13980 **** **** **** **** **** **** **** **** **** +13981 **** **** **** **** **** **** **** **** **** +13982 **** **** **** **** **** **** **** **** **** +13983 **** **** **** **** **** **** **** **** **** +13984 **** **** **** **** **** **** **** **** **** +13985 **** **** **** **** **** **** **** **** **** +13986 **** **** **** **** **** **** **** **** **** +13987 **** **** **** **** **** **** **** **** **** +13988 **** **** **** **** **** **** **** **** **** +13989 **** **** **** **** **** **** **** **** **** +13990 **** **** **** **** **** **** **** **** **** +13991 **** **** **** **** **** **** **** **** **** +13992 **** **** **** **** **** **** **** **** **** +13993 **** **** **** **** **** **** **** **** **** +13994 **** **** **** **** **** **** **** **** **** +13995 **** **** **** **** **** **** **** **** **** +13996 **** **** **** **** **** **** **** **** **** +13997 **** **** **** **** **** **** **** **** **** +13998 **** **** **** **** **** **** **** **** **** +13999 ####END_OF_NEW_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +14000 **Psionic_Powers** **** **** **** **** **** **** **** **** +14001 Bolt **** **** **** **** **** **** **** **** +14002 CallToMind **** **** **** **** **** **** **** **** +14003 CharmPerson **** **** **** **** **** **** **** **** +14004 CrystalShard **** **** **** **** **** **** **** **** +14005 Daze **** **** **** **** **** **** **** **** +14006 Deceleration **** **** **** **** **** **** **** **** +14007 DefPrecog **** **** **** **** **** **** **** **** +14008 Demoralize **** **** **** **** **** **** **** **** +14009 Disable **** **** **** **** **** **** **** **** +14010 DissipatingTouch **** **** **** **** **** **** **** **** +14011 Distract **** **** **** **** **** **** **** **** +14012 EmptyMind **** **** **** **** **** **** **** **** +14013 Conceal_Thoughts **** **** **** **** **** **** **** **** +14014 EnergyRay_Cold **** **** **** **** **** **** **** **** +14015 EnergyRay_Elec **** **** **** **** **** **** **** **** +14016 EnergyRay_Fire **** **** **** **** **** **** **** **** +14017 EnergyRay_Sonic **** **** **** **** **** **** **** **** +14018 EntanglingEctoplasm **** **** **** **** **** **** **** **** +14019 ForceScreen **** **** **** **** **** **** **** **** +14020 Grease **** **** **** **** **** **** **** **** +14021 Hammer **** **** **** **** **** **** **** **** +14022 InertialArmour **** **** **** **** **** **** **** **** +14023 MindThrust **** **** **** **** **** **** **** **** +14024 MyLight **** **** **** **** **** **** **** **** +14025 OffPrecog **** **** **** **** **** **** **** **** +14026 OffPresc **** **** **** **** **** **** **** **** +14027 Stomp **** **** **** **** **** **** **** **** +14028 Synesthete **** **** **** **** **** **** **** **** +14029 ThickSkin **** **** **** **** **** **** **** **** +14030 Vigor **** **** **** **** **** **** **** **** +14031 Empathy **** **** **** **** **** **** **** **** +14032 Far_Hand **** **** **** **** **** **** **** **** +14033 Matter_Agitation **** **** **** **** **** **** **** **** +14034 Skate **** **** **** **** **** **** **** **** +14035 Telempathic_Projection **** **** **** **** **** **** **** **** +14036 AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +14037 AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +14038 AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +14039 AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +14040 AstralConstruct_Conversation **** **** **** **** **** **** **** **** +14041 Burst **** **** **** **** **** **** **** **** +14042 DestinyDissonance **** **** **** **** **** **** **** **** +14043 PrecognitionMain **** **** **** **** **** **** **** **** +14044 PrecognitionAttack **** **** **** **** **** **** **** **** +14045 PrecognitionDamage **** **** **** **** **** **** **** **** +14046 PrecognitionSaves **** **** **** **** **** **** **** **** +14047 PrecognitionSkills **** **** **** **** **** **** **** **** +14048 BiteOfTheWolf **** **** **** **** **** **** **** **** +14049 ClawsOfTheBeast **** **** **** **** **** **** **** **** +14050 CreateSound **** **** **** **** **** **** **** **** +14051 BestowPower **** **** **** **** **** **** **** **** +14052 Biofeedback **** **** **** **** **** **** **** **** +14053 BrainLock **** **** **** **** **** **** **** **** +14054 ConcBlast **** **** **** **** **** **** **** **** +14055 ConcealAmorpha **** **** **** **** **** **** **** **** +14056 SwarmOfCrystals **** **** **** **** **** **** **** **** +14057 DissolvingTouch **** **** **** **** **** **** **** **** +14058 EgoWhip **** **** **** **** **** **** **** **** +14059 ElfSight **** **** **** **** **** **** **** **** +14060 EnergyAdaptAcid **** **** **** **** **** **** **** **** +14061 EnergyAdaptCold **** **** **** **** **** **** **** **** +14062 EnergyAdaptElec **** **** **** **** **** **** **** **** +14063 EnergyAdaptFire **** **** **** **** **** **** **** **** +14064 EnergyAdaptSonic **** **** **** **** **** **** **** **** +14065 Body_Equilibrium **** **** **** **** **** **** **** **** +14066 PainfulStrike **** **** **** **** **** **** **** **** +14067 EnergyPush_Cold **** **** **** **** **** **** **** **** +14068 EnergyPush_Elec **** **** **** **** **** **** **** **** +14069 EnergyPush_Fire **** **** **** **** **** **** **** **** +14070 EnergyPush_Sonic **** **** **** **** **** **** **** **** +14071 Lock **** **** **** **** **** **** **** **** +14072 EnergyStun_Cold **** **** **** **** **** **** **** **** +14073 EnergyStun_Elec **** **** **** **** **** **** **** **** +14074 EnergyStun_Fire **** **** **** **** **** **** **** **** +14075 EnergyStun_Sonic **** **** **** **** **** **** **** **** +14076 Identify **** **** **** **** **** **** **** **** +14077 IdInsinuation **** **** **** **** **** **** **** **** +14078 InflictPain **** **** **** **** **** **** **** **** +14079 Knock **** **** **** **** **** **** **** **** +14080 MindDisrupt **** **** **** **** **** **** **** **** +14081 RecallAgony **** **** **** **** **** **** **** **** +14082 ThoughtShield **** **** **** **** **** **** **** **** +14083 Dissolving_Weapon **** **** **** **** **** **** **** **** +14084 SharePain **** **** **** **** **** **** **** **** +14085 ControlAir **** **** **** **** **** **** **** **** +14086 ControlSound **** **** **** **** **** **** **** **** +14087 RepairDamage **** **** **** **** **** **** **** **** +14088 Aversion **** **** **** **** **** **** **** **** +14089 DimensionSwap **** **** **** **** **** **** **** **** +14090 EmpathicTransfer **** **** **** **** **** **** **** **** +14091 Energy_Missile_Cold **** **** **** **** **** **** **** **** +14092 Energy_Missile_Elec **** **** **** **** **** **** **** **** +14093 Energy_Missile_Fire **** **** **** **** **** **** **** **** +14094 Energy_Missile_Sonic **** **** **** **** **** **** **** **** +14095 AnimalAffinity **** **** **** **** **** **** **** **** +14096 StrengthOfMyEnemy **** **** **** **** **** **** **** **** +14097 Chameleon **** **** **** **** **** **** **** **** +14098 ClairvoyantSense **** **** **** **** **** **** **** **** +14099 Cloud_Mind **** **** **** **** **** **** **** **** +14100 BodyAdjustment **** **** **** **** **** **** **** **** +14101 Greater_Amorpha **** **** **** **** **** **** **** **** +14102 Darkvision **** **** **** **** **** **** **** **** +14103 Psiblast **** **** **** **** **** **** **** **** +14104 Danger_Sense **** **** **** **** **** **** **** **** +14105 Energy_Bolt_Cold **** **** **** **** **** **** **** **** +14106 Energy_Bolt_Elec **** **** **** **** **** **** **** **** +14107 Energy_Bolt_Fire **** **** **** **** **** **** **** **** +14108 Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +14109 Energy_Burst_Cold **** **** **** **** **** **** **** **** +14110 Energy_Burst_Elec **** **** **** **** **** **** **** **** +14111 Energy_Burst_Fire **** **** **** **** **** **** **** **** +14112 Energy_Burst_Sonic **** **** **** **** **** **** **** **** +14113 Energy_Retort_Cold **** **** **** **** **** **** **** **** +14114 Energy_Retort_Elec **** **** **** **** **** **** **** **** +14115 Energy_Retort_Fire **** **** **** **** **** **** **** **** +14116 Energy_Retort_Sonic **** **** **** **** **** **** **** **** +14117 Exhale_BlackDrag **** **** **** **** **** **** **** **** +14118 Eradicate_Invisibility **** **** **** **** **** **** **** **** +14119 SharePainForced **** **** **** **** **** **** **** **** +14120 Keen_Edge **** **** **** **** **** **** **** **** +14121 MentalBarrier **** **** **** **** **** **** **** **** +14122 Mindtrap **** **** **** **** **** **** **** **** +14123 Touchsight **** **** **** **** **** **** **** **** +14124 BodyPurification **** **** **** **** **** **** **** **** +14125 Dispel_Psionics **** **** **** **** **** **** **** **** +14126 Energy_Wall_Cold **** **** **** **** **** **** **** **** +14127 Energy_Wall_Elec **** **** **** **** **** **** **** **** +14128 Energy_Wall_Fire **** **** **** **** **** **** **** **** +14129 Energy_Wall_Sonic **** **** **** **** **** **** **** **** +14130 Hustle **** **** **** **** **** **** **** **** +14131 TimeHop **** **** **** **** **** **** **** **** +14132 UbiqVision **** **** **** **** **** **** **** **** +14133 EctoCocoon **** **** **** **** **** **** **** **** +14134 CrisisBreath **** **** **** **** **** **** **** **** +14135 EmpathicTransferHostile **** **** **** **** **** **** **** **** +14136 FateLink **** **** **** **** **** **** **** **** +14137 DimensionSlide **** **** **** **** **** **** **** **** +14138 EctoplasmicForm **** **** **** **** **** **** **** **** +14139 EnergyCone_Cold **** **** **** **** **** **** **** **** +14140 EnergyCone_Elec **** **** **** **** **** **** **** **** +14141 EnergyCone_Fire **** **** **** **** **** **** **** **** +14142 EnergyCone_Sonic **** **** **** **** **** **** **** **** +14143 ClawOfTheVampire **** **** **** **** **** **** **** **** +14144 DuodimensionalClaw **** **** **** **** **** **** **** **** +14145 VampiricWeapon **** **** **** **** **** **** **** **** +14146 EscapeDetection **** **** **** **** **** **** **** **** +14147 InertialBar **** **** **** **** **** **** **** **** +14148 SteadfastPercep **** **** **** **** **** **** **** **** +14149 DetectRemoteViewing **** **** **** **** **** **** **** **** +14150 EmpathicFeedback **** **** **** **** **** **** **** **** +14151 EnergyAdaption **** **** **** **** **** **** **** **** +14152 Freedom_of_Movement **** **** **** **** **** **** **** **** +14153 Mindwipe **** **** **** **** **** **** **** **** +14154 PowerLeech **** **** **** **** **** **** **** **** +14155 PsychicReformation **** **** **** **** **** **** **** **** +14156 TelekineticManeuver **** **** **** **** **** **** **** **** +14157 DimensionalAnchor **** **** **** **** **** **** **** **** +14158 Dismissal **** **** **** **** **** **** **** **** +14159 DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +14160 DimensionDoor_Party **** **** **** **** **** **** **** **** +14161 Dominate_Psionic **** **** **** **** **** **** **** **** +14162 DimensionDoor_Master **** **** **** **** **** **** **** **** +14163 DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +14164 DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +14165 EnergyBall_Cold **** **** **** **** **** **** **** **** +14166 EnergyBall_Elec **** **** **** **** **** **** **** **** +14167 EnergyBall_Fire **** **** **** **** **** **** **** **** +14168 EnergyBall_Sonic **** **** **** **** **** **** **** **** +14169 PsychicVampire **** **** **** **** **** **** **** **** +14170 ClawofEnergyCold **** **** **** **** **** **** **** **** +14171 ClawofEnergyElec **** **** **** **** **** **** **** **** +14172 ClawofEnergyFire **** **** **** **** **** **** **** **** +14173 Immovability **** **** **** **** **** **** **** **** +14174 Truevenom **** **** **** **** **** **** **** **** +14175 TruevenomWeapon **** **** **** **** **** **** **** **** +14176 WeaponofEnergyCold **** **** **** **** **** **** **** **** +14177 WeaponofEnergyElec **** **** **** **** **** **** **** **** +14178 WeaponofEnergyFire **** **** **** **** **** **** **** **** +14179 IntellectFortress **** **** **** **** **** **** **** **** +14180 RemoteViewing **** **** **** **** **** **** **** **** +14181 BaleTeleport **** **** **** **** **** **** **** **** +14182 EctoplasmicShambler **** **** **** **** **** **** **** **** +14183 Power_Resistance **** **** **** **** **** **** **** **** +14184 PsychicCrush **** **** **** **** **** **** **** **** +14185 TowerIronWill **** **** **** **** **** **** **** **** +14186 True_Seeing **** **** **** **** **** **** **** **** +14187 Catapsi **** **** **** **** **** **** **** **** +14188 ShatterMindBlank **** **** **** **** **** **** **** **** +14189 HailCrystals **** **** **** **** **** **** **** **** +14190 SecondChance **** **** **** **** **** **** **** **** +14191 Teleport_SelfOnly **** **** **** **** **** **** **** **** +14192 Teleport_Party **** **** **** **** **** **** **** **** +14193 EnergyCurrent_Cold **** **** **** **** **** **** **** **** +14194 EnergyCurrent_Elec **** **** **** **** **** **** **** **** +14195 EnergyCurrent_Fire **** **** **** **** **** **** **** **** +14196 EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +14197 PsionicRevivify **** **** **** **** **** **** **** **** +14198 Psychofeedback **** **** **** **** **** **** **** **** +14199 ClairtangentHand **** **** **** **** **** **** **** **** +14200 BreathBlackDragon **** **** **** **** **** **** **** **** +14201 Disintegrate **** **** **** **** **** **** **** **** +14202 Crystallize **** **** **** **** **** **** **** **** +14203 FuseFlesh **** **** **** **** **** **** **** **** +14204 Retrieve **** **** **** **** **** **** **** **** +14205 TemporalAcceleration **** **** **** **** **** **** **** **** +14206 Banishment **** **** **** **** **** **** **** **** +14207 GreatPrecognitionMain **** **** **** **** **** **** **** **** +14208 GreatPrecognitionAttack **** **** **** **** **** **** **** **** +14209 GreatPrecognitionDamage **** **** **** **** **** **** **** **** +14210 GreatPrecognitionSaves **** **** **** **** **** **** **** **** +14211 GreatPrecognitionSkills **** **** **** **** **** **** **** **** +14212 RestorationPsionic **** **** **** **** **** **** **** **** +14213 DispellingBuffer **** **** **** **** **** **** **** **** +14214 FormOfDoom **** **** **** **** **** **** **** **** +14215 NullPsionicsField **** **** **** **** **** **** **** **** +14216 RemoteViewTrap **** **** **** **** **** **** **** **** +14217 Cloud_Mind_Mass **** **** **** **** **** **** **** **** +14218 CrisisLife **** **** **** **** **** **** **** **** +14219 Decerebrate **** **** **** **** **** **** **** **** +14220 EnergyWaveCold **** **** **** **** **** **** **** **** +14221 EnergyWaveElec **** **** **** **** **** **** **** **** +14222 EnergyWaveFire **** **** **** **** **** **** **** **** +14223 EnergyWaveSonic **** **** **** **** **** **** **** **** +14224 Insanity **** **** **** **** **** **** **** **** +14225 Mind_BlankPersonal **** **** **** **** **** **** **** **** +14226 OakBody **** **** **** **** **** **** **** **** +14227 Ultrablast **** **** **** **** **** **** **** **** +14228 EvadeBurst **** **** **** **** **** **** **** **** +14229 MomentOfPrescienceAttack **** **** **** **** **** **** **** **** +14230 MomentOfPrescienceArmour **** **** **** **** **** **** **** **** +14231 MomentOfPrescienceSaves **** **** **** **** **** **** **** **** +14232 MomentOfPrescienceSkills **** **** **** **** **** **** **** **** +14233 EctoCocoonMass **** **** **** **** **** **** **** **** +14234 EtherealJaunt **** **** **** **** **** **** **** **** +14235 Reddopsi **** **** **** **** **** **** **** **** +14236 Sequester **** **** **** **** **** **** **** **** +14237 RecallDeath **** **** **** **** **** **** **** **** +14238 IronBody **** **** **** **** **** **** **** **** +14239 PsionicMind_Blank **** **** **** **** **** **** **** **** +14240 TrueMetabolism **** **** **** **** **** **** **** **** +14241 Shadow_Body **** **** **** **** **** **** **** **** +14242 AstralSeed **** **** **** **** **** **** **** **** +14243 TimeHopMass **** **** **** **** **** **** **** **** +14244 Hypercognition **** **** **** **** **** **** **** **** +14245 GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +14246 GreaterTeleport_Party **** **** **** **** **** **** **** **** +14247 Assimilate **** **** **** **** **** **** **** **** +14248 Etherealness **** **** **** **** **** **** **** **** +14249 Microcosm **** **** **** **** **** **** **** **** +14250 TimelessBody **** **** **** **** **** **** **** **** +14251 Genesis **** **** **** **** **** **** **** **** +14252 PsychicChirurgery_Repair **** **** **** **** **** **** **** **** +14253 TeleportationCircle_Visible **** **** **** **** **** **** **** **** +14254 TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +14255 PsychicChirurgery_Transfer_TODO **** **** **** **** **** **** **** **** +14256 TornadoBlast **** **** **** **** **** **** **** **** +14257 CallWeaponry **** **** **** **** **** **** **** **** +14258 Compression **** **** **** **** **** **** **** **** +14259 Expansion **** **** **** **** **** **** **** **** +14260 ControlObject **** **** **** **** **** **** **** **** +14261 MetaphysicalClaw **** **** **** **** **** **** **** **** +14262 MetaphysicalWeapon **** **** **** **** **** **** **** **** +14263 Prevenom **** **** **** **** **** **** **** **** +14264 PrevenomWeapon **** **** **** **** **** **** **** **** +14265 GripOfIron **** **** **** **** **** **** **** **** +14266 PsionicLionsCharge **** **** **** **** **** **** **** **** +14267 **** **** **** **** **** **** **** **** **** +14268 **** **** **** **** **** **** **** **** **** +14269 **** **** **** **** **** **** **** **** **** +14270 **** **** **** **** **** **** **** **** **** +14271 **** **** **** **** **** **** **** **** **** +14272 **** **** **** **** **** **** **** **** **** +14273 **** **** **** **** **** **** **** **** **** +14274 **** **** **** **** **** **** **** **** **** +14275 **** **** **** **** **** **** **** **** **** +14276 **** **** **** **** **** **** **** **** **** +14277 **** **** **** **** **** **** **** **** **** +14278 **** **** **** **** **** **** **** **** **** +14279 **** **** **** **** **** **** **** **** **** +14280 **** **** **** **** **** **** **** **** **** +14281 **** **** **** **** **** **** **** **** **** +14282 **** **** **** **** **** **** **** **** **** +14283 **** **** **** **** **** **** **** **** **** +14284 **** **** **** **** **** **** **** **** **** +14285 **** **** **** **** **** **** **** **** **** +14286 **** **** **** **** **** **** **** **** **** +14287 **** **** **** **** **** **** **** **** **** +14288 **** **** **** **** **** **** **** **** **** +14289 **** **** **** **** **** **** **** **** **** +14290 **** **** **** **** **** **** **** **** **** +14291 **** **** **** **** **** **** **** **** **** +14292 **** **** **** **** **** **** **** **** **** +14293 **** **** **** **** **** **** **** **** **** +14294 **** **** **** **** **** **** **** **** **** +14295 **** **** **** **** **** **** **** **** **** +14296 **** **** **** **** **** **** **** **** **** +14297 **** **** **** **** **** **** **** **** **** +14298 **** **** **** **** **** **** **** **** **** +14299 **** **** **** **** **** **** **** **** **** +14300 **** **** **** **** **** **** **** **** **** +14301 **** **** **** **** **** **** **** **** **** +14302 **** **** **** **** **** **** **** **** **** +14303 **** **** **** **** **** **** **** **** **** +14304 **** **** **** **** **** **** **** **** **** +14305 **** **** **** **** **** **** **** **** **** +14306 **** **** **** **** **** **** **** **** **** +14307 **** **** **** **** **** **** **** **** **** +14308 **** **** **** **** **** **** **** **** **** +14309 **** **** **** **** **** **** **** **** **** +14310 **** **** **** **** **** **** **** **** **** +14311 **** **** **** **** **** **** **** **** **** +14312 **** **** **** **** **** **** **** **** **** +14313 **** **** **** **** **** **** **** **** **** +14314 **** **** **** **** **** **** **** **** **** +14315 **** **** **** **** **** **** **** **** **** +14316 **** **** **** **** **** **** **** **** **** +14317 **** **** **** **** **** **** **** **** **** +14318 **** **** **** **** **** **** **** **** **** +14319 **** **** **** **** **** **** **** **** **** +14320 **** **** **** **** **** **** **** **** **** +14321 **** **** **** **** **** **** **** **** **** +14322 **** **** **** **** **** **** **** **** **** +14323 **** **** **** **** **** **** **** **** **** +14324 **** **** **** **** **** **** **** **** **** +14325 **** **** **** **** **** **** **** **** **** +14326 **** **** **** **** **** **** **** **** **** +14327 **** **** **** **** **** **** **** **** **** +14328 **** **** **** **** **** **** **** **** **** +14329 **** **** **** **** **** **** **** **** **** +14330 AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +14331 EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +14332 Precognition_RadialMaster **** **** **** **** **** **** **** **** +14333 EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +14334 EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +14335 EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +14336 Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +14337 EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +14338 EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +14339 EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +14340 EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +14341 Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +14342 EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +14343 Teleport_RadialMaster **** **** **** **** **** **** **** **** +14344 EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +14345 GreatPrecognition_RadialMaster **** **** **** **** **** **** **** **** +14346 EnergyWave_RadialMaster **** **** **** **** **** **** **** **** +14347 MomentOfPrescience_RadialMaster **** **** **** **** **** **** **** **** +14348 GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +14349 TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +14350 ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14351 WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14352 **** **** **** **** **** **** **** **** **** +14353 **** **** **** **** **** **** **** **** **** +14354 **** **** **** **** **** **** **** **** **** +14355 **** **** **** **** **** **** **** **** **** +14356 **** **** **** **** **** **** **** **** **** +14357 **** **** **** **** **** **** **** **** **** +14358 **** **** **** **** **** **** **** **** **** +14359 **** **** **** **** **** **** **** **** **** +14360 ####START_OF_PSI_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +14361 Psychic_Rogue_Bolt **** **** **** **** **** **** **** **** +14362 Psychic_Rogue_Burst **** **** **** **** **** **** **** **** +14363 Psychic_Rogue_Compression **** **** **** **** **** **** **** **** +14364 Psychic_Rogue_Conceal_Thoughts **** **** **** **** **** **** **** **** +14365 Psychic_Rogue_ControlObject **** **** **** **** **** **** **** **** +14366 Psychic_Rogue_CreateSound **** **** **** **** **** **** **** **** +14367 Psychic_Rogue_DefPrecog **** **** **** **** **** **** **** **** +14368 Psychic_Rogue_Disable **** **** **** **** **** **** **** **** +14369 Psychic_Rogue_Distract **** **** **** **** **** **** **** **** +14370 Psychic_Rogue_ElfSight **** **** **** **** **** **** **** **** +14371 Psychic_Rogue_Empathy **** **** **** **** **** **** **** **** +14372 Psychic_Rogue_EmptyMind **** **** **** **** **** **** **** **** +14373 Psychic_Rogue_EntanglingEctoplasm **** **** **** **** **** **** **** **** +14374 Psychic_Rogue_Far_Hand **** **** **** **** **** **** **** **** +14375 Psychic_Rogue_ForceScreen **** **** **** **** **** **** **** **** +14376 Psychic_Rogue_MyLight **** **** **** **** **** **** **** **** +14377 Psychic_Rogue_OffPrecog **** **** **** **** **** **** **** **** +14378 Psychic_Rogue_OffPresc **** **** **** **** **** **** **** **** +14379 Psychic_Rogue_Skate **** **** **** **** **** **** **** **** +14380 Psychic_Rogue_Vigor **** **** **** **** **** **** **** **** +14381 Psychic_Rogue_AnimalAffinity **** **** **** **** **** **** **** **** +14382 Psychic_Rogue_Aversion **** **** **** **** **** **** **** **** +14383 Psychic_Rogue_Body_Equilibrium **** **** **** **** **** **** **** **** +14384 Psychic_Rogue_Chameleon **** **** **** **** **** **** **** **** +14385 Psychic_Rogue_Cloud_Mind **** **** **** **** **** **** **** **** +14386 Psychic_Rogue_ConcealAmorpha **** **** **** **** **** **** **** **** +14387 Psychic_Rogue_ControlObject **** **** **** **** **** **** **** **** +14388 Psychic_Rogue_ControlSound **** **** **** **** **** **** **** **** +14389 Psychic_Rogue_Darkvision **** **** **** **** **** **** **** **** +14390 Psychic_Rogue_Knock **** **** **** **** **** **** **** **** +14391 Psychic_Rogue_ThoughtShield **** **** **** **** **** **** **** **** +14392 Psychic_Rogue_BodyAdjustment **** **** **** **** **** **** **** **** +14393 Psychic_Rogue_BodyPurification **** **** **** **** **** **** **** **** +14394 Psychic_Rogue_ControlAir **** **** **** **** **** **** **** **** +14395 Psychic_Rogue_DimensionSlide **** **** **** **** **** **** **** **** +14396 Psychic_Rogue_EscapeDetection **** **** **** **** **** **** **** **** +14397 Psychic_Rogue_Greater_Amorpha **** **** **** **** **** **** **** **** +14398 Psychic_Rogue_Hustle **** **** **** **** **** **** **** **** +14399 Psychic_Rogue_Keen_Edge **** **** **** **** **** **** **** **** +14400 Psychic_Rogue_MentalBarrier **** **** **** **** **** **** **** **** +14401 Psychic_Rogue_UbiqVision **** **** **** **** **** **** **** **** +14402 Psychic_Rogue_DimensionDoor_Master **** **** **** **** **** **** **** **** +14403 Psychic_Rogue_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +14404 Psychic_Rogue_DimensionDoor_Party **** **** **** **** **** **** **** **** +14405 Psychic_Rogue_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +14406 Psychic_Rogue_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +14407 Psychic_Rogue_Freedom_of_Movement **** **** **** **** **** **** **** **** +14408 Psychic_Rogue_SteadfastPercep **** **** **** **** **** **** **** **** +14409 Psychic_Rogue_TelekineticManeuver **** **** **** **** **** **** **** **** +14410 Psychic_Rogue_Power_Resistance **** **** **** **** **** **** **** **** +14411 Psychic_Rogue_RemoteViewing **** **** **** **** **** **** **** **** +14412 Psychic_Rogue_Retrieve **** **** **** **** **** **** **** **** +14413 Psychic_Rogue_PsionicRevivify **** **** **** **** **** **** **** **** +14414 Psychic_Rogue_True_Seeing **** **** **** **** **** **** **** **** +14415 Psion_AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +14416 Psion_AstralConstruct_Conversation **** **** **** **** **** **** **** **** +14417 Psion_AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +14418 Psion_AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +14419 Psion_AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +14420 Psion_AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +14421 Psion_BiteOfTheWolf **** **** **** **** **** **** **** **** +14422 Psion_Bolt **** **** **** **** **** **** **** **** +14423 Psion_Burst **** **** **** **** **** **** **** **** +14424 Psion_CallToMind **** **** **** **** **** **** **** **** +14425 Psion_CallWeaponry **** **** **** **** **** **** **** **** +14426 Psion_CharmPerson **** **** **** **** **** **** **** **** +14427 Psion_ClawsOfTheBeast **** **** **** **** **** **** **** **** +14428 Psion_Compression **** **** **** **** **** **** **** **** +14429 Psion_Conceal_Thoughts **** **** **** **** **** **** **** **** +14430 Psion_ControlObject **** **** **** **** **** **** **** **** +14431 Psion_CreateSound **** **** **** **** **** **** **** **** +14432 Psion_CrystalShard **** **** **** **** **** **** **** **** +14433 Psion_Daze **** **** **** **** **** **** **** **** +14434 Psion_Deceleration **** **** **** **** **** **** **** **** +14435 Psion_DefPrecog **** **** **** **** **** **** **** **** +14436 Psion_Demoralize **** **** **** **** **** **** **** **** +14437 Psion_DestinyDissonance **** **** **** **** **** **** **** **** +14438 Psion_Disable **** **** **** **** **** **** **** **** +14439 Psion_DissipatingTouch **** **** **** **** **** **** **** **** +14440 Psion_Distract **** **** **** **** **** **** **** **** +14441 Psion_Empathy **** **** **** **** **** **** **** **** +14442 Psion_EmptyMind **** **** **** **** **** **** **** **** +14443 Psion_EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +14444 Psion_EnergyRay_Cold **** **** **** **** **** **** **** **** +14445 Psion_EnergyRay_Elec **** **** **** **** **** **** **** **** +14446 Psion_EnergyRay_Fire **** **** **** **** **** **** **** **** +14447 Psion_EnergyRay_Sonic **** **** **** **** **** **** **** **** +14448 Psion_EntanglingEctoplasm **** **** **** **** **** **** **** **** +14449 Psion_Expansion **** **** **** **** **** **** **** **** +14450 Psion_Far_Hand **** **** **** **** **** **** **** **** +14451 Psion_ForceScreen **** **** **** **** **** **** **** **** +14452 Psion_Grease **** **** **** **** **** **** **** **** +14453 Psion_Hammer **** **** **** **** **** **** **** **** +14454 Psion_InertialArmour **** **** **** **** **** **** **** **** +14455 Psion_Matter_Agitation **** **** **** **** **** **** **** **** +14456 Psion_MetaphysicalClaw **** **** **** **** **** **** **** **** +14457 Psion_MetaphysicalWeapon **** **** **** **** **** **** **** **** +14458 Psion_MindThrust **** **** **** **** **** **** **** **** +14459 Psion_MyLight **** **** **** **** **** **** **** **** +14460 Psion_OffPrecog **** **** **** **** **** **** **** **** +14461 Psion_OffPresc **** **** **** **** **** **** **** **** +14462 Psion_Precognition_RadialMaster **** **** **** **** **** **** **** **** +14463 Psion_PrecognitionMain **** **** **** **** **** **** **** **** +14464 Psion_PrecognitionAttack **** **** **** **** **** **** **** **** +14465 Psion_PrecognitionDamage **** **** **** **** **** **** **** **** +14466 Psion_PrecognitionSaves **** **** **** **** **** **** **** **** +14467 Psion_PrecognitionSkills **** **** **** **** **** **** **** **** +14468 Psion_Prevenom **** **** **** **** **** **** **** **** +14469 Psion_PrevenomWeapon **** **** **** **** **** **** **** **** +14470 Psion_Skate **** **** **** **** **** **** **** **** +14471 Psion_Stomp **** **** **** **** **** **** **** **** +14472 Psion_Synesthete **** **** **** **** **** **** **** **** +14473 Psion_Telempathic_Projection **** **** **** **** **** **** **** **** +14474 Psion_ThickSkin **** **** **** **** **** **** **** **** +14475 Psion_Vigor **** **** **** **** **** **** **** **** +14476 Psion_AnimalAffinity **** **** **** **** **** **** **** **** +14477 Psion_Aversion **** **** **** **** **** **** **** **** +14478 Psion_BestowPower **** **** **** **** **** **** **** **** +14479 Psion_Biofeedback **** **** **** **** **** **** **** **** +14480 Psion_Body_Equilibrium **** **** **** **** **** **** **** **** +14481 Psion_BrainLock **** **** **** **** **** **** **** **** +14482 Psion_Chameleon **** **** **** **** **** **** **** **** +14483 Psion_ClairvoyantSense **** **** **** **** **** **** **** **** +14484 Psion_Cloud_Mind **** **** **** **** **** **** **** **** +14485 Psion_ConcBlast **** **** **** **** **** **** **** **** +14486 Psion_ConcealAmorpha **** **** **** **** **** **** **** **** +14487 Psion_ControlAir **** **** **** **** **** **** **** **** +14488 Psion_ControlSound **** **** **** **** **** **** **** **** +14489 Psion_SwarmOfCrystals **** **** **** **** **** **** **** **** +14490 Psion_DimensionSwap **** **** **** **** **** **** **** **** +14491 Psion_DissolvingTouch **** **** **** **** **** **** **** **** +14492 Psion_Dissolving_Weapon **** **** **** **** **** **** **** **** +14493 Psion_EgoWhip **** **** **** **** **** **** **** **** +14494 Psion_ElfSight **** **** **** **** **** **** **** **** +14495 Psion_EmpathicTransfer **** **** **** **** **** **** **** **** +14496 Psion_EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +14497 Psion_EnergyAdaptAcid **** **** **** **** **** **** **** **** +14498 Psion_EnergyAdaptCold **** **** **** **** **** **** **** **** +14499 Psion_EnergyAdaptElec **** **** **** **** **** **** **** **** +14500 Psion_EnergyAdaptFire **** **** **** **** **** **** **** **** +14501 Psion_EnergyAdaptSonic **** **** **** **** **** **** **** **** +14502 Psion_Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +14503 Psion_Energy_Missile_Cold **** **** **** **** **** **** **** **** +14504 Psion_Energy_Missile_Elec **** **** **** **** **** **** **** **** +14505 Psion_Energy_Missile_Fire **** **** **** **** **** **** **** **** +14506 Psion_Energy_Missile_Sonic **** **** **** **** **** **** **** **** +14507 Psion_EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +14508 Psion_EnergyPush_Cold **** **** **** **** **** **** **** **** +14509 Psion_EnergyPush_Elec **** **** **** **** **** **** **** **** +14510 Psion_EnergyPush_Fire **** **** **** **** **** **** **** **** +14511 Psion_EnergyPush_Sonic **** **** **** **** **** **** **** **** +14512 Psion_EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +14513 Psion_EnergyStun_Cold **** **** **** **** **** **** **** **** +14514 Psion_EnergyStun_Elec **** **** **** **** **** **** **** **** +14515 Psion_EnergyStun_Fire **** **** **** **** **** **** **** **** +14516 Psion_EnergyStun_Sonic **** **** **** **** **** **** **** **** +14517 Psion_Identify **** **** **** **** **** **** **** **** +14518 Psion_IdInsinuation **** **** **** **** **** **** **** **** +14519 Psion_InflictPain **** **** **** **** **** **** **** **** +14520 Psion_Knock **** **** **** **** **** **** **** **** +14521 Psion_Lock **** **** **** **** **** **** **** **** +14522 Psion_MindDisrupt **** **** **** **** **** **** **** **** +14523 Psion_PainfulStrike **** **** **** **** **** **** **** **** +14524 Psion_RecallAgony **** **** **** **** **** **** **** **** +14525 Psion_RepairDamage **** **** **** **** **** **** **** **** +14526 Psion_SharePain **** **** **** **** **** **** **** **** +14527 Psion_StrengthOfMyEnemy **** **** **** **** **** **** **** **** +14528 Psion_ThoughtShield **** **** **** **** **** **** **** **** +14529 Psion_BodyAdjustment **** **** **** **** **** **** **** **** +14530 Psion_BodyPurification **** **** **** **** **** **** **** **** +14531 Psion_ClawOfTheVampire **** **** **** **** **** **** **** **** +14532 Psion_CrisisBreath **** **** **** **** **** **** **** **** +14533 Psion_Danger_Sense **** **** **** **** **** **** **** **** +14534 Psion_Darkvision **** **** **** **** **** **** **** **** +14535 Psion_DimensionSlide **** **** **** **** **** **** **** **** +14536 Psion_Dispel_Psionics **** **** **** **** **** **** **** **** +14537 Psion_DuodimensionalClaw **** **** **** **** **** **** **** **** +14538 Psion_EctoCocoon **** **** **** **** **** **** **** **** +14539 Psion_EctoplasmicForm **** **** **** **** **** **** **** **** +14540 Psion_EmpathicTransferHostile **** **** **** **** **** **** **** **** +14541 Psion_EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +14542 Psion_Energy_Bolt_Cold **** **** **** **** **** **** **** **** +14543 Psion_Energy_Bolt_Elec **** **** **** **** **** **** **** **** +14544 Psion_Energy_Bolt_Fire **** **** **** **** **** **** **** **** +14545 Psion_Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +14546 Psion_EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +14547 Psion_Energy_Burst_Cold **** **** **** **** **** **** **** **** +14548 Psion_Energy_Burst_Elec **** **** **** **** **** **** **** **** +14549 Psion_Energy_Burst_Fire **** **** **** **** **** **** **** **** +14550 Psion_Energy_Burst_Sonic **** **** **** **** **** **** **** **** +14551 Psion_Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +14552 Psion_EnergyCone_Cold **** **** **** **** **** **** **** **** +14553 Psion_EnergyCone_Elec **** **** **** **** **** **** **** **** +14554 Psion_EnergyCone_Fire **** **** **** **** **** **** **** **** +14555 Psion_EnergyCone_Sonic **** **** **** **** **** **** **** **** +14556 Psion_EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +14557 Psion_Energy_Retort_Cold **** **** **** **** **** **** **** **** +14558 Psion_Energy_Retort_Elec **** **** **** **** **** **** **** **** +14559 Psion_Energy_Retort_Fire **** **** **** **** **** **** **** **** +14560 Psion_Energy_Retort_Sonic **** **** **** **** **** **** **** **** +14561 Psion_EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +14562 Psion_Energy_Wall_Cold **** **** **** **** **** **** **** **** +14563 Psion_Energy_Wall_Elec **** **** **** **** **** **** **** **** +14564 Psion_Energy_Wall_Fire **** **** **** **** **** **** **** **** +14565 Psion_Energy_Wall_Sonic **** **** **** **** **** **** **** **** +14566 Psion_Eradicate_Invisibility **** **** **** **** **** **** **** **** +14567 Psion_EscapeDetection **** **** **** **** **** **** **** **** +14568 Psion_Exhale_BlackDrag **** **** **** **** **** **** **** **** +14569 Psion_FateLink **** **** **** **** **** **** **** **** +14570 Psion_Greater_Amorpha **** **** **** **** **** **** **** **** +14571 Psion_Hustle **** **** **** **** **** **** **** **** +14572 Psion_Keen_Edge **** **** **** **** **** **** **** **** +14573 Psion_MentalBarrier **** **** **** **** **** **** **** **** +14574 Psion_Mindtrap **** **** **** **** **** **** **** **** +14575 Psion_Psiblast **** **** **** **** **** **** **** **** +14576 Psion_SharePainForced **** **** **** **** **** **** **** **** +14577 Psion_TimeHop **** **** **** **** **** **** **** **** +14578 Psion_Touchsight **** **** **** **** **** **** **** **** +14579 Psion_UbiqVision **** **** **** **** **** **** **** **** +14580 Psion_VampiricWeapon **** **** **** **** **** **** **** **** +14581 Psion_ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14582 Psion_ClawofEnergyCold **** **** **** **** **** **** **** **** +14583 Psion_ClawofEnergyElec **** **** **** **** **** **** **** **** +14584 Psion_ClawofEnergyFire **** **** **** **** **** **** **** **** +14585 Psion_DetectRemoteViewing **** **** **** **** **** **** **** **** +14586 Psion_DimensionalAnchor **** **** **** **** **** **** **** **** +14587 Psion_DimensionDoor_Master **** **** **** **** **** **** **** **** +14588 Psion_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +14589 Psion_DimensionDoor_Party **** **** **** **** **** **** **** **** +14590 Psion_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +14591 Psion_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +14592 Psion_Dismissal **** **** **** **** **** **** **** **** +14593 Psion_EmpathicFeedback **** **** **** **** **** **** **** **** +14594 Psion_EnergyAdaption **** **** **** **** **** **** **** **** +14595 Psion_EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +14596 Psion_EnergyBall_Cold **** **** **** **** **** **** **** **** +14597 Psion_EnergyBall_Elec **** **** **** **** **** **** **** **** +14598 Psion_EnergyBall_Fire **** **** **** **** **** **** **** **** +14599 Psion_EnergyBall_Sonic **** **** **** **** **** **** **** **** +14600 Psion_Freedom_of_Movement **** **** **** **** **** **** **** **** +14601 Psion_Immovability **** **** **** **** **** **** **** **** +14602 Psion_InertialBar **** **** **** **** **** **** **** **** +14603 Psion_IntellectFortress **** **** **** **** **** **** **** **** +14604 Psion_Mindwipe **** **** **** **** **** **** **** **** +14605 Psion_PowerLeech **** **** **** **** **** **** **** **** +14606 Psion_Dominate_Psionic **** **** **** **** **** **** **** **** +14607 Psion_PsychicReformation **** **** **** **** **** **** **** **** +14608 Psion_PsychicVampire **** **** **** **** **** **** **** **** +14609 Psion_RemoteViewing **** **** **** **** **** **** **** **** +14610 Psion_SteadfastPercep **** **** **** **** **** **** **** **** +14611 Psion_TelekineticManeuver **** **** **** **** **** **** **** **** +14612 Psion_Truevenom **** **** **** **** **** **** **** **** +14613 Psion_TruevenomWeapon **** **** **** **** **** **** **** **** +14614 Psion_WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14615 Psion_WeaponofEnergyCold **** **** **** **** **** **** **** **** +14616 Psion_WeaponofEnergyElec **** **** **** **** **** **** **** **** +14617 Psion_WeaponofEnergyFire **** **** **** **** **** **** **** **** +14618 Psion_BaleTeleport **** **** **** **** **** **** **** **** +14619 Psion_Catapsi **** **** **** **** **** **** **** **** +14620 Psion_ClairtangentHand **** **** **** **** **** **** **** **** +14621 Psion_EctoplasmicShambler **** **** **** **** **** **** **** **** +14622 Psion_EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +14623 Psion_EnergyCurrent_Cold **** **** **** **** **** **** **** **** +14624 Psion_EnergyCurrent_Elec **** **** **** **** **** **** **** **** +14625 Psion_EnergyCurrent_Fire **** **** **** **** **** **** **** **** +14626 Psion_EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +14627 Psion_HailCrystals **** **** **** **** **** **** **** **** +14628 Psion_Power_Resistance **** **** **** **** **** **** **** **** +14629 Psion_PsionicRevivify **** **** **** **** **** **** **** **** +14630 Psion_PsychicCrush **** **** **** **** **** **** **** **** +14631 Psion_Psychofeedback **** **** **** **** **** **** **** **** +14632 Psion_SecondChance **** **** **** **** **** **** **** **** +14633 Psion_ShatterMindBlank **** **** **** **** **** **** **** **** +14634 Psion_Teleport_RadialMaster **** **** **** **** **** **** **** **** +14635 Psion_Teleport_SelfOnly **** **** **** **** **** **** **** **** +14636 Psion_Teleport_Party **** **** **** **** **** **** **** **** +14637 Psion_TowerIronWill **** **** **** **** **** **** **** **** +14638 Psion_True_Seeing **** **** **** **** **** **** **** **** +14639 Psion_Banishment **** **** **** **** **** **** **** **** +14640 Psion_BreathBlackDragon **** **** **** **** **** **** **** **** +14641 Psion_Cloud_Mind_Mass **** **** **** **** **** **** **** **** +14642 Psion_Crystallize **** **** **** **** **** **** **** **** +14643 Psion_Disintegrate **** **** **** **** **** **** **** **** +14644 Psion_DispellingBuffer **** **** **** **** **** **** **** **** +14645 Psion_FormOfDoom **** **** **** **** **** **** **** **** +14646 Psion_FuseFlesh **** **** **** **** **** **** **** **** +14647 Psion_GreatPrecognition_RadialMaster **** **** **** **** **** **** **** **** +14648 Psion_GreatPrecognitionMain **** **** **** **** **** **** **** **** +14649 Psion_GreatPrecognitionAttack **** **** **** **** **** **** **** **** +14650 Psion_GreatPrecognitionDamage **** **** **** **** **** **** **** **** +14651 Psion_GreatPrecognitionSaves **** **** **** **** **** **** **** **** +14652 Psion_GreatPrecognitionSkills **** **** **** **** **** **** **** **** +14653 Psion_NullPsionicsField **** **** **** **** **** **** **** **** +14654 Psion_RemoteViewTrap **** **** **** **** **** **** **** **** +14655 Psion_RestorationPsionic **** **** **** **** **** **** **** **** +14656 Psion_Retrieve **** **** **** **** **** **** **** **** +14657 Psion_TemporalAcceleration **** **** **** **** **** **** **** **** +14658 Psion_CrisisLife **** **** **** **** **** **** **** **** +14659 Psion_Decerebrate **** **** **** **** **** **** **** **** +14660 Psion_EctoCocoonMass **** **** **** **** **** **** **** **** +14661 Psion_EnergyWave_RadialMaster **** **** **** **** **** **** **** **** +14662 Psion_EnergyWaveCold **** **** **** **** **** **** **** **** +14663 Psion_EnergyWaveElec **** **** **** **** **** **** **** **** +14664 Psion_EnergyWaveFire **** **** **** **** **** **** **** **** +14665 Psion_EnergyWaveSonic **** **** **** **** **** **** **** **** +14666 Psion_EtherealJaunt **** **** **** **** **** **** **** **** +14667 Psion_EvadeBurst **** **** **** **** **** **** **** **** +14668 Psion_Insanity **** **** **** **** **** **** **** **** +14669 Psion_Mind_BlankPersonal **** **** **** **** **** **** **** **** +14670 Psion_MomentOfPrescience_RadialMaster **** **** **** **** **** **** **** **** +14671 Psion_MomentOfPrescienceAttack **** **** **** **** **** **** **** **** +14672 Psion_MomentOfPrescienceArmour **** **** **** **** **** **** **** **** +14673 Psion_MomentOfPrescienceSaves **** **** **** **** **** **** **** **** +14674 Psion_MomentOfPrescienceSkills **** **** **** **** **** **** **** **** +14675 Psion_OakBody **** **** **** **** **** **** **** **** +14676 Psion_Reddopsi **** **** **** **** **** **** **** **** +14677 Psion_Sequester **** **** **** **** **** **** **** **** +14678 Psion_Ultrablast **** **** **** **** **** **** **** **** +14679 Psion_AstralSeed **** **** **** **** **** **** **** **** +14680 Psion_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +14681 Psion_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +14682 Psion_GreaterTeleport_Party **** **** **** **** **** **** **** **** +14683 Psion_Hypercognition **** **** **** **** **** **** **** **** +14684 Psion_IronBody **** **** **** **** **** **** **** **** +14685 Psion_PsionicMind_Blank **** **** **** **** **** **** **** **** +14686 Psion_RecallDeath **** **** **** **** **** **** **** **** +14687 Psion_Shadow_Body **** **** **** **** **** **** **** **** +14688 Psion_TimeHopMass **** **** **** **** **** **** **** **** +14689 Psion_TrueMetabolism **** **** **** **** **** **** **** **** +14690 Psion_Assimilate **** **** **** **** **** **** **** **** +14691 Psion_Etherealness **** **** **** **** **** **** **** **** +14692 Psion_Genesis **** **** **** **** **** **** **** **** +14693 Psion_Microcosm **** **** **** **** **** **** **** **** +14694 Psion_PsychicChirurgery_Repair **** **** **** **** **** **** **** **** +14695 Psion_TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +14696 Psion_TeleportationCircle_Visible **** **** **** **** **** **** **** **** +14697 Psion_TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +14698 Psion_TimelessBody **** **** **** **** **** **** **** **** +14699 Psion_TornadoBlast **** **** **** **** **** **** **** **** +14700 Psychic_Warrior_AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +14701 Psychic_Warrior_AstralConstruct_Conversation **** **** **** **** **** **** **** **** +14702 Psychic_Warrior_AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +14703 Psychic_Warrior_AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +14704 Psychic_Warrior_AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +14705 Psychic_Warrior_AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +14706 Psychic_Warrior_Biofeedback **** **** **** **** **** **** **** **** +14707 Psychic_Warrior_BiteOfTheWolf **** **** **** **** **** **** **** **** +14708 Psychic_Warrior_Bolt **** **** **** **** **** **** **** **** +14709 Psychic_Warrior_Burst **** **** **** **** **** **** **** **** +14710 Psychic_Warrior_CallToMind **** **** **** **** **** **** **** **** +14711 Psychic_Warrior_CallWeaponry **** **** **** **** **** **** **** **** +14712 Psychic_Warrior_Chameleon **** **** **** **** **** **** **** **** +14713 Psychic_Warrior_CharmPerson **** **** **** **** **** **** **** **** +14714 Psychic_Warrior_ClawsOfTheBeast **** **** **** **** **** **** **** **** +14715 Psychic_Warrior_Compression **** **** **** **** **** **** **** **** +14716 Psychic_Warrior_Conceal_Thoughts **** **** **** **** **** **** **** **** +14717 Psychic_Warrior_ControlObject **** **** **** **** **** **** **** **** +14718 Psychic_Warrior_CreateSound **** **** **** **** **** **** **** **** +14719 Psychic_Warrior_CrystalShard **** **** **** **** **** **** **** **** +14720 Psychic_Warrior_Daze **** **** **** **** **** **** **** **** +14721 Psychic_Warrior_Deceleration **** **** **** **** **** **** **** **** +14722 Psychic_Warrior_DefPrecog **** **** **** **** **** **** **** **** +14723 Psychic_Warrior_Demoralize **** **** **** **** **** **** **** **** +14724 Psychic_Warrior_DestinyDissonance **** **** **** **** **** **** **** **** +14725 Psychic_Warrior_Disable **** **** **** **** **** **** **** **** +14726 Psychic_Warrior_DissipatingTouch **** **** **** **** **** **** **** **** +14727 Psychic_Warrior_Distract **** **** **** **** **** **** **** **** +14728 Psychic_Warrior_ElfSight **** **** **** **** **** **** **** **** +14729 Psychic_Warrior_Empathy **** **** **** **** **** **** **** **** +14730 Psychic_Warrior_EmptyMind **** **** **** **** **** **** **** **** +14731 Psychic_Warrior_EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +14732 Psychic_Warrior_EnergyRay_Cold **** **** **** **** **** **** **** **** +14733 Psychic_Warrior_EnergyRay_Elec **** **** **** **** **** **** **** **** +14734 Psychic_Warrior_EnergyRay_Fire **** **** **** **** **** **** **** **** +14735 Psychic_Warrior_EnergyRay_Sonic **** **** **** **** **** **** **** **** +14736 Psychic_Warrior_EntanglingEctoplasm **** **** **** **** **** **** **** **** +14737 Psychic_Warrior_Expansion **** **** **** **** **** **** **** **** +14738 Psychic_Warrior_Far_Hand **** **** **** **** **** **** **** **** +14739 Psychic_Warrior_ForceScreen **** **** **** **** **** **** **** **** +14740 Psychic_Warrior_Grease **** **** **** **** **** **** **** **** +14741 Psychic_Warrior_Hammer **** **** **** **** **** **** **** **** +14742 Psychic_Warrior_InertialArmour **** **** **** **** **** **** **** **** +14743 Psychic_Warrior_Matter_Agitation **** **** **** **** **** **** **** **** +14744 Psychic_Warrior_MetaphysicalClaw **** **** **** **** **** **** **** **** +14745 Psychic_Warrior_MetaphysicalWeapon **** **** **** **** **** **** **** **** +14746 Psychic_Warrior_MindThrust **** **** **** **** **** **** **** **** +14747 Psychic_Warrior_MyLight **** **** **** **** **** **** **** **** +14748 Psychic_Warrior_OffPrecog **** **** **** **** **** **** **** **** +14749 Psychic_Warrior_OffPresc **** **** **** **** **** **** **** **** +14750 Psychic_Warrior_Precognition_RadialMaster **** **** **** **** **** **** **** **** +14751 Psychic_Warrior_PrecognitionMain **** **** **** **** **** **** **** **** +14752 Psychic_Warrior_PrecognitionAttack **** **** **** **** **** **** **** **** +14753 Psychic_Warrior_PrecognitionDamage **** **** **** **** **** **** **** **** +14754 Psychic_Warrior_PrecognitionSaves **** **** **** **** **** **** **** **** +14755 Psychic_Warrior_PrecognitionSkills **** **** **** **** **** **** **** **** +14756 Psychic_Warrior_Prevenom **** **** **** **** **** **** **** **** +14757 Psychic_Warrior_PrevenomWeapon **** **** **** **** **** **** **** **** +14758 Psychic_Warrior_Skate **** **** **** **** **** **** **** **** +14759 Psychic_Warrior_Stomp **** **** **** **** **** **** **** **** +14760 Psychic_Warrior_Synesthete **** **** **** **** **** **** **** **** +14761 Psychic_Warrior_Telempathic_Projection **** **** **** **** **** **** **** **** +14762 Psychic_Warrior_ThickSkin **** **** **** **** **** **** **** **** +14763 Psychic_Warrior_Vigor **** **** **** **** **** **** **** **** +14764 Psychic_Warrior_AnimalAffinity **** **** **** **** **** **** **** **** +14765 Psychic_Warrior_Aversion **** **** **** **** **** **** **** **** +14766 Psychic_Warrior_BestowPower **** **** **** **** **** **** **** **** +14767 Psychic_Warrior_BodyAdjustment **** **** **** **** **** **** **** **** +14768 Psychic_Warrior_Body_Equilibrium **** **** **** **** **** **** **** **** +14769 Psychic_Warrior_BodyPurification **** **** **** **** **** **** **** **** +14770 Psychic_Warrior_BrainLock **** **** **** **** **** **** **** **** +14771 Psychic_Warrior_ClairvoyantSense **** **** **** **** **** **** **** **** +14772 Psychic_Warrior_Cloud_Mind **** **** **** **** **** **** **** **** +14773 Psychic_Warrior_ConcBlast **** **** **** **** **** **** **** **** +14774 Psychic_Warrior_ConcealAmorpha **** **** **** **** **** **** **** **** +14775 Psychic_Warrior_ControlAir **** **** **** **** **** **** **** **** +14776 Psychic_Warrior_ControlSound **** **** **** **** **** **** **** **** +14777 Psychic_Warrior_SwarmOfCrystals **** **** **** **** **** **** **** **** +14778 Psychic_Warrior_Darkvision **** **** **** **** **** **** **** **** +14779 Psychic_Warrior_DimensionSwap **** **** **** **** **** **** **** **** +14780 Psychic_Warrior_DissolvingTouch **** **** **** **** **** **** **** **** +14781 Psychic_Warrior_Dissolving_Weapon **** **** **** **** **** **** **** **** +14782 Psychic_Warrior_EgoWhip **** **** **** **** **** **** **** **** +14783 Psychic_Warrior_EmpathicTransfer **** **** **** **** **** **** **** **** +14784 Psychic_Warrior_EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +14785 Psychic_Warrior_EnergyAdaptAcid **** **** **** **** **** **** **** **** +14786 Psychic_Warrior_EnergyAdaptCold **** **** **** **** **** **** **** **** +14787 Psychic_Warrior_EnergyAdaptElec **** **** **** **** **** **** **** **** +14788 Psychic_Warrior_EnergyAdaptFire **** **** **** **** **** **** **** **** +14789 Psychic_Warrior_EnergyAdaptSonic **** **** **** **** **** **** **** **** +14790 Psychic_Warrior_Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +14791 Psychic_Warrior_Energy_Missile_Cold **** **** **** **** **** **** **** **** +14792 Psychic_Warrior_Energy_Missile_Elec **** **** **** **** **** **** **** **** +14793 Psychic_Warrior_Energy_Missile_Fire **** **** **** **** **** **** **** **** +14794 Psychic_Warrior_Energy_Missile_Sonic **** **** **** **** **** **** **** **** +14795 Psychic_Warrior_EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +14796 Psychic_Warrior_EnergyPush_Cold **** **** **** **** **** **** **** **** +14797 Psychic_Warrior_EnergyPush_Elec **** **** **** **** **** **** **** **** +14798 Psychic_Warrior_EnergyPush_Fire **** **** **** **** **** **** **** **** +14799 Psychic_Warrior_EnergyPush_Sonic **** **** **** **** **** **** **** **** +14800 Psychic_Warrior_EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +14801 Psychic_Warrior_EnergyStun_Cold **** **** **** **** **** **** **** **** +14802 Psychic_Warrior_EnergyStun_Elec **** **** **** **** **** **** **** **** +14803 Psychic_Warrior_EnergyStun_Fire **** **** **** **** **** **** **** **** +14804 Psychic_Warrior_EnergyStun_Sonic **** **** **** **** **** **** **** **** +14805 Psychic_Warrior_Hustle **** **** **** **** **** **** **** **** +14806 Psychic_Warrior_Identify **** **** **** **** **** **** **** **** +14807 Psychic_Warrior_IdInsinuation **** **** **** **** **** **** **** **** +14808 Psychic_Warrior_InflictPain **** **** **** **** **** **** **** **** +14809 Psychic_Warrior_Knock **** **** **** **** **** **** **** **** +14810 Psychic_Warrior_Lock **** **** **** **** **** **** **** **** +14811 Psychic_Warrior_MindDisrupt **** **** **** **** **** **** **** **** +14812 Psychic_Warrior_PainfulStrike **** **** **** **** **** **** **** **** +14813 Psychic_Warrior_RecallAgony **** **** **** **** **** **** **** **** +14814 Psychic_Warrior_RepairDamage **** **** **** **** **** **** **** **** +14815 Psychic_Warrior_SharePain **** **** **** **** **** **** **** **** +14816 Psychic_Warrior_StrengthOfMyEnemy **** **** **** **** **** **** **** **** +14817 Psychic_Warrior_ThoughtShield **** **** **** **** **** **** **** **** +14818 Psychic_Warrior_ClawOfTheVampire **** **** **** **** **** **** **** **** +14819 Psychic_Warrior_CrisisBreath **** **** **** **** **** **** **** **** +14820 Psychic_Warrior_Danger_Sense **** **** **** **** **** **** **** **** +14821 Psychic_Warrior_DimensionSlide **** **** **** **** **** **** **** **** +14822 Psychic_Warrior_Dispel_Psionics **** **** **** **** **** **** **** **** +14823 Psychic_Warrior_DuodimensionalClaw **** **** **** **** **** **** **** **** +14824 Psychic_Warrior_EctoCocoon **** **** **** **** **** **** **** **** +14825 Psychic_Warrior_EctoplasmicForm **** **** **** **** **** **** **** **** +14826 Psychic_Warrior_EmpathicFeedback **** **** **** **** **** **** **** **** +14827 Psychic_Warrior_EmpathicTransferHostile **** **** **** **** **** **** **** **** +14828 Psychic_Warrior_EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +14829 Psychic_Warrior_Energy_Bolt_Cold **** **** **** **** **** **** **** **** +14830 Psychic_Warrior_Energy_Bolt_Elec **** **** **** **** **** **** **** **** +14831 Psychic_Warrior_Energy_Bolt_Fire **** **** **** **** **** **** **** **** +14832 Psychic_Warrior_Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +14833 Psychic_Warrior_EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +14834 Psychic_Warrior_Energy_Burst_Cold **** **** **** **** **** **** **** **** +14835 Psychic_Warrior_Energy_Burst_Elec **** **** **** **** **** **** **** **** +14836 Psychic_Warrior_Energy_Burst_Fire **** **** **** **** **** **** **** **** +14837 Psychic_Warrior_Energy_Burst_Sonic **** **** **** **** **** **** **** **** +14838 Psychic_Warrior_Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +14839 Psychic_Warrior_EnergyCone_Cold **** **** **** **** **** **** **** **** +14840 Psychic_Warrior_EnergyCone_Elec **** **** **** **** **** **** **** **** +14841 Psychic_Warrior_EnergyCone_Fire **** **** **** **** **** **** **** **** +14842 Psychic_Warrior_EnergyCone_Sonic **** **** **** **** **** **** **** **** +14843 Psychic_Warrior_EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +14844 Psychic_Warrior_Energy_Retort_Cold **** **** **** **** **** **** **** **** +14845 Psychic_Warrior_Energy_Retort_Elec **** **** **** **** **** **** **** **** +14846 Psychic_Warrior_Energy_Retort_Fire **** **** **** **** **** **** **** **** +14847 Psychic_Warrior_Energy_Retort_Sonic **** **** **** **** **** **** **** **** +14848 Psychic_Warrior_EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +14849 Psychic_Warrior_Energy_Wall_Cold **** **** **** **** **** **** **** **** +14850 Psychic_Warrior_Energy_Wall_Elec **** **** **** **** **** **** **** **** +14851 Psychic_Warrior_Energy_Wall_Fire **** **** **** **** **** **** **** **** +14852 Psychic_Warrior_Energy_Wall_Sonic **** **** **** **** **** **** **** **** +14853 Psychic_Warrior_Eradicate_Invisibility **** **** **** **** **** **** **** **** +14854 Psychic_Warrior_EscapeDetection **** **** **** **** **** **** **** **** +14855 Psychic_Warrior_EvadeBurst **** **** **** **** **** **** **** **** +14856 Psychic_Warrior_Exhale_BlackDrag **** **** **** **** **** **** **** **** +14857 Psychic_Warrior_FateLink **** **** **** **** **** **** **** **** +14858 Psychic_Warrior_Greater_Amorpha **** **** **** **** **** **** **** **** +14859 Psychic_Warrior_Keen_Edge **** **** **** **** **** **** **** **** +14860 Psychic_Warrior_MentalBarrier **** **** **** **** **** **** **** **** +14861 Psychic_Warrior_Mindtrap **** **** **** **** **** **** **** **** +14862 Psychic_Warrior_Psiblast **** **** **** **** **** **** **** **** +14863 Psychic_Warrior_SharePainForced **** **** **** **** **** **** **** **** +14864 Psychic_Warrior_TimeHop **** **** **** **** **** **** **** **** +14865 Psychic_Warrior_Touchsight **** **** **** **** **** **** **** **** +14866 Psychic_Warrior_UbiqVision **** **** **** **** **** **** **** **** +14867 Psychic_Warrior_VampiricWeapon **** **** **** **** **** **** **** **** +14868 Psychic_Warrior_ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14869 Psychic_Warrior_ClawofEnergyCold **** **** **** **** **** **** **** **** +14870 Psychic_Warrior_ClawofEnergyElec **** **** **** **** **** **** **** **** +14871 Psychic_Warrior_ClawofEnergyFire **** **** **** **** **** **** **** **** +14872 Psychic_Warrior_DetectRemoteViewing **** **** **** **** **** **** **** **** +14873 Psychic_Warrior_DimensionalAnchor **** **** **** **** **** **** **** **** +14874 Psychic_Warrior_DimensionDoor_Master **** **** **** **** **** **** **** **** +14875 Psychic_Warrior_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +14876 Psychic_Warrior_DimensionDoor_Party **** **** **** **** **** **** **** **** +14877 Psychic_Warrior_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +14878 Psychic_Warrior_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +14879 Psychic_Warrior_Dismissal **** **** **** **** **** **** **** **** +14880 Psychic_Warrior_EnergyAdaption **** **** **** **** **** **** **** **** +14881 Psychic_Warrior_EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +14882 Psychic_Warrior_EnergyBall_Cold **** **** **** **** **** **** **** **** +14883 Psychic_Warrior_EnergyBall_Elec **** **** **** **** **** **** **** **** +14884 Psychic_Warrior_EnergyBall_Fire **** **** **** **** **** **** **** **** +14885 Psychic_Warrior_EnergyBall_Sonic **** **** **** **** **** **** **** **** +14886 Psychic_Warrior_Freedom_of_Movement **** **** **** **** **** **** **** **** +14887 Psychic_Warrior_Immovability **** **** **** **** **** **** **** **** +14888 Psychic_Warrior_InertialBar **** **** **** **** **** **** **** **** +14889 Psychic_Warrior_IntellectFortress **** **** **** **** **** **** **** **** +14890 Psychic_Warrior_Mindwipe **** **** **** **** **** **** **** **** +14891 Psychic_Warrior_PowerLeech **** **** **** **** **** **** **** **** +14892 Psychic_Warrior_Dominate_Psionic **** **** **** **** **** **** **** **** +14893 Psychic_Warrior_PsychicReformation **** **** **** **** **** **** **** **** +14894 Psychic_Warrior_PsychicVampire **** **** **** **** **** **** **** **** +14895 Psychic_Warrior_RemoteViewing **** **** **** **** **** **** **** **** +14896 Psychic_Warrior_SteadfastPercep **** **** **** **** **** **** **** **** +14897 Psychic_Warrior_TelekineticManeuver **** **** **** **** **** **** **** **** +14898 Psychic_Warrior_Truevenom **** **** **** **** **** **** **** **** +14899 Psychic_Warrior_TruevenomWeapon **** **** **** **** **** **** **** **** +14900 Psychic_Warrior_WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +14901 Psychic_Warrior_WeaponofEnergyCold **** **** **** **** **** **** **** **** +14902 Psychic_Warrior_WeaponofEnergyElec **** **** **** **** **** **** **** **** +14903 Psychic_Warrior_WeaponofEnergyFire **** **** **** **** **** **** **** **** +14904 Psychic_Warrior_BaleTeleport **** **** **** **** **** **** **** **** +14905 Psychic_Warrior_Catapsi **** **** **** **** **** **** **** **** +14906 Psychic_Warrior_ClairtangentHand **** **** **** **** **** **** **** **** +14907 Psychic_Warrior_EctoplasmicShambler **** **** **** **** **** **** **** **** +14908 Psychic_Warrior_EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +14909 Psychic_Warrior_EnergyCurrent_Cold **** **** **** **** **** **** **** **** +14910 Psychic_Warrior_EnergyCurrent_Elec **** **** **** **** **** **** **** **** +14911 Psychic_Warrior_EnergyCurrent_Fire **** **** **** **** **** **** **** **** +14912 Psychic_Warrior_EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +14913 Psychic_Warrior_HailCrystals **** **** **** **** **** **** **** **** +14914 Psychic_Warrior_OakBody **** **** **** **** **** **** **** **** +14915 Psychic_Warrior_Power_Resistance **** **** **** **** **** **** **** **** +14916 Psychic_Warrior_PsionicRevivify **** **** **** **** **** **** **** **** +14917 Psychic_Warrior_PsychicCrush **** **** **** **** **** **** **** **** +14918 Psychic_Warrior_Psychofeedback **** **** **** **** **** **** **** **** +14919 Psychic_Warrior_SecondChance **** **** **** **** **** **** **** **** +14920 Psychic_Warrior_ShatterMindBlank **** **** **** **** **** **** **** **** +14921 Psychic_Warrior_Teleport_RadialMaster **** **** **** **** **** **** **** **** +14922 Psychic_Warrior_Teleport_SelfOnly **** **** **** **** **** **** **** **** +14923 Psychic_Warrior_Teleport_Party **** **** **** **** **** **** **** **** +14924 Psychic_Warrior_TowerIronWill **** **** **** **** **** **** **** **** +14925 Psychic_Warrior_True_Seeing **** **** **** **** **** **** **** **** +14926 Psychic_Warrior_Banishment **** **** **** **** **** **** **** **** +14927 Psychic_Warrior_BreathBlackDragon **** **** **** **** **** **** **** **** +14928 Psychic_Warrior_Cloud_Mind_Mass **** **** **** **** **** **** **** **** +14929 Psychic_Warrior_Crystallize **** **** **** **** **** **** **** **** +14930 Psychic_Warrior_Disintegrate **** **** **** **** **** **** **** **** +14931 Psychic_Warrior_DispellingBuffer **** **** **** **** **** **** **** **** +14932 Psychic_Warrior_FormOfDoom **** **** **** **** **** **** **** **** +14933 Psychic_Warrior_FuseFlesh **** **** **** **** **** **** **** **** +14934 Psychic_Warrior_GreatPrecognition_RadialMaster **** **** **** **** **** **** **** **** +14935 Psychic_Warrior_GreatPrecognitionMain **** **** **** **** **** **** **** **** +14936 Psychic_Warrior_GreatPrecognitionAttack **** **** **** **** **** **** **** **** +14937 Psychic_Warrior_GreatPrecognitionDamage **** **** **** **** **** **** **** **** +14938 Psychic_Warrior_GreatPrecognitionSaves **** **** **** **** **** **** **** **** +14939 Psychic_Warrior_GreatPrecognitionSkills **** **** **** **** **** **** **** **** +14940 Psychic_Warrior_Mind_BlankPersonal **** **** **** **** **** **** **** **** +14941 Psychic_Warrior_NullPsionicsField **** **** **** **** **** **** **** **** +14942 Psychic_Warrior_RemoteViewTrap **** **** **** **** **** **** **** **** +14943 Psychic_Warrior_RestorationPsionic **** **** **** **** **** **** **** **** +14944 Psychic_Warrior_Retrieve **** **** **** **** **** **** **** **** +14945 Psychic_Warrior_TemporalAcceleration **** **** **** **** **** **** **** **** +14946 Wilder_AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +14947 Wilder_AstralConstruct_Conversation **** **** **** **** **** **** **** **** +14948 Wilder_AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +14949 Wilder_AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +14950 Wilder_AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +14951 Wilder_AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +14952 Wilder_BiteOfTheWolf **** **** **** **** **** **** **** **** +14953 Wilder_Bolt **** **** **** **** **** **** **** **** +14954 Wilder_Burst **** **** **** **** **** **** **** **** +14955 Wilder_CallToMind **** **** **** **** **** **** **** **** +14956 Wilder_CallWeaponry **** **** **** **** **** **** **** **** +14957 Wilder_CharmPerson **** **** **** **** **** **** **** **** +14958 Wilder_ClawsOfTheBeast **** **** **** **** **** **** **** **** +14959 Wilder_Compression **** **** **** **** **** **** **** **** +14960 Wilder_Conceal_Thoughts **** **** **** **** **** **** **** **** +14961 Wilder_ControlObject **** **** **** **** **** **** **** **** +14962 Wilder_CreateSound **** **** **** **** **** **** **** **** +14963 Wilder_CrystalShard **** **** **** **** **** **** **** **** +14964 Wilder_Daze **** **** **** **** **** **** **** **** +14965 Wilder_Deceleration **** **** **** **** **** **** **** **** +14966 Wilder_DefPrecog **** **** **** **** **** **** **** **** +14967 Wilder_Demoralize **** **** **** **** **** **** **** **** +14968 Wilder_DestinyDissonance **** **** **** **** **** **** **** **** +14969 Wilder_Disable **** **** **** **** **** **** **** **** +14970 Wilder_DissipatingTouch **** **** **** **** **** **** **** **** +14971 Wilder_Distract **** **** **** **** **** **** **** **** +14972 Wilder_Empathy **** **** **** **** **** **** **** **** +14973 Wilder_EmptyMind **** **** **** **** **** **** **** **** +14974 Wilder_EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +14975 Wilder_EnergyRay_Cold **** **** **** **** **** **** **** **** +14976 Wilder_EnergyRay_Elec **** **** **** **** **** **** **** **** +14977 Wilder_EnergyRay_Fire **** **** **** **** **** **** **** **** +14978 Wilder_EnergyRay_Sonic **** **** **** **** **** **** **** **** +14979 Wilder_EntanglingEctoplasm **** **** **** **** **** **** **** **** +14980 Wilder_Expansion **** **** **** **** **** **** **** **** +14981 Wilder_Far_Hand **** **** **** **** **** **** **** **** +14982 Wilder_ForceScreen **** **** **** **** **** **** **** **** +14983 Wilder_Grease **** **** **** **** **** **** **** **** +14984 Wilder_Hammer **** **** **** **** **** **** **** **** +14985 Wilder_InertialArmour **** **** **** **** **** **** **** **** +14986 Wilder_Matter_Agitation **** **** **** **** **** **** **** **** +14987 Wilder_MetaphysicalClaw **** **** **** **** **** **** **** **** +14988 Wilder_MetaphysicalWeapon **** **** **** **** **** **** **** **** +14989 Wilder_MindThrust **** **** **** **** **** **** **** **** +14990 Wilder_MyLight **** **** **** **** **** **** **** **** +14991 Wilder_OffPrecog **** **** **** **** **** **** **** **** +14992 Wilder_OffPresc **** **** **** **** **** **** **** **** +14993 Wilder_Precognition_RadialMaster **** **** **** **** **** **** **** **** +14994 Wilder_PrecognitionMain **** **** **** **** **** **** **** **** +14995 Wilder_PrecognitionAttack **** **** **** **** **** **** **** **** +14996 Wilder_PrecognitionDamage **** **** **** **** **** **** **** **** +14997 Wilder_PrecognitionSaves **** **** **** **** **** **** **** **** +14998 Wilder_PrecognitionSkills **** **** **** **** **** **** **** **** +14999 Wilder_Prevenom **** **** **** **** **** **** **** **** +15000 Wilder_PrevenomWeapon **** **** **** **** **** **** **** **** +15001 Wilder_Skate **** **** **** **** **** **** **** **** +15002 Wilder_Stomp **** **** **** **** **** **** **** **** +15003 Wilder_Synesthete **** **** **** **** **** **** **** **** +15004 Wilder_Telempathic_Projection **** **** **** **** **** **** **** **** +15005 Wilder_ThickSkin **** **** **** **** **** **** **** **** +15006 Wilder_Vigor **** **** **** **** **** **** **** **** +15007 Wilder_AnimalAffinity **** **** **** **** **** **** **** **** +15008 Wilder_Aversion **** **** **** **** **** **** **** **** +15009 Wilder_BestowPower **** **** **** **** **** **** **** **** +15010 Wilder_Biofeedback **** **** **** **** **** **** **** **** +15011 Wilder_Body_Equilibrium **** **** **** **** **** **** **** **** +15012 Wilder_BrainLock **** **** **** **** **** **** **** **** +15013 Wilder_Chameleon **** **** **** **** **** **** **** **** +15014 Wilder_ClairvoyantSense **** **** **** **** **** **** **** **** +15015 Wilder_Cloud_Mind **** **** **** **** **** **** **** **** +15016 Wilder_ConcBlast **** **** **** **** **** **** **** **** +15017 Wilder_ConcealAmorpha **** **** **** **** **** **** **** **** +15018 Wilder_ControlAir **** **** **** **** **** **** **** **** +15019 Wilder_ControlSound **** **** **** **** **** **** **** **** +15020 Wilder_SwarmOfCrystals **** **** **** **** **** **** **** **** +15021 Wilder_DimensionSwap **** **** **** **** **** **** **** **** +15022 Wilder_DissolvingTouch **** **** **** **** **** **** **** **** +15023 Wilder_Dissolving_Weapon **** **** **** **** **** **** **** **** +15024 Wilder_EgoWhip **** **** **** **** **** **** **** **** +15025 Wilder_ElfSight **** **** **** **** **** **** **** **** +15026 Wilder_EmpathicTransfer **** **** **** **** **** **** **** **** +15027 Wilder_EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +15028 Wilder_EnergyAdaptAcid **** **** **** **** **** **** **** **** +15029 Wilder_EnergyAdaptCold **** **** **** **** **** **** **** **** +15030 Wilder_EnergyAdaptElec **** **** **** **** **** **** **** **** +15031 Wilder_EnergyAdaptFire **** **** **** **** **** **** **** **** +15032 Wilder_EnergyAdaptSonic **** **** **** **** **** **** **** **** +15033 Wilder_Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +15034 Wilder_Energy_Missile_Cold **** **** **** **** **** **** **** **** +15035 Wilder_Energy_Missile_Elec **** **** **** **** **** **** **** **** +15036 Wilder_Energy_Missile_Fire **** **** **** **** **** **** **** **** +15037 Wilder_Energy_Missile_Sonic **** **** **** **** **** **** **** **** +15038 Wilder_EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +15039 Wilder_EnergyPush_Cold **** **** **** **** **** **** **** **** +15040 Wilder_EnergyPush_Elec **** **** **** **** **** **** **** **** +15041 Wilder_EnergyPush_Fire **** **** **** **** **** **** **** **** +15042 Wilder_EnergyPush_Sonic **** **** **** **** **** **** **** **** +15043 Wilder_EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +15044 Wilder_EnergyStun_Cold **** **** **** **** **** **** **** **** +15045 Wilder_EnergyStun_Elec **** **** **** **** **** **** **** **** +15046 Wilder_EnergyStun_Fire **** **** **** **** **** **** **** **** +15047 Wilder_EnergyStun_Sonic **** **** **** **** **** **** **** **** +15048 Wilder_Identify **** **** **** **** **** **** **** **** +15049 Wilder_IdInsinuation **** **** **** **** **** **** **** **** +15050 Wilder_InflictPain **** **** **** **** **** **** **** **** +15051 Wilder_Knock **** **** **** **** **** **** **** **** +15052 Wilder_Lock **** **** **** **** **** **** **** **** +15053 Wilder_MindDisrupt **** **** **** **** **** **** **** **** +15054 Wilder_PainfulStrike **** **** **** **** **** **** **** **** +15055 Wilder_RecallAgony **** **** **** **** **** **** **** **** +15056 Wilder_RepairDamage **** **** **** **** **** **** **** **** +15057 Wilder_SharePain **** **** **** **** **** **** **** **** +15058 Wilder_StrengthOfMyEnemy **** **** **** **** **** **** **** **** +15059 Wilder_ThoughtShield **** **** **** **** **** **** **** **** +15060 Wilder_BodyAdjustment **** **** **** **** **** **** **** **** +15061 Wilder_BodyPurification **** **** **** **** **** **** **** **** +15062 Wilder_ClawOfTheVampire **** **** **** **** **** **** **** **** +15063 Wilder_CrisisBreath **** **** **** **** **** **** **** **** +15064 Wilder_Danger_Sense **** **** **** **** **** **** **** **** +15065 Wilder_Darkvision **** **** **** **** **** **** **** **** +15066 Wilder_DimensionSlide **** **** **** **** **** **** **** **** +15067 Wilder_Dispel_Psionics **** **** **** **** **** **** **** **** +15068 Wilder_DuodimensionalClaw **** **** **** **** **** **** **** **** +15069 Wilder_EctoCocoon **** **** **** **** **** **** **** **** +15070 Wilder_EctoplasmicForm **** **** **** **** **** **** **** **** +15071 Wilder_EmpathicTransferHostile **** **** **** **** **** **** **** **** +15072 Wilder_EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +15073 Wilder_Energy_Bolt_Cold **** **** **** **** **** **** **** **** +15074 Wilder_Energy_Bolt_Elec **** **** **** **** **** **** **** **** +15075 Wilder_Energy_Bolt_Fire **** **** **** **** **** **** **** **** +15076 Wilder_Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +15077 Wilder_EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +15078 Wilder_Energy_Burst_Cold **** **** **** **** **** **** **** **** +15079 Wilder_Energy_Burst_Elec **** **** **** **** **** **** **** **** +15080 Wilder_Energy_Burst_Fire **** **** **** **** **** **** **** **** +15081 Wilder_Energy_Burst_Sonic **** **** **** **** **** **** **** **** +15082 Wilder_Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +15083 Wilder_EnergyCone_Cold **** **** **** **** **** **** **** **** +15084 Wilder_EnergyCone_Elec **** **** **** **** **** **** **** **** +15085 Wilder_EnergyCone_Fire **** **** **** **** **** **** **** **** +15086 Wilder_EnergyCone_Sonic **** **** **** **** **** **** **** **** +15087 Wilder_EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +15088 Wilder_Energy_Retort_Cold **** **** **** **** **** **** **** **** +15089 Wilder_Energy_Retort_Elec **** **** **** **** **** **** **** **** +15090 Wilder_Energy_Retort_Fire **** **** **** **** **** **** **** **** +15091 Wilder_Energy_Retort_Sonic **** **** **** **** **** **** **** **** +15092 Wilder_EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +15093 Wilder_Energy_Wall_Cold **** **** **** **** **** **** **** **** +15094 Wilder_Energy_Wall_Elec **** **** **** **** **** **** **** **** +15095 Wilder_Energy_Wall_Fire **** **** **** **** **** **** **** **** +15096 Wilder_Energy_Wall_Sonic **** **** **** **** **** **** **** **** +15097 Wilder_Eradicate_Invisibility **** **** **** **** **** **** **** **** +15098 Wilder_EscapeDetection **** **** **** **** **** **** **** **** +15099 Wilder_Exhale_BlackDrag **** **** **** **** **** **** **** **** +15100 Wilder_FateLink **** **** **** **** **** **** **** **** +15101 Wilder_Greater_Amorpha **** **** **** **** **** **** **** **** +15102 Wilder_Hustle **** **** **** **** **** **** **** **** +15103 Wilder_Keen_Edge **** **** **** **** **** **** **** **** +15104 Wilder_MentalBarrier **** **** **** **** **** **** **** **** +15105 Wilder_Mindtrap **** **** **** **** **** **** **** **** +15106 Wilder_Psiblast **** **** **** **** **** **** **** **** +15107 Wilder_SharePainForced **** **** **** **** **** **** **** **** +15108 Wilder_TimeHop **** **** **** **** **** **** **** **** +15109 Wilder_Touchsight **** **** **** **** **** **** **** **** +15110 Wilder_UbiqVision **** **** **** **** **** **** **** **** +15111 Wilder_VampiricWeapon **** **** **** **** **** **** **** **** +15112 Wilder_ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15113 Wilder_ClawofEnergyCold **** **** **** **** **** **** **** **** +15114 Wilder_ClawofEnergyElec **** **** **** **** **** **** **** **** +15115 Wilder_ClawofEnergyFire **** **** **** **** **** **** **** **** +15116 Wilder_DetectRemoteViewing **** **** **** **** **** **** **** **** +15117 Wilder_DimensionalAnchor **** **** **** **** **** **** **** **** +15118 Wilder_DimensionDoor_Master **** **** **** **** **** **** **** **** +15119 Wilder_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +15120 Wilder_DimensionDoor_Party **** **** **** **** **** **** **** **** +15121 Wilder_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +15122 Wilder_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +15123 Wilder_Dismissal **** **** **** **** **** **** **** **** +15124 Wilder_EmpathicFeedback **** **** **** **** **** **** **** **** +15125 Wilder_EnergyAdaption **** **** **** **** **** **** **** **** +15126 Wilder_EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +15127 Wilder_EnergyBall_Cold **** **** **** **** **** **** **** **** +15128 Wilder_EnergyBall_Elec **** **** **** **** **** **** **** **** +15129 Wilder_EnergyBall_Fire **** **** **** **** **** **** **** **** +15130 Wilder_EnergyBall_Sonic **** **** **** **** **** **** **** **** +15131 Wilder_Freedom_of_Movement **** **** **** **** **** **** **** **** +15132 Wilder_Immovability **** **** **** **** **** **** **** **** +15133 Wilder_InertialBar **** **** **** **** **** **** **** **** +15134 Wilder_IntellectFortress **** **** **** **** **** **** **** **** +15135 Wilder_Mindwipe **** **** **** **** **** **** **** **** +15136 Wilder_PowerLeech **** **** **** **** **** **** **** **** +15137 Wilder_Dominate_Psionic **** **** **** **** **** **** **** **** +15138 Wilder_PsychicReformation **** **** **** **** **** **** **** **** +15139 Wilder_PsychicVampire **** **** **** **** **** **** **** **** +15140 Wilder_RemoteViewing **** **** **** **** **** **** **** **** +15141 Wilder_SteadfastPercep **** **** **** **** **** **** **** **** +15142 Wilder_TelekineticManeuver **** **** **** **** **** **** **** **** +15143 Wilder_Truevenom **** **** **** **** **** **** **** **** +15144 Wilder_TruevenomWeapon **** **** **** **** **** **** **** **** +15145 Wilder_WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15146 Wilder_WeaponofEnergyCold **** **** **** **** **** **** **** **** +15147 Wilder_WeaponofEnergyElec **** **** **** **** **** **** **** **** +15148 Wilder_WeaponofEnergyFire **** **** **** **** **** **** **** **** +15149 Wilder_BaleTeleport **** **** **** **** **** **** **** **** +15150 Wilder_Catapsi **** **** **** **** **** **** **** **** +15151 Wilder_ClairtangentHand **** **** **** **** **** **** **** **** +15152 Wilder_EctoplasmicShambler **** **** **** **** **** **** **** **** +15153 Wilder_EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +15154 Wilder_EnergyCurrent_Cold **** **** **** **** **** **** **** **** +15155 Wilder_EnergyCurrent_Elec **** **** **** **** **** **** **** **** +15156 Wilder_EnergyCurrent_Fire **** **** **** **** **** **** **** **** +15157 Wilder_EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +15158 Wilder_HailCrystals **** **** **** **** **** **** **** **** +15159 Wilder_Power_Resistance **** **** **** **** **** **** **** **** +15160 Wilder_PsionicRevivify **** **** **** **** **** **** **** **** +15161 Wilder_PsychicCrush **** **** **** **** **** **** **** **** +15162 Wilder_Psychofeedback **** **** **** **** **** **** **** **** +15163 Wilder_SecondChance **** **** **** **** **** **** **** **** +15164 Wilder_ShatterMindBlank **** **** **** **** **** **** **** **** +15165 Wilder_Teleport_RadialMaster **** **** **** **** **** **** **** **** +15166 Wilder_Teleport_SelfOnly **** **** **** **** **** **** **** **** +15167 Wilder_Teleport_Party **** **** **** **** **** **** **** **** +15168 Wilder_TowerIronWill **** **** **** **** **** **** **** **** +15169 Wilder_True_Seeing **** **** **** **** **** **** **** **** +15170 Wilder_Banishment **** **** **** **** **** **** **** **** +15171 Wilder_BreathBlackDragon **** **** **** **** **** **** **** **** +15172 Wilder_Cloud_Mind_Mass **** **** **** **** **** **** **** **** +15173 Wilder_Crystallize **** **** **** **** **** **** **** **** +15174 Wilder_Disintegrate **** **** **** **** **** **** **** **** +15175 Wilder_DispellingBuffer **** **** **** **** **** **** **** **** +15176 Wilder_FormOfDoom **** **** **** **** **** **** **** **** +15177 Wilder_FuseFlesh **** **** **** **** **** **** **** **** +15178 Wilder_GreatPrecognition_RadialMaster **** **** **** **** **** **** **** **** +15179 Wilder_GreatPrecognitionMain **** **** **** **** **** **** **** **** +15180 Wilder_GreatPrecognitionAttack **** **** **** **** **** **** **** **** +15181 Wilder_GreatPrecognitionDamage **** **** **** **** **** **** **** **** +15182 Wilder_GreatPrecognitionSaves **** **** **** **** **** **** **** **** +15183 Wilder_GreatPrecognitionSkills **** **** **** **** **** **** **** **** +15184 Wilder_NullPsionicsField **** **** **** **** **** **** **** **** +15185 Wilder_RemoteViewTrap **** **** **** **** **** **** **** **** +15186 Wilder_RestorationPsionic **** **** **** **** **** **** **** **** +15187 Wilder_Retrieve **** **** **** **** **** **** **** **** +15188 Wilder_TemporalAcceleration **** **** **** **** **** **** **** **** +15189 Wilder_CrisisLife **** **** **** **** **** **** **** **** +15190 Wilder_Decerebrate **** **** **** **** **** **** **** **** +15191 Wilder_EctoCocoonMass **** **** **** **** **** **** **** **** +15192 Wilder_EnergyWave_RadialMaster **** **** **** **** **** **** **** **** +15193 Wilder_EnergyWaveCold **** **** **** **** **** **** **** **** +15194 Wilder_EnergyWaveElec **** **** **** **** **** **** **** **** +15195 Wilder_EnergyWaveFire **** **** **** **** **** **** **** **** +15196 Wilder_EnergyWaveSonic **** **** **** **** **** **** **** **** +15197 Wilder_EtherealJaunt **** **** **** **** **** **** **** **** +15198 Wilder_EvadeBurst **** **** **** **** **** **** **** **** +15199 Wilder_Insanity **** **** **** **** **** **** **** **** +15200 Wilder_Mind_BlankPersonal **** **** **** **** **** **** **** **** +15201 Wilder_MomentOfPrescience_RadialMaster **** **** **** **** **** **** **** **** +15202 Wilder_MomentOfPrescienceAttack **** **** **** **** **** **** **** **** +15203 Wilder_MomentOfPrescienceArmour **** **** **** **** **** **** **** **** +15204 Wilder_MomentOfPrescienceSaves **** **** **** **** **** **** **** **** +15205 Wilder_MomentOfPrescienceSkills **** **** **** **** **** **** **** **** +15206 Wilder_OakBody **** **** **** **** **** **** **** **** +15207 Wilder_Reddopsi **** **** **** **** **** **** **** **** +15208 Wilder_Sequester **** **** **** **** **** **** **** **** +15209 Wilder_Ultrablast **** **** **** **** **** **** **** **** +15210 Wilder_AstralSeed **** **** **** **** **** **** **** **** +15211 Wilder_GreaterTeleport_RadialMaster **** **** **** **** **** **** **** **** +15212 Wilder_GreaterTeleport_SelfOnly **** **** **** **** **** **** **** **** +15213 Wilder_GreaterTeleport_Party **** **** **** **** **** **** **** **** +15214 Wilder_Hypercognition **** **** **** **** **** **** **** **** +15215 Wilder_IronBody **** **** **** **** **** **** **** **** +15216 Wilder_PsionicMind_Blank **** **** **** **** **** **** **** **** +15217 Wilder_RecallDeath **** **** **** **** **** **** **** **** +15218 Wilder_Shadow_Body **** **** **** **** **** **** **** **** +15219 Wilder_TimeHopMass **** **** **** **** **** **** **** **** +15220 Wilder_TrueMetabolism **** **** **** **** **** **** **** **** +15221 Wilder_Assimilate **** **** **** **** **** **** **** **** +15222 Wilder_Etherealness **** **** **** **** **** **** **** **** +15223 Wilder_Genesis **** **** **** **** **** **** **** **** +15224 Wilder_Microcosm **** **** **** **** **** **** **** **** +15225 Wilder_PsychicChirurgery_Repair **** **** **** **** **** **** **** **** +15226 Wilder_TeleportationCircle_RadialMaster **** **** **** **** **** **** **** **** +15227 Wilder_TeleportationCircle_Visible **** **** **** **** **** **** **** **** +15228 Wilder_TeleportationCircle_Hidden **** **** **** **** **** **** **** **** +15229 Wilder_TimelessBody **** **** **** **** **** **** **** **** +15230 Wilder_TornadoBlast **** **** **** **** **** **** **** **** +15231 FistOfZouken_AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +15232 FistOfZouken_AstralConstruct_Conversation **** **** **** **** **** **** **** **** +15233 FistOfZouken_AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +15234 FistOfZouken_AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +15235 FistOfZouken_AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +15236 FistOfZouken_AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +15237 FistOfZouken_Biofeedback **** **** **** **** **** **** **** **** +15238 FistOfZouken_BiteOfTheWolf **** **** **** **** **** **** **** **** +15239 FistOfZouken_Bolt **** **** **** **** **** **** **** **** +15240 FistOfZouken_Burst **** **** **** **** **** **** **** **** +15241 FistOfZouken_CallToMind **** **** **** **** **** **** **** **** +15242 FistOfZouken_CallWeaponry **** **** **** **** **** **** **** **** +15243 FistOfZouken_Chameleon **** **** **** **** **** **** **** **** +15244 FistOfZouken_CharmPerson **** **** **** **** **** **** **** **** +15245 FistOfZouken_ClawsOfTheBeast **** **** **** **** **** **** **** **** +15246 FistOfZouken_Compression **** **** **** **** **** **** **** **** +15247 FistOfZouken_Conceal_Thoughts **** **** **** **** **** **** **** **** +15248 FistOfZouken_ControlObject **** **** **** **** **** **** **** **** +15249 FistOfZouken_CreateSound **** **** **** **** **** **** **** **** +15250 FistOfZouken_CrystalShard **** **** **** **** **** **** **** **** +15251 FistOfZouken_Daze **** **** **** **** **** **** **** **** +15252 FistOfZouken_Deceleration **** **** **** **** **** **** **** **** +15253 FistOfZouken_DefPrecog **** **** **** **** **** **** **** **** +15254 FistOfZouken_Demoralize **** **** **** **** **** **** **** **** +15255 FistOfZouken_DestinyDissonance **** **** **** **** **** **** **** **** +15256 FistOfZouken_Disable **** **** **** **** **** **** **** **** +15257 FistOfZouken_DissipatingTouch **** **** **** **** **** **** **** **** +15258 FistOfZouken_Distract **** **** **** **** **** **** **** **** +15259 FistOfZouken_ElfSight **** **** **** **** **** **** **** **** +15260 FistOfZouken_Empathy **** **** **** **** **** **** **** **** +15261 FistOfZouken_EmptyMind **** **** **** **** **** **** **** **** +15262 FistOfZouken_EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +15263 FistOfZouken_EnergyRay_Cold **** **** **** **** **** **** **** **** +15264 FistOfZouken_EnergyRay_Elec **** **** **** **** **** **** **** **** +15265 FistOfZouken_EnergyRay_Fire **** **** **** **** **** **** **** **** +15266 FistOfZouken_EnergyRay_Sonic **** **** **** **** **** **** **** **** +15267 FistOfZouken_EntanglingEctoplasm **** **** **** **** **** **** **** **** +15268 FistOfZouken_Expansion **** **** **** **** **** **** **** **** +15269 FistOfZouken_Far_Hand **** **** **** **** **** **** **** **** +15270 FistOfZouken_ForceScreen **** **** **** **** **** **** **** **** +15271 FistOfZouken_Grease **** **** **** **** **** **** **** **** +15272 FistOfZouken_Hammer **** **** **** **** **** **** **** **** +15273 FistOfZouken_InertialArmour **** **** **** **** **** **** **** **** +15274 FistOfZouken_Matter_Agitation **** **** **** **** **** **** **** **** +15275 FistOfZouken_MetaphysicalClaw **** **** **** **** **** **** **** **** +15276 FistOfZouken_MetaphysicalWeapon **** **** **** **** **** **** **** **** +15277 FistOfZouken_MindThrust **** **** **** **** **** **** **** **** +15278 FistOfZouken_MyLight **** **** **** **** **** **** **** **** +15279 FistOfZouken_OffPrecog **** **** **** **** **** **** **** **** +15280 FistOfZouken_OffPresc **** **** **** **** **** **** **** **** +15281 FistOfZouken_Precognition_RadialMaster **** **** **** **** **** **** **** **** +15282 FistOfZouken_PrecognitionMain **** **** **** **** **** **** **** **** +15283 FistOfZouken_PrecognitionAttack **** **** **** **** **** **** **** **** +15284 FistOfZouken_PrecognitionDamage **** **** **** **** **** **** **** **** +15285 FistOfZouken_PrecognitionSaves **** **** **** **** **** **** **** **** +15286 FistOfZouken_PrecognitionSkills **** **** **** **** **** **** **** **** +15287 FistOfZouken_Prevenom **** **** **** **** **** **** **** **** +15288 FistOfZouken_PrevenomWeapon **** **** **** **** **** **** **** **** +15289 FistOfZouken_Skate **** **** **** **** **** **** **** **** +15290 FistOfZouken_Stomp **** **** **** **** **** **** **** **** +15291 FistOfZouken_Synesthete **** **** **** **** **** **** **** **** +15292 FistOfZouken_Telempathic_Projection **** **** **** **** **** **** **** **** +15293 FistOfZouken_ThickSkin **** **** **** **** **** **** **** **** +15294 FistOfZouken_Vigor **** **** **** **** **** **** **** **** +15295 FistOfZouken_AnimalAffinity **** **** **** **** **** **** **** **** +15296 FistOfZouken_Aversion **** **** **** **** **** **** **** **** +15297 FistOfZouken_BestowPower **** **** **** **** **** **** **** **** +15298 FistOfZouken_BodyAdjustment **** **** **** **** **** **** **** **** +15299 FistOfZouken_Body_Equilibrium **** **** **** **** **** **** **** **** +15300 FistOfZouken_BodyPurification **** **** **** **** **** **** **** **** +15301 FistOfZouken_BrainLock **** **** **** **** **** **** **** **** +15302 FistOfZouken_ClairvoyantSense **** **** **** **** **** **** **** **** +15303 FistOfZouken_Cloud_Mind **** **** **** **** **** **** **** **** +15304 FistOfZouken_ConcBlast **** **** **** **** **** **** **** **** +15305 FistOfZouken_ConcealAmorpha **** **** **** **** **** **** **** **** +15306 FistOfZouken_ControlAir **** **** **** **** **** **** **** **** +15307 FistOfZouken_ControlSound **** **** **** **** **** **** **** **** +15308 FistOfZouken_SwarmOfCrystals **** **** **** **** **** **** **** **** +15309 FistOfZouken_Darkvision **** **** **** **** **** **** **** **** +15310 FistOfZouken_DimensionSwap **** **** **** **** **** **** **** **** +15311 FistOfZouken_DissolvingTouch **** **** **** **** **** **** **** **** +15312 FistOfZouken_Dissolving_Weapon **** **** **** **** **** **** **** **** +15313 FistOfZouken_EgoWhip **** **** **** **** **** **** **** **** +15314 FistOfZouken_EmpathicTransfer **** **** **** **** **** **** **** **** +15315 FistOfZouken_EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +15316 FistOfZouken_EnergyAdaptAcid **** **** **** **** **** **** **** **** +15317 FistOfZouken_EnergyAdaptCold **** **** **** **** **** **** **** **** +15318 FistOfZouken_EnergyAdaptElec **** **** **** **** **** **** **** **** +15319 FistOfZouken_EnergyAdaptFire **** **** **** **** **** **** **** **** +15320 FistOfZouken_EnergyAdaptSonic **** **** **** **** **** **** **** **** +15321 FistOfZouken_Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +15322 FistOfZouken_Energy_Missile_Cold **** **** **** **** **** **** **** **** +15323 FistOfZouken_Energy_Missile_Elec **** **** **** **** **** **** **** **** +15324 FistOfZouken_Energy_Missile_Fire **** **** **** **** **** **** **** **** +15325 FistOfZouken_Energy_Missile_Sonic **** **** **** **** **** **** **** **** +15326 FistOfZouken_EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +15327 FistOfZouken_EnergyPush_Cold **** **** **** **** **** **** **** **** +15328 FistOfZouken_EnergyPush_Elec **** **** **** **** **** **** **** **** +15329 FistOfZouken_EnergyPush_Fire **** **** **** **** **** **** **** **** +15330 FistOfZouken_EnergyPush_Sonic **** **** **** **** **** **** **** **** +15331 FistOfZouken_EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +15332 FistOfZouken_EnergyStun_Cold **** **** **** **** **** **** **** **** +15333 FistOfZouken_EnergyStun_Elec **** **** **** **** **** **** **** **** +15334 FistOfZouken_EnergyStun_Fire **** **** **** **** **** **** **** **** +15335 FistOfZouken_EnergyStun_Sonic **** **** **** **** **** **** **** **** +15336 FistOfZouken_Hustle **** **** **** **** **** **** **** **** +15337 FistOfZouken_Identify **** **** **** **** **** **** **** **** +15338 FistOfZouken_IdInsinuation **** **** **** **** **** **** **** **** +15339 FistOfZouken_InflictPain **** **** **** **** **** **** **** **** +15340 FistOfZouken_Knock **** **** **** **** **** **** **** **** +15341 FistOfZouken_Lock **** **** **** **** **** **** **** **** +15342 FistOfZouken_MindDisrupt **** **** **** **** **** **** **** **** +15343 FistOfZouken_PainfulStrike **** **** **** **** **** **** **** **** +15344 FistOfZouken_RecallAgony **** **** **** **** **** **** **** **** +15345 FistOfZouken_RepairDamage **** **** **** **** **** **** **** **** +15346 FistOfZouken_SharePain **** **** **** **** **** **** **** **** +15347 FistOfZouken_StrengthOfMyEnemy **** **** **** **** **** **** **** **** +15348 FistOfZouken_ThoughtShield **** **** **** **** **** **** **** **** +15349 FistOfZouken_ClawOfTheVampire **** **** **** **** **** **** **** **** +15350 FistOfZouken_CrisisBreath **** **** **** **** **** **** **** **** +15351 FistOfZouken_Danger_Sense **** **** **** **** **** **** **** **** +15352 FistOfZouken_DimensionSlide **** **** **** **** **** **** **** **** +15353 FistOfZouken_Dispel_Psionics **** **** **** **** **** **** **** **** +15354 FistOfZouken_DuodimensionalClaw **** **** **** **** **** **** **** **** +15355 FistOfZouken_EctoCocoon **** **** **** **** **** **** **** **** +15356 FistOfZouken_EctoplasmicForm **** **** **** **** **** **** **** **** +15357 FistOfZouken_EmpathicFeedback **** **** **** **** **** **** **** **** +15358 FistOfZouken_EmpathicTransferHostile **** **** **** **** **** **** **** **** +15359 FistOfZouken_EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +15360 FistOfZouken_Energy_Bolt_Cold **** **** **** **** **** **** **** **** +15361 FistOfZouken_Energy_Bolt_Elec **** **** **** **** **** **** **** **** +15362 FistOfZouken_Energy_Bolt_Fire **** **** **** **** **** **** **** **** +15363 FistOfZouken_Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +15364 FistOfZouken_EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +15365 FistOfZouken_Energy_Burst_Cold **** **** **** **** **** **** **** **** +15366 FistOfZouken_Energy_Burst_Elec **** **** **** **** **** **** **** **** +15367 FistOfZouken_Energy_Burst_Fire **** **** **** **** **** **** **** **** +15368 FistOfZouken_Energy_Burst_Sonic **** **** **** **** **** **** **** **** +15369 FistOfZouken_Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +15370 FistOfZouken_EnergyCone_Cold **** **** **** **** **** **** **** **** +15371 FistOfZouken_EnergyCone_Elec **** **** **** **** **** **** **** **** +15372 FistOfZouken_EnergyCone_Fire **** **** **** **** **** **** **** **** +15373 FistOfZouken_EnergyCone_Sonic **** **** **** **** **** **** **** **** +15374 FistOfZouken_EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +15375 FistOfZouken_Energy_Retort_Cold **** **** **** **** **** **** **** **** +15376 FistOfZouken_Energy_Retort_Elec **** **** **** **** **** **** **** **** +15377 FistOfZouken_Energy_Retort_Fire **** **** **** **** **** **** **** **** +15378 FistOfZouken_Energy_Retort_Sonic **** **** **** **** **** **** **** **** +15379 FistOfZouken_EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +15380 FistOfZouken_Energy_Wall_Cold **** **** **** **** **** **** **** **** +15381 FistOfZouken_Energy_Wall_Elec **** **** **** **** **** **** **** **** +15382 FistOfZouken_Energy_Wall_Fire **** **** **** **** **** **** **** **** +15383 FistOfZouken_Energy_Wall_Sonic **** **** **** **** **** **** **** **** +15384 FistOfZouken_Eradicate_Invisibility **** **** **** **** **** **** **** **** +15385 FistOfZouken_EscapeDetection **** **** **** **** **** **** **** **** +15386 FistOfZouken_EvadeBurst **** **** **** **** **** **** **** **** +15387 FistOfZouken_Exhale_BlackDrag **** **** **** **** **** **** **** **** +15388 FistOfZouken_FateLink **** **** **** **** **** **** **** **** +15389 FistOfZouken_Greater_Amorpha **** **** **** **** **** **** **** **** +15390 FistOfZouken_Keen_Edge **** **** **** **** **** **** **** **** +15391 FistOfZouken_MentalBarrier **** **** **** **** **** **** **** **** +15392 FistOfZouken_Mindtrap **** **** **** **** **** **** **** **** +15393 FistOfZouken_Psiblast **** **** **** **** **** **** **** **** +15394 FistOfZouken_SharePainForced **** **** **** **** **** **** **** **** +15395 FistOfZouken_TimeHop **** **** **** **** **** **** **** **** +15396 FistOfZouken_Touchsight **** **** **** **** **** **** **** **** +15397 FistOfZouken_UbiqVision **** **** **** **** **** **** **** **** +15398 FistOfZouken_VampiricWeapon **** **** **** **** **** **** **** **** +15399 FistOfZouken_ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15400 FistOfZouken_ClawofEnergyCold **** **** **** **** **** **** **** **** +15401 FistOfZouken_ClawofEnergyElec **** **** **** **** **** **** **** **** +15402 FistOfZouken_ClawofEnergyFire **** **** **** **** **** **** **** **** +15403 FistOfZouken_DetectRemoteViewing **** **** **** **** **** **** **** **** +15404 FistOfZouken_DimensionalAnchor **** **** **** **** **** **** **** **** +15405 FistOfZouken_DimensionDoor_Master **** **** **** **** **** **** **** **** +15406 FistOfZouken_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +15407 FistOfZouken_DimensionDoor_Party **** **** **** **** **** **** **** **** +15408 FistOfZouken_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +15409 FistOfZouken_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +15410 FistOfZouken_Dismissal **** **** **** **** **** **** **** **** +15411 FistOfZouken_EnergyAdaption **** **** **** **** **** **** **** **** +15412 FistOfZouken_EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +15413 FistOfZouken_EnergyBall_Cold **** **** **** **** **** **** **** **** +15414 FistOfZouken_EnergyBall_Elec **** **** **** **** **** **** **** **** +15415 FistOfZouken_EnergyBall_Fire **** **** **** **** **** **** **** **** +15416 FistOfZouken_EnergyBall_Sonic **** **** **** **** **** **** **** **** +15417 FistOfZouken_Freedom_of_Movement **** **** **** **** **** **** **** **** +15418 FistOfZouken_Immovability **** **** **** **** **** **** **** **** +15419 FistOfZouken_InertialBar **** **** **** **** **** **** **** **** +15420 FistOfZouken_IntellectFortress **** **** **** **** **** **** **** **** +15421 FistOfZouken_Mindwipe **** **** **** **** **** **** **** **** +15422 FistOfZouken_PowerLeech **** **** **** **** **** **** **** **** +15423 FistOfZouken_Dominate_Psionic **** **** **** **** **** **** **** **** +15424 FistOfZouken_PsychicReformation **** **** **** **** **** **** **** **** +15425 FistOfZouken_PsychicVampire **** **** **** **** **** **** **** **** +15426 FistOfZouken_RemoteViewing **** **** **** **** **** **** **** **** +15427 FistOfZouken_SteadfastPercep **** **** **** **** **** **** **** **** +15428 FistOfZouken_TelekineticManeuver **** **** **** **** **** **** **** **** +15429 FistOfZouken_Truevenom **** **** **** **** **** **** **** **** +15430 FistOfZouken_TruevenomWeapon **** **** **** **** **** **** **** **** +15431 FistOfZouken_WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15432 FistOfZouken_WeaponofEnergyCold **** **** **** **** **** **** **** **** +15433 FistOfZouken_WeaponofEnergyElec **** **** **** **** **** **** **** **** +15434 FistOfZouken_WeaponofEnergyFire **** **** **** **** **** **** **** **** +15435 FistOfZouken_BaleTeleport **** **** **** **** **** **** **** **** +15436 FistOfZouken_Catapsi **** **** **** **** **** **** **** **** +15437 FistOfZouken_ClairtangentHand **** **** **** **** **** **** **** **** +15438 FistOfZouken_EctoplasmicShambler **** **** **** **** **** **** **** **** +15439 FistOfZouken_EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +15440 FistOfZouken_EnergyCurrent_Cold **** **** **** **** **** **** **** **** +15441 FistOfZouken_EnergyCurrent_Elec **** **** **** **** **** **** **** **** +15442 FistOfZouken_EnergyCurrent_Fire **** **** **** **** **** **** **** **** +15443 FistOfZouken_EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +15444 FistOfZouken_HailCrystals **** **** **** **** **** **** **** **** +15445 FistOfZouken_OakBody **** **** **** **** **** **** **** **** +15446 FistOfZouken_Power_Resistance **** **** **** **** **** **** **** **** +15447 FistOfZouken_PsionicRevivify **** **** **** **** **** **** **** **** +15448 FistOfZouken_PsychicCrush **** **** **** **** **** **** **** **** +15449 FistOfZouken_Psychofeedback **** **** **** **** **** **** **** **** +15450 FistOfZouken_SecondChance **** **** **** **** **** **** **** **** +15451 FistOfZouken_ShatterMindBlank **** **** **** **** **** **** **** **** +15452 FistOfZouken_Teleport_RadialMaster **** **** **** **** **** **** **** **** +15453 FistOfZouken_Teleport_SelfOnly **** **** **** **** **** **** **** **** +15454 FistOfZouken_Teleport_Party **** **** **** **** **** **** **** **** +15455 FistOfZouken_TowerIronWill **** **** **** **** **** **** **** **** +15456 FistOfZouken_True_Seeing **** **** **** **** **** **** **** **** +15457 Warmind_AstralConstruct_RadialMaster **** **** **** **** **** **** **** **** +15458 Warmind_AstralConstruct_Conversation **** **** **** **** **** **** **** **** +15459 Warmind_AstralConstruct_Slot1 **** **** **** **** **** **** **** **** +15460 Warmind_AstralConstruct_Slot2 **** **** **** **** **** **** **** **** +15461 Warmind_AstralConstruct_Slot3 **** **** **** **** **** **** **** **** +15462 Warmind_AstralConstruct_Slot4 **** **** **** **** **** **** **** **** +15463 Warmind_Biofeedback **** **** **** **** **** **** **** **** +15464 Warmind_BiteOfTheWolf **** **** **** **** **** **** **** **** +15465 Warmind_Bolt **** **** **** **** **** **** **** **** +15466 Warmind_Burst **** **** **** **** **** **** **** **** +15467 Warmind_CallToMind **** **** **** **** **** **** **** **** +15468 Warmind_CallWeaponry **** **** **** **** **** **** **** **** +15469 Warmind_Chameleon **** **** **** **** **** **** **** **** +15470 Warmind_CharmPerson **** **** **** **** **** **** **** **** +15471 Warmind_ClawsOfTheBeast **** **** **** **** **** **** **** **** +15472 Warmind_Compression **** **** **** **** **** **** **** **** +15473 Warmind_Conceal_Thoughts **** **** **** **** **** **** **** **** +15474 Warmind_ControlObject **** **** **** **** **** **** **** **** +15475 Warmind_CreateSound **** **** **** **** **** **** **** **** +15476 Warmind_CrystalShard **** **** **** **** **** **** **** **** +15477 Warmind_Daze **** **** **** **** **** **** **** **** +15478 Warmind_Deceleration **** **** **** **** **** **** **** **** +15479 Warmind_DefPrecog **** **** **** **** **** **** **** **** +15480 Warmind_Demoralize **** **** **** **** **** **** **** **** +15481 Warmind_DestinyDissonance **** **** **** **** **** **** **** **** +15482 Warmind_Disable **** **** **** **** **** **** **** **** +15483 Warmind_DissipatingTouch **** **** **** **** **** **** **** **** +15484 Warmind_Distract **** **** **** **** **** **** **** **** +15485 Warmind_ElfSight **** **** **** **** **** **** **** **** +15486 Warmind_Empathy **** **** **** **** **** **** **** **** +15487 Warmind_EmptyMind **** **** **** **** **** **** **** **** +15488 Warmind_EnergyRay_RadialMaster **** **** **** **** **** **** **** **** +15489 Warmind_EnergyRay_Cold **** **** **** **** **** **** **** **** +15490 Warmind_EnergyRay_Elec **** **** **** **** **** **** **** **** +15491 Warmind_EnergyRay_Fire **** **** **** **** **** **** **** **** +15492 Warmind_EnergyRay_Sonic **** **** **** **** **** **** **** **** +15493 Warmind_EntanglingEctoplasm **** **** **** **** **** **** **** **** +15494 Warmind_Expansion **** **** **** **** **** **** **** **** +15495 Warmind_Far_Hand **** **** **** **** **** **** **** **** +15496 Warmind_ForceScreen **** **** **** **** **** **** **** **** +15497 Warmind_Grease **** **** **** **** **** **** **** **** +15498 Warmind_Hammer **** **** **** **** **** **** **** **** +15499 Warmind_InertialArmour **** **** **** **** **** **** **** **** +15500 Warmind_Matter_Agitation **** **** **** **** **** **** **** **** +15501 Warmind_MetaphysicalClaw **** **** **** **** **** **** **** **** +15502 Warmind_MetaphysicalWeapon **** **** **** **** **** **** **** **** +15503 Warmind_MindThrust **** **** **** **** **** **** **** **** +15504 Warmind_MyLight **** **** **** **** **** **** **** **** +15505 Warmind_OffPrecog **** **** **** **** **** **** **** **** +15506 Warmind_OffPresc **** **** **** **** **** **** **** **** +15507 Warmind_Precognition_RadialMaster **** **** **** **** **** **** **** **** +15508 Warmind_PrecognitionMain **** **** **** **** **** **** **** **** +15509 Warmind_PrecognitionAttack **** **** **** **** **** **** **** **** +15510 Warmind_PrecognitionDamage **** **** **** **** **** **** **** **** +15511 Warmind_PrecognitionSaves **** **** **** **** **** **** **** **** +15512 Warmind_PrecognitionSkills **** **** **** **** **** **** **** **** +15513 Warmind_Prevenom **** **** **** **** **** **** **** **** +15514 Warmind_PrevenomWeapon **** **** **** **** **** **** **** **** +15515 Warmind_Skate **** **** **** **** **** **** **** **** +15516 Warmind_Stomp **** **** **** **** **** **** **** **** +15517 Warmind_Synesthete **** **** **** **** **** **** **** **** +15518 Warmind_Telempathic_Projection **** **** **** **** **** **** **** **** +15519 Warmind_ThickSkin **** **** **** **** **** **** **** **** +15520 Warmind_Vigor **** **** **** **** **** **** **** **** +15521 Warmind_AnimalAffinity **** **** **** **** **** **** **** **** +15522 Warmind_Aversion **** **** **** **** **** **** **** **** +15523 Warmind_BestowPower **** **** **** **** **** **** **** **** +15524 Warmind_BodyAdjustment **** **** **** **** **** **** **** **** +15525 Warmind_Body_Equilibrium **** **** **** **** **** **** **** **** +15526 Warmind_BodyPurification **** **** **** **** **** **** **** **** +15527 Warmind_BrainLock **** **** **** **** **** **** **** **** +15528 Warmind_ClairvoyantSense **** **** **** **** **** **** **** **** +15529 Warmind_Cloud_Mind **** **** **** **** **** **** **** **** +15530 Warmind_ConcBlast **** **** **** **** **** **** **** **** +15531 Warmind_ConcealAmorpha **** **** **** **** **** **** **** **** +15532 Warmind_ControlAir **** **** **** **** **** **** **** **** +15533 Warmind_ControlSound **** **** **** **** **** **** **** **** +15534 Warmind_SwarmOfCrystals **** **** **** **** **** **** **** **** +15535 Warmind_Darkvision **** **** **** **** **** **** **** **** +15536 Warmind_DimensionSwap **** **** **** **** **** **** **** **** +15537 Warmind_DissolvingTouch **** **** **** **** **** **** **** **** +15538 Warmind_Dissolving_Weapon **** **** **** **** **** **** **** **** +15539 Warmind_EgoWhip **** **** **** **** **** **** **** **** +15540 Warmind_EmpathicTransfer **** **** **** **** **** **** **** **** +15541 Warmind_EnergyAdaptSpec_RadialMaster **** **** **** **** **** **** **** **** +15542 Warmind_EnergyAdaptAcid **** **** **** **** **** **** **** **** +15543 Warmind_EnergyAdaptCold **** **** **** **** **** **** **** **** +15544 Warmind_EnergyAdaptElec **** **** **** **** **** **** **** **** +15545 Warmind_EnergyAdaptFire **** **** **** **** **** **** **** **** +15546 Warmind_EnergyAdaptSonic **** **** **** **** **** **** **** **** +15547 Warmind_Energy_Missile_RadialMaster **** **** **** **** **** **** **** **** +15548 Warmind_Energy_Missile_Cold **** **** **** **** **** **** **** **** +15549 Warmind_Energy_Missile_Elec **** **** **** **** **** **** **** **** +15550 Warmind_Energy_Missile_Fire **** **** **** **** **** **** **** **** +15551 Warmind_Energy_Missile_Sonic **** **** **** **** **** **** **** **** +15552 Warmind_EnergyPush_RadialMaster **** **** **** **** **** **** **** **** +15553 Warmind_EnergyPush_Cold **** **** **** **** **** **** **** **** +15554 Warmind_EnergyPush_Elec **** **** **** **** **** **** **** **** +15555 Warmind_EnergyPush_Fire **** **** **** **** **** **** **** **** +15556 Warmind_EnergyPush_Sonic **** **** **** **** **** **** **** **** +15557 Warmind_EnergyStun_RadialMaster **** **** **** **** **** **** **** **** +15558 Warmind_EnergyStun_Cold **** **** **** **** **** **** **** **** +15559 Warmind_EnergyStun_Elec **** **** **** **** **** **** **** **** +15560 Warmind_EnergyStun_Fire **** **** **** **** **** **** **** **** +15561 Warmind_EnergyStun_Sonic **** **** **** **** **** **** **** **** +15562 Warmind_Hustle **** **** **** **** **** **** **** **** +15563 Warmind_Identify **** **** **** **** **** **** **** **** +15564 Warmind_IdInsinuation **** **** **** **** **** **** **** **** +15565 Warmind_InflictPain **** **** **** **** **** **** **** **** +15566 Warmind_Knock **** **** **** **** **** **** **** **** +15567 Warmind_Lock **** **** **** **** **** **** **** **** +15568 Warmind_MindDisrupt **** **** **** **** **** **** **** **** +15569 Warmind_PainfulStrike **** **** **** **** **** **** **** **** +15570 Warmind_RecallAgony **** **** **** **** **** **** **** **** +15571 Warmind_RepairDamage **** **** **** **** **** **** **** **** +15572 Warmind_SharePain **** **** **** **** **** **** **** **** +15573 Warmind_StrengthOfMyEnemy **** **** **** **** **** **** **** **** +15574 Warmind_ThoughtShield **** **** **** **** **** **** **** **** +15575 Warmind_ClawOfTheVampire **** **** **** **** **** **** **** **** +15576 Warmind_CrisisBreath **** **** **** **** **** **** **** **** +15577 Warmind_Danger_Sense **** **** **** **** **** **** **** **** +15578 Warmind_DimensionSlide **** **** **** **** **** **** **** **** +15579 Warmind_Dispel_Psionics **** **** **** **** **** **** **** **** +15580 Warmind_DuodimensionalClaw **** **** **** **** **** **** **** **** +15581 Warmind_EctoCocoon **** **** **** **** **** **** **** **** +15582 Warmind_EctoplasmicForm **** **** **** **** **** **** **** **** +15583 Warmind_EmpathicFeedback **** **** **** **** **** **** **** **** +15584 Warmind_EmpathicTransferHostile **** **** **** **** **** **** **** **** +15585 Warmind_EnergyBolt_RadialMaster **** **** **** **** **** **** **** **** +15586 Warmind_Energy_Bolt_Cold **** **** **** **** **** **** **** **** +15587 Warmind_Energy_Bolt_Elec **** **** **** **** **** **** **** **** +15588 Warmind_Energy_Bolt_Fire **** **** **** **** **** **** **** **** +15589 Warmind_Energy_Bolt_Sonic **** **** **** **** **** **** **** **** +15590 Warmind_EnergyBurst_RadialMaster **** **** **** **** **** **** **** **** +15591 Warmind_Energy_Burst_Cold **** **** **** **** **** **** **** **** +15592 Warmind_Energy_Burst_Elec **** **** **** **** **** **** **** **** +15593 Warmind_Energy_Burst_Fire **** **** **** **** **** **** **** **** +15594 Warmind_Energy_Burst_Sonic **** **** **** **** **** **** **** **** +15595 Warmind_Energy_Cone_RadialMaster **** **** **** **** **** **** **** **** +15596 Warmind_EnergyCone_Cold **** **** **** **** **** **** **** **** +15597 Warmind_EnergyCone_Elec **** **** **** **** **** **** **** **** +15598 Warmind_EnergyCone_Fire **** **** **** **** **** **** **** **** +15599 Warmind_EnergyCone_Sonic **** **** **** **** **** **** **** **** +15600 Warmind_EnergyRetort_RadialMaster **** **** **** **** **** **** **** **** +15601 Warmind_Energy_Retort_Cold **** **** **** **** **** **** **** **** +15602 Warmind_Energy_Retort_Elec **** **** **** **** **** **** **** **** +15603 Warmind_Energy_Retort_Fire **** **** **** **** **** **** **** **** +15604 Warmind_Energy_Retort_Sonic **** **** **** **** **** **** **** **** +15605 Warmind_EnergyWall_RadialMaster **** **** **** **** **** **** **** **** +15606 Warmind_Energy_Wall_Cold **** **** **** **** **** **** **** **** +15607 Warmind_Energy_Wall_Elec **** **** **** **** **** **** **** **** +15608 Warmind_Energy_Wall_Fire **** **** **** **** **** **** **** **** +15609 Warmind_Energy_Wall_Sonic **** **** **** **** **** **** **** **** +15610 Warmind_Eradicate_Invisibility **** **** **** **** **** **** **** **** +15611 Warmind_EscapeDetection **** **** **** **** **** **** **** **** +15612 Warmind_EvadeBurst **** **** **** **** **** **** **** **** +15613 Warmind_Exhale_BlackDrag **** **** **** **** **** **** **** **** +15614 Warmind_FateLink **** **** **** **** **** **** **** **** +15615 Warmind_Greater_Amorpha **** **** **** **** **** **** **** **** +15616 Warmind_Keen_Edge **** **** **** **** **** **** **** **** +15617 Warmind_MentalBarrier **** **** **** **** **** **** **** **** +15618 Warmind_Mindtrap **** **** **** **** **** **** **** **** +15619 Warmind_Psiblast **** **** **** **** **** **** **** **** +15620 Warmind_SharePainForced **** **** **** **** **** **** **** **** +15621 Warmind_TimeHop **** **** **** **** **** **** **** **** +15622 Warmind_Touchsight **** **** **** **** **** **** **** **** +15623 Warmind_UbiqVision **** **** **** **** **** **** **** **** +15624 Warmind_VampiricWeapon **** **** **** **** **** **** **** **** +15625 Warmind_ClawOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15626 Warmind_ClawofEnergyCold **** **** **** **** **** **** **** **** +15627 Warmind_ClawofEnergyElec **** **** **** **** **** **** **** **** +15628 Warmind_ClawofEnergyFire **** **** **** **** **** **** **** **** +15629 Warmind_DetectRemoteViewing **** **** **** **** **** **** **** **** +15630 Warmind_DimensionalAnchor **** **** **** **** **** **** **** **** +15631 Warmind_DimensionDoor_Master **** **** **** **** **** **** **** **** +15632 Warmind_DimensionDoor_SelfOnly **** **** **** **** **** **** **** **** +15633 Warmind_DimensionDoor_Party **** **** **** **** **** **** **** **** +15634 Warmind_DimensionDoor_DirDist_SelfOnly **** **** **** **** **** **** **** **** +15635 Warmind_DimensionDoor_DirDist_Party **** **** **** **** **** **** **** **** +15636 Warmind_Dismissal **** **** **** **** **** **** **** **** +15637 Warmind_EnergyAdaption **** **** **** **** **** **** **** **** +15638 Warmind_EnergyBall_RadialMaster **** **** **** **** **** **** **** **** +15639 Warmind_EnergyBall_Cold **** **** **** **** **** **** **** **** +15640 Warmind_EnergyBall_Elec **** **** **** **** **** **** **** **** +15641 Warmind_EnergyBall_Fire **** **** **** **** **** **** **** **** +15642 Warmind_EnergyBall_Sonic **** **** **** **** **** **** **** **** +15643 Warmind_Freedom_of_Movement **** **** **** **** **** **** **** **** +15644 Warmind_Immovability **** **** **** **** **** **** **** **** +15645 Warmind_InertialBar **** **** **** **** **** **** **** **** +15646 Warmind_IntellectFortress **** **** **** **** **** **** **** **** +15647 Warmind_Mindwipe **** **** **** **** **** **** **** **** +15648 Warmind_PowerLeech **** **** **** **** **** **** **** **** +15649 Warmind_Dominate_Psionic **** **** **** **** **** **** **** **** +15650 Warmind_PsychicReformation **** **** **** **** **** **** **** **** +15651 Warmind_PsychicVampire **** **** **** **** **** **** **** **** +15652 Warmind_RemoteViewing **** **** **** **** **** **** **** **** +15653 Warmind_SteadfastPercep **** **** **** **** **** **** **** **** +15654 Warmind_TelekineticManeuver **** **** **** **** **** **** **** **** +15655 Warmind_Truevenom **** **** **** **** **** **** **** **** +15656 Warmind_TruevenomWeapon **** **** **** **** **** **** **** **** +15657 Warmind_WeaponOfEnergy_RadialMaster **** **** **** **** **** **** **** **** +15658 Warmind_WeaponofEnergyCold **** **** **** **** **** **** **** **** +15659 Warmind_WeaponofEnergyElec **** **** **** **** **** **** **** **** +15660 Warmind_WeaponofEnergyFire **** **** **** **** **** **** **** **** +15661 Warmind_BaleTeleport **** **** **** **** **** **** **** **** +15662 Warmind_Catapsi **** **** **** **** **** **** **** **** +15663 Warmind_ClairtangentHand **** **** **** **** **** **** **** **** +15664 Warmind_EctoplasmicShambler **** **** **** **** **** **** **** **** +15665 Warmind_EnergyCurrent_RadialMaster **** **** **** **** **** **** **** **** +15666 Warmind_EnergyCurrent_Cold **** **** **** **** **** **** **** **** +15667 Warmind_EnergyCurrent_Elec **** **** **** **** **** **** **** **** +15668 Warmind_EnergyCurrent_Fire **** **** **** **** **** **** **** **** +15669 Warmind_EnergyCurrent_Sonic **** **** **** **** **** **** **** **** +15670 Warmind_HailCrystals **** **** **** **** **** **** **** **** +15671 Warmind_OakBody **** **** **** **** **** **** **** **** +15672 Warmind_Power_Resistance **** **** **** **** **** **** **** **** +15673 Warmind_PsionicRevivify **** **** **** **** **** **** **** **** +15674 Warmind_PsychicCrush **** **** **** **** **** **** **** **** +15675 Warmind_Psychofeedback **** **** **** **** **** **** **** **** +15676 Warmind_SecondChance **** **** **** **** **** **** **** **** +15677 Warmind_ShatterMindBlank **** **** **** **** **** **** **** **** +15678 Warmind_Teleport_RadialMaster **** **** **** **** **** **** **** **** +15679 Warmind_Teleport_SelfOnly **** **** **** **** **** **** **** **** +15680 Warmind_Teleport_Party **** **** **** **** **** **** **** **** +15681 Warmind_TowerIronWill **** **** **** **** **** **** **** **** +15682 Warmind_True_Seeing **** **** **** **** **** **** **** **** +15683 PsychicWarrior_GripOfIron **** **** **** **** **** **** **** **** +15684 FistOfZuoken_GripOfIron **** **** **** **** **** **** **** **** +15685 Warmind_GripOfIron **** **** **** **** **** **** **** **** +15686 Psion_GripOfIron **** **** **** **** **** **** **** **** +15687 Wilder_GripOfIron **** **** **** **** **** **** **** **** +15688 PsychicRogue_GripOfIron **** **** **** **** **** **** **** **** +15689 **** **** **** **** **** **** **** **** **** +15690 **** **** **** **** **** **** **** **** **** +15691 **** **** **** **** **** **** **** **** **** +15692 **** **** **** **** **** **** **** **** **** +15693 **** **** **** **** **** **** **** **** **** +15694 **** **** **** **** **** **** **** **** **** +15695 **** **** **** **** **** **** **** **** **** +15696 **** **** **** **** **** **** **** **** **** +15697 **** **** **** **** **** **** **** **** **** +15698 **** **** **** **** **** **** **** **** **** +15699 **** **** **** **** **** **** **** **** **** +15700 **** **** **** **** **** **** **** **** **** +15701 **** **** **** **** **** **** **** **** **** +15702 **** **** **** **** **** **** **** **** **** +15703 **** **** **** **** **** **** **** **** **** +15704 **** **** **** **** **** **** **** **** **** +15705 **** **** **** **** **** **** **** **** **** +15706 **** **** **** **** **** **** **** **** **** +15707 **** **** **** **** **** **** **** **** **** +15708 **** **** **** **** **** **** **** **** **** +15709 **** **** **** **** **** **** **** **** **** +15710 **** **** **** **** **** **** **** **** **** +15711 **** **** **** **** **** **** **** **** **** +15712 **** **** **** **** **** **** **** **** **** +15713 **** **** **** **** **** **** **** **** **** +15714 **** **** **** **** **** **** **** **** **** +15715 **** **** **** **** **** **** **** **** **** +15716 **** **** **** **** **** **** **** **** **** +15717 **** **** **** **** **** **** **** **** **** +15718 **** **** **** **** **** **** **** **** **** +15719 **** **** **** **** **** **** **** **** **** +15720 **** **** **** **** **** **** **** **** **** +15721 **** **** **** **** **** **** **** **** **** +15722 **** **** **** **** **** **** **** **** **** +15723 **** **** **** **** **** **** **** **** **** +15724 **** **** **** **** **** **** **** **** **** +15725 **** **** **** **** **** **** **** **** **** +15726 **** **** **** **** **** **** **** **** **** +15727 **** **** **** **** **** **** **** **** **** +15728 **** **** **** **** **** **** **** **** **** +15729 **** **** **** **** **** **** **** **** **** +15730 **** **** **** **** **** **** **** **** **** +15731 **** **** **** **** **** **** **** **** **** +15732 **** **** **** **** **** **** **** **** **** +15733 **** **** **** **** **** **** **** **** **** +15734 **** **** **** **** **** **** **** **** **** +15735 **** **** **** **** **** **** **** **** **** +15736 **** **** **** **** **** **** **** **** **** +15737 **** **** **** **** **** **** **** **** **** +15738 **** **** **** **** **** **** **** **** **** +15739 **** **** **** **** **** **** **** **** **** +15740 **** **** **** **** **** **** **** **** **** +15741 **** **** **** **** **** **** **** **** **** +15742 **** **** **** **** **** **** **** **** **** +15743 **** **** **** **** **** **** **** **** **** +15744 **** **** **** **** **** **** **** **** **** +15745 **** **** **** **** **** **** **** **** **** +15746 **** **** **** **** **** **** **** **** **** +15747 **** **** **** **** **** **** **** **** **** +15748 **** **** **** **** **** **** **** **** **** +15749 **** **** **** **** **** **** **** **** **** +15750 **** **** **** **** **** **** **** **** **** +15751 **** **** **** **** **** **** **** **** **** +15752 **** **** **** **** **** **** **** **** **** +15753 **** **** **** **** **** **** **** **** **** +15754 **** **** **** **** **** **** **** **** **** +15755 **** **** **** **** **** **** **** **** **** +15756 **** **** **** **** **** **** **** **** **** +15757 **** **** **** **** **** **** **** **** **** +15758 **** **** **** **** **** **** **** **** **** +15759 **** **** **** **** **** **** **** **** **** +15760 **** **** **** **** **** **** **** **** **** +15761 **** **** **** **** **** **** **** **** **** +15762 **** **** **** **** **** **** **** **** **** +15763 **** **** **** **** **** **** **** **** **** +15764 **** **** **** **** **** **** **** **** **** +15765 **** **** **** **** **** **** **** **** **** +15766 **** **** **** **** **** **** **** **** **** +15767 **** **** **** **** **** **** **** **** **** +15768 **** **** **** **** **** **** **** **** **** +15769 **** **** **** **** **** **** **** **** **** +15770 **** **** **** **** **** **** **** **** **** +15771 **** **** **** **** **** **** **** **** **** +15772 **** **** **** **** **** **** **** **** **** +15773 **** **** **** **** **** **** **** **** **** +15774 **** **** **** **** **** **** **** **** **** +15775 **** **** **** **** **** **** **** **** **** +15776 **** **** **** **** **** **** **** **** **** +15777 **** **** **** **** **** **** **** **** **** +15778 **** **** **** **** **** **** **** **** **** +15779 **** **** **** **** **** **** **** **** **** +15780 **** **** **** **** **** **** **** **** **** +15781 **** **** **** **** **** **** **** **** **** +15782 **** **** **** **** **** **** **** **** **** +15783 **** **** **** **** **** **** **** **** **** +15784 **** **** **** **** **** **** **** **** **** +15785 **** **** **** **** **** **** **** **** **** +15786 **** **** **** **** **** **** **** **** **** +15787 **** **** **** **** **** **** **** **** **** +15788 **** **** **** **** **** **** **** **** **** +15789 **** **** **** **** **** **** **** **** **** +15790 **** **** **** **** **** **** **** **** **** +15791 **** **** **** **** **** **** **** **** **** +15792 **** **** **** **** **** **** **** **** **** +15793 **** **** **** **** **** **** **** **** **** +15794 **** **** **** **** **** **** **** **** **** +15795 **** **** **** **** **** **** **** **** **** +15796 **** **** **** **** **** **** **** **** **** +15797 **** **** **** **** **** **** **** **** **** +15798 **** **** **** **** **** **** **** **** **** +15799 ####END_OF_PSI_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +15800 ####START_OF_TOB_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +15801 Crusader_BlisteringFlourish **** **** **** **** **** **** **** **** +15802 Crusader_BurningBlade **** **** **** **** **** **** **** **** +15803 Crusader_BurningBrand **** **** **** **** **** **** **** **** +15804 Crusader_DeathMark **** **** **** **** **** **** **** **** +15805 Crusader_DesertTempest **** **** **** **** **** **** **** **** +15806 Crusader_DistractingEmber **** **** **** **** **** **** **** **** +15807 Crusader_DragonsFlame **** **** **** **** **** **** **** **** +15808 Crusader_FanTheFlames **** **** **** **** **** **** **** **** +15809 Crusader_FieryAssault **** **** **** **** **** **** **** **** +15810 Crusader_FireRiposte **** **** **** **** **** **** **** **** +15811 Crusader_Firesnake **** **** **** **** **** **** **** **** +15812 Crusader_FlamesBlessing **** **** **** **** **** **** **** **** +15813 Crusader_FlashingSun **** **** **** **** **** **** **** **** +15814 Crusader_HatchlingsFlame **** **** **** **** **** **** **** **** +15815 Crusader_HolocaustCloak **** **** **** **** **** **** **** **** +15816 Crusader_InfernoBlade **** **** **** **** **** **** **** **** +15817 Crusader_InfernoBlast **** **** **** **** **** **** **** **** +15818 Crusader_LeapingFlame **** **** **** **** **** **** **** **** +15819 Crusader_LingeringInferno **** **** **** **** **** **** **** **** +15820 Crusader_RingOfFire **** **** **** **** **** **** **** **** +15821 Crusader_RisingPhoenix **** **** **** **** **** **** **** **** +15822 Crusader_SalamanderCharge **** **** **** **** **** **** **** **** +15823 Crusader_SearingBlade **** **** **** **** **** **** **** **** +15824 Crusader_SearingCharge **** **** **** **** **** **** **** **** +15825 Crusader_WindStride **** **** **** **** **** **** **** **** +15826 Crusader_WyrmsFlame **** **** **** **** **** **** **** **** +15827 Crusader_ZephyrDance **** **** **** **** **** **** **** **** +15828 Crusader_AuraOfChaos **** **** **** **** **** **** **** **** +15829 Crusader_AuraOfPerfectOrder **** **** **** **** **** **** **** **** +15830 Crusader_AuraOfTriumph **** **** **** **** **** **** **** **** +15831 Crusader_AuraOfTyranny **** **** **** **** **** **** **** **** +15832 Crusader_CastigatingStrike **** **** **** **** **** **** **** **** +15833 Crusader_CrusadersStrike **** **** **** **** **** **** **** **** +15834 Crusader_DauntingStrike **** **** **** **** **** **** **** **** +15835 Crusader_DefensiveRebuke **** **** **** **** **** **** **** **** +15836 Crusader_DivineSurge **** **** **** **** **** **** **** **** +15837 Crusader_DivineSurgeGreater **** **** **** **** **** **** **** **** +15838 Crusader_DivineSurgeGreaterSub1 **** **** **** **** **** **** **** **** +15839 Crusader_DivineSurgeGreaterSub2 **** **** **** **** **** **** **** **** +15840 Crusader_DivineSurgeGreaterSub3 **** **** **** **** **** **** **** **** +15841 Crusader_DoomCharge **** **** **** **** **** **** **** **** +15842 Crusader_EntanglingBlade **** **** **** **** **** **** **** **** +15843 Crusader_Foehammer **** **** **** **** **** **** **** **** +15844 Crusader_ImmortalFortitude **** **** **** **** **** **** **** **** +15845 Crusader_IronGuardsGlare **** **** **** **** **** **** **** **** +15846 Crusader_LawBearer **** **** **** **** **** **** **** **** +15847 Crusader_MartialSpirit **** **** **** **** **** **** **** **** +15848 Crusader_RadiantCharge **** **** **** **** **** **** **** **** +15849 Crusader_RallyingStrike **** **** **** **** **** **** **** **** +15850 Crusader_RevitalizingStrike **** **** **** **** **** **** **** **** +15851 Crusader_ShieldBlock **** **** **** **** **** **** **** **** +15852 Crusader_ShieldCounter **** **** **** **** **** **** **** **** +15853 Crusader_StrikeOfRighteousVitality **** **** **** **** **** **** **** **** +15854 Crusader_ThicketOfBlades **** **** **** **** **** **** **** **** +15855 Crusader_TideOfChaos **** **** **** **** **** **** **** **** +15856 Crusader_VanguardStrike **** **** **** **** **** **** **** **** +15857 Crusader_ActionBeforeThought **** **** **** **** **** **** **** **** +15858 Crusader_AvalancheOfBlades **** **** **** **** **** **** **** **** +15859 Crusader_BoundingAssault **** **** **** **** **** **** **** **** +15860 Crusader_DiamondDefense **** **** **** **** **** **** **** **** +15861 Crusader_DiamondNightmareBlade **** **** **** **** **** **** **** **** +15862 Crusader_DisruptingBlow **** **** **** **** **** **** **** **** +15863 Crusader_EmeraldRazor **** **** **** **** **** **** **** **** +15864 Crusader_HearingTheAir **** **** **** **** **** **** **** **** +15865 Crusader_InsightfulStrike **** **** **** **** **** **** **** **** +15866 Crusader_InsightfulStrikeGreater **** **** **** **** **** **** **** **** +15867 Crusader_MindOverBody **** **** **** **** **** **** **** **** +15868 Crusader_MindStrike **** **** **** **** **** **** **** **** +15869 Crusader_MomentOfAlacrity **** **** **** **** **** **** **** **** +15870 Crusader_MomentOfPerfectMind **** **** **** **** **** **** **** **** +15871 Crusader_PearlOfBlackDoubt **** **** **** **** **** **** **** **** +15872 Crusader_QuicksilverMotion **** **** **** **** **** **** **** **** +15873 Crusader_RapidCounter **** **** **** **** **** **** **** **** +15874 Crusader_RubyNightmareBlade **** **** **** **** **** **** **** **** +15875 Crusader_SapphireNightmareBlade **** **** **** **** **** **** **** **** +15876 Crusader_StanceOfAlacrity **** **** **** **** **** **** **** **** +15877 Crusader_StanceOfClarity **** **** **** **** **** **** **** **** +15878 Crusader_TimeStandsStill **** **** **** **** **** **** **** **** +15879 Crusader_AbsoluteSteel **** **** **** **** **** **** **** **** +15880 Crusader_AdamantineHurricane **** **** **** **** **** **** **** **** +15881 Crusader_DancingBladeForm **** **** **** **** **** **** **** **** +15882 Crusader_DazingStrike **** **** **** **** **** **** **** **** +15883 Crusader_DisarmingStrike **** **** **** **** **** **** **** **** +15884 Crusader_ExorcismOfSteel **** **** **** **** **** **** **** **** +15885 Crusader_FinishingMove **** **** **** **** **** **** **** **** +15886 Crusader_IronHeartEndurance **** **** **** **** **** **** **** **** +15887 Crusader_IronHeartFocus **** **** **** **** **** **** **** **** +15888 Crusader_IronHeartSurge **** **** **** **** **** **** **** **** +15889 Crusader_LightningRecovery **** **** **** **** **** **** **** **** +15890 Crusader_LightningThrow **** **** **** **** **** **** **** **** +15891 Crusader_ManticoreParry **** **** **** **** **** **** **** **** +15892 Crusader_MithralTornado **** **** **** **** **** **** **** **** +15893 Crusader_PunishingStance **** **** **** **** **** **** **** **** +15894 Crusader_ScythingBlade **** **** **** **** **** **** **** **** +15895 Crusader_SteelWind **** **** **** **** **** **** **** **** +15896 Crusader_SteelyStrike **** **** **** **** **** **** **** **** +15897 Crusader_StrikeOfPerfectClarity **** **** **** **** **** **** **** **** +15898 Crusader_SupremeBladeParry **** **** **** **** **** **** **** **** +15899 Crusader_WallOfBlades **** **** **** **** **** **** **** **** +15900 Crusader_BafflingDefense **** **** **** **** **** **** **** **** +15901 Crusader_BallistaThrow **** **** **** **** **** **** **** **** +15902 Crusader_CleverPositioning **** **** **** **** **** **** **** **** +15903 Crusader_CometThrow **** **** **** **** **** **** **** **** +15904 Crusader_CounterCharge **** **** **** **** **** **** **** **** +15905 Crusader_DevastatingThrow **** **** **** **** **** **** **** **** +15906 Crusader_FeignedOpening **** **** **** **** **** **** **** **** +15907 Crusader_FoolsStrike **** **** **** **** **** **** **** **** +15908 Crusader_GhostlyDefense **** **** **** **** **** **** **** **** +15909 Crusader_GiantKillingStyle **** **** **** **** **** **** **** **** +15910 Crusader_HydraSlayingStrike **** **** **** **** **** **** **** **** +15911 Crusader_MightyThrow **** **** **** **** **** **** **** **** +15912 Crusader_MirroredPursuit **** **** **** **** **** **** **** **** +15913 Crusader_ScorpionParry **** **** **** **** **** **** **** **** +15914 Crusader_ShiftingDefense **** **** **** **** **** **** **** **** +15915 Crusader_SoaringThrow **** **** **** **** **** **** **** **** +15916 Crusader_StalkingShadow **** **** **** **** **** **** **** **** +15917 Crusader_StepOfTheWind **** **** **** **** **** **** **** **** +15918 Crusader_StrikeOfTheBrokenShield **** **** **** **** **** **** **** **** +15919 Crusader_TornadoThrow **** **** **** **** **** **** **** **** +15920 Crusader_AssassinsStance **** **** **** **** **** **** **** **** +15921 Crusader_BalanceOnTheSky **** **** **** **** **** **** **** **** +15922 Crusader_BloodlettingStrike **** **** **** **** **** **** **** **** +15923 Crusader_ChildOfShadow **** **** **** **** **** **** **** **** +15924 Crusader_ClingingShadowStrike **** **** **** **** **** **** **** **** +15925 Crusader_CloakOfDeception **** **** **** **** **** **** **** **** +15926 Crusader_DanceOfTheSpider **** **** **** **** **** **** **** **** +15927 Crusader_DeathInTheDark **** **** **** **** **** **** **** **** +15928 Crusader_DrainVitality **** **** **** **** **** **** **** **** +15929 Crusader_EnervatingShadowStrike **** **** **** **** **** **** **** **** +15930 Crusader_FiveShadowCreepingIceEnervationStrike **** **** **** **** **** **** **** **** +15931 Crusader_GhostBlade **** **** **** **** **** **** **** **** +15932 Crusader_HandOfDeath **** **** **** **** **** **** **** **** +15933 Crusader_IslandOfBlades **** **** **** **** **** **** **** **** +15934 Crusader_ObscuringShadowVeil **** **** **** **** **** **** **** **** +15935 Crusader_OneWithShadow **** **** **** **** **** **** **** **** +15936 Crusader_ShadowBladeTechnique **** **** **** **** **** **** **** **** +15937 Crusader_ShadowBlink **** **** **** **** **** **** **** **** +15938 Crusader_ShadowGarrote **** **** **** **** **** **** **** **** +15939 Crusader_ShadowJaunt **** **** **** **** **** **** **** **** +15940 Crusader_ShadowNoose **** **** **** **** **** **** **** **** +15941 Crusader_ShadowStride **** **** **** **** **** **** **** **** +15942 Crusader_StalkerInTheNight **** **** **** **** **** **** **** **** +15943 Crusader_StepOfTheDancingMoth **** **** **** **** **** **** **** **** +15944 Crusader_StrengthDrainingStrike **** **** **** **** **** **** **** **** +15945 Crusader_AdamantineBones **** **** **** **** **** **** **** **** +15946 Crusader_AncientMountainHammer **** **** **** **** **** **** **** **** +15947 Crusader_BonesplittingStrike **** **** **** **** **** **** **** **** +15948 Crusader_Bonecrusher **** **** **** **** **** **** **** **** +15949 Crusader_BoulderRoll **** **** **** **** **** **** **** **** +15950 Crusader_ChargingMinotaur **** **** **** **** **** **** **** **** +15951 Crusader_ColossusStrike **** **** **** **** **** **** **** **** +15952 Crusader_CrushingVise **** **** **** **** **** **** **** **** +15953 Crusader_CrushingWeightOfTheMountain **** **** **** **** **** **** **** **** +15954 Crusader_EarthstrikeQuake **** **** **** **** **** **** **** **** +15955 Crusader_ElderMountainHammer **** **** **** **** **** **** **** **** +15956 Crusader_GiantsStance **** **** **** **** **** **** **** **** +15957 Crusader_IronBones **** **** **** **** **** **** **** **** +15958 Crusader_IrresistibleMountainStrike **** **** **** **** **** **** **** **** +15959 Crusader_MountainAvalanche **** **** **** **** **** **** **** **** +15960 Crusader_MountainHammer **** **** **** **** **** **** **** **** +15961 Crusader_MountainTombstoneStrike **** **** **** **** **** **** **** **** +15962 Crusader_OverwhelmingMountainStrike **** **** **** **** **** **** **** **** +15963 Crusader_RootsOfTheMountain **** **** **** **** **** **** **** **** +15964 Crusader_StoneBones **** **** **** **** **** **** **** **** +15965 Crusader_StoneDragonsFury **** **** **** **** **** **** **** **** +15966 Crusader_StoneVise **** **** **** **** **** **** **** **** +15967 Crusader_StonefootStance **** **** **** **** **** **** **** **** +15968 Crusader_StrengthOfStone **** **** **** **** **** **** **** **** +15969 Crusader_BloodInTheWater **** **** **** **** **** **** **** **** +15970 Crusader_ClawAtTheMoon **** **** **** **** **** **** **** **** +15971 Crusader_DancingMongoose **** **** **** **** **** **** **** **** +15972 Crusader_DeathFromAbove **** **** **** **** **** **** **** **** +15973 Crusader_FeralDeathBlow **** **** **** **** **** **** **** **** +15974 Crusader_FleshRipper **** **** **** **** **** **** **** **** +15975 Crusader_FountainOfBlood **** **** **** **** **** **** **** **** +15976 Crusader_GirallonWindmillFleshRip **** **** **** **** **** **** **** **** +15977 Crusader_HamstringAttack **** **** **** **** **** **** **** **** +15978 Crusader_HuntersSense **** **** **** **** **** **** **** **** +15979 Crusader_LeapingDragonStance **** **** **** **** **** **** **** **** +15980 Crusader_PouncingCharge **** **** **** **** **** **** **** **** +15981 Crusader_PreyOnTheWeak **** **** **** **** **** **** **** **** +15982 Crusader_RabidBearStrike **** **** **** **** **** **** **** **** +15983 Crusader_RabidWolfStrike **** **** **** **** **** **** **** **** +15984 Crusader_RagingMongoose **** **** **** **** **** **** **** **** +15985 Crusader_SoaringRaptorStrike **** **** **** **** **** **** **** **** +15986 Crusader_SuddenLeap **** **** **** **** **** **** **** **** +15987 Crusader_SwoopingDragonStrike **** **** **** **** **** **** **** **** +15988 Crusader_WolfClimbsTheMountain **** **** **** **** **** **** **** **** +15989 Crusader_WolfFangStrike **** **** **** **** **** **** **** **** +15990 Crusader_WolfPackTactics **** **** **** **** **** **** **** **** +15991 Crusader_WolverineStance **** **** **** **** **** **** **** **** +15992 Crusader_BattleLeadersCharge **** **** **** **** **** **** **** **** +15993 Crusader_BolsteringVoice **** **** **** **** **** **** **** **** +15994 Crusader_ClarionCall **** **** **** **** **** **** **** **** +15995 Crusader_CoveringStrike **** **** **** **** **** **** **** **** +15996 Crusader_DouseTheFlames **** **** **** **** **** **** **** **** +15997 Crusader_FlankingManeuver **** **** **** **** **** **** **** **** +15998 Crusader_LeadingTheAttack **** **** **** **** **** **** **** **** +15999 Crusader_LeadingTheCharge **** **** **** **** **** **** **** **** +16000 Crusader_LionsRoar **** **** **** **** **** **** **** **** +16001 Crusader_OrderForgedFromChaos **** **** **** **** **** **** **** **** +16002 Crusader_PressTheAdvantage **** **** **** **** **** **** **** **** +16003 Crusader_SwarmTactics **** **** **** **** **** **** **** **** +16004 Crusader_SwarmingAssault **** **** **** **** **** **** **** **** +16005 Crusader_TacticalStrike **** **** **** **** **** **** **** **** +16006 Crusader_TacticsOfTheWolf **** **** **** **** **** **** **** **** +16007 Crusader_WarLeadersCharge **** **** **** **** **** **** **** **** +16008 Crusader_WarMastersCharge **** **** **** **** **** **** **** **** +16009 Crusader_WhiteRavenHammer **** **** **** **** **** **** **** **** +16010 Crusader_WhiteRavenStrike **** **** **** **** **** **** **** **** +16011 Crusader_WhiteRavenTactics **** **** **** **** **** **** **** **** +16012 Swordsage_BlisteringFlourish **** **** **** **** **** **** **** **** +16013 Swordsage_BurningBlade **** **** **** **** **** **** **** **** +16014 Swordsage_BurningBrand **** **** **** **** **** **** **** **** +16015 Swordsage_DeathMark **** **** **** **** **** **** **** **** +16016 Swordsage_DesertTempest **** **** **** **** **** **** **** **** +16017 Swordsage_DistractingEmber **** **** **** **** **** **** **** **** +16018 Swordsage_DragonsFlame **** **** **** **** **** **** **** **** +16019 Swordsage_FanTheFlames **** **** **** **** **** **** **** **** +16020 Swordsage_FieryAssault **** **** **** **** **** **** **** **** +16021 Swordsage_FireRiposte **** **** **** **** **** **** **** **** +16022 Swordsage_Firesnake **** **** **** **** **** **** **** **** +16023 Swordsage_FlamesBlessing **** **** **** **** **** **** **** **** +16024 Swordsage_FlashingSun **** **** **** **** **** **** **** **** +16025 Swordsage_HatchlingsFlame **** **** **** **** **** **** **** **** +16026 Swordsage_HolocaustCloak **** **** **** **** **** **** **** **** +16027 Swordsage_InfernoBlade **** **** **** **** **** **** **** **** +16028 Swordsage_InfernoBlast **** **** **** **** **** **** **** **** +16029 Swordsage_LeapingFlame **** **** **** **** **** **** **** **** +16030 Swordsage_LingeringInferno **** **** **** **** **** **** **** **** +16031 Swordsage_RingOfFire **** **** **** **** **** **** **** **** +16032 Swordsage_RisingPhoenix **** **** **** **** **** **** **** **** +16033 Swordsage_SalamanderCharge **** **** **** **** **** **** **** **** +16034 Swordsage_SearingBlade **** **** **** **** **** **** **** **** +16035 Swordsage_SearingCharge **** **** **** **** **** **** **** **** +16036 Swordsage_WindStride **** **** **** **** **** **** **** **** +16037 Swordsage_WyrmsFlame **** **** **** **** **** **** **** **** +16038 Swordsage_ZephyrDance **** **** **** **** **** **** **** **** +16039 Swordsage_AuraOfChaos **** **** **** **** **** **** **** **** +16040 Swordsage_AuraOfPerfectOrder **** **** **** **** **** **** **** **** +16041 Swordsage_AuraOfTriumph **** **** **** **** **** **** **** **** +16042 Swordsage_AuraOfTyranny **** **** **** **** **** **** **** **** +16043 Swordsage_CastigatingStrike **** **** **** **** **** **** **** **** +16044 Swordsage_CrusadersStrike **** **** **** **** **** **** **** **** +16045 Swordsage_DauntingStrike **** **** **** **** **** **** **** **** +16046 Swordsage_DefensiveRebuke **** **** **** **** **** **** **** **** +16047 Swordsage_DivineSurge **** **** **** **** **** **** **** **** +16048 Swordsage_DivineSurgeGreater **** **** **** **** **** **** **** **** +16049 Swordsage_DivineSurgeGreaterSub1 **** **** **** **** **** **** **** **** +16050 Swordsage_DivineSurgeGreaterSub2 **** **** **** **** **** **** **** **** +16051 Swordsage_DivineSurgeGreaterSub3 **** **** **** **** **** **** **** **** +16052 Swordsage_DoomCharge **** **** **** **** **** **** **** **** +16053 Swordsage_EntanglingBlade **** **** **** **** **** **** **** **** +16054 Swordsage_Foehammer **** **** **** **** **** **** **** **** +16055 Swordsage_ImmortalFortitude **** **** **** **** **** **** **** **** +16056 Swordsage_IronGuardsGlare **** **** **** **** **** **** **** **** +16057 Swordsage_LawBearer **** **** **** **** **** **** **** **** +16058 Swordsage_MartialSpirit **** **** **** **** **** **** **** **** +16059 Swordsage_RadiantCharge **** **** **** **** **** **** **** **** +16060 Swordsage_RallyingStrike **** **** **** **** **** **** **** **** +16061 Swordsage_RevitalizingStrike **** **** **** **** **** **** **** **** +16062 Swordsage_ShieldBlock **** **** **** **** **** **** **** **** +16063 Swordsage_ShieldCounter **** **** **** **** **** **** **** **** +16064 Swordsage_StrikeOfRighteousVitality **** **** **** **** **** **** **** **** +16065 Swordsage_ThicketOfBlades **** **** **** **** **** **** **** **** +16066 Swordsage_TideOfChaos **** **** **** **** **** **** **** **** +16067 Swordsage_VanguardStrike **** **** **** **** **** **** **** **** +16068 Swordsage_ActionBeforeThought **** **** **** **** **** **** **** **** +16069 Swordsage_AvalancheOfBlades **** **** **** **** **** **** **** **** +16070 Swordsage_BoundingAssault **** **** **** **** **** **** **** **** +16071 Swordsage_DiamondDefense **** **** **** **** **** **** **** **** +16072 Swordsage_DiamondNightmareBlade **** **** **** **** **** **** **** **** +16073 Swordsage_DisruptingBlow **** **** **** **** **** **** **** **** +16074 Swordsage_EmeraldRazor **** **** **** **** **** **** **** **** +16075 Swordsage_HearingTheAir **** **** **** **** **** **** **** **** +16076 Swordsage_InsightfulStrike **** **** **** **** **** **** **** **** +16077 Swordsage_InsightfulStrikeGreater **** **** **** **** **** **** **** **** +16078 Swordsage_MindOverBody **** **** **** **** **** **** **** **** +16079 Swordsage_MindStrike **** **** **** **** **** **** **** **** +16080 Swordsage_MomentOfAlacrity **** **** **** **** **** **** **** **** +16081 Swordsage_MomentOfPerfectMind **** **** **** **** **** **** **** **** +16082 Swordsage_PearlOfBlackDoubt **** **** **** **** **** **** **** **** +16083 Swordsage_QuicksilverMotion **** **** **** **** **** **** **** **** +16084 Swordsage_RapidCounter **** **** **** **** **** **** **** **** +16085 Swordsage_RubyNightmareBlade **** **** **** **** **** **** **** **** +16086 Swordsage_SapphireNightmareBlade **** **** **** **** **** **** **** **** +16087 Swordsage_StanceOfAlacrity **** **** **** **** **** **** **** **** +16088 Swordsage_StanceOfClarity **** **** **** **** **** **** **** **** +16089 Swordsage_TimeStandsStill **** **** **** **** **** **** **** **** +16090 Swordsage_AbsoluteSteel **** **** **** **** **** **** **** **** +16091 Swordsage_AdamantineHurricane **** **** **** **** **** **** **** **** +16092 Swordsage_DancingBladeForm **** **** **** **** **** **** **** **** +16093 Swordsage_DazingStrike **** **** **** **** **** **** **** **** +16094 Swordsage_DisarmingStrike **** **** **** **** **** **** **** **** +16095 Swordsage_ExorcismOfSteel **** **** **** **** **** **** **** **** +16096 Swordsage_FinishingMove **** **** **** **** **** **** **** **** +16097 Swordsage_IronHeartEndurance **** **** **** **** **** **** **** **** +16098 Swordsage_IronHeartFocus **** **** **** **** **** **** **** **** +16099 Swordsage_IronHeartSurge **** **** **** **** **** **** **** **** +16100 Swordsage_LightningRecovery **** **** **** **** **** **** **** **** +16101 Swordsage_LightningThrow **** **** **** **** **** **** **** **** +16102 Swordsage_ManticoreParry **** **** **** **** **** **** **** **** +16103 Swordsage_MithralTornado **** **** **** **** **** **** **** **** +16104 Swordsage_PunishingStance **** **** **** **** **** **** **** **** +16105 Swordsage_ScythingBlade **** **** **** **** **** **** **** **** +16106 Swordsage_SteelWind **** **** **** **** **** **** **** **** +16107 Swordsage_SteelyStrike **** **** **** **** **** **** **** **** +16108 Swordsage_StrikeOfPerfectClarity **** **** **** **** **** **** **** **** +16109 Swordsage_SupremeBladeParry **** **** **** **** **** **** **** **** +16110 Swordsage_WallOfBlades **** **** **** **** **** **** **** **** +16111 Swordsage_BafflingDefense **** **** **** **** **** **** **** **** +16112 Swordsage_BallistaThrow **** **** **** **** **** **** **** **** +16113 Swordsage_CleverPositioning **** **** **** **** **** **** **** **** +16114 Swordsage_CometThrow **** **** **** **** **** **** **** **** +16115 Swordsage_CounterCharge **** **** **** **** **** **** **** **** +16116 Swordsage_DevastatingThrow **** **** **** **** **** **** **** **** +16117 Swordsage_FeignedOpening **** **** **** **** **** **** **** **** +16118 Swordsage_FoolsStrike **** **** **** **** **** **** **** **** +16119 Swordsage_GhostlyDefense **** **** **** **** **** **** **** **** +16120 Swordsage_GiantKillingStyle **** **** **** **** **** **** **** **** +16121 Swordsage_HydraSlayingStrike **** **** **** **** **** **** **** **** +16122 Swordsage_MightyThrow **** **** **** **** **** **** **** **** +16123 Swordsage_MirroredPursuit **** **** **** **** **** **** **** **** +16124 Swordsage_ScorpionParry **** **** **** **** **** **** **** **** +16125 Swordsage_ShiftingDefense **** **** **** **** **** **** **** **** +16126 Swordsage_SoaringThrow **** **** **** **** **** **** **** **** +16127 Swordsage_StalkingShadow **** **** **** **** **** **** **** **** +16128 Swordsage_StepOfTheWind **** **** **** **** **** **** **** **** +16129 Swordsage_StrikeOfTheBrokenShield **** **** **** **** **** **** **** **** +16130 Swordsage_TornadoThrow **** **** **** **** **** **** **** **** +16131 Swordsage_AssassinsStance **** **** **** **** **** **** **** **** +16132 Swordsage_BalanceOnTheSky **** **** **** **** **** **** **** **** +16133 Swordsage_BloodlettingStrike **** **** **** **** **** **** **** **** +16134 Swordsage_ChildOfShadow **** **** **** **** **** **** **** **** +16135 Swordsage_ClingingShadowStrike **** **** **** **** **** **** **** **** +16136 Swordsage_CloakOfDeception **** **** **** **** **** **** **** **** +16137 Swordsage_DanceOfTheSpider **** **** **** **** **** **** **** **** +16138 Swordsage_DeathInTheDark **** **** **** **** **** **** **** **** +16139 Swordsage_DrainVitality **** **** **** **** **** **** **** **** +16140 Swordsage_EnervatingShadowStrike **** **** **** **** **** **** **** **** +16141 Swordsage_FiveShadowCreepingIceEnervationStrike **** **** **** **** **** **** **** **** +16142 Swordsage_GhostBlade **** **** **** **** **** **** **** **** +16143 Swordsage_HandOfDeath **** **** **** **** **** **** **** **** +16144 Swordsage_IslandOfBlades **** **** **** **** **** **** **** **** +16145 Swordsage_ObscuringShadowVeil **** **** **** **** **** **** **** **** +16146 Swordsage_OneWithShadow **** **** **** **** **** **** **** **** +16147 Swordsage_ShadowBladeTechnique **** **** **** **** **** **** **** **** +16148 Swordsage_ShadowBlink **** **** **** **** **** **** **** **** +16149 Swordsage_ShadowGarrote **** **** **** **** **** **** **** **** +16150 Swordsage_ShadowJaunt **** **** **** **** **** **** **** **** +16151 Swordsage_ShadowNoose **** **** **** **** **** **** **** **** +16152 Swordsage_ShadowStride **** **** **** **** **** **** **** **** +16153 Swordsage_StalkerInTheNight **** **** **** **** **** **** **** **** +16154 Swordsage_StepOfTheDancingMoth **** **** **** **** **** **** **** **** +16155 Swordsage_StrengthDrainingStrike **** **** **** **** **** **** **** **** +16156 Swordsage_AdamantineBones **** **** **** **** **** **** **** **** +16157 Swordsage_AncientMountainHammer **** **** **** **** **** **** **** **** +16158 Swordsage_BonesplittingStrike **** **** **** **** **** **** **** **** +16159 Swordsage_Bonecrusher **** **** **** **** **** **** **** **** +16160 Swordsage_BoulderRoll **** **** **** **** **** **** **** **** +16161 Swordsage_ChargingMinotaur **** **** **** **** **** **** **** **** +16162 Swordsage_ColossusStrike **** **** **** **** **** **** **** **** +16163 Swordsage_CrushingVise **** **** **** **** **** **** **** **** +16164 Swordsage_CrushingWeightOfTheMountain **** **** **** **** **** **** **** **** +16165 Swordsage_EarthstrikeQuake **** **** **** **** **** **** **** **** +16166 Swordsage_ElderMountainHammer **** **** **** **** **** **** **** **** +16167 Swordsage_GiantsStance **** **** **** **** **** **** **** **** +16168 Swordsage_IronBones **** **** **** **** **** **** **** **** +16169 Swordsage_IrresistibleMountainStrike **** **** **** **** **** **** **** **** +16170 Swordsage_MountainAvalanche **** **** **** **** **** **** **** **** +16171 Swordsage_MountainHammer **** **** **** **** **** **** **** **** +16172 Swordsage_MountainTombstoneStrike **** **** **** **** **** **** **** **** +16173 Swordsage_OverwhelmingMountainStrike **** **** **** **** **** **** **** **** +16174 Swordsage_RootsOfTheMountain **** **** **** **** **** **** **** **** +16175 Swordsage_StoneBones **** **** **** **** **** **** **** **** +16176 Swordsage_StoneDragonsFury **** **** **** **** **** **** **** **** +16177 Swordsage_StoneVise **** **** **** **** **** **** **** **** +16178 Swordsage_StonefootStance **** **** **** **** **** **** **** **** +16179 Swordsage_StrengthOfStone **** **** **** **** **** **** **** **** +16180 Swordsage_BloodInTheWater **** **** **** **** **** **** **** **** +16181 Swordsage_ClawAtTheMoon **** **** **** **** **** **** **** **** +16182 Swordsage_DancingMongoose **** **** **** **** **** **** **** **** +16183 Swordsage_DeathFromAbove **** **** **** **** **** **** **** **** +16184 Swordsage_FeralDeathBlow **** **** **** **** **** **** **** **** +16185 Swordsage_FleshRipper **** **** **** **** **** **** **** **** +16186 Swordsage_FountainOfBlood **** **** **** **** **** **** **** **** +16187 Swordsage_GirallonWindmillFleshRip **** **** **** **** **** **** **** **** +16188 Swordsage_HamstringAttack **** **** **** **** **** **** **** **** +16189 Swordsage_HuntersSense **** **** **** **** **** **** **** **** +16190 Swordsage_LeapingDragonStance **** **** **** **** **** **** **** **** +16191 Swordsage_PouncingCharge **** **** **** **** **** **** **** **** +16192 Swordsage_PreyOnTheWeak **** **** **** **** **** **** **** **** +16193 Swordsage_RabidBearStrike **** **** **** **** **** **** **** **** +16194 Swordsage_RabidWolfStrike **** **** **** **** **** **** **** **** +16195 Swordsage_RagingMongoose **** **** **** **** **** **** **** **** +16196 Swordsage_SoaringRaptorStrike **** **** **** **** **** **** **** **** +16197 Swordsage_SuddenLeap **** **** **** **** **** **** **** **** +16198 Swordsage_SwoopingDragonStrike **** **** **** **** **** **** **** **** +16199 Swordsage_WolfClimbsTheMountain **** **** **** **** **** **** **** **** +16200 Swordsage_WolfFangStrike **** **** **** **** **** **** **** **** +16201 Swordsage_WolfPackTactics **** **** **** **** **** **** **** **** +16202 Swordsage_WolverineStance **** **** **** **** **** **** **** **** +16203 Swordsage_BattleLeadersCharge **** **** **** **** **** **** **** **** +16204 Swordsage_BolsteringVoice **** **** **** **** **** **** **** **** +16205 Swordsage_ClarionCall **** **** **** **** **** **** **** **** +16206 Swordsage_CoveringStrike **** **** **** **** **** **** **** **** +16207 Swordsage_DouseTheFlames **** **** **** **** **** **** **** **** +16208 Swordsage_FlankingManeuver **** **** **** **** **** **** **** **** +16209 Swordsage_LeadingTheAttack **** **** **** **** **** **** **** **** +16210 Swordsage_LeadingTheCharge **** **** **** **** **** **** **** **** +16211 Swordsage_LionsRoar **** **** **** **** **** **** **** **** +16212 Swordsage_OrderForgedFromChaos **** **** **** **** **** **** **** **** +16213 Swordsage_PressTheAdvantage **** **** **** **** **** **** **** **** +16214 Swordsage_SwarmTactics **** **** **** **** **** **** **** **** +16215 Swordsage_SwarmingAssault **** **** **** **** **** **** **** **** +16216 Swordsage_TacticalStrike **** **** **** **** **** **** **** **** +16217 Swordsage_TacticsOfTheWolf **** **** **** **** **** **** **** **** +16218 Swordsage_WarLeadersCharge **** **** **** **** **** **** **** **** +16219 Swordsage_WarMastersCharge **** **** **** **** **** **** **** **** +16220 Swordsage_WhiteRavenHammer **** **** **** **** **** **** **** **** +16221 Swordsage_WhiteRavenStrike **** **** **** **** **** **** **** **** +16222 Swordsage_WhiteRavenTactics **** **** **** **** **** **** **** **** +16223 Warblade_BlisteringFlourish **** **** **** **** **** **** **** **** +16224 Warblade_BurningBlade **** **** **** **** **** **** **** **** +16225 Warblade_BurningBrand **** **** **** **** **** **** **** **** +16226 Warblade_DeathMark **** **** **** **** **** **** **** **** +16227 Warblade_DesertTempest **** **** **** **** **** **** **** **** +16228 Warblade_DistractingEmber **** **** **** **** **** **** **** **** +16229 Warblade_DragonsFlame **** **** **** **** **** **** **** **** +16230 Warblade_FanTheFlames **** **** **** **** **** **** **** **** +16231 Warblade_FieryAssault **** **** **** **** **** **** **** **** +16232 Warblade_FireRiposte **** **** **** **** **** **** **** **** +16233 Warblade_Firesnake **** **** **** **** **** **** **** **** +16234 Warblade_FlamesBlessing **** **** **** **** **** **** **** **** +16235 Warblade_FlashingSun **** **** **** **** **** **** **** **** +16236 Warblade_HatchlingsFlame **** **** **** **** **** **** **** **** +16237 Warblade_HolocaustCloak **** **** **** **** **** **** **** **** +16238 Warblade_InfernoBlade **** **** **** **** **** **** **** **** +16239 Warblade_InfernoBlast **** **** **** **** **** **** **** **** +16240 Warblade_LeapingFlame **** **** **** **** **** **** **** **** +16241 Warblade_LingeringInferno **** **** **** **** **** **** **** **** +16242 Warblade_RingOfFire **** **** **** **** **** **** **** **** +16243 Warblade_RisingPhoenix **** **** **** **** **** **** **** **** +16244 Warblade_SalamanderCharge **** **** **** **** **** **** **** **** +16245 Warblade_SearingBlade **** **** **** **** **** **** **** **** +16246 Warblade_SearingCharge **** **** **** **** **** **** **** **** +16247 Warblade_WindStride **** **** **** **** **** **** **** **** +16248 Warblade_WyrmsFlame **** **** **** **** **** **** **** **** +16249 Warblade_ZephyrDance **** **** **** **** **** **** **** **** +16250 Warblade_AuraOfChaos **** **** **** **** **** **** **** **** +16251 Warblade_AuraOfPerfectOrder **** **** **** **** **** **** **** **** +16252 Warblade_AuraOfTriumph **** **** **** **** **** **** **** **** +16253 Warblade_AuraOfTyranny **** **** **** **** **** **** **** **** +16254 Warblade_CastigatingStrike **** **** **** **** **** **** **** **** +16255 Warblade_CrusadersStrike **** **** **** **** **** **** **** **** +16256 Warblade_DauntingStrike **** **** **** **** **** **** **** **** +16257 Warblade_DefensiveRebuke **** **** **** **** **** **** **** **** +16258 Warblade_DivineSurge **** **** **** **** **** **** **** **** +16259 Warblade_DivineSurgeGreater **** **** **** **** **** **** **** **** +16260 Warblade_DivineSurgeGreaterSub1 **** **** **** **** **** **** **** **** +16261 Warblade_DivineSurgeGreaterSub2 **** **** **** **** **** **** **** **** +16262 Warblade_DivineSurgeGreaterSub3 **** **** **** **** **** **** **** **** +16263 Warblade_DoomCharge **** **** **** **** **** **** **** **** +16264 Warblade_EntanglingBlade **** **** **** **** **** **** **** **** +16265 Warblade_Foehammer **** **** **** **** **** **** **** **** +16266 Warblade_ImmortalFortitude **** **** **** **** **** **** **** **** +16267 Warblade_IronGuardsGlare **** **** **** **** **** **** **** **** +16268 Warblade_LawBearer **** **** **** **** **** **** **** **** +16269 Warblade_MartialSpirit **** **** **** **** **** **** **** **** +16270 Warblade_RadiantCharge **** **** **** **** **** **** **** **** +16271 Warblade_RallyingStrike **** **** **** **** **** **** **** **** +16272 Warblade_RevitalizingStrike **** **** **** **** **** **** **** **** +16273 Warblade_ShieldBlock **** **** **** **** **** **** **** **** +16274 Warblade_ShieldCounter **** **** **** **** **** **** **** **** +16275 Warblade_StrikeOfRighteousVitality **** **** **** **** **** **** **** **** +16276 Warblade_ThicketOfBlades **** **** **** **** **** **** **** **** +16277 Warblade_TideOfChaos **** **** **** **** **** **** **** **** +16278 Warblade_VanguardStrike **** **** **** **** **** **** **** **** +16279 Warblade_ActionBeforeThought **** **** **** **** **** **** **** **** +16280 Warblade_AvalancheOfBlades **** **** **** **** **** **** **** **** +16281 Warblade_BoundingAssault **** **** **** **** **** **** **** **** +16282 Warblade_DiamondDefense **** **** **** **** **** **** **** **** +16283 Warblade_DiamondNightmareBlade **** **** **** **** **** **** **** **** +16284 Warblade_DisruptingBlow **** **** **** **** **** **** **** **** +16285 Warblade_EmeraldRazor **** **** **** **** **** **** **** **** +16286 Warblade_HearingTheAir **** **** **** **** **** **** **** **** +16287 Warblade_InsightfulStrike **** **** **** **** **** **** **** **** +16288 Warblade_InsightfulStrikeGreater **** **** **** **** **** **** **** **** +16289 Warblade_MindOverBody **** **** **** **** **** **** **** **** +16290 Warblade_MindStrike **** **** **** **** **** **** **** **** +16291 Warblade_MomentOfAlacrity **** **** **** **** **** **** **** **** +16292 Warblade_MomentOfPerfectMind **** **** **** **** **** **** **** **** +16293 Warblade_PearlOfBlackDoubt **** **** **** **** **** **** **** **** +16294 Warblade_QuicksilverMotion **** **** **** **** **** **** **** **** +16295 Warblade_RapidCounter **** **** **** **** **** **** **** **** +16296 Warblade_RubyNightmareBlade **** **** **** **** **** **** **** **** +16297 Warblade_SapphireNightmareBlade **** **** **** **** **** **** **** **** +16298 Warblade_StanceOfAlacrity **** **** **** **** **** **** **** **** +16299 ####END_OF_TOB_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +16300 Templates_16300-16999 **** **** **** **** **** **** **** **** +16301 Celestial_Smite_Evil **** **** **** **** **** **** **** **** +16302 Fiendish_Smite_Good **** **** **** **** **** **** **** **** +16303 Half_Celestial_Smite_Evil **** **** **** **** **** **** **** **** +16304 Half_Celestial_Protection_from_Evil **** **** **** **** **** **** **** **** +16305 Half_Celestial_Bless **** **** **** **** **** **** **** **** +16306 Half_Celestial_Aid **** **** **** **** **** **** **** **** +16307 Half_Celestial_Detect_Evil **** **** **** **** **** **** **** **** +16308 Half_Celestial_Cure_Serious_Wounds **** **** **** **** **** **** **** **** +16309 Half_Celestial_Neutralize_Poison **** **** **** **** **** **** **** **** +16310 Half_Celestial_HolySmite **** **** **** **** **** **** **** **** +16311 Half_Celestial_Remove_Disease **** **** **** **** **** **** **** **** +16312 Half_Celestial_DispelEvil **** **** **** **** **** **** **** **** +16313 Half_Celestial_Holy_Word **** **** **** **** **** **** **** **** +16314 Half_Celestial_HolyAura **** **** **** **** **** **** **** **** +16315 Half_Celestial_Hallow **** **** **** **** **** **** **** **** +16316 Half_Celestial_Mass_Charm **** **** **** **** **** **** **** **** +16317 Half_Celestial_Summon_Creature_IX **** **** **** **** **** **** **** **** +16318 Half_Celestial_Summon_Creature_IX_Air **** **** **** **** **** **** **** **** +16319 Half_Celestial_Summon_Creature_IX_Earth **** **** **** **** **** **** **** **** +16320 Half_Celestial_Summon_Creature_IX_Fire **** **** **** **** **** **** **** **** +16321 Half_Celestial_Summon_Creature_IX_Water **** **** **** **** **** **** **** **** +16322 Half_Celestial_Resurrection **** **** **** **** **** **** **** **** +16323 Half_Celestial_Daylight **** **** **** **** **** **** **** **** +16324 Half_Fiendish_Smite_Good **** **** **** **** **** **** **** **** +16325 Half_Fiendish_Darkness **** **** **** **** **** **** **** **** +16326 Half_Fiendish_Desecrate **** **** **** **** **** **** **** **** +16327 Half_Fiendish_Unholy_Blight **** **** **** **** **** **** **** **** +16328 Half_Fiendish_Poison **** **** **** **** **** **** **** **** +16329 Half_Fiendish_Contagion **** **** **** **** **** **** **** **** +16330 Half_Fiendish_Blasphemy **** **** **** **** **** **** **** **** +16331 Half_Fiendish_Unholy_Aura **** **** **** **** **** **** **** **** +16332 Half_Fiendish_Unhallow **** **** **** **** **** **** **** **** +16333 Half_Fiendish_Horrid_Wilting **** **** **** **** **** **** **** **** +16334 Half_Fiendish_Summon_Creature_IX **** **** **** **** **** **** **** **** +16335 Half_Fiendish_Summon_Creature_IX_Air **** **** **** **** **** **** **** **** +16336 Half_Fiendish_Summon_Creature_IX_Earth **** **** **** **** **** **** **** **** +16337 Half_Fiendish_Summon_Creature_IX_Fire **** **** **** **** **** **** **** **** +16338 Half_Fiendish_Summon_Creature_IX_Water **** **** **** **** **** **** **** **** +16339 Half_Fiendish_Destruction **** **** **** **** **** **** **** **** +16340 Lich_Fear_Aura **** **** **** **** **** **** **** **** +16341 Lich_Paralyzing_Touch **** **** **** **** **** **** **** **** +16342 Lich_Appearance **** **** **** **** **** **** **** **** +16343 Demilich_Alter_Self **** **** **** **** **** **** **** **** +16344 Demilich_Alter_Self_Learn **** **** **** **** **** **** **** **** +16345 Demilich_Alter_Self_Options **** **** **** **** **** **** **** **** +16346 Demilich_Alter_Self_QS1 **** **** **** **** **** **** **** **** +16347 Demilich_Alter_Self_QS2 **** **** **** **** **** **** **** **** +16348 Demilich_Alter_Self_QS3 **** **** **** **** **** **** **** **** +16349 Demilich_Astral_Projection **** **** **** **** **** **** **** **** +16350 Demilich_Create_Greater_Undead **** **** **** **** **** **** **** **** +16351 Demilich_Create_Undead **** **** **** **** **** **** **** **** +16352 Demilich_Death_Knell **** **** **** **** **** **** **** **** +16353 Demilich_Enervation **** **** **** **** **** **** **** **** +16354 Demilich_Greater_Dispel_Magic **** **** **** **** **** **** **** **** +16355 Demilich_Harm **** **** **** **** **** **** **** **** +16356 Demilich_Summon_Creature_I **** **** **** **** **** **** **** **** +16357 Demilich_Summon_Creature_II **** **** **** **** **** **** **** **** +16358 Demilich_Summon_Creature_III **** **** **** **** **** **** **** **** +16359 Demilich_Summon_Creature_IV **** **** **** **** **** **** **** **** +16360 Demilich_Summon_Creature_V **** **** **** **** **** **** **** **** +16361 Demilich_Summon_Creature_VI **** **** **** **** **** **** **** **** +16362 Demilich_Summon_Creature_VII **** **** **** **** **** **** **** **** +16363 Demilich_Summon_Creature_VII_Air **** **** **** **** **** **** **** **** +16364 Demilich_Summon_Creature_VII_Earth **** **** **** **** **** **** **** **** +16365 Demilich_Summon_Creature_VII_Fire **** **** **** **** **** **** **** **** +16366 Demilich_Summon_Creature_VII_Water **** **** **** **** **** **** **** **** +16367 Demilich_Summon_Creature_VIII **** **** **** **** **** **** **** **** +16368 Demilich_Summon_Creature_VIII_Air **** **** **** **** **** **** **** **** +16369 Demilich_Summon_Creature_VIII_Earth **** **** **** **** **** **** **** **** +16370 Demilich_Summon_Creature_VIII_Fire **** **** **** **** **** **** **** **** +16371 Demilich_Summon_Creature_VIII_Water **** **** **** **** **** **** **** **** +16372 Demilich_Summon_Creature_IX **** **** **** **** **** **** **** **** +16373 Demilich_Summon_Creature_IX_Air **** **** **** **** **** **** **** **** +16374 Demilich_Summon_Creature_IX_Earth **** **** **** **** **** **** **** **** +16375 Demilich_Summon_Creature_IX_Fire **** **** **** **** **** **** **** **** +16376 Demilich_Summon_Creature_IX_Water **** **** **** **** **** **** **** **** +16377 Demilich_Telekinesis **** **** **** **** **** **** **** **** +16378 Demilich_Weird **** **** **** **** **** **** **** **** +16379 Demilich_Greater_Planar_Ally **** **** **** **** **** **** **** **** +16380 HalfDragon_Breath_Weapon **** **** **** **** **** **** **** **** +16381 Archlich_Turn_Undead **** **** **** **** **** **** **** **** +16382 Saint_Bless **** **** **** **** **** **** **** **** +16383 Saint_Guidance_Placeholder **** **** **** **** **** **** **** **** +16384 Saint_Resistance **** **** **** **** **** **** **** **** +16385 Saint_Virtue **** **** **** **** **** **** **** **** +16386 Saint_Protective_Aura **** **** **** **** **** **** **** **** +16387 **** **** **** **** **** **** **** **** **** +16388 **** **** **** **** **** **** **** **** **** +16389 **WeaponsOfLegacy** **** **** **** **** **** **** **** **** +16390 BBB_Darkvision **** **** **** **** **** **** **** **** +16391 BBB_Longstrider **** **** **** **** **** **** **** **** +16392 BBB_Lesser_Restoration **** **** **** **** **** **** **** **** +16393 BBB_Teleport_SelfOnly **** **** **** **** **** **** **** **** +16394 BBB_Protection_from_Evil **** **** **** **** **** **** **** **** +16395 BBB_Drowseeker **** **** **** **** **** **** **** **** +16396 BBB_ShockingShot **** **** **** **** **** **** **** **** +16397 BBB_PierceTheBlackHeart **** **** **** **** **** **** **** **** +16398 Steadfast_vigor **** **** **** **** **** **** **** **** +16399 Steadfast_slow **** **** **** **** **** **** **** **** +16400 Flay_SnakeSting **** **** **** **** **** **** **** **** +16401 Flay_WhipWrap **** **** **** **** **** **** **** **** +16402 CrimsonRuination_FrozenFate **** **** **** **** **** **** **** **** +16403 Devious_DetectThoughts **** **** **** **** **** **** **** **** +16404 SimpleBow_TrueSeeing **** **** **** **** **** **** **** **** +16405 SimpleBow_Prescience **** **** **** **** **** **** **** **** +16406 SimpleBow_Focus **** **** **** **** **** **** **** **** +16407 Aradros_Extend **** **** **** **** **** **** **** **** +16408 Aradros_Survive_Master **** **** **** **** **** **** **** **** +16409 Aradros_Survive_Acid **** **** **** **** **** **** **** **** +16410 Aradros_Survive_Cold **** **** **** **** **** **** **** **** +16411 Aradros_Survive_Elec **** **** **** **** **** **** **** **** +16412 Aradros_Survive_Fire **** **** **** **** **** **** **** **** +16413 Aradros_Survive_Sonic **** **** **** **** **** **** **** **** +16414 Guurgal_Force **** **** **** **** **** **** **** **** +16415 Guurgal_Rage **** **** **** **** **** **** **** **** +16416 DivSpark_Fear **** **** **** **** **** **** **** **** +16417 DivSpark_Light **** **** **** **** **** **** **** **** +16418 Wargirds_Haste **** **** **** **** **** **** **** **** +16419 Wargirds_Stoneskin **** **** **** **** **** **** **** **** +16420 DesertWind_FierySlash **** **** **** **** **** **** **** **** +16421 DesertWind_HowlingWind **** **** **** **** **** **** **** **** +16422 DesertWind_FanFlames **** **** **** **** **** **** **** **** +16423 DesertWind_DustDesert **** **** **** **** **** **** **** **** +16424 Mindsplinter_VirtueDenied **** **** **** **** **** **** **** **** +16425 Mindsplinter_KissOfDeath **** **** **** **** **** **** **** **** +16426 Mindsplinter_BattleShriek **** **** **** **** **** **** **** **** +16427 Mindsplinter_RuinousHowl **** **** **** **** **** **** **** **** +16428 NotchedSpear_ParliamentOfFishes **** **** **** **** **** **** **** **** +16429 NotchedSpear_ConcealmentKraken **** **** **** **** **** **** **** **** +16430 NotchedSpear_ScionSea **** **** **** **** **** **** **** **** +16431 NotchedSpear_CommandSeaChildren **** **** **** **** **** **** **** **** +16432 Ur_SwiftStride **** **** **** **** **** **** **** **** +16433 Ur_HealingTotem **** **** **** **** **** **** **** **** +16434 Ur_SavageTransformation **** **** **** **** **** **** **** **** +16435 FlamecastersBolt_MarkTarget **** **** **** **** **** **** **** **** +16436 FlamecastersBolt_Morale **** **** **** **** **** **** **** **** +16437 FlamecastersBolt_Fireball **** **** **** **** **** **** **** **** +16438 StalkersBow_StalkersInsight **** **** **** **** **** **** **** **** +16439 StalkersBow_Ethereal **** **** **** **** **** **** **** **** +16440 Exordius_Guidance **** **** **** **** **** **** **** **** +16441 Exordius_Cure **** **** **** **** **** **** **** **** +16442 Exordius_Dismissal **** **** **** **** **** **** **** **** +16443 Caladbolg_Imprison **** **** **** **** **** **** **** **** +16444 HammerWitches_Detect **** **** **** **** **** **** **** **** +16445 HammerWitches_Spellbreaker **** **** **** **** **** **** **** **** +16446 HammerWitches_AMF **** **** **** **** **** **** **** **** +16447 HammerWitches_Dispel **** **** **** **** **** **** **** **** +16448 HammerWitches_Mantle **** **** **** **** **** **** **** **** +16449 SlingOfTheDireWind_StunningStone **** **** **** **** **** **** **** **** +16450 SlingOfTheDireWind_GustOfWind **** **** **** **** **** **** **** **** +16451 SlingOfTheDireWind_WindWall **** **** **** **** **** **** **** **** +16452 Treebrother_Shillelagh **** **** **** **** **** **** **** **** +16453 Treebrother_Charm_Plant **** **** **** **** **** **** **** **** +16454 Treebrother_Entangle **** **** **** **** **** **** **** **** +16455 Treebrother_Owls_Insight **** **** **** **** **** **** **** **** +16456 Treebrother_Changestaff **** **** **** **** **** **** **** **** +16457 FullMoonsTrick_Rage **** **** **** **** **** **** **** **** +16458 FullMoonsTrick_Invis **** **** **** **** **** **** **** **** +16459 FiendkillersFlail_Darkvis **** **** **** **** **** **** **** **** +16460 FiendkillersFlail_Detect **** **** **** **** **** **** **** **** +16461 ScalesBalance_Detect **** **** **** **** **** **** **** **** +16462 ScalesBalance_Cure **** **** **** **** **** **** **** **** +16463 ScalesBalance_Knell **** **** **** **** **** **** **** **** +16464 ScalesBalance_Enerv **** **** **** **** **** **** **** **** +16465 ScalesBalance_Heal **** **** **** **** **** **** **** **** +16466 ScalesBalance_Finger **** **** **** **** **** **** **** **** +16467 ShishiO_Charm **** **** **** **** **** **** **** **** +16468 ShishiO_Summon **** **** **** **** **** **** **** **** +16469 ShishiO_Poly **** **** **** **** **** **** **** **** +16470 ShishiO_Shout **** **** **** **** **** **** **** **** +16471 Dymondheart_ShedBolts **** **** **** **** **** **** **** **** +16472 Dymondheart_Deflect **** **** **** **** **** **** **** **** +16473 Dymondheart_Daylight **** **** **** **** **** **** **** **** +16474 Dymondheart_Cure **** **** **** **** **** **** **** **** +16475 Dymondheart_Banish **** **** **** **** **** **** **** **** +16476 Sunsword_Daylight **** **** **** **** **** **** **** **** +16477 Sunsword_Death_Ward **** **** **** **** **** **** **** **** +16478 Sunsword_Banish **** **** **** **** **** **** **** **** +16479 Sunsword_Undeath_to_Death **** **** **** **** **** **** **** **** +16480 Blackrazor_Detect **** **** **** **** **** **** **** **** +16481 Blackrazor_Knell **** **** **** **** **** **** **** **** +16482 Blackrazor_Haste **** **** **** **** **** **** **** **** +16483 Ramethene_Detect **** **** **** **** **** **** **** **** +16484 Ramethene_Smite **** **** **** **** **** **** **** **** +16485 Ramethene_Resist_Elements **** **** **** **** **** **** **** **** +16486 Ramethene_Cloudkill **** **** **** **** **** **** **** **** +16487 Ramethene_SuddenMaximize **** **** **** **** **** **** **** **** +16488 Ramethene_Horrid_Wilting **** **** **** **** **** **** **** **** +16489 Wyrmbane_Cause_Fear **** **** **** **** **** **** **** **** +16490 Wyrmbane_Lightning_Bolt **** **** **** **** **** **** **** **** +16491 Wyrmbane_Sudden_Emp **** **** **** **** **** **** **** **** +16492 Wyrmbane_Breath_Lightning **** **** **** **** **** **** **** **** +16493 Whelm_Detect_Giant **** **** **** **** **** **** **** **** +16494 Whelm_Locate_Object **** **** **** **** **** **** **** **** +16495 Whelm_Detect_Goblin **** **** **** **** **** **** **** **** +16496 Ravenkind_Dancing_Lights **** **** **** **** **** **** **** **** +16497 Ravenkind_Light **** **** **** **** **** **** **** **** +16498 Ravenkind_Flare **** **** **** **** **** **** **** **** +16499 Ravenkind_Detect_Undead **** **** **** **** **** **** **** **** +16500 Ravenkind_Halt_Undead **** **** **** **** **** **** **** **** +16501 Ravenkind_Cure_Light_Wounds **** **** **** **** **** **** **** **** +16502 Ravenkind_Daylight **** **** **** **** **** **** **** **** +16503 Ravenkind_Death_Ward **** **** **** **** **** **** **** **** +16504 Ravenkind_Break_Enchantment **** **** **** **** **** **** **** **** +16505 Ravenkind_Mass_Heal **** **** **** **** **** **** **** **** +16506 LastCitadel_LeadingTheAttack **** **** **** **** **** **** **** **** +16507 LastCitadel_Prayer **** **** **** **** **** **** **** **** +16508 LastCitadel_Remove_Fear **** **** **** **** **** **** **** **** +16509 LastCitadel_Cure_Critical_Wounds **** **** **** **** **** **** **** **** +16510 LastCitadel_Blade_Barrier **** **** **** **** **** **** **** **** +16511 LastCitadel_Heal **** **** **** **** **** **** **** **** +16512 Unfettered_ChargingMinotaur **** **** **** **** **** **** **** **** +16513 Unfettered_ENLARGE_PERSON **** **** **** **** **** **** **** **** +16514 Unfettered_Etherealness **** **** **** **** **** **** **** **** +16515 Unfettered_Stoneskin **** **** **** **** **** **** **** **** +16516 Unfettered_Mordenkainens_Sword **** **** **** **** **** **** **** **** +16517 Hillcrusher_Earthen_Might **** **** **** **** **** **** **** **** +16518 Hillcrusher_Soften_Earth **** **** **** **** **** **** **** **** +16519 Hillcrusher_Fangs_of_Stone **** **** **** **** **** **** **** **** +16520 Hillcrusher_Raise_the_Earth **** **** **** **** **** **** **** **** +16521 Hillcrusher_Shake_the_Earth **** **** **** **** **** **** **** **** +16522 DesertWindToB_BurningBlade **** **** **** **** **** **** **** **** +16523 DesertWindToB_FanTheFlames **** **** **** **** **** **** **** **** +16524 DesertWindToB_WyrmsFlame **** **** **** **** **** **** **** **** +16525 Faithful_FaithfulStrike **** **** **** **** **** **** **** **** +16526 Faithful_Detect_Evil **** **** **** **** **** **** **** **** +16527 Faithful_Lesser_Restoration **** **** **** **** **** **** **** **** +16528 Faithful_Restoration **** **** **** **** **** **** **** **** +16529 Faithful_Resiliency **** **** **** **** **** **** **** **** +16530 Faithful_ImmortalFortitude **** **** **** **** **** **** **** **** +16531 SupernalClarity_SapphireNightmareBlade **** **** **** **** **** **** **** **** +16532 SupernalClarity_PsychicPoise **** **** **** **** **** **** **** **** +16533 SupernalClarity_Haste **** **** **** **** **** **** **** **** +16534 SupernalClarity_Freeeeeedom **** **** **** **** **** **** **** **** +16535 SupernalClarity_Time_Stop **** **** **** **** **** **** **** **** +16536 Kamate_SteelWind **** **** **** **** **** **** **** **** +16537 Kamate_ShockingGrasp **** **** **** **** **** **** **** **** +16538 Kamate_Lightning_Bolt **** **** **** **** **** **** **** **** +16539 Kamate_Chain_Lightning **** **** **** **** **** **** **** **** +16540 Kamate_True_Strike **** **** **** **** **** **** **** **** +16541 Eventide_CometThrow **** **** **** **** **** **** **** **** +16542 Eventide_BafflingDefense **** **** **** **** **** **** **** **** +16543 Eventide_Improved_Invisibility **** **** **** **** **** **** **** **** +16544 Umbral_Invisibility **** **** **** **** **** **** **** **** +16545 Umbral_Shadowstep **** **** **** **** **** **** **** **** +16546 Umbral_SpeedWeapon **** **** **** **** **** **** **** **** +16547 TigerFang_FrenziedCharge **** **** **** **** **** **** **** **** +16548 TigerFang_BattleFever **** **** **** **** **** **** **** **** +16549 TigerFang_Haste **** **** **** **** **** **** **** **** +16550 Bullybasher_KnockSilly **** **** **** **** **** **** **** **** +16551 Bullybasher_StoneGathering **** **** **** **** **** **** **** **** +16552 Bullybasher_LightningPunch **** **** **** **** **** **** **** **** +16553 Bullybasher_GiantBearing **** **** **** **** **** **** **** **** +16554 Lorestealer_Read_Magic **** **** **** **** **** **** **** **** +16555 Lorestealer_DetectMagic **** **** **** **** **** **** **** **** +16556 Lorestealer_Axecasting **** **** **** **** **** **** **** **** +16557 Durindana_Daylight **** **** **** **** **** **** **** **** +16558 Durindana_Death_Ward **** **** **** **** **** **** **** **** +16559 Durindana_Hallow **** **** **** **** **** **** **** **** +16560 Durindana_Dazzle **** **** **** **** **** **** **** **** +16561 Thaas_Detect_Demon **** **** **** **** **** **** **** **** +16562 Thaas_ObstructSummoning **** **** **** **** **** **** **** **** +16563 Thaas_Banishment **** **** **** **** **** **** **** **** +16564 Thaas_Teleport **** **** **** **** **** **** **** **** +16565 Quickspur_Entropic_Shield **** **** **** **** **** **** **** **** +16566 Quickspur_Resist_Elements **** **** **** **** **** **** **** **** +16567 Quickspur_PhantomSteed **** **** **** **** **** **** **** **** +16568 Quickspur_Blur **** **** **** **** **** **** **** **** +16569 Quickspur_Stoneskin **** **** **** **** **** **** **** **** +16570 BES_FIRE_OF_THE_HEART **** **** **** **** **** **** **** **** +16571 BES_ENTHRALLING_LIGHT **** **** **** **** **** **** **** **** +16572 BES_COLOR_SPRAY **** **** **** **** **** **** **** **** +16573 BES_BLINDING_FLASH **** **** **** **** **** **** **** **** +16574 BES_SHOOTING_STARS **** **** **** **** **** **** **** **** +16575 BES_GLITTERING_MOTES **** **** **** **** **** **** **** **** +16576 BES_TWINKLE **** **** **** **** **** **** **** **** +16577 BES_SILVER_STARLIGHT **** **** **** **** **** **** **** **** +16578 BES_STARLIGHT_DISPELLING **** **** **** **** **** **** **** **** +16579 BES_TALES_IN_THE_SKY **** **** **** **** **** **** **** **** +16580 BES_CALL_DOWN_A_STAR **** **** **** **** **** **** **** **** +16581 **** **** **** **** **** **** **** **** **** +16582 **** **** **** **** **** **** **** **** **** +16583 **** **** **** **** **** **** **** **** **** +16584 **** **** **** **** **** **** **** **** **** +16585 **** **** **** **** **** **** **** **** **** +16586 **** **** **** **** **** **** **** **** **** +16587 **** **** **** **** **** **** **** **** **** +16588 **** **** **** **** **** **** **** **** **** +16589 **** **** **** **** **** **** **** **** **** +16590 Templates_16300-16999 **** **** **** **** **** **** **** **** +16591 **** **** **** **** **** **** **** **** **** +16592 **** **** **** **** **** **** **** **** **** +16593 **** **** **** **** **** **** **** **** **** +16594 **** **** **** **** **** **** **** **** **** +16595 **** **** **** **** **** **** **** **** **** +16596 **** **** **** **** **** **** **** **** **** +16597 **** **** **** **** **** **** **** **** **** +16598 **** **** **** **** **** **** **** **** **** +16599 **** **** **** **** **** **** **** **** **** +16600 Templates_16300-16999 **** **** **** **** **** **** **** **** +16601 **** **** **** **** **** **** **** **** **** +16602 **** **** **** **** **** **** **** **** **** +16603 **** **** **** **** **** **** **** **** **** +16604 **** **** **** **** **** **** **** **** **** +16605 **** **** **** **** **** **** **** **** **** +16606 **** **** **** **** **** **** **** **** **** +16607 **** **** **** **** **** **** **** **** **** +16608 **** **** **** **** **** **** **** **** **** +16609 **** **** **** **** **** **** **** **** **** +16610 Templates_16300-16999 **** **** **** **** **** **** **** **** +16611 **** **** **** **** **** **** **** **** **** +16612 **** **** **** **** **** **** **** **** **** +16613 **** **** **** **** **** **** **** **** **** +16614 **** **** **** **** **** **** **** **** **** +16615 **** **** **** **** **** **** **** **** **** +16616 **** **** **** **** **** **** **** **** **** +16617 **** **** **** **** **** **** **** **** **** +16618 **** **** **** **** **** **** **** **** **** +16619 **** **** **** **** **** **** **** **** **** +16620 Templates_16300-16999 **** **** **** **** **** **** **** **** +16621 **** **** **** **** **** **** **** **** **** +16622 **** **** **** **** **** **** **** **** **** +16623 **** **** **** **** **** **** **** **** **** +16624 **** **** **** **** **** **** **** **** **** +16625 **** **** **** **** **** **** **** **** **** +16626 **** **** **** **** **** **** **** **** **** +16627 **** **** **** **** **** **** **** **** **** +16628 **** **** **** **** **** **** **** **** **** +16629 **** **** **** **** **** **** **** **** **** +16630 Templates_16300-16999 **** **** **** **** **** **** **** **** +16631 **** **** **** **** **** **** **** **** **** +16632 **** **** **** **** **** **** **** **** **** +16633 **** **** **** **** **** **** **** **** **** +16634 **** **** **** **** **** **** **** **** **** +16635 **** **** **** **** **** **** **** **** **** +16636 **** **** **** **** **** **** **** **** **** +16637 **** **** **** **** **** **** **** **** **** +16638 **** **** **** **** **** **** **** **** **** +16639 **** **** **** **** **** **** **** **** **** +16640 Templates_16300-16999 **** **** **** **** **** **** **** **** +16641 **** **** **** **** **** **** **** **** **** +16642 **** **** **** **** **** **** **** **** **** +16643 **** **** **** **** **** **** **** **** **** +16644 **** **** **** **** **** **** **** **** **** +16645 **** **** **** **** **** **** **** **** **** +16646 **** **** **** **** **** **** **** **** **** +16647 **** **** **** **** **** **** **** **** **** +16648 **** **** **** **** **** **** **** **** **** +16649 **** **** **** **** **** **** **** **** **** +16650 Templates_16300-16999 **** **** **** **** **** **** **** **** +16651 **** **** **** **** **** **** **** **** **** +16652 **** **** **** **** **** **** **** **** **** +16653 **** **** **** **** **** **** **** **** **** +16654 **** **** **** **** **** **** **** **** **** +16655 **** **** **** **** **** **** **** **** **** +16656 **** **** **** **** **** **** **** **** **** +16657 **** **** **** **** **** **** **** **** **** +16658 **** **** **** **** **** **** **** **** **** +16659 **** **** **** **** **** **** **** **** **** +16660 Templates_16300-16999 **** **** **** **** **** **** **** **** +16661 **** **** **** **** **** **** **** **** **** +16662 **** **** **** **** **** **** **** **** **** +16663 **** **** **** **** **** **** **** **** **** +16664 **** **** **** **** **** **** **** **** **** +16665 **** **** **** **** **** **** **** **** **** +16666 **** **** **** **** **** **** **** **** **** +16667 **** **** **** **** **** **** **** **** **** +16668 **** **** **** **** **** **** **** **** **** +16669 **** **** **** **** **** **** **** **** **** +16670 Templates_16300-16999 **** **** **** **** **** **** **** **** +16671 **** **** **** **** **** **** **** **** **** +16672 **** **** **** **** **** **** **** **** **** +16673 **** **** **** **** **** **** **** **** **** +16674 **** **** **** **** **** **** **** **** **** +16675 **** **** **** **** **** **** **** **** **** +16676 **** **** **** **** **** **** **** **** **** +16677 **** **** **** **** **** **** **** **** **** +16678 **** **** **** **** **** **** **** **** **** +16679 **** **** **** **** **** **** **** **** **** +16680 Templates_16300-16999 **** **** **** **** **** **** **** **** +16681 **** **** **** **** **** **** **** **** **** +16682 **** **** **** **** **** **** **** **** **** +16683 **** **** **** **** **** **** **** **** **** +16684 **** **** **** **** **** **** **** **** **** +16685 **** **** **** **** **** **** **** **** **** +16686 **** **** **** **** **** **** **** **** **** +16687 **** **** **** **** **** **** **** **** **** +16688 **** **** **** **** **** **** **** **** **** +16689 **** **** **** **** **** **** **** **** **** +16690 Templates_16300-16999 **** **** **** **** **** **** **** **** +16691 **** **** **** **** **** **** **** **** **** +16692 **** **** **** **** **** **** **** **** **** +16693 **** **** **** **** **** **** **** **** **** +16694 **** **** **** **** **** **** **** **** **** +16695 **** **** **** **** **** **** **** **** **** +16696 **** **** **** **** **** **** **** **** **** +16697 **** **** **** **** **** **** **** **** **** +16698 **** **** **** **** **** **** **** **** **** +16699 **** **** **** **** **** **** **** **** **** +16700 Templates_16300-16999 **** **** **** **** **** **** **** **** +16701 **** **** **** **** **** **** **** **** **** +16702 **** **** **** **** **** **** **** **** **** +16703 **** **** **** **** **** **** **** **** **** +16704 **** **** **** **** **** **** **** **** **** +16705 **** **** **** **** **** **** **** **** **** +16706 **** **** **** **** **** **** **** **** **** +16707 **** **** **** **** **** **** **** **** **** +16708 **** **** **** **** **** **** **** **** **** +16709 **** **** **** **** **** **** **** **** **** +16710 Templates_16300-16999 **** **** **** **** **** **** **** **** +16711 **** **** **** **** **** **** **** **** **** +16712 **** **** **** **** **** **** **** **** **** +16713 **** **** **** **** **** **** **** **** **** +16714 **** **** **** **** **** **** **** **** **** +16715 **** **** **** **** **** **** **** **** **** +16716 **** **** **** **** **** **** **** **** **** +16717 **** **** **** **** **** **** **** **** **** +16718 **** **** **** **** **** **** **** **** **** +16719 **** **** **** **** **** **** **** **** **** +16720 Templates_16300-16999 **** **** **** **** **** **** **** **** +16721 **** **** **** **** **** **** **** **** **** +16722 **** **** **** **** **** **** **** **** **** +16723 **** **** **** **** **** **** **** **** **** +16724 **** **** **** **** **** **** **** **** **** +16725 **** **** **** **** **** **** **** **** **** +16726 **** **** **** **** **** **** **** **** **** +16727 **** **** **** **** **** **** **** **** **** +16728 **** **** **** **** **** **** **** **** **** +16729 **** **** **** **** **** **** **** **** **** +16730 Templates_16300-16999 **** **** **** **** **** **** **** **** +16731 **** **** **** **** **** **** **** **** **** +16732 **** **** **** **** **** **** **** **** **** +16733 **** **** **** **** **** **** **** **** **** +16734 **** **** **** **** **** **** **** **** **** +16735 **** **** **** **** **** **** **** **** **** +16736 **** **** **** **** **** **** **** **** **** +16737 **** **** **** **** **** **** **** **** **** +16738 **** **** **** **** **** **** **** **** **** +16739 **** **** **** **** **** **** **** **** **** +16740 Templates_16300-16999 **** **** **** **** **** **** **** **** +16741 **** **** **** **** **** **** **** **** **** +16742 **** **** **** **** **** **** **** **** **** +16743 **** **** **** **** **** **** **** **** **** +16744 **** **** **** **** **** **** **** **** **** +16745 **** **** **** **** **** **** **** **** **** +16746 **** **** **** **** **** **** **** **** **** +16747 **** **** **** **** **** **** **** **** **** +16748 **** **** **** **** **** **** **** **** **** +16749 **** **** **** **** **** **** **** **** **** +16750 Templates_16300-16999 **** **** **** **** **** **** **** **** +16751 **** **** **** **** **** **** **** **** **** +16752 **** **** **** **** **** **** **** **** **** +16753 **** **** **** **** **** **** **** **** **** +16754 **** **** **** **** **** **** **** **** **** +16755 **** **** **** **** **** **** **** **** **** +16756 **** **** **** **** **** **** **** **** **** +16757 **** **** **** **** **** **** **** **** **** +16758 **** **** **** **** **** **** **** **** **** +16759 **** **** **** **** **** **** **** **** **** +16760 Templates_16300-16999 **** **** **** **** **** **** **** **** +16761 **** **** **** **** **** **** **** **** **** +16762 **** **** **** **** **** **** **** **** **** +16763 **** **** **** **** **** **** **** **** **** +16764 **** **** **** **** **** **** **** **** **** +16765 **** **** **** **** **** **** **** **** **** +16766 **** **** **** **** **** **** **** **** **** +16767 **** **** **** **** **** **** **** **** **** +16768 **** **** **** **** **** **** **** **** **** +16769 **** **** **** **** **** **** **** **** **** +16770 Templates_16300-16999 **** **** **** **** **** **** **** **** +16771 **** **** **** **** **** **** **** **** **** +16772 **** **** **** **** **** **** **** **** **** +16773 **** **** **** **** **** **** **** **** **** +16774 **** **** **** **** **** **** **** **** **** +16775 **** **** **** **** **** **** **** **** **** +16776 **** **** **** **** **** **** **** **** **** +16777 **** **** **** **** **** **** **** **** **** +16778 **** **** **** **** **** **** **** **** **** +16779 **** **** **** **** **** **** **** **** **** +16780 Templates_16300-16999 **** **** **** **** **** **** **** **** +16781 **** **** **** **** **** **** **** **** **** +16782 **** **** **** **** **** **** **** **** **** +16783 **** **** **** **** **** **** **** **** **** +16784 **** **** **** **** **** **** **** **** **** +16785 **** **** **** **** **** **** **** **** **** +16786 **** **** **** **** **** **** **** **** **** +16787 **** **** **** **** **** **** **** **** **** +16788 **** **** **** **** **** **** **** **** **** +16789 **** **** **** **** **** **** **** **** **** +16790 Templates_16300-16999 **** **** **** **** **** **** **** **** +16791 **** **** **** **** **** **** **** **** **** +16792 **** **** **** **** **** **** **** **** **** +16793 **** **** **** **** **** **** **** **** **** +16794 **** **** **** **** **** **** **** **** **** +16795 **** **** **** **** **** **** **** **** **** +16796 **** **** **** **** **** **** **** **** **** +16797 **** **** **** **** **** **** **** **** **** +16798 **** **** **** **** **** **** **** **** **** +16799 **** **** **** **** **** **** **** **** **** +16800 Templates_16300-16999 **** **** **** **** **** **** **** **** +16801 **** **** **** **** **** **** **** **** **** +16802 **** **** **** **** **** **** **** **** **** +16803 **** **** **** **** **** **** **** **** **** +16804 **** **** **** **** **** **** **** **** **** +16805 **** **** **** **** **** **** **** **** **** +16806 **** **** **** **** **** **** **** **** **** +16807 **** **** **** **** **** **** **** **** **** +16808 **** **** **** **** **** **** **** **** **** +16809 **** **** **** **** **** **** **** **** **** +16810 Templates_16300-16999 **** **** **** **** **** **** **** **** +16811 **** **** **** **** **** **** **** **** **** +16812 **** **** **** **** **** **** **** **** **** +16813 **** **** **** **** **** **** **** **** **** +16814 **** **** **** **** **** **** **** **** **** +16815 **** **** **** **** **** **** **** **** **** +16816 **** **** **** **** **** **** **** **** **** +16817 **** **** **** **** **** **** **** **** **** +16818 **** **** **** **** **** **** **** **** **** +16819 **** **** **** **** **** **** **** **** **** +16820 Templates_16300-16999 **** **** **** **** **** **** **** **** +16821 **** **** **** **** **** **** **** **** **** +16822 **** **** **** **** **** **** **** **** **** +16823 **** **** **** **** **** **** **** **** **** +16824 **** **** **** **** **** **** **** **** **** +16825 **** **** **** **** **** **** **** **** **** +16826 **** **** **** **** **** **** **** **** **** +16827 **** **** **** **** **** **** **** **** **** +16828 **** **** **** **** **** **** **** **** **** +16829 **** **** **** **** **** **** **** **** **** +16830 Templates_16300-16999 **** **** **** **** **** **** **** **** +16831 **** **** **** **** **** **** **** **** **** +16832 **** **** **** **** **** **** **** **** **** +16833 **** **** **** **** **** **** **** **** **** +16834 **** **** **** **** **** **** **** **** **** +16835 **** **** **** **** **** **** **** **** **** +16836 **** **** **** **** **** **** **** **** **** +16837 **** **** **** **** **** **** **** **** **** +16838 **** **** **** **** **** **** **** **** **** +16839 **** **** **** **** **** **** **** **** **** +16840 Templates_16300-16999 **** **** **** **** **** **** **** **** +16841 **** **** **** **** **** **** **** **** **** +16842 **** **** **** **** **** **** **** **** **** +16843 **** **** **** **** **** **** **** **** **** +16844 **** **** **** **** **** **** **** **** **** +16845 **** **** **** **** **** **** **** **** **** +16846 **** **** **** **** **** **** **** **** **** +16847 **** **** **** **** **** **** **** **** **** +16848 **** **** **** **** **** **** **** **** **** +16849 **** **** **** **** **** **** **** **** **** +16850 Templates_16300-16999 **** **** **** **** **** **** **** **** +16851 **** **** **** **** **** **** **** **** **** +16852 **** **** **** **** **** **** **** **** **** +16853 **** **** **** **** **** **** **** **** **** +16854 **** **** **** **** **** **** **** **** **** +16855 **** **** **** **** **** **** **** **** **** +16856 **** **** **** **** **** **** **** **** **** +16857 **** **** **** **** **** **** **** **** **** +16858 **** **** **** **** **** **** **** **** **** +16859 **** **** **** **** **** **** **** **** **** +16860 Templates_16300-16999 **** **** **** **** **** **** **** **** +16861 **** **** **** **** **** **** **** **** **** +16862 **** **** **** **** **** **** **** **** **** +16863 **** **** **** **** **** **** **** **** **** +16864 **** **** **** **** **** **** **** **** **** +16865 **** **** **** **** **** **** **** **** **** +16866 **** **** **** **** **** **** **** **** **** +16867 **** **** **** **** **** **** **** **** **** +16868 **** **** **** **** **** **** **** **** **** +16869 **** **** **** **** **** **** **** **** **** +16870 Templates_16300-16999 **** **** **** **** **** **** **** **** +16871 **** **** **** **** **** **** **** **** **** +16872 **** **** **** **** **** **** **** **** **** +16873 **** **** **** **** **** **** **** **** **** +16874 **** **** **** **** **** **** **** **** **** +16875 **** **** **** **** **** **** **** **** **** +16876 **** **** **** **** **** **** **** **** **** +16877 **** **** **** **** **** **** **** **** **** +16878 **** **** **** **** **** **** **** **** **** +16879 **** **** **** **** **** **** **** **** **** +16880 Templates_16300-16999 **** **** **** **** **** **** **** **** +16881 **** **** **** **** **** **** **** **** **** +16882 **** **** **** **** **** **** **** **** **** +16883 **** **** **** **** **** **** **** **** **** +16884 **** **** **** **** **** **** **** **** **** +16885 **** **** **** **** **** **** **** **** **** +16886 **** **** **** **** **** **** **** **** **** +16887 **** **** **** **** **** **** **** **** **** +16888 **** **** **** **** **** **** **** **** **** +16889 **** **** **** **** **** **** **** **** **** +16890 Templates_16300-16999 **** **** **** **** **** **** **** **** +16891 **** **** **** **** **** **** **** **** **** +16892 **** **** **** **** **** **** **** **** **** +16893 **** **** **** **** **** **** **** **** **** +16894 **** **** **** **** **** **** **** **** **** +16895 **** **** **** **** **** **** **** **** **** +16896 **** **** **** **** **** **** **** **** **** +16897 **** **** **** **** **** **** **** **** **** +16898 **** **** **** **** **** **** **** **** **** +16899 **** **** **** **** **** **** **** **** **** +16900 Templates_16300-16999 **** **** **** **** **** **** **** **** +16901 **** **** **** **** **** **** **** **** **** +16902 **** **** **** **** **** **** **** **** **** +16903 **** **** **** **** **** **** **** **** **** +16904 **** **** **** **** **** **** **** **** **** +16905 **** **** **** **** **** **** **** **** **** +16906 **** **** **** **** **** **** **** **** **** +16907 **** **** **** **** **** **** **** **** **** +16908 **** **** **** **** **** **** **** **** **** +16909 **** **** **** **** **** **** **** **** **** +16910 Templates_16300-16999 **** **** **** **** **** **** **** **** +16911 **** **** **** **** **** **** **** **** **** +16912 **** **** **** **** **** **** **** **** **** +16913 **** **** **** **** **** **** **** **** **** +16914 **** **** **** **** **** **** **** **** **** +16915 **** **** **** **** **** **** **** **** **** +16916 **** **** **** **** **** **** **** **** **** +16917 **** **** **** **** **** **** **** **** **** +16918 **** **** **** **** **** **** **** **** **** +16919 **** **** **** **** **** **** **** **** **** +16920 Templates_16300-16999 **** **** **** **** **** **** **** **** +16921 **** **** **** **** **** **** **** **** **** +16922 **** **** **** **** **** **** **** **** **** +16923 **** **** **** **** **** **** **** **** **** +16924 **** **** **** **** **** **** **** **** **** +16925 **** **** **** **** **** **** **** **** **** +16926 **** **** **** **** **** **** **** **** **** +16927 **** **** **** **** **** **** **** **** **** +16928 **** **** **** **** **** **** **** **** **** +16929 **** **** **** **** **** **** **** **** **** +16930 Templates_16300-16999 **** **** **** **** **** **** **** **** +16931 **** **** **** **** **** **** **** **** **** +16932 **** **** **** **** **** **** **** **** **** +16933 **** **** **** **** **** **** **** **** **** +16934 **** **** **** **** **** **** **** **** **** +16935 **** **** **** **** **** **** **** **** **** +16936 **** **** **** **** **** **** **** **** **** +16937 **** **** **** **** **** **** **** **** **** +16938 **** **** **** **** **** **** **** **** **** +16939 **** **** **** **** **** **** **** **** **** +16940 Templates_16300-16999 **** **** **** **** **** **** **** **** +16941 **** **** **** **** **** **** **** **** **** +16942 **** **** **** **** **** **** **** **** **** +16943 **** **** **** **** **** **** **** **** **** +16944 **** **** **** **** **** **** **** **** **** +16945 **** **** **** **** **** **** **** **** **** +16946 **** **** **** **** **** **** **** **** **** +16947 **** **** **** **** **** **** **** **** **** +16948 **** **** **** **** **** **** **** **** **** +16949 **** **** **** **** **** **** **** **** **** +16950 Templates_16300-16999 **** **** **** **** **** **** **** **** +16951 **** **** **** **** **** **** **** **** **** +16952 **** **** **** **** **** **** **** **** **** +16953 **** **** **** **** **** **** **** **** **** +16954 **** **** **** **** **** **** **** **** **** +16955 **** **** **** **** **** **** **** **** **** +16956 **** **** **** **** **** **** **** **** **** +16957 **** **** **** **** **** **** **** **** **** +16958 **** **** **** **** **** **** **** **** **** +16959 **** **** **** **** **** **** **** **** **** +16960 Templates_16300-16999 **** **** **** **** **** **** **** **** +16961 **** **** **** **** **** **** **** **** **** +16962 **** **** **** **** **** **** **** **** **** +16963 **** **** **** **** **** **** **** **** **** +16964 **** **** **** **** **** **** **** **** **** +16965 **** **** **** **** **** **** **** **** **** +16966 **** **** **** **** **** **** **** **** **** +16967 **** **** **** **** **** **** **** **** **** +16968 **** **** **** **** **** **** **** **** **** +16969 **** **** **** **** **** **** **** **** **** +16970 Templates_16300-16999 **** **** **** **** **** **** **** **** +16971 **** **** **** **** **** **** **** **** **** +16972 **** **** **** **** **** **** **** **** **** +16973 **** **** **** **** **** **** **** **** **** +16974 **** **** **** **** **** **** **** **** **** +16975 **** **** **** **** **** **** **** **** **** +16976 **** **** **** **** **** **** **** **** **** +16977 **** **** **** **** **** **** **** **** **** +16978 **** **** **** **** **** **** **** **** **** +16979 **** **** **** **** **** **** **** **** **** +16980 Templates_16300-16999 **** **** **** **** **** **** **** **** +16981 **** **** **** **** **** **** **** **** **** +16982 **** **** **** **** **** **** **** **** **** +16983 **** **** **** **** **** **** **** **** **** +16984 **** **** **** **** **** **** **** **** **** +16985 **** **** **** **** **** **** **** **** **** +16986 **** **** **** **** **** **** **** **** **** +16987 **** **** **** **** **** **** **** **** **** +16988 **** **** **** **** **** **** **** **** **** +16989 **** **** **** **** **** **** **** **** **** +16990 Templates_16300-16999 **** **** **** **** **** **** **** **** +16991 **** **** **** **** **** **** **** **** **** +16992 **** **** **** **** **** **** **** **** **** +16993 **** **** **** **** **** **** **** **** **** +16994 **** **** **** **** **** **** **** **** **** +16995 **** **** **** **** **** **** **** **** **** +16996 **** **** **** **** **** **** **** **** **** +16997 **** **** **** **** **** **** **** **** **** +16998 **** **** **** **** **** **** **** **** **** +16999 Templates_16300-16999 **** **** **** **** **** **** **** **** +17000 **** **** **** **** **** **** **** **** **** +17001 **** **** **** **** **** **** **** **** **** +17002 **** **** **** **** **** **** **** **** **** +17003 **** **** **** **** **** **** **** **** **** +17004 **** **** **** **** **** **** **** **** **** +17005 **** **** **** **** **** **** **** **** **** +17006 **** **** **** **** **** **** **** **** **** +17007 **** **** **** **** **** **** **** **** **** +17008 **** **** **** **** **** **** **** **** **** +17009 **** **** **** **** **** **** **** **** **** +17010 **** **** **** **** **** **** **** **** **** +17011 **** **** **** **** **** **** **** **** **** +17012 **** **** **** **** **** **** **** **** **** +17013 **** **** **** **** **** **** **** **** **** +17014 **** **** **** **** **** **** **** **** **** +17015 **** **** **** **** **** **** **** **** **** +17016 **** **** **** **** **** **** **** **** **** +17017 **** **** **** **** **** **** **** **** **** +17018 **** **** **** **** **** **** **** **** **** +17019 **** **** **** **** **** **** **** **** **** +17020 **** **** **** **** **** **** **** **** **** +17021 **** **** **** **** **** **** **** **** **** +17022 **** **** **** **** **** **** **** **** **** +17023 **** **** **** **** **** **** **** **** **** +17024 **** **** **** **** **** **** **** **** **** +17025 **** **** **** **** **** **** **** **** **** +17026 **** **** **** **** **** **** **** **** **** +17027 **** **** **** **** **** **** **** **** **** +17028 **** **** **** **** **** **** **** **** **** +17029 **** **** **** **** **** **** **** **** **** +17030 **** **** **** **** **** **** **** **** **** +17031 **** **** **** **** **** **** **** **** **** +17032 **** **** **** **** **** **** **** **** **** +17033 **** **** **** **** **** **** **** **** **** +17034 **** **** **** **** **** **** **** **** **** +17035 **** **** **** **** **** **** **** **** **** +17036 **** **** **** **** **** **** **** **** **** +17037 **** **** **** **** **** **** **** **** **** +17038 **** **** **** **** **** **** **** **** **** +17039 **** **** **** **** **** **** **** **** **** +17040 **** **** **** **** **** **** **** **** **** +17041 **** **** **** **** **** **** **** **** **** +17042 **** **** **** **** **** **** **** **** **** +17043 **** **** **** **** **** **** **** **** **** +17044 **** **** **** **** **** **** **** **** **** +17045 **** **** **** **** **** **** **** **** **** +17046 **** **** **** **** **** **** **** **** **** +17047 **** **** **** **** **** **** **** **** **** +17048 **** **** **** **** **** **** **** **** **** +17049 **** **** **** **** **** **** **** **** **** +17050 **** **** **** **** **** **** **** **** **** +17051 **** **** **** **** **** **** **** **** **** +17052 **** **** **** **** **** **** **** **** **** +17053 **** **** **** **** **** **** **** **** **** +17054 **** **** **** **** **** **** **** **** **** +17055 **** **** **** **** **** **** **** **** **** +17056 **** **** **** **** **** **** **** **** **** +17057 **** **** **** **** **** **** **** **** **** +17058 **** **** **** **** **** **** **** **** **** +17059 **** **** **** **** **** **** **** **** **** +17060 **** **** **** **** **** **** **** **** **** +17061 **** **** **** **** **** **** **** **** **** +17062 **** **** **** **** **** **** **** **** **** +17063 **** **** **** **** **** **** **** **** **** +17064 **** **** **** **** **** **** **** **** **** +17065 **** **** **** **** **** **** **** **** **** +17066 **** **** **** **** **** **** **** **** **** +17067 **** **** **** **** **** **** **** **** **** +17068 **** **** **** **** **** **** **** **** **** +17069 **** **** **** **** **** **** **** **** **** +17070 **** **** **** **** **** **** **** **** **** +17071 **** **** **** **** **** **** **** **** **** +17072 **** **** **** **** **** **** **** **** **** +17073 **** **** **** **** **** **** **** **** **** +17074 **** **** **** **** **** **** **** **** **** +17075 **** **** **** **** **** **** **** **** **** +17076 **** **** **** **** **** **** **** **** **** +17077 **** **** **** **** **** **** **** **** **** +17078 **** **** **** **** **** **** **** **** **** +17079 **** **** **** **** **** **** **** **** **** +17080 **** **** **** **** **** **** **** **** **** +17081 **** **** **** **** **** **** **** **** **** +17082 **** **** **** **** **** **** **** **** **** +17083 **** **** **** **** **** **** **** **** **** +17084 **** **** **** **** **** **** **** **** **** +17085 **** **** **** **** **** **** **** **** **** +17086 **** **** **** **** **** **** **** **** **** +17087 **** **** **** **** **** **** **** **** **** +17088 **** **** **** **** **** **** **** **** **** +17089 **** **** **** **** **** **** **** **** **** +17090 **** **** **** **** **** **** **** **** **** +17091 **** **** **** **** **** **** **** **** **** +17092 **** **** **** **** **** **** **** **** **** +17093 **** **** **** **** **** **** **** **** **** +17094 **** **** **** **** **** **** **** **** **** +17095 **** **** **** **** **** **** **** **** **** +17096 **** **** **** **** **** **** **** **** **** +17097 **** **** **** **** **** **** **** **** **** +17098 **** **** **** **** **** **** **** **** **** +17099 **** **** **** **** **** **** **** **** **** +17100 **** **** **** **** **** **** **** **** **** +17101 **** **** **** **** **** **** **** **** **** +17102 **** **** **** **** **** **** **** **** **** +17103 **** **** **** **** **** **** **** **** **** +17104 **** **** **** **** **** **** **** **** **** +17105 **** **** **** **** **** **** **** **** **** +17106 **** **** **** **** **** **** **** **** **** +17107 **** **** **** **** **** **** **** **** **** +17108 **** **** **** **** **** **** **** **** **** +17109 **** **** **** **** **** **** **** **** **** +17110 **** **** **** **** **** **** **** **** **** +17111 **** **** **** **** **** **** **** **** **** +17112 **** **** **** **** **** **** **** **** **** +17113 **** **** **** **** **** **** **** **** **** +17114 **** **** **** **** **** **** **** **** **** +17115 **** **** **** **** **** **** **** **** **** +17116 **** **** **** **** **** **** **** **** **** +17117 **** **** **** **** **** **** **** **** **** +17118 **** **** **** **** **** **** **** **** **** +17119 **** **** **** **** **** **** **** **** **** +17120 **** **** **** **** **** **** **** **** **** +17121 **** **** **** **** **** **** **** **** **** +17122 **** **** **** **** **** **** **** **** **** +17123 **** **** **** **** **** **** **** **** **** +17124 **** **** **** **** **** **** **** **** **** +17125 **** **** **** **** **** **** **** **** **** +17126 **** **** **** **** **** **** **** **** **** +17127 **** **** **** **** **** **** **** **** **** +17128 **** **** **** **** **** **** **** **** **** +17129 **** **** **** **** **** **** **** **** **** +17130 **** **** **** **** **** **** **** **** **** +17131 **** **** **** **** **** **** **** **** **** +17132 **** **** **** **** **** **** **** **** **** +17133 **** **** **** **** **** **** **** **** **** +17134 **** **** **** **** **** **** **** **** **** +17135 **** **** **** **** **** **** **** **** **** +17136 **** **** **** **** **** **** **** **** **** +17137 **** **** **** **** **** **** **** **** **** +17138 **** **** **** **** **** **** **** **** **** +17139 **** **** **** **** **** **** **** **** **** +17140 **** **** **** **** **** **** **** **** **** +17141 **** **** **** **** **** **** **** **** **** +17142 **** **** **** **** **** **** **** **** **** +17143 **** **** **** **** **** **** **** **** **** +17144 **** **** **** **** **** **** **** **** **** +17145 **** **** **** **** **** **** **** **** **** +17146 **** **** **** **** **** **** **** **** **** +17147 **** **** **** **** **** **** **** **** **** +17148 **** **** **** **** **** **** **** **** **** +17149 **** **** **** **** **** **** **** **** **** +17150 **** **** **** **** **** **** **** **** **** +17151 **** **** **** **** **** **** **** **** **** +17152 **** **** **** **** **** **** **** **** **** +17153 **** **** **** **** **** **** **** **** **** +17154 **** **** **** **** **** **** **** **** **** +17155 **** **** **** **** **** **** **** **** **** +17156 **** **** **** **** **** **** **** **** **** +17157 **** **** **** **** **** **** **** **** **** +17158 **** **** **** **** **** **** **** **** **** +17159 **** **** **** **** **** **** **** **** **** +17160 **** **** **** **** **** **** **** **** **** +17161 **** **** **** **** **** **** **** **** **** +17162 **** **** **** **** **** **** **** **** **** +17163 **** **** **** **** **** **** **** **** **** +17164 **** **** **** **** **** **** **** **** **** +17165 **** **** **** **** **** **** **** **** **** +17166 **** **** **** **** **** **** **** **** **** +17167 **** **** **** **** **** **** **** **** **** +17168 **** **** **** **** **** **** **** **** **** +17169 **** **** **** **** **** **** **** **** **** +17170 **** **** **** **** **** **** **** **** **** +17171 **** **** **** **** **** **** **** **** **** +17172 **** **** **** **** **** **** **** **** **** +17173 **** **** **** **** **** **** **** **** **** +17174 **** **** **** **** **** **** **** **** **** +17175 **** **** **** **** **** **** **** **** **** +17176 **** **** **** **** **** **** **** **** **** +17177 **** **** **** **** **** **** **** **** **** +17178 **** **** **** **** **** **** **** **** **** +17179 **** **** **** **** **** **** **** **** **** +17180 **** **** **** **** **** **** **** **** **** +17181 **** **** **** **** **** **** **** **** **** +17182 **** **** **** **** **** **** **** **** **** +17183 **** **** **** **** **** **** **** **** **** +17184 **** **** **** **** **** **** **** **** **** +17185 **** **** **** **** **** **** **** **** **** +17186 **** **** **** **** **** **** **** **** **** +17187 **** **** **** **** **** **** **** **** **** +17188 **** **** **** **** **** **** **** **** **** +17189 **** **** **** **** **** **** **** **** **** +17190 **** **** **** **** **** **** **** **** **** +17191 **** **** **** **** **** **** **** **** **** +17192 **** **** **** **** **** **** **** **** **** +17193 **** **** **** **** **** **** **** **** **** +17194 **** **** **** **** **** **** **** **** **** +17195 **** **** **** **** **** **** **** **** **** +17196 **** **** **** **** **** **** **** **** **** +17197 **** **** **** **** **** **** **** **** **** +17198 **** **** **** **** **** **** **** **** **** +17199 **** **** **** **** **** **** **** **** **** +17200 **** **** **** **** **** **** **** **** **** +17201 **** **** **** **** **** **** **** **** **** +17202 **** **** **** **** **** **** **** **** **** +17203 **** **** **** **** **** **** **** **** **** +17204 **** **** **** **** **** **** **** **** **** +17205 **** **** **** **** **** **** **** **** **** +17206 **** **** **** **** **** **** **** **** **** +17207 **** **** **** **** **** **** **** **** **** +17208 **** **** **** **** **** **** **** **** **** +17209 **** **** **** **** **** **** **** **** **** +17210 **** **** **** **** **** **** **** **** **** +17211 **** **** **** **** **** **** **** **** **** +17212 **** **** **** **** **** **** **** **** **** +17213 **** **** **** **** **** **** **** **** **** +17214 **** **** **** **** **** **** **** **** **** +17215 **** **** **** **** **** **** **** **** **** +17216 **** **** **** **** **** **** **** **** **** +17217 **** **** **** **** **** **** **** **** **** +17218 **** **** **** **** **** **** **** **** **** +17219 **** **** **** **** **** **** **** **** **** +17220 **** **** **** **** **** **** **** **** **** +17221 **** **** **** **** **** **** **** **** **** +17222 **** **** **** **** **** **** **** **** **** +17223 **** **** **** **** **** **** **** **** **** +17224 **** **** **** **** **** **** **** **** **** +17225 **** **** **** **** **** **** **** **** **** +17226 **** **** **** **** **** **** **** **** **** +17227 **** **** **** **** **** **** **** **** **** +17228 **** **** **** **** **** **** **** **** **** +17229 **** **** **** **** **** **** **** **** **** +17230 **** **** **** **** **** **** **** **** **** +17231 **** **** **** **** **** **** **** **** **** +17232 **** **** **** **** **** **** **** **** **** +17233 **** **** **** **** **** **** **** **** **** +17234 **** **** **** **** **** **** **** **** **** +17235 **** **** **** **** **** **** **** **** **** +17236 **** **** **** **** **** **** **** **** **** +17237 **** **** **** **** **** **** **** **** **** +17238 **** **** **** **** **** **** **** **** **** +17239 **** **** **** **** **** **** **** **** **** +17240 **** **** **** **** **** **** **** **** **** +17241 **** **** **** **** **** **** **** **** **** +17242 **** **** **** **** **** **** **** **** **** +17243 SPELL_REGEN_LIGHT_WOUNDS **** **** **** **** **** **** **** **** +17244 SPELL_REGEN_MODERATE_WOUNDS **** **** **** **** **** **** **** **** +17245 SPELL_REGEN_SERIOUS_WOUNDS **** **** **** **** **** **** **** **** +17246 SPELL_REGEN_CRITICAL_WOUNDS **** **** **** **** **** **** **** **** +17247 SPELL_SPEED_WIND **** **** **** **** **** **** **** **** +17248 SPELL_SPIRIT_WORM **** **** **** **** **** **** **** **** +17249 SPELL_SPIRITUAL_WEAPON **** **** **** **** **** **** **** **** +17250 SPELL_TORTISE_SHELL **** **** **** **** **** **** **** **** +17251 BattleBlessing **** **** **** **** **** **** **** **** +17252 TN_Wail_of_the_Banshee **** **** **** **** **** **** **** **** +17253 TN_Horrid_Wilting **** **** **** **** **** **** **** **** +17254 Spontaneous_Summoning **** **** **** **** **** **** **** **** +17255 Troglodyte_Stench **** **** **** **** **** **** **** **** +17256 FEAT_PRC_HIPS **** **** **** **** **** **** **** **** +17257 Hexblade_SwiftCast **** **** **** **** **** **** **** **** +17258 ET_GTEATREACH_BLAST **** **** **** **** **** **** **** **** +17259 ET_GTEATREACH_BLAST_CONVO **** **** **** **** **** **** **** **** +17260 ET_GTEATREACH_BLAST_QUICK1 **** **** **** **** **** **** **** **** +17261 ET_GTEATREACH_BLAST_QUICK2 **** **** **** **** **** **** **** **** +17262 ET_GTEATREACH_BLAST_QUICK3 **** **** **** **** **** **** **** **** +17263 ET_GTEATREACH_BLAST_QUICK4 **** **** **** **** **** **** **** **** +17264 ET_SPELLBLAST **** **** **** **** **** **** **** **** +17265 ET_SPELLBLAST_CONVO **** **** **** **** **** **** **** **** +17266 ET_SPELLBLAST_QUICK1 **** **** **** **** **** **** **** **** +17267 ET_SPELLBLAST_QUICK2 **** **** **** **** **** **** **** **** +17268 ET_SPELLBLAST_QUICK3 **** **** **** **** **** **** **** **** +17269 ET_SPELLBLAST_QUICK4 **** **** **** **** **** **** **** **** +17270 ED_CORRUPTING_BLAST **** **** **** **** **** **** **** **** +17271 ED_DAMAGE_REDUCTION **** **** **** **** **** **** **** **** +17272 ED_FEARFUL_GLARE **** **** **** **** **** **** **** **** +17273 ED_FIENDISH_RESISTANCE **** **** **** **** **** **** **** **** +17274 ED_HEALING_BLAST **** **** **** **** **** **** **** **** +17275 ED_PROTECTIVE_AURA **** **** **** **** **** **** **** **** +17276 ED_STRENGTH_OF_WILL **** **** **** **** **** **** **** **** +17277 ED_WILD_FRENZY **** **** **** **** **** **** **** **** +17278 Eldritch_Spellweave **** **** **** **** **** **** **** **** +17279 DivineMetamagic_Empower **** **** **** **** **** **** **** **** +17280 DivineMetamagic_Extend **** **** **** **** **** **** **** **** +17281 DivineMetamagic_Maximize **** **** **** **** **** **** **** **** +17282 Hellfire_Blast **** **** **** **** **** **** **** **** +17283 Hellfire_Spear **** **** **** **** **** **** **** **** +17284 Hellfire_Glaive **** **** **** **** **** **** **** **** +17285 Hellfire_Blow **** **** **** **** **** **** **** **** +17286 Hellfire_Chain **** **** **** **** **** **** **** **** +17287 Hellfire_Cone **** **** **** **** **** **** **** **** +17288 Hellfire_Line **** **** **** **** **** **** **** **** +17289 Hellfire_Doom **** **** **** **** **** **** **** **** +17290 Hellfire_Infusion **** **** **** **** **** **** **** **** +17291 Hellfire_Infusion_Extend **** **** **** **** **** **** **** **** +17292 Hellfire_Infusion_Empower **** **** **** **** **** **** **** **** +17293 Hellfire_Infusion_Widen **** **** **** **** **** **** **** **** +17294 Hellfire_Infusion_Maximize **** **** **** **** **** **** **** **** +17295 Hellfire_Shield **** **** **** **** **** **** **** **** +17296 Secular_Authority **** **** **** **** **** **** **** **** +17297 KotMC_TrueStrike **** **** **** **** **** **** **** **** +17298 Shifter_LearnShape **** **** **** **** **** **** **** **** +17299 FEAT_HEXTOR_BSTRIKE_MODE **** **** **** **** **** **** **** **** +17300 **** **** **** **** **** **** **** **** **** +17301 BlisteringFlourish **** **** **** **** **** **** **** **** +17302 BurningBlade **** **** **** **** **** **** **** **** +17303 BurningBrand **** **** **** **** **** **** **** **** +17304 DeathMark **** **** **** **** **** **** **** **** +17305 DesertTempest **** **** **** **** **** **** **** **** +17306 DistractingEmber **** **** **** **** **** **** **** **** +17307 DragonsFlame **** **** **** **** **** **** **** **** +17308 FanTheFlames **** **** **** **** **** **** **** **** +17309 FieryAssault **** **** **** **** **** **** **** **** +17310 FireRiposte **** **** **** **** **** **** **** **** +17311 Firesnake **** **** **** **** **** **** **** **** +17312 FlamesBlessing **** **** **** **** **** **** **** **** +17313 FlashingSun **** **** **** **** **** **** **** **** +17314 HatchlingsFlame **** **** **** **** **** **** **** **** +17315 HolocaustCloak **** **** **** **** **** **** **** **** +17316 InfernoBlade **** **** **** **** **** **** **** **** +17317 InfernoBlast **** **** **** **** **** **** **** **** +17318 LeapingFlame **** **** **** **** **** **** **** **** +17319 LingeringInferno **** **** **** **** **** **** **** **** +17320 RingOfFire **** **** **** **** **** **** **** **** +17321 RisingPhoenix **** **** **** **** **** **** **** **** +17322 SalamanderCharge **** **** **** **** **** **** **** **** +17323 SearingBlade **** **** **** **** **** **** **** **** +17324 SearingCharge **** **** **** **** **** **** **** **** +17325 WindStride **** **** **** **** **** **** **** **** +17326 WyrmsFlame **** **** **** **** **** **** **** **** +17327 ZephyrDance **** **** **** **** **** **** **** **** +17328 AuraOfChaos **** **** **** **** **** **** **** **** +17329 AuraOfPerfectOrder **** **** **** **** **** **** **** **** +17330 AuraOfTriumph **** **** **** **** **** **** **** **** +17331 AuraOfTyranny **** **** **** **** **** **** **** **** +17332 CastigatingStrike **** **** **** **** **** **** **** **** +17333 CrusadersStrike **** **** **** **** **** **** **** **** +17334 DauntingStrike **** **** **** **** **** **** **** **** +17335 DefensiveRebuke **** **** **** **** **** **** **** **** +17336 DivineSurge **** **** **** **** **** **** **** **** +17337 DivineSurgeGreater **** **** **** **** **** **** **** **** +17338 DoomCharge **** **** **** **** **** **** **** **** +17339 EntanglingBlade **** **** **** **** **** **** **** **** +17340 Foehammer **** **** **** **** **** **** **** **** +17341 ImmortalFortitude **** **** **** **** **** **** **** **** +17342 IronGuardsGlare **** **** **** **** **** **** **** **** +17343 LawBearer **** **** **** **** **** **** **** **** +17344 MartialSpirit **** **** **** **** **** **** **** **** +17345 RadiantCharge **** **** **** **** **** **** **** **** +17346 RallyingStrike **** **** **** **** **** **** **** **** +17347 RevitalizingStrike **** **** **** **** **** **** **** **** +17348 ShieldBlock **** **** **** **** **** **** **** **** +17349 ShieldCounter **** **** **** **** **** **** **** **** +17350 StrikeOfRighteousVitality **** **** **** **** **** **** **** **** +17351 ThicketOfBlades **** **** **** **** **** **** **** **** +17352 TideOfChaos **** **** **** **** **** **** **** **** +17353 VanguardStrike **** **** **** **** **** **** **** **** +17354 ActionBeforeThought **** **** **** **** **** **** **** **** +17355 AvalancheOfBlades **** **** **** **** **** **** **** **** +17356 BoundingAssault **** **** **** **** **** **** **** **** +17357 DiamondDefense **** **** **** **** **** **** **** **** +17358 DiamondNightmareBlade **** **** **** **** **** **** **** **** +17359 DisruptingBlow **** **** **** **** **** **** **** **** +17360 EmeraldRazor **** **** **** **** **** **** **** **** +17361 HearingTheAir **** **** **** **** **** **** **** **** +17362 InsightfulStrike **** **** **** **** **** **** **** **** +17363 InsightfulStrikeGreater **** **** **** **** **** **** **** **** +17364 MindOverBody **** **** **** **** **** **** **** **** +17365 MindStrike **** **** **** **** **** **** **** **** +17366 MomentOfAlacrity **** **** **** **** **** **** **** **** +17367 MomentOfPerfectMind **** **** **** **** **** **** **** **** +17368 PearlOfBlackDoubt **** **** **** **** **** **** **** **** +17369 QuicksilverMotion **** **** **** **** **** **** **** **** +17370 RapidCounter **** **** **** **** **** **** **** **** +17371 RubyNightmareBlade **** **** **** **** **** **** **** **** +17372 SapphireNightmareBlade **** **** **** **** **** **** **** **** +17373 StanceOfAlacrity **** **** **** **** **** **** **** **** +17374 StanceOfClarity **** **** **** **** **** **** **** **** +17375 TimeStandsStill **** **** **** **** **** **** **** **** +17376 AbsoluteSteel **** **** **** **** **** **** **** **** +17377 AdamantineHurricane **** **** **** **** **** **** **** **** +17378 DancingBladeForm **** **** **** **** **** **** **** **** +17379 DazingStrike **** **** **** **** **** **** **** **** +17380 DisarmingStrike **** **** **** **** **** **** **** **** +17381 ExorcismOfSteel **** **** **** **** **** **** **** **** +17382 FinishingMove **** **** **** **** **** **** **** **** +17383 IronHeartEndurance **** **** **** **** **** **** **** **** +17384 IronHeartFocus **** **** **** **** **** **** **** **** +17385 IronHeartSurge **** **** **** **** **** **** **** **** +17386 LightningRecovery **** **** **** **** **** **** **** **** +17387 LightningThrow **** **** **** **** **** **** **** **** +17388 ManticoreParry **** **** **** **** **** **** **** **** +17389 MithralTornado **** **** **** **** **** **** **** **** +17390 PunishingStance **** **** **** **** **** **** **** **** +17391 ScythingBlade **** **** **** **** **** **** **** **** +17392 SteelWind **** **** **** **** **** **** **** **** +17393 SteelyStrike **** **** **** **** **** **** **** **** +17394 StrikeOfPerfectClarity **** **** **** **** **** **** **** **** +17395 SupremeBladeParry **** **** **** **** **** **** **** **** +17396 WallOfBlades **** **** **** **** **** **** **** **** +17397 BafflingDefense **** **** **** **** **** **** **** **** +17398 BallistaThrow **** **** **** **** **** **** **** **** +17399 CleverPositioning **** **** **** **** **** **** **** **** +17400 CometThrow **** **** **** **** **** **** **** **** +17401 CounterCharge **** **** **** **** **** **** **** **** +17402 DevastatingThrow **** **** **** **** **** **** **** **** +17403 FeignedOpening **** **** **** **** **** **** **** **** +17404 FoolsStrike **** **** **** **** **** **** **** **** +17405 GhostlyDefense **** **** **** **** **** **** **** **** +17406 GiantKillingStyle **** **** **** **** **** **** **** **** +17407 HydraSlayingStrike **** **** **** **** **** **** **** **** +17408 MightyThrow **** **** **** **** **** **** **** **** +17409 MirroredPursuit **** **** **** **** **** **** **** **** +17410 ScorpionParry **** **** **** **** **** **** **** **** +17411 ShiftingDefense **** **** **** **** **** **** **** **** +17412 SoaringThrow **** **** **** **** **** **** **** **** +17413 StalkingShadow **** **** **** **** **** **** **** **** +17414 StepOfTheWind **** **** **** **** **** **** **** **** +17415 StrikeOfTheBrokenShield **** **** **** **** **** **** **** **** +17416 TornadoThrow **** **** **** **** **** **** **** **** +17417 AssassinsStance **** **** **** **** **** **** **** **** +17418 BalanceOnTheSky **** **** **** **** **** **** **** **** +17419 BloodlettingStrike **** **** **** **** **** **** **** **** +17420 ChildOfShadow **** **** **** **** **** **** **** **** +17421 ClingingShadowStrike **** **** **** **** **** **** **** **** +17422 CloakOfDeception **** **** **** **** **** **** **** **** +17423 DanceOfTheSpider **** **** **** **** **** **** **** **** +17424 DeathInTheDark **** **** **** **** **** **** **** **** +17425 DrainVitality **** **** **** **** **** **** **** **** +17426 EnervatingShadowStrike **** **** **** **** **** **** **** **** +17427 FiveShadowCreepingIceEnervationStrike **** **** **** **** **** **** **** **** +17428 GhostBlade **** **** **** **** **** **** **** **** +17429 HandOfDeath **** **** **** **** **** **** **** **** +17430 IslandOfBlades **** **** **** **** **** **** **** **** +17431 ObscuringShadowVeil **** **** **** **** **** **** **** **** +17432 OneWithShadow **** **** **** **** **** **** **** **** +17433 ShadowBladeTechnique **** **** **** **** **** **** **** **** +17434 ShadowBlink **** **** **** **** **** **** **** **** +17435 ShadowGarrote **** **** **** **** **** **** **** **** +17436 ShadowJaunt **** **** **** **** **** **** **** **** +17437 ShadowNoose **** **** **** **** **** **** **** **** +17438 ShadowStride **** **** **** **** **** **** **** **** +17439 StalkerInTheNight **** **** **** **** **** **** **** **** +17440 StepOfTheDancingMoth **** **** **** **** **** **** **** **** +17441 StrengthDrainingStrike **** **** **** **** **** **** **** **** +17442 AdamantineBones **** **** **** **** **** **** **** **** +17443 AncientMountainHammer **** **** **** **** **** **** **** **** +17444 BonesplittingStrike **** **** **** **** **** **** **** **** +17445 Bonecrusher **** **** **** **** **** **** **** **** +17446 BoulderRoll **** **** **** **** **** **** **** **** +17447 ChargingMinotaur **** **** **** **** **** **** **** **** +17448 ColossusStrike **** **** **** **** **** **** **** **** +17449 CrushingVise **** **** **** **** **** **** **** **** +17450 CrushingWeightOfTheMountain **** **** **** **** **** **** **** **** +17451 EarthstrikeQuake **** **** **** **** **** **** **** **** +17452 ElderMountainHammer **** **** **** **** **** **** **** **** +17453 GiantsStance **** **** **** **** **** **** **** **** +17454 IronBones **** **** **** **** **** **** **** **** +17455 IrresistibleMountainStrike **** **** **** **** **** **** **** **** +17456 MountainAvalanche **** **** **** **** **** **** **** **** +17457 MountainHammer **** **** **** **** **** **** **** **** +17458 MountainTombstoneStrike **** **** **** **** **** **** **** **** +17459 OverwhelmingMountainStrike **** **** **** **** **** **** **** **** +17460 RootsOfTheMountain **** **** **** **** **** **** **** **** +17461 StoneBones **** **** **** **** **** **** **** **** +17462 StoneDragonsFury **** **** **** **** **** **** **** **** +17463 StoneVise **** **** **** **** **** **** **** **** +17464 StonefootStance **** **** **** **** **** **** **** **** +17465 RisingPhoenix_FullAttack **** **** **** **** **** **** **** **** +17466 **** **** **** **** **** **** **** **** **** +17467 **** **** **** **** **** **** **** **** **** +17468 StrengthOfStone **** **** **** **** **** **** **** **** +17469 BloodInTheWater **** **** **** **** **** **** **** **** +17470 ClawAtTheMoon **** **** **** **** **** **** **** **** +17471 DancingMongoose **** **** **** **** **** **** **** **** +17472 DeathFromAbove **** **** **** **** **** **** **** **** +17473 FeralDeathBlow **** **** **** **** **** **** **** **** +17474 FleshRipper **** **** **** **** **** **** **** **** +17475 FountainOfBlood **** **** **** **** **** **** **** **** +17476 GirallonWindmillFleshRip **** **** **** **** **** **** **** **** +17477 HamstringAttack **** **** **** **** **** **** **** **** +17478 HuntersSense **** **** **** **** **** **** **** **** +17479 LeapingDragonStance **** **** **** **** **** **** **** **** +17480 PouncingCharge **** **** **** **** **** **** **** **** +17481 PreyOnTheWeak **** **** **** **** **** **** **** **** +17482 RabidBearStrike **** **** **** **** **** **** **** **** +17483 RabidWolfStrike **** **** **** **** **** **** **** **** +17484 RagingMongoose **** **** **** **** **** **** **** **** +17485 SoaringRaptorStrike **** **** **** **** **** **** **** **** +17486 SuddenLeap **** **** **** **** **** **** **** **** +17487 SwoopingDragonStrike **** **** **** **** **** **** **** **** +17488 WolfClimbsTheMountain **** **** **** **** **** **** **** **** +17489 WolfFangStrike **** **** **** **** **** **** **** **** +17490 WolfPackTactics **** **** **** **** **** **** **** **** +17491 WolverineStance **** **** **** **** **** **** **** **** +17492 BattleLeadersCharge **** **** **** **** **** **** **** **** +17493 BolsteringVoice **** **** **** **** **** **** **** **** +17494 ClarionCall **** **** **** **** **** **** **** **** +17495 CoveringStrike **** **** **** **** **** **** **** **** +17496 DouseTheFlames **** **** **** **** **** **** **** **** +17497 FlankingManeuver **** **** **** **** **** **** **** **** +17498 LeadingTheAttack **** **** **** **** **** **** **** **** +17499 LeadingTheCharge **** **** **** **** **** **** **** **** +17500 LionsRoar **** **** **** **** **** **** **** **** +17501 OrderForgedFromChaos **** **** **** **** **** **** **** **** +17502 PressTheAdvantage **** **** **** **** **** **** **** **** +17503 SwarmTactics **** **** **** **** **** **** **** **** +17504 SwarmingAssault **** **** **** **** **** **** **** **** +17505 TacticalStrike **** **** **** **** **** **** **** **** +17506 TacticsOfTheWolf **** **** **** **** **** **** **** **** +17507 WarLeadersCharge **** **** **** **** **** **** **** **** +17508 WarMastersCharge **** **** **** **** **** **** **** **** +17509 WhiteRavenHammer **** **** **** **** **** **** **** **** +17510 WhiteRavenStrike **** **** **** **** **** **** **** **** +17511 WhiteRavenTactics **** **** **** **** **** **** **** **** +17512 **** **** **** **** **** **** **** **** **** +17513 **** **** **** **** **** **** **** **** **** +17514 **** **** **** **** **** **** **** **** **** +17515 **** **** **** **** **** **** **** **** **** +17516 **** **** **** **** **** **** **** **** **** +17517 **** **** **** **** **** **** **** **** **** +17518 **** **** **** **** **** **** **** **** **** +17519 **** **** **** **** **** **** **** **** **** +17520 ####START_OF_TOB_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +17521 Warblade_StanceOfClarity **** **** **** **** **** **** **** **** +17522 Warblade_TimeStandsStill **** **** **** **** **** **** **** **** +17523 Warblade_AbsoluteSteel **** **** **** **** **** **** **** **** +17524 Warblade_AdamantineHurricane **** **** **** **** **** **** **** **** +17525 Warblade_DancingBladeForm **** **** **** **** **** **** **** **** +17526 Warblade_DazingStrike **** **** **** **** **** **** **** **** +17527 Warblade_DisarmingStrike **** **** **** **** **** **** **** **** +17528 Warblade_ExorcismOfSteel **** **** **** **** **** **** **** **** +17529 Warblade_FinishingMove **** **** **** **** **** **** **** **** +17530 Warblade_IronHeartEndurance **** **** **** **** **** **** **** **** +17531 Warblade_IronHeartFocus **** **** **** **** **** **** **** **** +17532 Warblade_IronHeartSurge **** **** **** **** **** **** **** **** +17533 Warblade_LightningRecovery **** **** **** **** **** **** **** **** +17534 Warblade_LightningThrow **** **** **** **** **** **** **** **** +17535 Warblade_ManticoreParry **** **** **** **** **** **** **** **** +17536 Warblade_MithralTornado **** **** **** **** **** **** **** **** +17537 Warblade_PunishingStance **** **** **** **** **** **** **** **** +17538 Warblade_ScythingBlade **** **** **** **** **** **** **** **** +17539 Warblade_SteelWind **** **** **** **** **** **** **** **** +17540 Warblade_SteelyStrike **** **** **** **** **** **** **** **** +17541 Warblade_StrikeOfPerfectClarity **** **** **** **** **** **** **** **** +17542 Warblade_SupremeBladeParry **** **** **** **** **** **** **** **** +17543 Warblade_WallOfBlades **** **** **** **** **** **** **** **** +17544 Warblade_BafflingDefense **** **** **** **** **** **** **** **** +17545 Warblade_BallistaThrow **** **** **** **** **** **** **** **** +17546 Warblade_CleverPositioning **** **** **** **** **** **** **** **** +17547 Warblade_CometThrow **** **** **** **** **** **** **** **** +17548 Warblade_CounterCharge **** **** **** **** **** **** **** **** +17549 Warblade_DevastatingThrow **** **** **** **** **** **** **** **** +17550 Warblade_FeignedOpening **** **** **** **** **** **** **** **** +17551 Warblade_FoolsStrike **** **** **** **** **** **** **** **** +17552 Warblade_GhostlyDefense **** **** **** **** **** **** **** **** +17553 Warblade_GiantKillingStyle **** **** **** **** **** **** **** **** +17554 Warblade_HydraSlayingStrike **** **** **** **** **** **** **** **** +17555 Warblade_MightyThrow **** **** **** **** **** **** **** **** +17556 Warblade_MirroredPursuit **** **** **** **** **** **** **** **** +17557 Warblade_ScorpionParry **** **** **** **** **** **** **** **** +17558 Warblade_ShiftingDefense **** **** **** **** **** **** **** **** +17559 Warblade_SoaringThrow **** **** **** **** **** **** **** **** +17560 Warblade_StalkingShadow **** **** **** **** **** **** **** **** +17561 Warblade_StepOfTheWind **** **** **** **** **** **** **** **** +17562 Warblade_StrikeOfTheBrokenShield **** **** **** **** **** **** **** **** +17563 Warblade_TornadoThrow **** **** **** **** **** **** **** **** +17564 Warblade_AssassinsStance **** **** **** **** **** **** **** **** +17565 Warblade_BalanceOnTheSky **** **** **** **** **** **** **** **** +17566 Warblade_BloodlettingStrike **** **** **** **** **** **** **** **** +17567 Warblade_ChildOfShadow **** **** **** **** **** **** **** **** +17568 Warblade_ClingingShadowStrike **** **** **** **** **** **** **** **** +17569 Warblade_CloakOfDeception **** **** **** **** **** **** **** **** +17570 Warblade_DanceOfTheSpider **** **** **** **** **** **** **** **** +17571 Warblade_DeathInTheDark **** **** **** **** **** **** **** **** +17572 Warblade_DrainVitality **** **** **** **** **** **** **** **** +17573 Warblade_EnervatingShadowStrike **** **** **** **** **** **** **** **** +17574 Warblade_FiveShadowCreepingIceEnervationStrike **** **** **** **** **** **** **** **** +17575 Warblade_GhostBlade **** **** **** **** **** **** **** **** +17576 Warblade_HandOfDeath **** **** **** **** **** **** **** **** +17577 Warblade_IslandOfBlades **** **** **** **** **** **** **** **** +17578 Warblade_ObscuringShadowVeil **** **** **** **** **** **** **** **** +17579 Warblade_OneWithShadow **** **** **** **** **** **** **** **** +17580 Warblade_ShadowBladeTechnique **** **** **** **** **** **** **** **** +17581 Warblade_ShadowBlink **** **** **** **** **** **** **** **** +17582 Warblade_ShadowGarrote **** **** **** **** **** **** **** **** +17583 Warblade_ShadowJaunt **** **** **** **** **** **** **** **** +17584 Warblade_ShadowNoose **** **** **** **** **** **** **** **** +17585 Warblade_ShadowStride **** **** **** **** **** **** **** **** +17586 Warblade_StalkerInTheNight **** **** **** **** **** **** **** **** +17587 Warblade_StepOfTheDancingMoth **** **** **** **** **** **** **** **** +17588 Warblade_StrengthDrainingStrike **** **** **** **** **** **** **** **** +17589 Warblade_AdamantineBones **** **** **** **** **** **** **** **** +17590 Warblade_AncientMountainHammer **** **** **** **** **** **** **** **** +17591 Warblade_BonesplittingStrike **** **** **** **** **** **** **** **** +17592 Warblade_Bonecrusher **** **** **** **** **** **** **** **** +17593 Warblade_BoulderRoll **** **** **** **** **** **** **** **** +17594 Warblade_ChargingMinotaur **** **** **** **** **** **** **** **** +17595 Warblade_ColossusStrike **** **** **** **** **** **** **** **** +17596 Warblade_CrushingVise **** **** **** **** **** **** **** **** +17597 Warblade_CrushingWeightOfTheMountain **** **** **** **** **** **** **** **** +17598 Warblade_EarthstrikeQuake **** **** **** **** **** **** **** **** +17599 Warblade_ElderMountainHammer **** **** **** **** **** **** **** **** +17600 Warblade_GiantsStance **** **** **** **** **** **** **** **** +17601 Warblade_IronBones **** **** **** **** **** **** **** **** +17602 Warblade_IrresistibleMountainStrike **** **** **** **** **** **** **** **** +17603 Warblade_MountainAvalanche **** **** **** **** **** **** **** **** +17604 Warblade_MountainHammer **** **** **** **** **** **** **** **** +17605 Warblade_MountainTombstoneStrike **** **** **** **** **** **** **** **** +17606 Warblade_OverwhelmingMountainStrike **** **** **** **** **** **** **** **** +17607 Warblade_RootsOfTheMountain **** **** **** **** **** **** **** **** +17608 Warblade_StoneBones **** **** **** **** **** **** **** **** +17609 Warblade_StoneDragonsFury **** **** **** **** **** **** **** **** +17610 Warblade_StoneVise **** **** **** **** **** **** **** **** +17611 Warblade_StonefootStance **** **** **** **** **** **** **** **** +17612 Warblade_StrengthOfStone **** **** **** **** **** **** **** **** +17613 Warblade_BloodInTheWater **** **** **** **** **** **** **** **** +17614 Warblade_ClawAtTheMoon **** **** **** **** **** **** **** **** +17615 Warblade_DancingMongoose **** **** **** **** **** **** **** **** +17616 Warblade_DeathFromAbove **** **** **** **** **** **** **** **** +17617 Warblade_FeralDeathBlow **** **** **** **** **** **** **** **** +17618 Warblade_FleshRipper **** **** **** **** **** **** **** **** +17619 Warblade_FountainOfBlood **** **** **** **** **** **** **** **** +17620 Warblade_GirallonWindmillFleshRip **** **** **** **** **** **** **** **** +17621 Warblade_HamstringAttack **** **** **** **** **** **** **** **** +17622 Warblade_HuntersSense **** **** **** **** **** **** **** **** +17623 Warblade_LeapingDragonStance **** **** **** **** **** **** **** **** +17624 Warblade_PouncingCharge **** **** **** **** **** **** **** **** +17625 Warblade_PreyOnTheWeak **** **** **** **** **** **** **** **** +17626 Warblade_RabidBearStrike **** **** **** **** **** **** **** **** +17627 Warblade_RabidWolfStrike **** **** **** **** **** **** **** **** +17628 Warblade_RagingMongoose **** **** **** **** **** **** **** **** +17629 Warblade_SoaringRaptorStrike **** **** **** **** **** **** **** **** +17630 Warblade_SuddenLeap **** **** **** **** **** **** **** **** +17631 Warblade_SwoopingDragonStrike **** **** **** **** **** **** **** **** +17632 Warblade_WolfClimbsTheMountain **** **** **** **** **** **** **** **** +17633 Warblade_WolfFangStrike **** **** **** **** **** **** **** **** +17634 Warblade_WolfPackTactics **** **** **** **** **** **** **** **** +17635 Warblade_WolverineStance **** **** **** **** **** **** **** **** +17636 Warblade_BattleLeadersCharge **** **** **** **** **** **** **** **** +17637 Warblade_BolsteringVoice **** **** **** **** **** **** **** **** +17638 Warblade_ClarionCall **** **** **** **** **** **** **** **** +17639 Warblade_CoveringStrike **** **** **** **** **** **** **** **** +17640 Warblade_DouseTheFlames **** **** **** **** **** **** **** **** +17641 Warblade_FlankingManeuver **** **** **** **** **** **** **** **** +17642 Warblade_LeadingTheAttack **** **** **** **** **** **** **** **** +17643 Warblade_LeadingTheCharge **** **** **** **** **** **** **** **** +17644 Warblade_LionsRoar **** **** **** **** **** **** **** **** +17645 Warblade_OrderForgedFromChaos **** **** **** **** **** **** **** **** +17646 Warblade_PressTheAdvantage **** **** **** **** **** **** **** **** +17647 Warblade_SwarmTactics **** **** **** **** **** **** **** **** +17648 Warblade_SwarmingAssault **** **** **** **** **** **** **** **** +17649 Warblade_TacticalStrike **** **** **** **** **** **** **** **** +17650 Warblade_TacticsOfTheWolf **** **** **** **** **** **** **** **** +17651 Warblade_WarLeadersCharge **** **** **** **** **** **** **** **** +17652 Warblade_WarMastersCharge **** **** **** **** **** **** **** **** +17653 Warblade_WhiteRavenHammer **** **** **** **** **** **** **** **** +17654 Warblade_WhiteRavenStrike **** **** **** **** **** **** **** **** +17655 Warblade_WhiteRavenTactics **** **** **** **** **** **** **** **** +17656 **** **** **** **** **** **** **** **** **** +17657 **** **** **** **** **** **** **** **** **** +17658 **** **** **** **** **** **** **** **** **** +17659 **** **** **** **** **** **** **** **** **** +17660 **** **** **** **** **** **** **** **** **** +17661 **** **** **** **** **** **** **** **** **** +17662 **** **** **** **** **** **** **** **** **** +17663 **** **** **** **** **** **** **** **** **** +17664 **** **** **** **** **** **** **** **** **** +17665 **** **** **** **** **** **** **** **** **** +17666 **** **** **** **** **** **** **** **** **** +17667 **** **** **** **** **** **** **** **** **** +17668 **** **** **** **** **** **** **** **** **** +17669 **** **** **** **** **** **** **** **** **** +17670 **** **** **** **** **** **** **** **** **** +17671 **** **** **** **** **** **** **** **** **** +17672 **** **** **** **** **** **** **** **** **** +17673 **** **** **** **** **** **** **** **** **** +17674 **** **** **** **** **** **** **** **** **** +17675 **** **** **** **** **** **** **** **** **** +17676 **** **** **** **** **** **** **** **** **** +17677 **** **** **** **** **** **** **** **** **** +17678 **** **** **** **** **** **** **** **** **** +17679 **** **** **** **** **** **** **** **** **** +17680 **** **** **** **** **** **** **** **** **** +17681 **** **** **** **** **** **** **** **** **** +17682 **** **** **** **** **** **** **** **** **** +17683 **** **** **** **** **** **** **** **** **** +17684 **** **** **** **** **** **** **** **** **** +17685 **** **** **** **** **** **** **** **** **** +17686 **** **** **** **** **** **** **** **** **** +17687 **** **** **** **** **** **** **** **** **** +17688 **** **** **** **** **** **** **** **** **** +17689 **** **** **** **** **** **** **** **** **** +17690 **** **** **** **** **** **** **** **** **** +17691 **** **** **** **** **** **** **** **** **** +17692 **** **** **** **** **** **** **** **** **** +17693 **** **** **** **** **** **** **** **** **** +17694 **** **** **** **** **** **** **** **** **** +17695 **** **** **** **** **** **** **** **** **** +17696 **** **** **** **** **** **** **** **** **** +17697 **** **** **** **** **** **** **** **** **** +17698 **** **** **** **** **** **** **** **** **** +17699 **** **** **** **** **** **** **** **** **** +17700 **** **** **** **** **** **** **** **** **** +17701 **** **** **** **** **** **** **** **** **** +17702 **** **** **** **** **** **** **** **** **** +17703 **** **** **** **** **** **** **** **** **** +17704 **** **** **** **** **** **** **** **** **** +17705 **** **** **** **** **** **** **** **** **** +17706 **** **** **** **** **** **** **** **** **** +17707 **** **** **** **** **** **** **** **** **** +17708 **** **** **** **** **** **** **** **** **** +17709 **** **** **** **** **** **** **** **** **** +17710 **** **** **** **** **** **** **** **** **** +17711 **** **** **** **** **** **** **** **** **** +17712 **** **** **** **** **** **** **** **** **** +17713 **** **** **** **** **** **** **** **** **** +17714 **** **** **** **** **** **** **** **** **** +17715 **** **** **** **** **** **** **** **** **** +17716 **** **** **** **** **** **** **** **** **** +17717 **** **** **** **** **** **** **** **** **** +17718 **** **** **** **** **** **** **** **** **** +17719 **** **** **** **** **** **** **** **** **** +17720 **** **** **** **** **** **** **** **** **** +17721 **** **** **** **** **** **** **** **** **** +17722 **** **** **** **** **** **** **** **** **** +17723 **** **** **** **** **** **** **** **** **** +17724 **** **** **** **** **** **** **** **** **** +17725 **** **** **** **** **** **** **** **** **** +17726 **** **** **** **** **** **** **** **** **** +17727 **** **** **** **** **** **** **** **** **** +17728 **** **** **** **** **** **** **** **** **** +17729 **** **** **** **** **** **** **** **** **** +17730 **** **** **** **** **** **** **** **** **** +17731 **** **** **** **** **** **** **** **** **** +17732 **** **** **** **** **** **** **** **** **** +17733 **** **** **** **** **** **** **** **** **** +17734 **** **** **** **** **** **** **** **** **** +17735 **** **** **** **** **** **** **** **** **** +17736 **** **** **** **** **** **** **** **** **** +17737 **** **** **** **** **** **** **** **** **** +17738 **** **** **** **** **** **** **** **** **** +17739 **** **** **** **** **** **** **** **** **** +17740 **** **** **** **** **** **** **** **** **** +17741 **** **** **** **** **** **** **** **** **** +17742 **** **** **** **** **** **** **** **** **** +17743 **** **** **** **** **** **** **** **** **** +17744 **** **** **** **** **** **** **** **** **** +17745 **** **** **** **** **** **** **** **** **** +17746 **** **** **** **** **** **** **** **** **** +17747 **** **** **** **** **** **** **** **** **** +17748 **** **** **** **** **** **** **** **** **** +17749 **** **** **** **** **** **** **** **** **** +17750 **** **** **** **** **** **** **** **** **** +17751 **** **** **** **** **** **** **** **** **** +17752 **** **** **** **** **** **** **** **** **** +17753 **** **** **** **** **** **** **** **** **** +17754 **** **** **** **** **** **** **** **** **** +17755 **** **** **** **** **** **** **** **** **** +17756 **** **** **** **** **** **** **** **** **** +17757 **** **** **** **** **** **** **** **** **** +17758 **** **** **** **** **** **** **** **** **** +17759 **** **** **** **** **** **** **** **** **** +17760 **** **** **** **** **** **** **** **** **** +17761 **** **** **** **** **** **** **** **** **** +17762 **** **** **** **** **** **** **** **** **** +17763 **** **** **** **** **** **** **** **** **** +17764 **** **** **** **** **** **** **** **** **** +17765 **** **** **** **** **** **** **** **** **** +17766 **** **** **** **** **** **** **** **** **** +17767 **** **** **** **** **** **** **** **** **** +17768 **** **** **** **** **** **** **** **** **** +17769 **** **** **** **** **** **** **** **** **** +17770 **** **** **** **** **** **** **** **** **** +17771 **** **** **** **** **** **** **** **** **** +17772 **** **** **** **** **** **** **** **** **** +17773 **** **** **** **** **** **** **** **** **** +17774 **** **** **** **** **** **** **** **** **** +17775 **** **** **** **** **** **** **** **** **** +17776 **** **** **** **** **** **** **** **** **** +17777 **** **** **** **** **** **** **** **** **** +17778 **** **** **** **** **** **** **** **** **** +17779 **** **** **** **** **** **** **** **** **** +17780 **** **** **** **** **** **** **** **** **** +17781 **** **** **** **** **** **** **** **** **** +17782 **** **** **** **** **** **** **** **** **** +17783 **** **** **** **** **** **** **** **** **** +17784 **** **** **** **** **** **** **** **** **** +17785 **** **** **** **** **** **** **** **** **** +17786 **** **** **** **** **** **** **** **** **** +17787 **** **** **** **** **** **** **** **** **** +17788 **** **** **** **** **** **** **** **** **** +17789 **** **** **** **** **** **** **** **** **** +17790 **** **** **** **** **** **** **** **** **** +17791 **** **** **** **** **** **** **** **** **** +17792 **** **** **** **** **** **** **** **** **** +17793 **** **** **** **** **** **** **** **** **** +17794 **** **** **** **** **** **** **** **** **** +17795 **** **** **** **** **** **** **** **** **** +17796 **** **** **** **** **** **** **** **** **** +17797 **** **** **** **** **** **** **** **** **** +17798 **** **** **** **** **** **** **** **** **** +17799 **** **** **** **** **** **** **** **** **** +17800 **** **** **** **** **** **** **** **** **** +17801 **** **** **** **** **** **** **** **** **** +17802 **** **** **** **** **** **** **** **** **** +17803 **** **** **** **** **** **** **** **** **** +17804 **** **** **** **** **** **** **** **** **** +17805 **** **** **** **** **** **** **** **** **** +17806 **** **** **** **** **** **** **** **** **** +17807 **** **** **** **** **** **** **** **** **** +17808 **** **** **** **** **** **** **** **** **** +17809 **** **** **** **** **** **** **** **** **** +17810 **** **** **** **** **** **** **** **** **** +17811 **** **** **** **** **** **** **** **** **** +17812 **** **** **** **** **** **** **** **** **** +17813 **** **** **** **** **** **** **** **** **** +17814 **** **** **** **** **** **** **** **** **** +17815 **** **** **** **** **** **** **** **** **** +17816 **** **** **** **** **** **** **** **** **** +17817 **** **** **** **** **** **** **** **** **** +17818 **** **** **** **** **** **** **** **** **** +17819 **** **** **** **** **** **** **** **** **** +17820 **** **** **** **** **** **** **** **** **** +17821 **** **** **** **** **** **** **** **** **** +17822 **** **** **** **** **** **** **** **** **** +17823 **** **** **** **** **** **** **** **** **** +17824 **** **** **** **** **** **** **** **** **** +17825 **** **** **** **** **** **** **** **** **** +17826 **** **** **** **** **** **** **** **** **** +17827 **** **** **** **** **** **** **** **** **** +17828 **** **** **** **** **** **** **** **** **** +17829 **** **** **** **** **** **** **** **** **** +17830 **** **** **** **** **** **** **** **** **** +17831 **** **** **** **** **** **** **** **** **** +17832 **** **** **** **** **** **** **** **** **** +17833 **** **** **** **** **** **** **** **** **** +17834 **** **** **** **** **** **** **** **** **** +17835 **** **** **** **** **** **** **** **** **** +17836 **** **** **** **** **** **** **** **** **** +17837 **** **** **** **** **** **** **** **** **** +17838 **** **** **** **** **** **** **** **** **** +17839 **** **** **** **** **** **** **** **** **** +17840 **** **** **** **** **** **** **** **** **** +17841 **** **** **** **** **** **** **** **** **** +17842 **** **** **** **** **** **** **** **** **** +17843 **** **** **** **** **** **** **** **** **** +17844 **** **** **** **** **** **** **** **** **** +17845 **** **** **** **** **** **** **** **** **** +17846 **** **** **** **** **** **** **** **** **** +17847 **** **** **** **** **** **** **** **** **** +17848 **** **** **** **** **** **** **** **** **** +17849 **** **** **** **** **** **** **** **** **** +17850 **** **** **** **** **** **** **** **** **** +17851 **** **** **** **** **** **** **** **** **** +17852 **** **** **** **** **** **** **** **** **** +17853 **** **** **** **** **** **** **** **** **** +17854 **** **** **** **** **** **** **** **** **** +17855 **** **** **** **** **** **** **** **** **** +17856 **** **** **** **** **** **** **** **** **** +17857 **** **** **** **** **** **** **** **** **** +17858 **** **** **** **** **** **** **** **** **** +17859 **** **** **** **** **** **** **** **** **** +17860 **** **** **** **** **** **** **** **** **** +17861 **** **** **** **** **** **** **** **** **** +17862 **** **** **** **** **** **** **** **** **** +17863 **** **** **** **** **** **** **** **** **** +17864 **** **** **** **** **** **** **** **** **** +17865 **** **** **** **** **** **** **** **** **** +17866 **** **** **** **** **** **** **** **** **** +17867 **** **** **** **** **** **** **** **** **** +17868 **** **** **** **** **** **** **** **** **** +17869 **** **** **** **** **** **** **** **** **** +17870 **** **** **** **** **** **** **** **** **** +17871 **** **** **** **** **** **** **** **** **** +17872 **** **** **** **** **** **** **** **** **** +17873 **** **** **** **** **** **** **** **** **** +17874 **** **** **** **** **** **** **** **** **** +17875 **** **** **** **** **** **** **** **** **** +17876 **** **** **** **** **** **** **** **** **** +17877 **** **** **** **** **** **** **** **** **** +17878 **** **** **** **** **** **** **** **** **** +17879 **** **** **** **** **** **** **** **** **** +17880 **** **** **** **** **** **** **** **** **** +17881 **** **** **** **** **** **** **** **** **** +17882 **** **** **** **** **** **** **** **** **** +17883 **** **** **** **** **** **** **** **** **** +17884 **** **** **** **** **** **** **** **** **** +17885 **** **** **** **** **** **** **** **** **** +17886 **** **** **** **** **** **** **** **** **** +17887 **** **** **** **** **** **** **** **** **** +17888 **** **** **** **** **** **** **** **** **** +17889 **** **** **** **** **** **** **** **** **** +17890 **** **** **** **** **** **** **** **** **** +17891 **** **** **** **** **** **** **** **** **** +17892 **** **** **** **** **** **** **** **** **** +17893 **** **** **** **** **** **** **** **** **** +17894 **** **** **** **** **** **** **** **** **** +17895 **** **** **** **** **** **** **** **** **** +17896 **** **** **** **** **** **** **** **** **** +17897 **** **** **** **** **** **** **** **** **** +17898 **** **** **** **** **** **** **** **** **** +17899 **** **** **** **** **** **** **** **** **** +17900 **** **** **** **** **** **** **** **** **** +17901 **** **** **** **** **** **** **** **** **** +17902 **** **** **** **** **** **** **** **** **** +17903 **** **** **** **** **** **** **** **** **** +17904 **** **** **** **** **** **** **** **** **** +17905 **** **** **** **** **** **** **** **** **** +17906 **** **** **** **** **** **** **** **** **** +17907 **** **** **** **** **** **** **** **** **** +17908 **** **** **** **** **** **** **** **** **** +17909 **** **** **** **** **** **** **** **** **** +17910 **** **** **** **** **** **** **** **** **** +17911 **** **** **** **** **** **** **** **** **** +17912 **** **** **** **** **** **** **** **** **** +17913 **** **** **** **** **** **** **** **** **** +17914 **** **** **** **** **** **** **** **** **** +17915 **** **** **** **** **** **** **** **** **** +17916 **** **** **** **** **** **** **** **** **** +17917 **** **** **** **** **** **** **** **** **** +17918 **** **** **** **** **** **** **** **** **** +17919 **** **** **** **** **** **** **** **** **** +17920 **** **** **** **** **** **** **** **** **** +17921 **** **** **** **** **** **** **** **** **** +17922 **** **** **** **** **** **** **** **** **** +17923 **** **** **** **** **** **** **** **** **** +17924 **** **** **** **** **** **** **** **** **** +17925 **** **** **** **** **** **** **** **** **** +17926 **** **** **** **** **** **** **** **** **** +17927 **** **** **** **** **** **** **** **** **** +17928 **** **** **** **** **** **** **** **** **** +17929 **** **** **** **** **** **** **** **** **** +17930 **** **** **** **** **** **** **** **** **** +17931 **** **** **** **** **** **** **** **** **** +17932 **** **** **** **** **** **** **** **** **** +17933 **** **** **** **** **** **** **** **** **** +17934 **** **** **** **** **** **** **** **** **** +17935 **** **** **** **** **** **** **** **** **** +17936 **** **** **** **** **** **** **** **** **** +17937 **** **** **** **** **** **** **** **** **** +17938 **** **** **** **** **** **** **** **** **** +17939 **** **** **** **** **** **** **** **** **** +17940 **** **** **** **** **** **** **** **** **** +17941 **** **** **** **** **** **** **** **** **** +17942 **** **** **** **** **** **** **** **** **** +17943 **** **** **** **** **** **** **** **** **** +17944 **** **** **** **** **** **** **** **** **** +17945 **** **** **** **** **** **** **** **** **** +17946 **** **** **** **** **** **** **** **** **** +17947 **** **** **** **** **** **** **** **** **** +17948 **** **** **** **** **** **** **** **** **** +17949 **** **** **** **** **** **** **** **** **** +17950 **** **** **** **** **** **** **** **** **** +17951 **** **** **** **** **** **** **** **** **** +17952 **** **** **** **** **** **** **** **** **** +17953 **** **** **** **** **** **** **** **** **** +17954 **** **** **** **** **** **** **** **** **** +17955 **** **** **** **** **** **** **** **** **** +17956 **** **** **** **** **** **** **** **** **** +17957 **** **** **** **** **** **** **** **** **** +17958 **** **** **** **** **** **** **** **** **** +17959 **** **** **** **** **** **** **** **** **** +17960 **** **** **** **** **** **** **** **** **** +17961 **** **** **** **** **** **** **** **** **** +17962 **** **** **** **** **** **** **** **** **** +17963 **** **** **** **** **** **** **** **** **** +17964 **** **** **** **** **** **** **** **** **** +17965 **** **** **** **** **** **** **** **** **** +17966 **** **** **** **** **** **** **** **** **** +17967 **** **** **** **** **** **** **** **** **** +17968 **** **** **** **** **** **** **** **** **** +17969 **** **** **** **** **** **** **** **** **** +17970 **** **** **** **** **** **** **** **** **** +17971 **** **** **** **** **** **** **** **** **** +17972 **** **** **** **** **** **** **** **** **** +17973 **** **** **** **** **** **** **** **** **** +17974 **** **** **** **** **** **** **** **** **** +17975 **** **** **** **** **** **** **** **** **** +17976 **** **** **** **** **** **** **** **** **** +17977 **** **** **** **** **** **** **** **** **** +17978 **** **** **** **** **** **** **** **** **** +17979 **** **** **** **** **** **** **** **** **** +17980 **** **** **** **** **** **** **** **** **** +17981 **** **** **** **** **** **** **** **** **** +17982 **** **** **** **** **** **** **** **** **** +17983 **** **** **** **** **** **** **** **** **** +17984 **** **** **** **** **** **** **** **** **** +17985 **** **** **** **** **** **** **** **** **** +17986 **** **** **** **** **** **** **** **** **** +17987 **** **** **** **** **** **** **** **** **** +17988 **** **** **** **** **** **** **** **** **** +17989 **** **** **** **** **** **** **** **** **** +17990 **** **** **** **** **** **** **** **** **** +17991 **** **** **** **** **** **** **** **** **** +17992 **** **** **** **** **** **** **** **** **** +17993 **** **** **** **** **** **** **** **** **** +17994 **** **** **** **** **** **** **** **** **** +17995 **** **** **** **** **** **** **** **** **** +17996 **** **** **** **** **** **** **** **** **** +17997 **** **** **** **** **** **** **** **** **** +17998 **** **** **** **** **** **** **** **** **** +17999 ####END_OF_TOB_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +18000 **BEGIN_INVOCATIONS** **** **** **** **** **** **** **** **** +18001 BeguilingInfluence **** **** **** **** **** **** **** **** +18002 BreathOfTheNight **** **** **** **** **** **** **** **** +18003 Darkness **** **** **** **** **** **** **** **** +18004 DeafeningRoar **** **** **** **** **** **** **** **** +18005 DraconicKnowledge **** **** **** **** **** **** **** **** +18006 EndureExposure **** **** **** **** **** **** **** **** +18007 MagicInsight **** **** **** **** **** **** **** **** +18008 ScaldingGust **** **** **** **** **** **** **** **** +18009 SeeTheUnseen **** **** **** **** **** **** **** **** +18010 Charm **** **** **** **** **** **** **** **** +18011 EnergyResistance **** **** **** **** **** **** **** **** +18012 EnergyResistanceAcid **** **** **** **** **** **** **** **** +18013 EnergyResistanceCold **** **** **** **** **** **** **** **** +18014 EnergyResistanceElectric **** **** **** **** **** **** **** **** +18015 EnergyResistanceFire **** **** **** **** **** **** **** **** +18016 EnergyResistanceSonic **** **** **** **** **** **** **** **** +18017 FrightfulPresence **** **** **** **** **** **** **** **** +18018 HumanoidShape **** **** **** **** **** **** **** **** +18019 HumanoidShape_Select_Form **** **** **** **** **** **** **** **** +18020 HumanoidShape_Options **** **** **** **** **** **** **** **** +18021 HumanoidShape_True_Form **** **** **** **** **** **** **** **** +18022 HumanoidShape_Quickslot_1 **** **** **** **** **** **** **** **** +18023 HumanoidShape_Quickslot_2 **** **** **** **** **** **** **** **** +18024 Voidsense **** **** **** **** **** **** **** **** +18025 VoraciousDispelling **** **** **** **** **** **** **** **** +18026 WalkUnseen **** **** **** **** **** **** **** **** +18027 AuraOfFlame **** **** **** **** **** **** **** **** +18028 ChillingFog **** **** **** **** **** **** **** **** +18029 DevourMagic **** **** **** **** **** **** **** **** +18030 DraconicToughness **** **** **** **** **** **** **** **** +18031 TerrifyingRoar **** **** **** **** **** **** **** **** +18032 EnergyImmunity **** **** **** **** **** **** **** **** +18033 EnergyImmunityAcid **** **** **** **** **** **** **** **** +18034 EnergyImmunityCold **** **** **** **** **** **** **** **** +18035 EnergyImmunityElectric **** **** **** **** **** **** **** **** +18036 EnergyImmunityFire **** **** **** **** **** **** **** **** +18037 EnergyImmunitySonic **** **** **** **** **** **** **** **** +18038 InstillVulnerability **** **** **** **** **** **** **** **** +18039 InstillVulnerability_Acid **** **** **** **** **** **** **** **** +18040 InstillVulnerability_Cold **** **** **** **** **** **** **** **** +18041 InstillVulnerability_Elec **** **** **** **** **** **** **** **** +18042 InstillVulnerability_Fire **** **** **** **** **** **** **** **** +18043 InstillVulnerability_Sonic **** **** **** **** **** **** **** **** +18044 **Warlock_Invocations** **** **** **** **** **** **** **** **** +18045 AllSeeingEyes **** **** **** **** **** **** **** **** +18046 BalefulUtterance **** **** **** **** **** **** **** **** +18047 CallOfTheBeast **** **** **** **** **** **** **** **** +18048 CocoonOfRefuse **** **** **** **** **** **** **** **** +18049 DarkOnesOwnLuck **** **** **** **** **** **** **** **** +18050 DarkOnesOwnLuck_Fort **** **** **** **** **** **** **** **** +18051 DarkOnesOwnLuck_Reflex **** **** **** **** **** **** **** **** +18052 DarkOnesOwnLuck_Will **** **** **** **** **** **** **** **** +18053 DevilsSight **** **** **** **** **** **** **** **** +18054 **Drain_Incarnum** **** **** **** **** **** **** **** **** +18055 EarthenGrasp **** **** **** **** **** **** **** **** +18056 EldritchGlaive **** **** **** **** **** **** **** **** +18057 EldritchGlaiveOnHit **** **** **** **** **** **** **** **** +18058 EldritchSpear **** **** **** **** **** **** **** **** +18059 EntropicWarding **** **** **** **** **** **** **** **** +18060 FrightfulBlast **** **** **** **** **** **** **** **** +18061 HammerBlast **** **** **** **** **** **** **** **** +18062 HideousBlow **** **** **** **** **** **** **** **** +18063 LeapsAndBounds **** **** **** **** **** **** **** **** +18064 MiasmicCloud **** **** **** **** **** **** **** **** +18065 OtherworldlyWhispers **** **** **** **** **** **** **** **** +18066 SerpentsTongue **** **** **** **** **** **** **** **** +18067 SickeningBlast **** **** **** **** **** **** **** **** +18068 SoulreavingAura **** **** **** **** **** **** **** **** +18069 SummonSwarm **** **** **** **** **** **** **** **** +18070 SummonSwarm_Rat **** **** **** **** **** **** **** **** +18071 SummonSwarm_Bat **** **** **** **** **** **** **** **** +18072 SwimmingTheStyx **** **** **** **** **** **** **** **** +18073 BanefulBlastAbberation **** **** **** **** **** **** **** **** +18074 BanefulBlastBeast **** **** **** **** **** **** **** **** +18075 BanefulBlastConstruct **** **** **** **** **** **** **** **** +18076 BanefulBlastDragon **** **** **** **** **** **** **** **** +18077 BanefulBlastDwarf **** **** **** **** **** **** **** **** +18078 BanefulBlastElemental **** **** **** **** **** **** **** **** +18079 BanefulBlastElf **** **** **** **** **** **** **** **** +18080 BanefulBlastFey **** **** **** **** **** **** **** **** +18081 BanefulBlastGiant **** **** **** **** **** **** **** **** +18082 BanefulBlastGoblinoid **** **** **** **** **** **** **** **** +18083 BanefulBlastGnome **** **** **** **** **** **** **** **** +18084 BanefulBlastHalfling **** **** **** **** **** **** **** **** +18085 BanefulBlastHuman **** **** **** **** **** **** **** **** +18086 BanefulBlastMonsterous **** **** **** **** **** **** **** **** +18087 BanefulBlastOrc **** **** **** **** **** **** **** **** +18088 BanefulBlastOutsider **** **** **** **** **** **** **** **** +18089 BanefulBlastPlant **** **** **** **** **** **** **** **** +18090 BanefulBlastReptilian **** **** **** **** **** **** **** **** +18091 BanefulBlastShapechanger **** **** **** **** **** **** **** **** +18092 BanefulBlastUndead **** **** **** **** **** **** **** **** +18093 BanefulBlastVermin **** **** **** **** **** **** **** **** +18094 BeshadowedBlast **** **** **** **** **** **** **** **** +18095 BrimstoneBlast **** **** **** **** **** **** **** **** +18096 ColdComfort **** **** **** **** **** **** **** **** +18097 CurseOfDespair **** **** **** **** **** **** **** **** +18098 DreadSeizure **** **** **** **** **** **** **** **** +18099 EldritchChain **** **** **** **** **** **** **** **** +18100 FleeTheScene **** **** **** **** **** **** **** **** +18101 FleeTheScene_Selected **** **** **** **** **** **** **** **** +18102 FleeTheScene_Direction_and_Distance **** **** **** **** **** **** **** **** +18103 HellrimeBlast **** **** **** **** **** **** **** **** +18104 HungryDarkness **** **** **** **** **** **** **** **** +18105 IgnoreThePyre **** **** **** **** **** **** **** **** +18106 IgnoreThePyreAcid **** **** **** **** **** **** **** **** +18107 IgnoreThePyreCold **** **** **** **** **** **** **** **** +18108 IgnoreThePyreElec **** **** **** **** **** **** **** **** +18109 IgnoreThePyreFire **** **** **** **** **** **** **** **** +18110 IgnoreThePyreSonic **** **** **** **** **** **** **** **** +18111 MaskOfFlesh **** **** **** **** **** **** **** **** +18112 MaskOfFleshFriendly **** **** **** **** **** **** **** **** +18113 MaskOfFleshHostile **** **** **** **** **** **** **** **** +18114 RelentlessDispelling **** **** **** **** **** **** **** **** +18115 SpiderShape **** **** **** **** **** **** **** **** +18116 **Steal_Incarnum** **** **** **** **** **** **** **** **** +18117 StonyGrasp **** **** **** **** **** **** **** **** +18118 TheDeadWalk **** **** **** **** **** **** **** **** +18119 WallOfGloom **** **** **** **** **** **** **** **** +18120 WitchwoodStep **** **** **** **** **** **** **** **** +18121 BewitchingBlast **** **** **** **** **** **** **** **** +18122 CausticMire **** **** **** **** **** **** **** **** +18123 ChillingTentacles **** **** **** **** **** **** **** **** +18124 DragonWard **** **** **** **** **** **** **** **** +18125 EldritchCone **** **** **** **** **** **** **** **** +18126 EldritchLine **** **** **** **** **** **** **** **** +18127 EnervatingShadow **** **** **** **** **** **** **** **** +18128 HellspawnedGrace **** **** **** **** **** **** **** **** +18129 HinderingBlast **** **** **** **** **** **** **** **** +18130 **Incarnum_Blast** **** **** **** **** **** **** **** **** +18131 NightmaresMadeReal **** **** **** **** **** **** **** **** +18132 NoxiousBlast **** **** **** **** **** **** **** **** +18133 PainfulSlumberOfTheAges **** **** **** **** **** **** **** **** +18134 PenetratingBlast **** **** **** **** **** **** **** **** +18135 TenaciousPlague **** **** **** **** **** **** **** **** +18136 VitriolicBlast **** **** **** **** **** **** **** **** +18137 WallOfPerilousFlame **** **** **** **** **** **** **** **** +18138 BindingBlast **** **** **** **** **** **** **** **** +18139 CastersLament **** **** **** **** **** **** **** **** +18140 DarkDiscorporation **** **** **** **** **** **** **** **** +18141 DarkForesight **** **** **** **** **** **** **** **** +18142 EldritchDoom **** **** **** **** **** **** **** **** +18143 **Incarnum_Shroud** **** **** **** **** **** **** **** **** +18144 PathOfShadow **** **** **** **** **** **** **** **** +18145 PathOfShadowSelf **** **** **** **** **** **** **** **** +18146 PathOfShadowParty **** **** **** **** **** **** **** **** +18147 RetributiveInvisibility **** **** **** **** **** **** **** **** +18148 StealSummoning **** **** **** **** **** **** **** **** +18149 UtterdarkBlast **** **** **** **** **** **** **** **** +18150 WordOfChanging **** **** **** **** **** **** **** **** +18151 **Enlightened_Spirit_Invocations** **** **** **** **** **** **** **** **** +18152 **** **** **** **** **** **** **** **** **** +18153 **** **** **** **** **** **** **** **** **** +18154 **** **** **** **** **** **** **** **** **** +18155 **** **** **** **** **** **** **** **** **** +18156 **** **** **** **** **** **** **** **** **** +18157 **** **** **** **** **** **** **** **** **** +18158 ####START_OF_INV_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +18159 Warlock_AllSeeingEyes **** **** **** **** **** **** **** **** +18160 Warlock_BalefulUtterance **** **** **** **** **** **** **** **** +18161 Warlock_BeguilingInfluence **** **** **** **** **** **** **** **** +18162 Warlock_BreathOfTheNight **** **** **** **** **** **** **** **** +18163 Warlock_CallOfTheBeast **** **** **** **** **** **** **** **** +18164 Warlock_CocoonOfRefuse **** **** **** **** **** **** **** **** +18165 Warlock_Darkness **** **** **** **** **** **** **** **** +18166 Warlock_DarkOnesOwnLuck **** **** **** **** **** **** **** **** +18167 Warlock_DarkOnesOwnLuck_Fort **** **** **** **** **** **** **** **** +18168 Warlock_DarkOnesOwnLuck_Reflex **** **** **** **** **** **** **** **** +18169 Warlock_DarkOnesOwnLuck_Will **** **** **** **** **** **** **** **** +18170 Warlock_DevilsSight **** **** **** **** **** **** **** **** +18171 Warlock_EarthenGrasp **** **** **** **** **** **** **** **** +18172 Warlock_EldritchGlaive **** **** **** **** **** **** **** **** +18173 Warlock_EldritchSpear **** **** **** **** **** **** **** **** +18174 Warlock_EntropicWarding **** **** **** **** **** **** **** **** +18175 Warlock_FrightfulBlast **** **** **** **** **** **** **** **** +18176 Warlock_HammerBlast **** **** **** **** **** **** **** **** +18177 Warlock_HideousBlow **** **** **** **** **** **** **** **** +18178 Warlock_LeapsAndBounds **** **** **** **** **** **** **** **** +18179 Warlock_MiasmicCloud **** **** **** **** **** **** **** **** +18180 Warlock_OtherworldlyWhispers **** **** **** **** **** **** **** **** +18181 Warlock_SeeTheUnseen **** **** **** **** **** **** **** **** +18182 Warlock_SerpentsTongue **** **** **** **** **** **** **** **** +18183 Warlock_SickeningBlast **** **** **** **** **** **** **** **** +18184 Warlock_SoulreavingAura **** **** **** **** **** **** **** **** +18185 Warlock_SummonSwarm **** **** **** **** **** **** **** **** +18186 Warlock_SummonSwarm_Rat **** **** **** **** **** **** **** **** +18187 Warlock_SummonSwarm_Bat **** **** **** **** **** **** **** **** +18188 Warlock_SwimmingTheStyx **** **** **** **** **** **** **** **** +18189 Warlock_BanefulBlastAbberation **** **** **** **** **** **** **** **** +18190 Warlock_BanefulBlastBeast **** **** **** **** **** **** **** **** +18191 Warlock_BanefulBlastConstruct **** **** **** **** **** **** **** **** +18192 Warlock_BanefulBlastDragon **** **** **** **** **** **** **** **** +18193 Warlock_BanefulBlastDwarf **** **** **** **** **** **** **** **** +18194 Warlock_BanefulBlastElemental **** **** **** **** **** **** **** **** +18195 Warlock_BanefulBlastElf **** **** **** **** **** **** **** **** +18196 Warlock_BanefulBlastFey **** **** **** **** **** **** **** **** +18197 Warlock_BanefulBlastGiant **** **** **** **** **** **** **** **** +18198 Warlock_BanefulBlastGoblinoid **** **** **** **** **** **** **** **** +18199 Warlock_BanefulBlastGnome **** **** **** **** **** **** **** **** +18200 Warlock_BanefulBlastHalfling **** **** **** **** **** **** **** **** +18201 Warlock_BanefulBlastHuman **** **** **** **** **** **** **** **** +18202 Warlock_BanefulBlastMonsterous **** **** **** **** **** **** **** **** +18203 Warlock_BanefulBlastOrc **** **** **** **** **** **** **** **** +18204 Warlock_BanefulBlastOutsider **** **** **** **** **** **** **** **** +18205 Warlock_BanefulBlastPlant **** **** **** **** **** **** **** **** +18206 Warlock_BanefulBlastReptilian **** **** **** **** **** **** **** **** +18207 Warlock_BanefulBlastShapechanger **** **** **** **** **** **** **** **** +18208 Warlock_BanefulBlastUndead **** **** **** **** **** **** **** **** +18209 Warlock_BanefulBlastVermin **** **** **** **** **** **** **** **** +18210 Warlock_BeshadowedBlast **** **** **** **** **** **** **** **** +18211 Warlock_BrimstoneBlast **** **** **** **** **** **** **** **** +18212 Warlock_Charm **** **** **** **** **** **** **** **** +18213 Warlock_ColdComfort **** **** **** **** **** **** **** **** +18214 Warlock_CurseOfDespair **** **** **** **** **** **** **** **** +18215 Warlock_DreadSeizure **** **** **** **** **** **** **** **** +18216 Warlock_EldritchChain **** **** **** **** **** **** **** **** +18217 Warlock_FleeTheScene **** **** **** **** **** **** **** **** +18218 Warlock_FleeTheScene_Selected **** **** **** **** **** **** **** **** +18219 Warlock_FleeTheScene_Direction_and_Distance **** **** **** **** **** **** **** **** +18220 Warlock_HellrimeBlast **** **** **** **** **** **** **** **** +18221 Warlock_HungryDarkness **** **** **** **** **** **** **** **** +18222 Warlock_IgnoreThePyre **** **** **** **** **** **** **** **** +18223 Warlock_IgnoreThePyreAcid **** **** **** **** **** **** **** **** +18224 Warlock_IgnoreThePyreCold **** **** **** **** **** **** **** **** +18225 Warlock_IgnoreThePyreElec **** **** **** **** **** **** **** **** +18226 Warlock_IgnoreThePyreFire **** **** **** **** **** **** **** **** +18227 Warlock_IgnoreThePyreSonic **** **** **** **** **** **** **** **** +18228 Warlock_MaskOfFlesh **** **** **** **** **** **** **** **** +18229 Warlock_MaskOfFleshFriendly **** **** **** **** **** **** **** **** +18230 Warlock_MaskOfFleshHostile **** **** **** **** **** **** **** **** +18231 Warlock_RelentlessDispelling **** **** **** **** **** **** **** **** +18232 Warlock_SpiderShape **** **** **** **** **** **** **** **** +18233 Warlock_StonyGrasp **** **** **** **** **** **** **** **** +18234 Warlock_TheDeadWalk **** **** **** **** **** **** **** **** +18235 Warlock_Voidsense **** **** **** **** **** **** **** **** +18236 Warlock_VoraciousDispelling **** **** **** **** **** **** **** **** +18237 Warlock_WalkUnseen **** **** **** **** **** **** **** **** +18238 Warlock_WallOfGloom **** **** **** **** **** **** **** **** +18239 Warlock_WitchwoodStep **** **** **** **** **** **** **** **** +18240 Warlock_BewitchingBlast **** **** **** **** **** **** **** **** +18241 Warlock_CausticMire **** **** **** **** **** **** **** **** +18242 Warlock_ChillingTentacles **** **** **** **** **** **** **** **** +18243 Warlock_DevourMagic **** **** **** **** **** **** **** **** +18244 Warlock_DragonWard **** **** **** **** **** **** **** **** +18245 Warlock_EldritchCone **** **** **** **** **** **** **** **** +18246 Warlock_EldritchLine **** **** **** **** **** **** **** **** +18247 Warlock_EnervatingShadow **** **** **** **** **** **** **** **** +18248 Warlock_HellspawnedGrace **** **** **** **** **** **** **** **** +18249 Warlock_HinderingBlast **** **** **** **** **** **** **** **** +18250 Warlock_NightmaresMadeReal **** **** **** **** **** **** **** **** +18251 Warlock_NoxiousBlast **** **** **** **** **** **** **** **** +18252 Warlock_PainfulSlumberOfTheAges **** **** **** **** **** **** **** **** +18253 Warlock_PenetratingBlast **** **** **** **** **** **** **** **** +18254 Warlock_TenaciousPlague **** **** **** **** **** **** **** **** +18255 Warlock_VitriolicBlast **** **** **** **** **** **** **** **** +18256 Warlock_WallOfPerilousFlame **** **** **** **** **** **** **** **** +18257 Warlock_BindingBlast **** **** **** **** **** **** **** **** +18258 Warlock_CastersLament **** **** **** **** **** **** **** **** +18259 Warlock_DarkDiscorporation **** **** **** **** **** **** **** **** +18260 Warlock_DarkForesight **** **** **** **** **** **** **** **** +18261 Warlock_EldritchDoom **** **** **** **** **** **** **** **** +18262 Warlock_PathOfShadow **** **** **** **** **** **** **** **** +18263 Warlock_PathOfShadowSelf **** **** **** **** **** **** **** **** +18264 Warlock_PathOfShadowParty **** **** **** **** **** **** **** **** +18265 Warlock_RetributiveInvisibility **** **** **** **** **** **** **** **** +18266 Warlock_StealSummoning **** **** **** **** **** **** **** **** +18267 Warlock_UtterdarkBlast **** **** **** **** **** **** **** **** +18268 Warlock_WordOfChanging **** **** **** **** **** **** **** **** +18269 DragonShaman_BeguilingInfluence **** **** **** **** **** **** **** **** +18270 DragonShaman_BreathOfTheNight **** **** **** **** **** **** **** **** +18271 DragonShaman_Darkness **** **** **** **** **** **** **** **** +18272 DragonShaman_DeafeningRoar **** **** **** **** **** **** **** **** +18273 DragonShaman_DraconicKnowledge **** **** **** **** **** **** **** **** +18274 DragonShaman_EndureExposure **** **** **** **** **** **** **** **** +18275 DragonShaman_MagicInsight **** **** **** **** **** **** **** **** +18276 DragonShaman_ScaldingGust **** **** **** **** **** **** **** **** +18277 DragonShaman_SeeTheUnseen **** **** **** **** **** **** **** **** +18278 Dragonfire_Adept_BeguilingInfluence **** **** **** **** **** **** **** **** +18279 Dragonfire_Adept_BreathOfTheNight **** **** **** **** **** **** **** **** +18280 Dragonfire_Adept_Darkness **** **** **** **** **** **** **** **** +18281 Dragonfire_Adept_DeafeningRoar **** **** **** **** **** **** **** **** +18282 Dragonfire_Adept_DraconicKnowledge **** **** **** **** **** **** **** **** +18283 Dragonfire_Adept_EndureExposure **** **** **** **** **** **** **** **** +18284 Dragonfire_Adept_MagicInsight **** **** **** **** **** **** **** **** +18285 Dragonfire_Adept_ScaldingGust **** **** **** **** **** **** **** **** +18286 Dragonfire_Adept_SeeTheUnseen **** **** **** **** **** **** **** **** +18287 Dragonfire_Adept_Charm **** **** **** **** **** **** **** **** +18288 Dragonfire_Adept_EnergyResistance **** **** **** **** **** **** **** **** +18289 Dragonfire_Adept_EnergyResistanceAcid **** **** **** **** **** **** **** **** +18290 Dragonfire_Adept_EnergyResistanceCold **** **** **** **** **** **** **** **** +18291 Dragonfire_Adept_EnergyResistanceElectric **** **** **** **** **** **** **** **** +18292 Dragonfire_Adept_EnergyResistanceFire **** **** **** **** **** **** **** **** +18293 Dragonfire_Adept_EnergyResistanceSonic **** **** **** **** **** **** **** **** +18294 Dragonfire_Adept_FrightfulPresence **** **** **** **** **** **** **** **** +18295 Dragonfire_Adept_HumanoidShape **** **** **** **** **** **** **** **** +18296 Dragonfire_Adept_HumanoidShape_Select_Form **** **** **** **** **** **** **** **** +18297 Dragonfire_Adept_HumanoidShape_Options **** **** **** **** **** **** **** **** +18298 Dragonfire_Adept_HumanoidShape_True_Form **** **** **** **** **** **** **** **** +18299 Dragonfire_Adept_HumanoidShape_Quickslot_1 **** **** **** **** **** **** **** **** +18300 Dragonfire_Adept_HumanoidShape_Quickslot_2 **** **** **** **** **** **** **** **** +18301 Dragonfire_Adept_Voidsense **** **** **** **** **** **** **** **** +18302 Dragonfire_Adept_VoraciousDispelling **** **** **** **** **** **** **** **** +18303 Dragonfire_Adept_WalkUnseen **** **** **** **** **** **** **** **** +18304 Dragonfire_Adept_AuraOfFlame **** **** **** **** **** **** **** **** +18305 Dragonfire_Adept_ChillingFog **** **** **** **** **** **** **** **** +18306 Dragonfire_Adept_DevourMagic **** **** **** **** **** **** **** **** +18307 Dragonfire_Adept_DraconicToughness **** **** **** **** **** **** **** **** +18308 Dragonfire_Adept_TerrifyingRoar **** **** **** **** **** **** **** **** +18309 Dragonfire_Adept_EnergyImmunity **** **** **** **** **** **** **** **** +18310 Dragonfire_Adept_EnergyImmunityAcid **** **** **** **** **** **** **** **** +18311 Dragonfire_Adept_EnergyImmunityCold **** **** **** **** **** **** **** **** +18312 Dragonfire_Adept_EnergyImmunityElectric **** **** **** **** **** **** **** **** +18313 Dragonfire_Adept_EnergyImmunityFire **** **** **** **** **** **** **** **** +18314 Dragonfire_Adept_EnergyImmunitySonic **** **** **** **** **** **** **** **** +18315 Dragonfire_Adept_InstillVulnerability **** **** **** **** **** **** **** **** +18316 Dragonfire_Adept_InstillVulnerability_Acid **** **** **** **** **** **** **** **** +18317 Dragonfire_Adept_InstillVulnerability_Cold **** **** **** **** **** **** **** **** +18318 Dragonfire_Adept_InstillVulnerability_Elec **** **** **** **** **** **** **** **** +18319 Dragonfire_Adept_InstillVulnerability_Fire **** **** **** **** **** **** **** **** +18320 Dragonfire_Adept_InstillVulnerability_Sonic **** **** **** **** **** **** **** **** +18321 **** **** **** **** **** **** **** **** **** +18322 **** **** **** **** **** **** **** **** **** +18323 **** **** **** **** **** **** **** **** **** +18324 **** **** **** **** **** **** **** **** **** +18325 **** **** **** **** **** **** **** **** **** +18326 **** **** **** **** **** **** **** **** **** +18327 **** **** **** **** **** **** **** **** **** +18328 **** **** **** **** **** **** **** **** **** +18329 **** **** **** **** **** **** **** **** **** +18330 **** **** **** **** **** **** **** **** **** +18331 **** **** **** **** **** **** **** **** **** +18332 **** **** **** **** **** **** **** **** **** +18333 **** **** **** **** **** **** **** **** **** +18334 **** **** **** **** **** **** **** **** **** +18335 **** **** **** **** **** **** **** **** **** +18336 **** **** **** **** **** **** **** **** **** +18337 **** **** **** **** **** **** **** **** **** +18338 **** **** **** **** **** **** **** **** **** +18339 **** **** **** **** **** **** **** **** **** +18340 **** **** **** **** **** **** **** **** **** +18341 **** **** **** **** **** **** **** **** **** +18342 **** **** **** **** **** **** **** **** **** +18343 **** **** **** **** **** **** **** **** **** +18344 **** **** **** **** **** **** **** **** **** +18345 **** **** **** **** **** **** **** **** **** +18346 **** **** **** **** **** **** **** **** **** +18347 **** **** **** **** **** **** **** **** **** +18348 **** **** **** **** **** **** **** **** **** +18349 **** **** **** **** **** **** **** **** **** +18350 ####END_OF_INV_SPELLBOOK_RESERVE **** **** **** **** **** **** **** **** +18351 ####START_OF_SHADOW_MAGIC_RESERVE **** **** **** **** **** **** **** **** +18352 BendPerspective **** **** **** **** **** **** **** **** +18353 CarpetShadow **** **** **** **** **** **** **** **** +18354 DuskAndDawn_Dusk **** **** **** **** **** **** **** **** +18355 DuskAndDawn_Dawn **** **** **** **** **** **** **** **** +18356 LifeFades **** **** **** **** **** **** **** **** +18357 MesmerizingShade **** **** **** **** **** **** **** **** +18358 SteelShadows **** **** **** **** **** **** **** **** +18359 VoiceOfShadow_Approach **** **** **** **** **** **** **** **** +18360 VoiceOfShadow_Drop **** **** **** **** **** **** **** **** +18361 VoiceOfShadow_Fall **** **** **** **** **** **** **** **** +18362 VoiceOfShadow_Flee **** **** **** **** **** **** **** **** +18363 VoiceOfShadow_Halt **** **** **** **** **** **** **** **** +18364 BlackFire **** **** **** **** **** **** **** **** +18365 CongressShadows **** **** **** **** **** **** **** **** +18366 FleshFails_Str **** **** **** **** **** **** **** **** +18367 FleshFails_Dex **** **** **** **** **** **** **** **** +18368 FleshFails_Con **** **** **** **** **** **** **** **** +18369 PiercingSight **** **** **** **** **** **** **** **** +18370 ShadowSkin **** **** **** **** **** **** **** **** +18371 SightEclipsed **** **** **** **** **** **** **** **** +18372 ThoughtsShadow_Int **** **** **** **** **** **** **** **** +18373 ThoughtsShadow_Wis **** **** **** **** **** **** **** **** +18374 ThoughtsShadow_Cha **** **** **** **** **** **** **** **** +18375 AfraidOfTheDark **** **** **** **** **** **** **** **** +18376 ClingingDarkness **** **** **** **** **** **** **** **** +18377 DancingShadows **** **** **** **** **** **** **** **** +18378 Flicker **** **** **** **** **** **** **** **** +18379 KillingShadows **** **** **** **** **** **** **** **** +18380 SharpShadows **** **** **** **** **** **** **** **** +18381 UmbralTouch **** **** **** **** **** **** **** **** +18382 AuraOfShade **** **** **** **** **** **** **** **** +18383 Bolster **** **** **** **** **** **** **** **** +18384 ShadowEvocation **** **** **** **** **** **** **** **** +18385 ShadowEvocation_Conv **** **** **** **** **** **** **** **** +18386 ShadowVision **** **** **** **** **** **** **** **** +18387 ShadowsFade **** **** **** **** **** **** **** **** +18388 StepIntoShadow_Self **** **** **** **** **** **** **** **** +18389 StepIntoShadow_Party **** **** **** **** **** **** **** **** +18390 WarpSpell **** **** **** **** **** **** **** **** +18391 CurtainShadows **** **** **** **** **** **** **** **** +18392 DarkAir **** **** **** **** **** **** **** **** +18393 EchoSpell **** **** **** **** **** **** **** **** +18394 FeignLife **** **** **** **** **** **** **** **** +18395 Languor_Slow **** **** **** **** **** **** **** **** +18396 Languor_Hold **** **** **** **** **** **** **** **** +18397 PassShadow_Self **** **** **** **** **** **** **** **** +18398 PassShadow_Party **** **** **** **** **** **** **** **** +18399 UnravelDweomer **** **** **** **** **** **** **** **** +18400 FloodShadows **** **** **** **** **** **** **** **** +18401 GreaterShadowEvocation **** **** **** **** **** **** **** **** +18402 GreaterShadowEvocation_Conv **** **** **** **** **** **** **** **** +18403 ShadowInvestiture **** **** **** **** **** **** **** **** +18404 ShadowStorm **** **** **** **** **** **** **** **** +18405 ShadowsFade_Greater **** **** **** **** **** **** **** **** +18406 Unveil **** **** **** **** **** **** **** **** +18407 VoyageShadow_Self **** **** **** **** **** **** **** **** +18408 VoyageShadow_Party **** **** **** **** **** **** **** **** +18409 DarkSoul **** **** **** **** **** **** **** **** +18410 EphemeralImage **** **** **** **** **** **** **** **** +18411 LifeFadesGreater **** **** **** **** **** **** **** **** +18412 PrisonNight **** **** **** **** **** **** **** **** +18413 UmbralServant **** **** **** **** **** **** **** **** +18414 TruthRevealed **** **** **** **** **** **** **** **** +18415 FarSight **** **** **** **** **** **** **** **** +18416 GrFleshFails_Str **** **** **** **** **** **** **** **** +18417 GrFleshFails_Dex **** **** **** **** **** **** **** **** +18418 GrFleshFails_Con **** **** **** **** **** **** **** **** +18419 ShadowPlague **** **** **** **** **** **** **** **** +18420 SoulPuppet **** **** **** **** **** **** **** **** +18421 TombNight **** **** **** **** **** **** **** **** +18422 UmbralBody **** **** **** **** **** **** **** **** +18423 ArmyShadow **** **** **** **** **** **** **** **** +18424 ConsumeEssence **** **** **** **** **** **** **** **** +18425 EphemeralStorm **** **** **** **** **** **** **** **** +18426 Reflections **** **** **** **** **** **** **** **** +18427 ShadowSurge **** **** **** **** **** **** **** **** +18428 ShadowTime **** **** **** **** **** **** **** **** +18429 **Class_Mysteries** **** **** **** **** **** **** **** **** +18430 Shadowcaster_BendPerspective **** **** **** **** **** **** **** **** +18431 Shadowcaster_CarpetShadow **** **** **** **** **** **** **** **** +18432 Shadowcaster_DuskAndDawn_RadialMaster **** **** **** **** **** **** **** **** +18433 Shadowcaster_DuskAndDawn_Dusk **** **** **** **** **** **** **** **** +18434 Shadowcaster_DuskAndDawn_Dawn **** **** **** **** **** **** **** **** +18435 Shadowcaster_LifeFades **** **** **** **** **** **** **** **** +18436 Shadowcaster_MesmerizingShade **** **** **** **** **** **** **** **** +18437 Shadowcaster_SteelShadows **** **** **** **** **** **** **** **** +18438 Shadowcaster_VoiceOfShadow_RadialMaster **** **** **** **** **** **** **** **** +18439 Shadowcaster_VoiceOfShadow_Approach **** **** **** **** **** **** **** **** +18440 Shadowcaster_VoiceOfShadow_Drop **** **** **** **** **** **** **** **** +18441 Shadowcaster_VoiceOfShadow_Fall **** **** **** **** **** **** **** **** +18442 Shadowcaster_VoiceOfShadow_Flee **** **** **** **** **** **** **** **** +18443 Shadowcaster_VoiceOfShadow_Halt **** **** **** **** **** **** **** **** +18444 Shadowcaster_BlackFire **** **** **** **** **** **** **** **** +18445 Shadowcaster_CongressShadows **** **** **** **** **** **** **** **** +18446 Shadowcaster_FleshFails_RadialMaster **** **** **** **** **** **** **** **** +18447 Shadowcaster_FleshFails_Str **** **** **** **** **** **** **** **** +18448 Shadowcaster_FleshFails_Dex **** **** **** **** **** **** **** **** +18449 Shadowcaster_FleshFails_Con **** **** **** **** **** **** **** **** +18450 Shadowcaster_PiercingSight **** **** **** **** **** **** **** **** +18451 Shadowcaster_ShadowSkin **** **** **** **** **** **** **** **** +18452 Shadowcaster_SightEclipsed **** **** **** **** **** **** **** **** +18453 Shadowcaster_ThoughtsShadow_RadialMaster **** **** **** **** **** **** **** **** +18454 Shadowcaster_ThoughtsShadow_Int **** **** **** **** **** **** **** **** +18455 Shadowcaster_ThoughtsShadow_Wis **** **** **** **** **** **** **** **** +18456 Shadowcaster_ThoughtsShadow_Cha **** **** **** **** **** **** **** **** +18457 Shadowcaster_AfraidOfTheDark **** **** **** **** **** **** **** **** +18458 Shadowcaster_ClingingDarkness **** **** **** **** **** **** **** **** +18459 Shadowcaster_DancingShadows **** **** **** **** **** **** **** **** +18460 Shadowcaster_Flicker **** **** **** **** **** **** **** **** +18461 Shadowcaster_KillingShadows **** **** **** **** **** **** **** **** +18462 Shadowcaster_SharpShadows **** **** **** **** **** **** **** **** +18463 Shadowcaster_UmbralTouch **** **** **** **** **** **** **** **** +18464 Shadowcaster_AuraOfShade **** **** **** **** **** **** **** **** +18465 Shadowcaster_Bolster **** **** **** **** **** **** **** **** +18466 Shadowcaster_ShadowEvocation_RadialMaster **** **** **** **** **** **** **** **** +18467 Shadowcaster_ShadowEvocation **** **** **** **** **** **** **** **** +18468 Shadowcaster_ShadowEvocation_Conv **** **** **** **** **** **** **** **** +18469 Shadowcaster_ShadowVision **** **** **** **** **** **** **** **** +18470 Shadowcaster_ShadowsFade **** **** **** **** **** **** **** **** +18471 Shadowcaster_StepIntoShadow_RadialMaster **** **** **** **** **** **** **** **** +18472 Shadowcaster_StepIntoShadow_Self **** **** **** **** **** **** **** **** +18473 Shadowcaster_StepIntoShadow_Party **** **** **** **** **** **** **** **** +18474 Shadowcaster_WarpSpell **** **** **** **** **** **** **** **** +18475 Shadowcaster_CurtainShadows **** **** **** **** **** **** **** **** +18476 Shadowcaster_DarkAir **** **** **** **** **** **** **** **** +18477 Shadowcaster_EchoSpell **** **** **** **** **** **** **** **** +18478 Shadowcaster_FeignLife **** **** **** **** **** **** **** **** +18479 Shadowcaster_Languor_RadialMaster **** **** **** **** **** **** **** **** +18480 Shadowcaster_Languor_Slow **** **** **** **** **** **** **** **** +18481 Shadowcaster_Languor_Hold **** **** **** **** **** **** **** **** +18482 Shadowcaster_PassIntoShadow_RadialMaster **** **** **** **** **** **** **** **** +18483 Shadowcaster_PassShadow_Self **** **** **** **** **** **** **** **** +18484 Shadowcaster_PassShadow_Party **** **** **** **** **** **** **** **** +18485 Shadowcaster_UnravelDweomer **** **** **** **** **** **** **** **** +18486 Shadowcaster_FloodShadows **** **** **** **** **** **** **** **** +18487 Shadowcaster_GreaterShadowEvocation_RadialMaster **** **** **** **** **** **** **** **** +18488 Shadowcaster_GreaterShadowEvocation **** **** **** **** **** **** **** **** +18489 Shadowcaster_GreaterShadowEvocation_Conv **** **** **** **** **** **** **** **** +18490 Shadowcaster_ShadowInvestiture **** **** **** **** **** **** **** **** +18491 Shadowcaster_ShadowStorm **** **** **** **** **** **** **** **** +18492 Shadowcaster_ShadowsFade_Greater **** **** **** **** **** **** **** **** +18493 Shadowcaster_Unveil **** **** **** **** **** **** **** **** +18494 Shadowcaster_VoyageShadow_RadialMaster **** **** **** **** **** **** **** **** +18495 Shadowcaster_VoyageShadow_Self **** **** **** **** **** **** **** **** +18496 Shadowcaster_VoyageShadow_Party **** **** **** **** **** **** **** **** +18497 Shadowcaster_DarkSoul **** **** **** **** **** **** **** **** +18498 Shadowcaster_EphemeralImage **** **** **** **** **** **** **** **** +18499 Shadowcaster_LifeFadesGreater **** **** **** **** **** **** **** **** +18500 Shadowcaster_PrisonNight **** **** **** **** **** **** **** **** +18501 Shadowcaster_UmbralServant **** **** **** **** **** **** **** **** +18502 Shadowcaster_TruthRevealed **** **** **** **** **** **** **** **** +18503 Shadowcaster_FarSight **** **** **** **** **** **** **** **** +18504 Shadowcaster_GrFleshFails_RadialMaster **** **** **** **** **** **** **** **** +18505 Shadowcaster_GrFleshFails_Str **** **** **** **** **** **** **** **** +18506 Shadowcaster_GrFleshFails_Dex **** **** **** **** **** **** **** **** +18507 Shadowcaster_GrFleshFails_Con **** **** **** **** **** **** **** **** +18508 Shadowcaster_ShadowPlague **** **** **** **** **** **** **** **** +18509 Shadowcaster_SoulPuppet **** **** **** **** **** **** **** **** +18510 Shadowcaster_TombNight **** **** **** **** **** **** **** **** +18511 Shadowcaster_UmbralBody **** **** **** **** **** **** **** **** +18512 Shadowcaster_ArmyShadow **** **** **** **** **** **** **** **** +18513 Shadowcaster_ConsumeEssence **** **** **** **** **** **** **** **** +18514 Shadowcaster_EphemeralStorm **** **** **** **** **** **** **** **** +18515 Shadowcaster_Reflections **** **** **** **** **** **** **** **** +18516 Shadowcaster_ShadowSurge **** **** **** **** **** **** **** **** +18517 Shadowcaster_ShadowTime **** **** **** **** **** **** **** **** +18518 **Shadowcasting_Feats** **** **** **** **** **** **** **** **** +18519 Flicker_Feat **** **** **** **** **** **** **** **** +18520 DarkSoul_Feat **** **** **** **** **** **** **** **** +18521 ArrowDusk **** **** **** **** **** **** **** **** +18522 BlackCandle_Master **** **** **** **** **** **** **** **** +18523 BlackCandle_Light **** **** **** **** **** **** **** **** +18524 BlackCandle_Dark **** **** **** **** **** **** **** **** +18525 CaulShadow **** **** **** **** **** **** **** **** +18526 MysticReflections **** **** **** **** **** **** **** **** +18527 SightObscured **** **** **** **** **** **** **** **** +18528 ShadowHood **** **** **** **** **** **** **** **** +18529 UmbralHand **** **** **** **** **** **** **** **** +18530 WidenedEyes **** **** **** **** **** **** **** **** +18531 EmpowerMystery **** **** **** **** **** **** **** **** +18532 ExtendMystery **** **** **** **** **** **** **** **** +18533 MaximizeMystery **** **** **** **** **** **** **** **** +18534 QuickenMystery **** **** **** **** **** **** **** **** +18535 StillMystery **** **** **** **** **** **** **** **** +18536 CloakShadows **** **** **** **** **** **** **** **** +18537 DancingShadows **** **** **** **** **** **** **** **** +18538 NightForm **** **** **** **** **** **** **** **** +18539 MastersBidding_Heal **** **** **** **** **** **** **** **** +18540 MastersBidding_Attack **** **** **** **** **** **** **** **** +18541 MastersBidding_Cold **** **** **** **** **** **** **** **** +18542 MastersBidding_DR **** **** **** **** **** **** **** **** +18543 MastersBidding_Speed **** **** **** **** **** **** **** **** +18544 InnateCounterspell **** **** **** **** **** **** **** **** +18545 EldritchDisruption **** **** **** **** **** **** **** **** +18546 EldritchVortex **** **** **** **** **** **** **** **** +18547 Shadowsmith_BendPerspective **** **** **** **** **** **** **** **** +18548 Shadowsmith_CarpetShadow **** **** **** **** **** **** **** **** +18549 Shadowsmith_DuskAndDawn_RadialMaster **** **** **** **** **** **** **** **** +18550 Shadowsmith_DuskAndDawn_Dusk **** **** **** **** **** **** **** **** +18551 Shadowsmith_DuskAndDawn_Dawn **** **** **** **** **** **** **** **** +18552 Shadowsmith_LifeFades **** **** **** **** **** **** **** **** +18553 Shadowsmith_MesmerizingShade **** **** **** **** **** **** **** **** +18554 Shadowsmith_SteelShadows **** **** **** **** **** **** **** **** +18555 Shadowsmith_VoiceOfShadow_RadialMaster **** **** **** **** **** **** **** **** +18556 Shadowsmith_VoiceOfShadow_Approach **** **** **** **** **** **** **** **** +18557 Shadowsmith_VoiceOfShadow_Drop **** **** **** **** **** **** **** **** +18558 Shadowsmith_VoiceOfShadow_Fall **** **** **** **** **** **** **** **** +18559 Shadowsmith_VoiceOfShadow_Flee **** **** **** **** **** **** **** **** +18560 Shadowsmith_VoiceOfShadow_Halt **** **** **** **** **** **** **** **** +18561 Shadowsmith_BlackFire **** **** **** **** **** **** **** **** +18562 Shadowsmith_CongressShadows **** **** **** **** **** **** **** **** +18563 Shadowsmith_FleshFails_RadialMaster **** **** **** **** **** **** **** **** +18564 Shadowsmith_FleshFails_Str **** **** **** **** **** **** **** **** +18565 Shadowsmith_FleshFails_Dex **** **** **** **** **** **** **** **** +18566 Shadowsmith_FleshFails_Con **** **** **** **** **** **** **** **** +18567 Shadowsmith_PiercingSight **** **** **** **** **** **** **** **** +18568 Shadowsmith_ShadowSkin **** **** **** **** **** **** **** **** +18569 Shadowsmith_SightEclipsed **** **** **** **** **** **** **** **** +18570 Shadowsmith_ThoughtsShadow_RadialMaster **** **** **** **** **** **** **** **** +18571 Shadowsmith_ThoughtsShadow_Int **** **** **** **** **** **** **** **** +18572 Shadowsmith_ThoughtsShadow_Wis **** **** **** **** **** **** **** **** +18573 Shadowsmith_ThoughtsShadow_Cha **** **** **** **** **** **** **** **** +18574 TouchOfShadow **** **** **** **** **** **** **** **** +18575 ShroudOfShadow **** **** **** **** **** **** **** **** +18576 ShadowCraft **** **** **** **** **** **** **** **** +18577 ArmorOfShadow **** **** **** **** **** **** **** **** +18578 WidenShroud **** **** **** **** **** **** **** **** +18579 **Web_Enhancement** **** **** **** **** **** **** **** **** +18580 QuickerThanTheEye **** **** **** **** **** **** **** **** +18581 TrailOfHaze **** **** **** **** **** **** **** **** +18582 UmbralFist **** **** **** **** **** **** **** **** +18583 FearfulGloom **** **** **** **** **** **** **** **** +18584 SickeningShadows **** **** **** **** **** **** **** **** +18585 DeadlyShade_Absorb **** **** **** **** **** **** **** **** +18586 DeadlyShade_Deal **** **** **** **** **** **** **** **** +18587 GraspingShadows **** **** **** **** **** **** **** **** +18588 MenagerieOfDarkness **** **** **** **** **** **** **** **** +18589 BlackLabyrinth **** **** **** **** **** **** **** **** +18590 **** **** **** **** **** **** **** **** **** +18591 Shadowcaster_QuickerThanTheEye **** **** **** **** **** **** **** **** +18592 Shadowcaster_TrailOfHaze **** **** **** **** **** **** **** **** +18593 Shadowcaster_UmbralFist **** **** **** **** **** **** **** **** +18594 Shadowcaster_FearfulGloom **** **** **** **** **** **** **** **** +18595 Shadowcaster_SickeningShadows **** **** **** **** **** **** **** **** +18596 Shadowcaster_DeadlyShade_RadialMaster **** **** **** **** **** **** **** **** +18597 Shadowcaster_DeadlyShade_Absorb **** **** **** **** **** **** **** **** +18598 Shadowcaster_DeadlyShade_Deal **** **** **** **** **** **** **** **** +18599 Shadowcaster_GraspingShadows **** **** **** **** **** **** **** **** +18600 Shadowcaster_MenagerieOfDarkness **** **** **** **** **** **** **** **** +18601 Shadowcaster_BlackLabyrinth **** **** **** **** **** **** **** **** +18602 Shadowsmith_QuickerThanTheEye **** **** **** **** **** **** **** **** +18603 Shadowsmith_TrailOfHaze **** **** **** **** **** **** **** **** +18604 **** **** **** **** **** **** **** **** **** +18605 UmbralFist_RadialMaster **** **** **** **** **** **** **** **** +18606 UmbralFist_BullRush **** **** **** **** **** **** **** **** +18607 UmbralFist_Disarm **** **** **** **** **** **** **** **** +18608 UmbralFist_Trip **** **** **** **** **** **** **** **** +18609 **** **** **** **** **** **** **** **** **** +18610 **** **** **** **** **** **** **** **** **** +18611 **** **** **** **** **** **** **** **** **** +18612 **** **** **** **** **** **** **** **** **** +18613 **** **** **** **** **** **** **** **** **** +18614 **** **** **** **** **** **** **** **** **** +18615 **** **** **** **** **** **** **** **** **** +18616 **** **** **** **** **** **** **** **** **** +18617 **** **** **** **** **** **** **** **** **** +18618 **** **** **** **** **** **** **** **** **** +18619 **** **** **** **** **** **** **** **** **** +18620 **** **** **** **** **** **** **** **** **** +18621 **** **** **** **** **** **** **** **** **** +18622 **** **** **** **** **** **** **** **** **** +18623 **** **** **** **** **** **** **** **** **** +18624 **** **** **** **** **** **** **** **** **** +18625 **** **** **** **** **** **** **** **** **** +18626 **** **** **** **** **** **** **** **** **** +18627 **** **** **** **** **** **** **** **** **** +18628 **** **** **** **** **** **** **** **** **** +18629 **** **** **** **** **** **** **** **** **** +18630 **** **** **** **** **** **** **** **** **** +18631 **** **** **** **** **** **** **** **** **** +18632 OpenSoulChakra **** **** **** **** **** **** **** **** +18633 Meldshield_Invest **** **** **** **** **** **** **** **** +18634 Meldshield **** **** **** **** **** **** **** **** +18635 DispellingOrb_Invest **** **** **** **** **** **** **** **** +18636 DispellingOrb **** **** **** **** **** **** **** **** +18637 MageShackles_Invest **** **** **** **** **** **** **** **** +18638 MageShackles **** **** **** **** **** **** **** **** +18639 Abrogation_Invest **** **** **** **** **** **** **** **** +18640 Abrogation **** **** **** **** **** **** **** **** +18641 SpiritFlay_Invest **** **** **** **** **** **** **** **** +18642 SpiritFlay **** **** **** **** **** **** **** **** +18643 Integument_Invest **** **** **** **** **** **** **** **** +18644 Integument **** **** **** **** **** **** **** **** +18645 Blademeld_Rebind **** **** **** **** **** **** **** **** +18646 Blademeld_Throat_Shout **** **** **** **** **** **** **** **** +18647 BladeMeld_Crown **** **** **** **** **** **** **** **** +18648 BladeMeld_Feet **** **** **** **** **** **** **** **** +18649 BladeMeld_Hands **** **** **** **** **** **** **** **** +18650 BladeMeld_Arms **** **** **** **** **** **** **** **** +18651 BladeMeld_Brow **** **** **** **** **** **** **** **** +18652 BladeMeld_Shoulders **** **** **** **** **** **** **** **** +18653 BladeMeld_Throat **** **** **** **** **** **** **** **** +18654 BladeMeld_Waist **** **** **** **** **** **** **** **** +18655 BladeMeld_Heart **** **** **** **** **** **** **** **** +18656 BladeMeld_Soul **** **** **** **** **** **** **** **** +18657 Necrocarnate_Harvest **** **** **** **** **** **** **** **** +18658 Necrocarnate_Soulshield **** **** **** **** **** **** **** **** +18659 Incandescent_Aura_Yes_Its_Blank **** **** **** **** **** **** **** **** +18660 Incandescent_Transcendence **** **** **** **** **** **** **** **** +18661 Incandescent_Aura_Invest **** **** **** **** **** **** **** **** +18662 Incandescent_Ray_Invest **** **** **** **** **** **** **** **** +18663 Incandescent_Ray **** **** **** **** **** **** **** **** +18664 Incandescent_Overload **** **** **** **** **** **** **** **** +18665 Incandescent_Countenance_Invest **** **** **** **** **** **** **** **** +18666 Incandescent_Countenance **** **** **** **** **** **** **** **** +18667 Incandescent_Heal_Invest **** **** **** **** **** **** **** **** +18668 Incandescent_Heal **** **** **** **** **** **** **** **** +18669 Incandescent_Strike_Invest **** **** **** **** **** **** **** **** +18670 Incandescent_Strike **** **** **** **** **** **** **** **** +18671 PRC_Attack **** **** **** **** **** **** **** **** +18672 Umbral_KissShadows_Invest **** **** **** **** **** **** **** **** +18673 Umbral_KissShadows **** **** **** **** **** **** **** **** +18674 Umbral_Soulchilling_Invest **** **** **** **** **** **** **** **** +18675 Umbral_Soulchilling **** **** **** **** **** **** **** **** +18676 Umbral_SightEyeless_Invest **** **** **** **** **** **** **** **** +18677 Umbral_SightEyeless **** **** **** **** **** **** **** **** +18678 Umbral_EmbraceShadow_Invest **** **** **** **** **** **** **** **** +18679 Umbral_EmbraceShadow **** **** **** **** **** **** **** **** +18680 Umbral_StepBodiless_Invest **** **** **** **** **** **** **** **** +18681 Umbral_StepBodiless **** **** **** **** **** **** **** **** +18682 Ironsoul_WeaponBond_Invest **** **** **** **** **** **** **** **** +18683 Ironsoul_WeaponBond **** **** **** **** **** **** **** **** +18684 Ironsoul_ArmorBond_Invest **** **** **** **** **** **** **** **** +18685 Ironsoul_ArmorBond **** **** **** **** **** **** **** **** +18686 Ironsoul_ShieldBond_Invest **** **** **** **** **** **** **** **** +18687 Ironsoul_ShieldBond **** **** **** **** **** **** **** **** +18688 Soulcaster_Distill **** **** **** **** **** **** **** **** +18689 SapphireHierarch_Smite **** **** **** **** **** **** **** **** +18690 Spinemeld_SpineEnhancement_Invest **** **** **** **** **** **** **** **** +18691 Spinemeld_SpineEnhancement **** **** **** **** **** **** **** **** +18692 Totemist_ReshapeTotemSoulmeld **** **** **** **** **** **** **** **** +18693 Totemist_TotemEmbodiment **** **** **** **** **** **** **** **** +18694 Soulborn_ShareDefence **** **** **** **** **** **** **** **** +18695 Soulborn_Smite **** **** **** **** **** **** **** **** +18696 Incarnate_PerfectMeldshaper **** **** **** **** **** **** **** **** +18697 Incarnate_RapidMeldshaping **** **** **** **** **** **** **** **** +18698 Incarnate_IncarnumRadiance **** **** **** **** **** **** **** **** +18699 Incarnate_DetectOpposition **** **** **** **** **** **** **** **** +18700 **INCARNUM** **** **** **** **** **** **** **** **** +18701 AcrobatBoots **** **** **** **** **** **** **** **** +18702 AdamantPauldrons **** **** **** **** **** **** **** **** +18703 CrystalHelm **** **** **** **** **** **** **** **** +18704 AnkhegBreastplate **** **** **** **** **** **** **** **** +18705 ApparitionRibbon **** **** **** **** **** **** **** **** +18706 ArcaneFocus **** **** **** **** **** **** **** **** +18707 ArmguardsofDisruption **** **** **** **** **** **** **** **** +18708 BasiliskMask **** **** **** **** **** **** **** **** +18709 BeastTamerCirclet **** **** **** **** **** **** **** **** +18710 BehirGorget **** **** **** **** **** **** **** **** +18711 BlinkShirt **** **** **** **** **** **** **** **** +18712 Bloodtalons **** **** **** **** **** **** **** **** +18713 BloodwarGauntlets **** **** **** **** **** **** **** **** +18714 BluesteelBracers **** **** **** **** **** **** **** **** +18715 BrassMane **** **** **** **** **** **** **** **** +18716 CeruleanSandals **** **** **** **** **** **** **** **** +18717 DiademofPurelight **** **** **** **** **** **** **** **** +18718 DisenchanterMask **** **** **** **** **** **** **** **** +18719 DisplacerMantle **** **** **** **** **** **** **** **** +18720 DissolvingSpittle **** **** **** **** **** **** **** **** +18721 DreadCarapace **** **** **** **** **** **** **** **** +18722 EnigmaHelm **** **** **** **** **** **** **** **** +18723 FearsomeMask **** **** **** **** **** **** **** **** +18724 FellmistRobe **** **** **** **** **** **** **** **** +18725 FlameCincture **** **** **** **** **** **** **** **** +18726 FrostHelm **** **** **** **** **** **** **** **** +18727 GirallonArms **** **** **** **** **** **** **** **** +18728 GlovesofthePoisonedSoul **** **** **** **** **** **** **** **** +18729 GorgonMask **** **** **** **** **** **** **** **** +18730 GreatRaptorMask **** **** **** **** **** **** **** **** +18731 HeartofFire **** **** **** **** **** **** **** **** +18732 HuntersCirclet **** **** **** **** **** **** **** **** +18733 IllusionVeil **** **** **** **** **** **** **** **** +18734 ImpulseBoots **** **** **** **** **** **** **** **** +18735 IncarnateAvatar **** **** **** **** **** **** **** **** +18736 IncarnateWeapon **** **** **** **** **** **** **** **** +18737 KeeneyeLenses **** **** **** **** **** **** **** **** +18738 KrakenMantle **** **** **** **** **** **** **** **** +18739 KrensharMask **** **** **** **** **** **** **** **** +18740 KruthikClaws **** **** **** **** **** **** **** **** +18741 LamiaBelt **** **** **** **** **** **** **** **** +18742 LammasuMantle **** **** **** **** **** **** **** **** +18743 LandsharkBoots **** **** **** **** **** **** **** **** +18744 LifebondVestments **** **** **** **** **** **** **** **** +18745 LightningGauntlets **** **** **** **** **** **** **** **** +18746 LuckyDice **** **** **** **** **** **** **** **** +18747 MagesSpectacles **** **** **** **** **** **** **** **** +18748 ManticoreBelt **** **** **** **** **** **** **** **** +18749 MantleofFlame **** **** **** **** **** **** **** **** +18750 MaulingGauntlets **** **** **** **** **** **** **** **** +18751 NecrocarnumCirclet **** **** **** **** **** **** **** **** +18752 NecrocarnumMantle **** **** **** **** **** **** **** **** +18753 NecrocarnumShroud **** **** **** **** **** **** **** **** +18754 NecrocarnumTouch **** **** **** **** **** **** **** **** +18755 NecrocarnumVestments **** **** **** **** **** **** **** **** +18756 NecrocarnumWeapon **** **** **** **** **** **** **** **** +18757 PauldronsofHealth **** **** **** **** **** **** **** **** +18758 PegasusCloak **** **** **** **** **** **** **** **** +18759 PhaseCloak **** **** **** **** **** **** **** **** +18760 PhoenixBelt **** **** **** **** **** **** **** **** +18761 PlanarChasuble **** **** **** **** **** **** **** **** +18762 PlanarWard **** **** **** **** **** **** **** **** +18763 Rageclaws **** **** **** **** **** **** **** **** +18764 RidingBracers **** **** **** **** **** **** **** **** +18765 SailorsBracers **** **** **** **** **** **** **** **** +18766 ShadowMantle **** **** **** **** **** **** **** **** +18767 SheduCrown **** **** **** **** **** **** **** **** +18768 SightingGloves **** **** **** **** **** **** **** **** +18769 SilvertongueMask **** **** **** **** **** **** **** **** +18770 SoulsparkFamiliar **** **** **** **** **** **** **** **** +18771 SoulspeakerCirclet **** **** **** **** **** **** **** **** +18772 SpellwardShirt **** **** **** **** **** **** **** **** +18773 SphinxClaws **** **** **** **** **** **** **** **** +18774 StrongheartVest **** **** **** **** **** **** **** **** +18775 TheftGloves **** **** **** **** **** **** **** **** +18776 TherapeuticMantle **** **** **** **** **** **** **** **** +18777 ThreefoldMaskoftheChimera **** **** **** **** **** **** **** **** +18778 ThunderstepBoots **** **** **** **** **** **** **** **** +18779 TotemAvatar **** **** **** **** **** **** **** **** +18780 TruthseekerGoggles **** **** **** **** **** **** **** **** +18781 UnicornHorn **** **** **** **** **** **** **** **** +18782 UrskanGreaves **** **** **** **** **** **** **** **** +18783 VitalityBelt **** **** **** **** **** **** **** **** +18784 WindCloak **** **** **** **** **** **** **** **** +18785 WinterMask **** **** **** **** **** **** **** **** +18786 WorgPelt **** **** **** **** **** **** **** **** +18787 WormtailBelt **** **** **** **** **** **** **** **** +18788 YrthakMask **** **** **** **** **** **** **** **** +18789 AstralVambraces **** **** **** **** **** **** **** **** +18790 CharmingVeil **** **** **** **** **** **** **** **** +18791 PsionsEyes **** **** **** **** **** **** **** **** +18792 PsionKillerMask **** **** **** **** **** **** **** **** +18793 PsychicFocus **** **** **** **** **** **** **** **** +18794 ClawsOfTheWyrm **** **** **** **** **** **** **** **** +18795 DragonMantle **** **** **** **** **** **** **** **** +18796 DragonTail **** **** **** **** **** **** **** **** +18797 DragonfireMask **** **** **** **** **** **** **** **** +18798 ElderSpirit **** **** **** **** **** **** **** **** +18799 **** **** **** **** **** **** **** **** **** +18800 AcrobatBoots **** **** **** **** **** **** **** **** +18801 AdamantPauldrons **** **** **** **** **** **** **** **** +18802 CrystalHelm **** **** **** **** **** **** **** **** +18803 AnkhegBreastplate **** **** **** **** **** **** **** **** +18804 ApparitionRibbon **** **** **** **** **** **** **** **** +18805 ArcaneFocus **** **** **** **** **** **** **** **** +18806 ArmguardsofDisruption **** **** **** **** **** **** **** **** +18807 BasiliskMask **** **** **** **** **** **** **** **** +18808 BeastTamerCirclet **** **** **** **** **** **** **** **** +18809 BehirGorget **** **** **** **** **** **** **** **** +18810 BlinkShirt **** **** **** **** **** **** **** **** +18811 Bloodtalons **** **** **** **** **** **** **** **** +18812 BloodwarGauntlets **** **** **** **** **** **** **** **** +18813 BluesteelBracers **** **** **** **** **** **** **** **** +18814 BrassMane **** **** **** **** **** **** **** **** +18815 CeruleanSandals **** **** **** **** **** **** **** **** +18816 DiademofPurelight **** **** **** **** **** **** **** **** +18817 DisenchanterMask **** **** **** **** **** **** **** **** +18818 DisplacerMantle **** **** **** **** **** **** **** **** +18819 DissolvingSpittle **** **** **** **** **** **** **** **** +18820 DreadCarapace **** **** **** **** **** **** **** **** +18821 EnigmaHelm **** **** **** **** **** **** **** **** +18822 FearsomeMask **** **** **** **** **** **** **** **** +18823 FellmistRobe **** **** **** **** **** **** **** **** +18824 FlameCincture **** **** **** **** **** **** **** **** +18825 FrostHelm **** **** **** **** **** **** **** **** +18826 GirallonArms **** **** **** **** **** **** **** **** +18827 GlovesofthePoisonedSoul **** **** **** **** **** **** **** **** +18828 GorgonMask **** **** **** **** **** **** **** **** +18829 GreatRaptorMask **** **** **** **** **** **** **** **** +18830 HeartofFire **** **** **** **** **** **** **** **** +18831 HuntersCirclet **** **** **** **** **** **** **** **** +18832 IllusionVeil **** **** **** **** **** **** **** **** +18833 ImpulseBoots **** **** **** **** **** **** **** **** +18834 IncarnateAvatar **** **** **** **** **** **** **** **** +18835 IncarnateWeapon **** **** **** **** **** **** **** **** +18836 KeeneyeLenses **** **** **** **** **** **** **** **** +18837 KrakenMantle **** **** **** **** **** **** **** **** +18838 KrensharMask **** **** **** **** **** **** **** **** +18839 KruthikClaws **** **** **** **** **** **** **** **** +18840 LamiaBelt **** **** **** **** **** **** **** **** +18841 LammasuMantle **** **** **** **** **** **** **** **** +18842 LandsharkBoots **** **** **** **** **** **** **** **** +18843 LifebondVestments **** **** **** **** **** **** **** **** +18844 LightningGauntlets **** **** **** **** **** **** **** **** +18845 LuckyDice **** **** **** **** **** **** **** **** +18846 MagesSpectacles **** **** **** **** **** **** **** **** +18847 ManticoreBelt **** **** **** **** **** **** **** **** +18848 MantleofFlame **** **** **** **** **** **** **** **** +18849 MaulingGauntlets **** **** **** **** **** **** **** **** +18850 NecrocarnumCirclet **** **** **** **** **** **** **** **** +18851 NecrocarnumMantle **** **** **** **** **** **** **** **** +18852 NecrocarnumShroud **** **** **** **** **** **** **** **** +18853 NecrocarnumTouch **** **** **** **** **** **** **** **** +18854 NecrocarnumVestments **** **** **** **** **** **** **** **** +18855 NecrocarnumWeapon **** **** **** **** **** **** **** **** +18856 PauldronsofHealth **** **** **** **** **** **** **** **** +18857 PegasusCloak **** **** **** **** **** **** **** **** +18858 PhaseCloak **** **** **** **** **** **** **** **** +18859 PhoenixBelt **** **** **** **** **** **** **** **** +18860 PlanarChasuble **** **** **** **** **** **** **** **** +18861 PlanarWard **** **** **** **** **** **** **** **** +18862 Rageclaws **** **** **** **** **** **** **** **** +18863 RidingBracers **** **** **** **** **** **** **** **** +18864 SailorsBracers **** **** **** **** **** **** **** **** +18865 ShadowMantle **** **** **** **** **** **** **** **** +18866 SheduCrown **** **** **** **** **** **** **** **** +18867 SightingGloves **** **** **** **** **** **** **** **** +18868 SilvertongueMask **** **** **** **** **** **** **** **** +18869 SoulsparkFamiliar **** **** **** **** **** **** **** **** +18870 SoulspeakerCirclet **** **** **** **** **** **** **** **** +18871 SpellwardShirt **** **** **** **** **** **** **** **** +18872 SphinxClaws **** **** **** **** **** **** **** **** +18873 StrongheartVest **** **** **** **** **** **** **** **** +18874 TheftGloves **** **** **** **** **** **** **** **** +18875 TherapeuticMantle **** **** **** **** **** **** **** **** +18876 ThreefoldMaskoftheChimera **** **** **** **** **** **** **** **** +18877 ThunderstepBoots **** **** **** **** **** **** **** **** +18878 TotemAvatar **** **** **** **** **** **** **** **** +18879 TruthseekerGoggles **** **** **** **** **** **** **** **** +18880 UnicornHorn **** **** **** **** **** **** **** **** +18881 UrskanGreaves **** **** **** **** **** **** **** **** +18882 VitalityBelt **** **** **** **** **** **** **** **** +18883 WindCloak **** **** **** **** **** **** **** **** +18884 WinterMask **** **** **** **** **** **** **** **** +18885 WorgPelt **** **** **** **** **** **** **** **** +18886 WormtailBelt **** **** **** **** **** **** **** **** +18887 YrthakMask **** **** **** **** **** **** **** **** +18888 AstralVambraces **** **** **** **** **** **** **** **** +18889 CharmingVeil **** **** **** **** **** **** **** **** +18890 PsionsEyes **** **** **** **** **** **** **** **** +18891 PsionKillerMask **** **** **** **** **** **** **** **** +18892 PsychicFocus **** **** **** **** **** **** **** **** +18893 ClawsOfTheWyrm **** **** **** **** **** **** **** **** +18894 DragonMantle **** **** **** **** **** **** **** **** +18895 DragonTail **** **** **** **** **** **** **** **** +18896 DragonfireMask **** **** **** **** **** **** **** **** +18897 ElderSpirit **** **** **** **** **** **** **** **** +18898 **** **** **** **** **** **** **** **** **** +18899 **** **** **** **** **** **** **** **** **** +18900 InvestEssentiaConversation **** **** **** **** **** **** **** **** +18901 AnkhegBreastplateThroatBind **** **** **** **** **** **** **** **** +18902 ApparitionRibbonThroatBind **** **** **** **** **** **** **** **** +18903 ArmguardsDisruptionArmsBind **** **** **** **** **** **** **** **** +18904 BasiliskMaskTotemBind **** **** **** **** **** **** **** **** +18905 BeastTamerCircletCrownBind **** **** **** **** **** **** **** **** +18906 BeastTamerCircletTotemBind **** **** **** **** **** **** **** **** +18907 BehirGorgetThroatBind **** **** **** **** **** **** **** **** +18908 BlinkShirtDimensionDoor_St **** **** **** **** **** **** **** **** +18909 BlinkShirtHeartBind **** **** **** **** **** **** **** **** +18910 BlinkShirtDimensionDoor_Mv **** **** **** **** **** **** **** **** +18911 BloodwarGauntletsArmBind **** **** **** **** **** **** **** **** +18912 BrassManeThroatBind **** **** **** **** **** **** **** **** +18913 CeruleanSandalsFeetBind **** **** **** **** **** **** **** **** +18914 DisenchanterMaskDetectMagic **** **** **** **** **** **** **** **** +18915 DisenchanterMaskTotemBind **** **** **** **** **** **** **** **** +18916 DisplacerMantleTotemBind **** **** **** **** **** **** **** **** +18917 DissolvingSpittleSpitAcid **** **** **** **** **** **** **** **** +18918 DreadCarapaceFootBind **** **** **** **** **** **** **** **** +18919 FlameCinctureWaistBind **** **** **** **** **** **** **** **** +18920 FrostHelmCrownBind **** **** **** **** **** **** **** **** +18921 FrostHelmTotemBind **** **** **** **** **** **** **** **** +18922 GlovesOfThePoisonedHandAbilityDamage **** **** **** **** **** **** **** **** +18923 GorgonMaskThroatBind **** **** **** **** **** **** **** **** +18924 GorgonMaskTotemBind **** **** **** **** **** **** **** **** +18925 IncarnateWeaponArmsBind **** **** **** **** **** **** **** **** +18926 KrensharMaskTotemBind **** **** **** **** **** **** **** **** +18927 LammasuMantleTotemBind **** **** **** **** **** **** **** **** +18928 LandsharkBootsFeetBind **** **** **** **** **** **** **** **** +18929 LandsharkBootsTotemBind **** **** **** **** **** **** **** **** +18930 LifebondVestmentsHeal **** **** **** **** **** **** **** **** +18931 LifebondVestmentsArmsBind **** **** **** **** **** **** **** **** +18932 LightningGauntletsZap **** **** **** **** **** **** **** **** +18933 LightningGauntletsHandsBind **** **** **** **** **** **** **** **** +18934 LuckyDice_RadialMaster **** **** **** **** **** **** **** **** +18935 LuckyDice_AttackDamage **** **** **** **** **** **** **** **** +18936 LuckyDice_SavingThrows **** **** **** **** **** **** **** **** +18937 LuckyDice_SkillAbilities **** **** **** **** **** **** **** **** +18938 MagesSpectaclesBrowBind **** **** **** **** **** **** **** **** +18939 ManticoreBeltTotemBind **** **** **** **** **** **** **** **** +18940 MantleOfFlameShouldersBind **** **** **** **** **** **** **** **** +18941 PhoenixBeltTotemBind **** **** **** **** **** **** **** **** +18942 PlanarChasubleSoulBind **** **** **** **** **** **** **** **** +18943 ShadowMantleShouldersBind **** **** **** **** **** **** **** **** +18944 SheduCrownHeartBind **** **** **** **** **** **** **** **** +18945 SilvertongueMaskThroatBind **** **** **** **** **** **** **** **** +18946 UnicornHornBrowBind **** **** **** **** **** **** **** **** +18947 WinterMaskColdTouch **** **** **** **** **** **** **** **** +18948 WinterMaskThroatBind **** **** **** **** **** **** **** **** +18949 WormtailBeltTotemBind **** **** **** **** **** **** **** **** +18950 YrthakMaskBrowBind **** **** **** **** **** **** **** **** +18951 YrthakMaskTotemBind **** **** **** **** **** **** **** **** +18952 NecrocarnumCircletCrownBind **** **** **** **** **** **** **** **** +18953 NecrocarnumShroudSoulBind **** **** **** **** **** **** **** **** +18954 NecrocarnumTouchEssentia **** **** **** **** **** **** **** **** +18955 NecrocarnumTouchArmsBind **** **** **** **** **** **** **** **** +18956 SoulsparkFamiliar_Attack **** **** **** **** **** **** **** **** +18957 SoulsparkFamiliar_Essentia **** **** **** **** **** **** **** **** +18958 PsionsEyesBrowBind **** **** **** **** **** **** **** **** +18959 PsionKillerMaskDetectMagic **** **** **** **** **** **** **** **** +18960 PsionKillerMaskTotemBind **** **** **** **** **** **** **** **** +18961 DragonTailSlam **** **** **** **** **** **** **** **** +18962 DragonTailTotemBind **** **** **** **** **** **** **** **** +18963 DragonfireMaskThroatBind **** **** **** **** **** **** **** **** +18964 DragonfireMaskTotemBind **** **** **** **** **** **** **** **** +18965 **** **** **** **** **** **** **** **** **** +18966 **** **** **** **** **** **** **** **** **** +18967 **** **** **** **** **** **** **** **** **** +18968 **** **** **** **** **** **** **** **** **** +18969 **** **** **** **** **** **** **** **** **** +18970 HealingSoul **** **** **** **** **** **** **** **** +18971 MidnightAugmentation **** **** **** **** **** **** **** **** +18972 PsycarnumBlade **** **** **** **** **** **** **** **** +18973 DusklingSpeed **** **** **** **** **** **** **** **** +18974 DivineSoultouch **** **** **** **** **** **** **** **** +18975 PsycarnumInfusion **** **** **** **** **** **** **** **** +18976 Epic_RapidMeldshaping **** **** **** **** **** **** **** **** +18977 Epic_RebindSoulmeld_Crown **** **** **** **** **** **** **** **** +18978 Epic_RebindSoulmeld_Feet **** **** **** **** **** **** **** **** +18979 Epic_RebindSoulmeld_Hands **** **** **** **** **** **** **** **** +18980 Epic_RebindSoulmeld_Arms **** **** **** **** **** **** **** **** +18981 Epic_RebindSoulmeld_Brow **** **** **** **** **** **** **** **** +18982 Epic_RebindSoulmeld_Shoulders **** **** **** **** **** **** **** **** +18983 Epic_RebindSoulmeld_Throat **** **** **** **** **** **** **** **** +18984 Epic_RebindSoulmeld_Waist **** **** **** **** **** **** **** **** +18985 Epic_RebindSoulmeld_Heart **** **** **** **** **** **** **** **** +18986 Epic_RebindSoulmeld_Soul **** **** **** **** **** **** **** **** +18987 Epic_RebindSoulmeld_Totem **** **** **** **** **** **** **** **** +18988 **** **** **** **** **** **** **** **** **** +18989 **** **** **** **** **** **** **** **** **** +18990 **** **** **** **** **** **** **** **** **** +18991 **** **** **** **** **** **** **** **** **** +18992 **** **** **** **** **** **** **** **** **** +18993 **** **** **** **** **** **** **** **** **** +18994 **** **** **** **** **** **** **** **** **** +18995 **** **** **** **** **** **** **** **** **** +18996 **** **** **** **** **** **** **** **** **** +18997 **** **** **** **** **** **** **** **** **** +18998 **** **** **** **** **** **** **** **** **** +18999 **** **** **** **** **** **** **** **** **** +19000 ####END_OF_SHADOW_MAGIC_RESERVE **** **** **** **** **** **** **** **** +19001 Spell_Rage **** **** **** **** **** **** **** **** +19002 Warrior_Cry **** **** **** **** **** **** **** **** +19003 Spell_Fury **** **** **** **** **** **** **** **** +19004 DK_Tactics **** **** **** **** **** **** **** **** +19005 DK_Puissance **** **** **** **** **** **** **** **** +19006 DK_Foe **** **** **** **** **** **** **** **** +19007 DK_DreadSecret **** **** **** **** **** **** **** **** +19008 DK_Foreknowledge **** **** **** **** **** **** **** **** +19009 Archivist_LearnSpell **** **** **** **** **** **** **** **** +19010 Witch_LearnSpell **** **** **** **** **** **** **** **** +19011 ArkamoiStrengthFromMagic **** **** **** **** **** **** **** **** +19012 LashemoiLesserStrengthFromPain **** **** **** **** **** **** **** **** +19013 TurlemoiStrengthFromPain **** **** **** **** **** **** **** **** +19014 HadrimoiSpeedFromPain **** **** **** **** **** **** **** **** +19015 GlouraUnearthlyGrace **** **** **** **** **** **** **** **** +19016 **** **** **** **** **** **** **** **** **** +19017 **** **** **** **** **** **** **** **** **** +19018 **** **** **** **** **** **** **** **** **** +19019 ####START_OF_BINDING **** **** **** **** **** **** **** **** +19020 Amon **** **** **** **** **** **** **** **** +19021 Aym **** **** **** **** **** **** **** **** +19022 Leraje **** **** **** **** **** **** **** **** +19023 Naberius **** **** **** **** **** **** **** **** +19024 Ronove **** **** **** **** **** **** **** **** +19025 DahlverNar **** **** **** **** **** **** **** **** +19026 Haagenti **** **** **** **** **** **** **** **** +19027 Malphas **** **** **** **** **** **** **** **** +19028 Savnok **** **** **** **** **** **** **** **** +19029 Andromalius **** **** **** **** **** **** **** **** +19030 Focalor **** **** **** **** **** **** **** **** +19031 Karsus **** **** **** **** **** **** **** **** +19032 Paimon **** **** **** **** **** **** **** **** +19033 Agares **** **** **** **** **** **** **** **** +19034 Andras **** **** **** **** **** **** **** **** +19035 Buer **** **** **** **** **** **** **** **** +19036 Eurynome **** **** **** **** **** **** **** **** +19037 Tenebrous **** **** **** **** **** **** **** **** +19038 Arete **** **** **** **** **** **** **** **** +19039 Astaroth **** **** **** **** **** **** **** **** +19040 Acererak **** **** **** **** **** **** **** **** +19041 Balam **** **** **** **** **** **** **** **** +19042 Dantalion **** **** **** **** **** **** **** **** +19043 Geryon **** **** **** **** **** **** **** **** +19044 Otiax **** **** **** **** **** **** **** **** +19045 Chupoclops **** **** **** **** **** **** **** **** +19046 Haures **** **** **** **** **** **** **** **** +19047 Ipos **** **** **** **** **** **** **** **** +19048 Shax **** **** **** **** **** **** **** **** +19049 Zagan **** **** **** **** **** **** **** **** +19050 Vanus **** **** **** **** **** **** **** **** +19051 TheTriad **** **** **** **** **** **** **** **** +19052 Desharis **** **** **** **** **** **** **** **** +19053 Zceryll **** **** **** **** **** **** **** **** +19054 Eligor **** **** **** **** **** **** **** **** +19055 Marchosias **** **** **** **** **** **** **** **** +19056 Ashardalon **** **** **** **** **** **** **** **** +19057 Halphax **** **** **** **** **** **** **** **** +19058 Orthos **** **** **** **** **** **** **** **** +19059 Abysm **** **** **** **** **** **** **** **** +19060 **** **** **** **** **** **** **** **** **** +19061 **** **** **** **** **** **** **** **** **** +19062 **** **** **** **** **** **** **** **** **** +19063 **** **** **** **** **** **** **** **** **** +19064 **** **** **** **** **** **** **** **** **** +19065 **** **** **** **** **** **** **** **** **** +19066 **** **** **** **** **** **** **** **** **** +19067 **** **** **** **** **** **** **** **** **** +19068 **** **** **** **** **** **** **** **** **** +19069 **** **** **** **** **** **** **** **** **** +19070 AmonFireBreath **** **** **** **** **** **** **** **** +19071 AymHaloOfFire **** **** **** **** **** **** **** **** +19072 LerajeRicochet **** **** **** **** **** **** **** **** +19073 NaberiusDisguise_Self_Radial_Master **** **** **** **** **** **** **** **** +19074 NaberiusDisguise_Self_Learn **** **** **** **** **** **** **** **** +19075 NaberiusDisguise_Self_Options **** **** **** **** **** **** **** **** +19076 NaberiusDisguise_Self_QS1 **** **** **** **** **** **** **** **** +19077 NaberiusDisguise_Self_QS2 **** **** **** **** **** **** **** **** +19078 NaberiusDisguise_Self_QS3 **** **** **** **** **** **** **** **** +19079 NaberiusCommand_RadialMaster **** **** **** **** **** **** **** **** +19080 NaberiusCommand_Approach **** **** **** **** **** **** **** **** +19081 NaberiusCommand_Drop **** **** **** **** **** **** **** **** +19082 NaberiusCommand_Fall **** **** **** **** **** **** **** **** +19083 NaberiusCommand_Flee **** **** **** **** **** **** **** **** +19084 NaberiusCommand_Halt **** **** **** **** **** **** **** **** +19085 RonoveFar_Hand **** **** **** **** **** **** **** **** +19086 RonoveBullrush **** **** **** **** **** **** **** **** +19087 DahlverNarMaddeningMoan **** **** **** **** **** **** **** **** +19088 DahlverNarSharePainForced **** **** **** **** **** **** **** **** +19089 HaagentiConfusingTouch **** **** **** **** **** **** **** **** +19090 MalphasArcaneEye **** **** **** **** **** **** **** **** +19091 MalphasInvisibility **** **** **** **** **** **** **** **** +19092 SavnokCallArmor **** **** **** **** **** **** **** **** +19093 SavnokMoveAlly **** **** **** **** **** **** **** **** +19094 AndromaliusTashas_Hideous_Laughter **** **** **** **** **** **** **** **** +19095 AndromaliusLocateObject **** **** **** **** **** **** **** **** +19096 AndromaliusSee_Invisibility **** **** **** **** **** **** **** **** +19097 FocalorAuraSadness **** **** **** **** **** **** **** **** +19098 FocalorLightningStrike **** **** **** **** **** **** **** **** +19099 FocalorBreath **** **** **** **** **** **** **** **** +19100 KarsusSenses **** **** **** **** **** **** **** **** +19101 KarsusTouch **** **** **** **** **** **** **** **** +19102 PaimonDanceOfDeath **** **** **** **** **** **** **** **** +19103 AgaresEarthshakingStep **** **** **** **** **** **** **** **** +19104 AgaresElementalCompanion **** **** **** **** **** **** **** **** +19105 AndrasSmite **** **** **** **** **** **** **** **** +19106 AndrasSowDiscord **** **** **** **** **** **** **** **** +19107 AndrasMount **** **** **** **** **** **** **** **** +19108 BuerHealingGift **** **** **** **** **** **** **** **** +19109 TenebrousDeeperDarkness **** **** **** **** **** **** **** **** +19110 TenebrousTouchVoid **** **** **** **** **** **** **** **** +19111 TenebrousTurnUndead **** **** **** **** **** **** **** **** +19112 TenebrousFlicker **** **** **** **** **** **** **** **** +19113 AcererakDetectUndead **** **** **** **** **** **** **** **** +19114 AcererakHideUndead **** **** **** **** **** **** **** **** +19115 AcererakParalyze **** **** **** **** **** **** **** **** +19116 BalamCunning **** **** **** **** **** **** **** **** +19117 BalamGlare **** **** **** **** **** **** **** **** +19118 DantalionAwe **** **** **** **** **** **** **** **** +19119 DantalionReadThoughts **** **** **** **** **** **** **** **** +19120 DantalionThoughtTravel **** **** **** **** **** **** **** **** +19121 GeryonAcidicGlare **** **** **** **** **** **** **** **** +19122 GeryonSwiftFlight **** **** **** **** **** **** **** **** +19123 OtiaxAirBlast **** **** **** **** **** **** **** **** +19124 OtiaxOpen **** **** **** **** **** **** **** **** +19125 OtiaxUnlock **** **** **** **** **** **** **** **** +19126 AreteResistance **** **** **** **** **** **** **** **** +19127 AstarothsBreath **** **** **** **** **** **** **** **** +19128 AstarothWord **** **** **** **** **** **** **** **** +19129 ChupoclopsAuraDespair **** **** **** **** **** **** **** **** +19130 ChupoclopsEthereal **** **** **** **** **** **** **** **** +19131 HauresMajorImage **** **** **** **** **** **** **** **** +19132 HauresPhantasmalKiller **** **** **** **** **** **** **** **** +19133 IposFlashInsight **** **** **** **** **** **** **** **** +19134 ShaxFreedomMovement **** **** **** **** **** **** **** **** +19135 ShaxStormStrike **** **** **** **** **** **** **** **** +19136 ZaganAversion **** **** **** **** **** **** **** **** +19137 VanusFreeAlly **** **** **** **** **** **** **** **** +19138 TheTriadSmite **** **** **** **** **** **** **** **** +19139 DesharisTeleport **** **** **** **** **** **** **** **** +19140 DesharisSmite **** **** **** **** **** **** **** **** +19141 DesharisAnimate **** **** **** **** **** **** **** **** +19142 ZceryllBoltsMadness **** **** **** **** **** **** **** **** +19143 ZceryllSummonAlien **** **** **** **** **** **** **** **** +19144 ZceryllTrueStrike **** **** **** **** **** **** **** **** +19145 EligorChromaticStrike_Radial_Master **** **** **** **** **** **** **** **** +19146 EligorChromaticStrike_Acid **** **** **** **** **** **** **** **** +19147 EligorChromaticStrike_Cold **** **** **** **** **** **** **** **** +19148 EligorChromaticStrike_Elec **** **** **** **** **** **** **** **** +19149 EligorChromaticStrike_Fire **** **** **** **** **** **** **** **** +19150 MarchosiasSmoke **** **** **** **** **** **** **** **** +19151 AshardalonFear **** **** **** **** **** **** **** **** +19152 AshardalonLocate **** **** **** **** **** **** **** **** +19153 HalphaxImprison **** **** **** **** **** **** **** **** +19154 HalphaxBarrier **** **** **** **** **** **** **** **** +19155 HalphaxMansion **** **** **** **** **** **** **** **** +19156 OrthosBreath **** **** **** **** **** **** **** **** +19157 **** **** **** **** **** **** **** **** **** +19158 **** **** **** **** **** **** **** **** **** +19159 **** **** **** **** **** **** **** **** **** +19160 **** **** **** **** **** **** **** **** **** +19161 **** **** **** **** **** **** **** **** **** +19162 **** **** **** **** **** **** **** **** **** +19163 **** **** **** **** **** **** **** **** **** +19164 **** **** **** **** **** **** **** **** **** +19165 **** **** **** **** **** **** **** **** **** +19166 **** **** **** **** **** **** **** **** **** +19167 **** **** **** **** **** **** **** **** **** +19168 **** **** **** **** **** **** **** **** **** +19169 **** **** **** **** **** **** **** **** **** +19170 BindVestige **** **** **** **** **** **** **** **** +19171 PactAugment **** **** **** **** **** **** **** **** +19172 ExpelVestige **** **** **** **** **** **** **** **** +19173 AnimaMageExploitVestige **** **** **** **** **** **** **** **** +19174 AnimaMageVestigeMetamagic **** **** **** **** **** **** **** **** +19175 AnimaMageVestigeCasting **** **** **** **** **** **** **** **** +19176 TenebrousRebuke **** **** **** **** **** **** **** **** +19177 TenebrousDestroyEmpowerUndead **** **** **** **** **** **** **** **** +19178 TenebrousUmbralBody **** **** **** **** **** **** **** **** +19179 TenebrousBlastVoid **** **** **** **** **** **** **** **** +19180 KnightOfTheSacredSealVestigesProtection **** **** **** **** **** **** **** **** +19181 KnightOfTheSacredSealVestigesPower **** **** **** **** **** **** **** **** +19182 KnightOfTheSacredSealVestigesSurge **** **** **** **** **** **** **** **** +19183 DantalionScholarship **** **** **** **** **** **** **** **** +19184 DantalionOverwhelmThoughts **** **** **** **** **** **** **** **** +19185 DantalionGlare **** **** **** **** **** **** **** **** +19186 **** **** **** **** **** **** **** **** **** +19187 **** **** **** **** **** **** **** **** **** +19188 **** **** **** **** **** **** **** **** **** +19189 **** **** **** **** **** **** **** **** **** +19190 **** **** **** **** **** **** **** **** **** +19191 **** **** **** **** **** **** **** **** **** +19192 **** **** **** **** **** **** **** **** **** +19193 **** **** **** **** **** **** **** **** **** +19194 **** **** **** **** **** **** **** **** **** +19195 **** **** **** **** **** **** **** **** **** +19196 **** **** **** **** **** **** **** **** **** +19197 **** **** **** **** **** **** **** **** **** +19198 **** **** **** **** **** **** **** **** **** +19199 **** **** **** **** **** **** **** **** **** +19200 **** **** **** **** **** **** **** **** **** +19201 **** **** **** **** **** **** **** **** **** +19202 **** **** **** **** **** **** **** **** **** +19203 **** **** **** **** **** **** **** **** **** +19204 **** **** **** **** **** **** **** **** **** +19205 **** **** **** **** **** **** **** **** **** +19206 **** **** **** **** **** **** **** **** **** +19207 **** **** **** **** **** **** **** **** **** +19208 **** **** **** **** **** **** **** **** **** +19209 **** **** **** **** **** **** **** **** **** +19210 **** **** **** **** **** **** **** **** **** +19211 **** **** **** **** **** **** **** **** **** +19212 **** **** **** **** **** **** **** **** **** +19213 **** **** **** **** **** **** **** **** **** +19214 **** **** **** **** **** **** **** **** **** +19215 **** **** **** **** **** **** **** **** **** +19216 **** **** **** **** **** **** **** **** **** +19217 **** **** **** **** **** **** **** **** **** +19218 **** **** **** **** **** **** **** **** **** +19219 **** **** **** **** **** **** **** **** **** +19220 **** **** **** **** **** **** **** **** **** +19221 **** **** **** **** **** **** **** **** **** +19222 **** **** **** **** **** **** **** **** **** +19223 **** **** **** **** **** **** **** **** **** +19224 **** **** **** **** **** **** **** **** **** +19225 **** **** **** **** **** **** **** **** **** +19226 **** **** **** **** **** **** **** **** **** +19227 **** **** **** **** **** **** **** **** **** +19228 **** **** **** **** **** **** **** **** **** +19229 **** **** **** **** **** **** **** **** **** +19230 **** **** **** **** **** **** **** **** **** +19231 **** **** **** **** **** **** **** **** **** +19232 **** **** **** **** **** **** **** **** **** +19233 **** **** **** **** **** **** **** **** **** +19234 **** **** **** **** **** **** **** **** **** +19235 **** **** **** **** **** **** **** **** **** +19236 **** **** **** **** **** **** **** **** **** +19237 **** **** **** **** **** **** **** **** **** +19238 **** **** **** **** **** **** **** **** **** +19239 **** **** **** **** **** **** **** **** **** +19240 **** **** **** **** **** **** **** **** **** +19241 **** **** **** **** **** **** **** **** **** +19242 **** **** **** **** **** **** **** **** **** +19243 **** **** **** **** **** **** **** **** **** +19244 **** **** **** **** **** **** **** **** **** +19245 **** **** **** **** **** **** **** **** **** +19246 **** **** **** **** **** **** **** **** **** +19247 **** **** **** **** **** **** **** **** **** +19248 **** **** **** **** **** **** **** **** **** +19249 **** **** **** **** **** **** **** **** **** +19250 **** **** **** **** **** **** **** **** **** +19251 **** **** **** **** **** **** **** **** **** +19252 **** **** **** **** **** **** **** **** **** +19253 **** **** **** **** **** **** **** **** **** +19254 **** **** **** **** **** **** **** **** **** +19255 **** **** **** **** **** **** **** **** **** +19256 **** **** **** **** **** **** **** **** **** +19257 **** **** **** **** **** **** **** **** **** +19258 **** **** **** **** **** **** **** **** **** +19259 **** **** **** **** **** **** **** **** **** +19260 **** **** **** **** **** **** **** **** **** +19261 **** **** **** **** **** **** **** **** **** +19262 **** **** **** **** **** **** **** **** **** +19263 **** **** **** **** **** **** **** **** **** +19264 **** **** **** **** **** **** **** **** **** +19265 **** **** **** **** **** **** **** **** **** +19266 **** **** **** **** **** **** **** **** **** +19267 **** **** **** **** **** **** **** **** **** +19268 **** **** **** **** **** **** **** **** **** +19269 **** **** **** **** **** **** **** **** **** +19270 **** **** **** **** **** **** **** **** **** +19271 **** **** **** **** **** **** **** **** **** +19272 **** **** **** **** **** **** **** **** **** +19273 **** **** **** **** **** **** **** **** **** +19274 **** **** **** **** **** **** **** **** **** +19275 **** **** **** **** **** **** **** **** **** +19276 **** **** **** **** **** **** **** **** **** +19277 Arcane_Boost_Attack_Bonus **** **** **** **** **** **** **** **** +19278 Arcane_Boost_Armor_Bones **** **** **** **** **** **** **** **** +19279 Arcane_Boost_Damage_Bonus **** **** **** **** **** **** **** **** +19280 Arcane_Boost_Elemental_Resistance **** **** **** **** **** **** **** **** +19281 Arcane_Boost_Save_Bonus **** **** **** **** **** **** **** **** +19282 DragonShaman_Fire_Cone **** **** **** **** **** **** **** **** +19283 DragonShaman_Frost_Cone **** **** **** **** **** **** **** **** +19284 DragonShaman_Electric_Cone **** **** **** **** **** **** **** **** +19285 DragonShaman_Acid_Cone **** **** **** **** **** **** **** **** +19286 Jade_Phoenix_SpellSelect **** **** **** **** **** **** **** **** +19287 Jade_Phoenix_SpellSelect_Convo **** **** **** **** **** **** **** **** +19288 Jade_Phoenix_SpellSelect_Quick1 **** **** **** **** **** **** **** **** +19289 Jade_Phoenix_SpellSelect_Quick2 **** **** **** **** **** **** **** **** +19290 Jade_Phoenix_SpellSelect_Quick3 **** **** **** **** **** **** **** **** +19291 Jade_Phoenix_SpellSelect_Quick4 **** **** **** **** **** **** **** **** +19292 Jade_Phoenix_ArcaneWrath **** **** **** **** **** **** **** **** +19293 Jade_Phoenix_RiteOfWaking **** **** **** **** **** **** **** **** +19294 **** **** **** **** **** **** **** **** **** +19295 **** **** **** **** **** **** **** **** **** +19296 Jade_Phoenix_MysticPhoenixStance **** **** **** **** **** **** **** **** +19297 Jade_Phoenix_MysticPhoenixStance_Unaugmented **** **** **** **** **** **** **** **** +19298 Jade_Phoenix_MysticPhoenixStance_Augmented **** **** **** **** **** **** **** **** +19299 Jade_Phoenix_EmpoweringStrike **** **** **** **** **** **** **** **** +19300 Jade_Phoenix_FirebirdStance **** **** **** **** **** **** **** **** +19301 Jade_Phoenix_FirebirdStance_Unaugmented **** **** **** **** **** **** **** **** +19302 Jade_Phoenix_FirebirdStance_Augmented **** **** **** **** **** **** **** **** +19303 Eternal_Blade_Blade_Guide_Dummy **** **** **** **** **** **** **** **** +19304 Jade_Phoenix_QuickeningStrike **** **** **** **** **** **** **** **** +19305 Jade_Phoenix_EmeraldImmolation **** **** **** **** **** **** **** **** +19306 MasterOfNineDualStance **** **** **** **** **** **** **** **** +19307 Eternal_Blade_Maneuver_Quickselects **** **** **** **** **** **** **** **** +19308 Eternal_Blade_Maneuver_Quickselects_Convo **** **** **** **** **** **** **** **** +19309 Eternal_Blade_Maneuver_Quickselects_Quick1 **** **** **** **** **** **** **** **** +19310 Eternal_Blade_Maneuver_Quickselects_Quick2 **** **** **** **** **** **** **** **** +19311 Eternal_Blade_Maneuver_Quickselects_Quick3 **** **** **** **** **** **** **** **** +19312 Eternal_Blade_Maneuver_Quickselects_Quick4 **** **** **** **** **** **** **** **** +19313 Eternal_Blade_Eternal_Training **** **** **** **** **** **** **** **** +19314 Eternal_Blade_Eternal_Training_Maneuver **** **** **** **** **** **** **** **** +19315 Eternal_Blade_Eternal_Training_Racial_Type **** **** **** **** **** **** **** **** +19316 Eternal_Blade_Guided_Strike **** **** **** **** **** **** **** **** +19317 Eternal_Blade_Defensive_Insight **** **** **** **** **** **** **** **** +19318 Eternal_Blade_Tactical_Insight **** **** **** **** **** **** **** **** +19319 Eternal_Blade_Island_In_Time **** **** **** **** **** **** **** **** +19320 ShadowSunNinjaTouchOfTheShadowSun **** **** **** **** **** **** **** **** +19321 ShadowSunNinjaFlameOfTheShadowSun **** **** **** **** **** **** **** **** +19322 ShadowSunNinjaFlameOfTheShadowSunAttack **** **** **** **** **** **** **** **** +19323 ShadowSunNinjaLightWithinDarkness **** **** **** **** **** **** **** **** +19324 ShadowSunNinjaDarknessWithinLight **** **** **** **** **** **** **** **** +19325 ShadowSunNinjaVoidOfTheShadowSun **** **** **** **** **** **** **** **** +19326 ShadowSunNinjaVoidOfTheShadowSunAttack **** **** **** **** **** **** **** **** +19327 ShadowSunNinjaChildOfShadowAnddLight **** **** **** **** **** **** **** **** +19328 ShadowSunNinjaBalanceOfLightAndDark **** **** **** **** **** **** **** **** +19329 ShadowSunNinjaBalanceOfLightAndDarkAttack **** **** **** **** **** **** **** **** +19330 RethDekala_VilefireBlast **** **** **** **** **** **** **** **** +19331 RethDekala_MartialSpirit **** **** **** **** **** **** **** **** +19332 RethDekala_ThicketOfBlades **** **** **** **** **** **** **** **** +19333 RethDekala_DauntingStrike **** **** **** **** **** **** **** **** +19334 RethDekala_DeathFromAbove **** **** **** **** **** **** **** **** +19335 RethDekala_DisarmingStrike **** **** **** **** **** **** **** **** +19336 RethDekala_EntanglingBlade **** **** **** **** **** **** **** **** +19337 RethDekala_WallOfBlades **** **** **** **** **** **** **** **** +19338 RethDekala_RecoverManeuver **** **** **** **** **** **** **** **** +19339 **** **** **** **** **** **** **** **** **** +19340 Shadow_Conjuration_Conversation **** **** **** **** **** **** **** **** +19341 PNP_SHADES **** **** **** **** **** **** **** **** +19342 PNP_SHADES_QS1 **** **** **** **** **** **** **** **** +19343 PNP_SHADES_QS2 **** **** **** **** **** **** **** **** +19344 PNP_SHADES_QS3 **** **** **** **** **** **** **** **** +19345 PNP_SHADES_QS4 **** **** **** **** **** **** **** **** +19346 PNP_SHADES_QS5 **** **** **** **** **** **** **** **** +19347 PNP_SHADOW_CONJURATION **** **** **** **** **** **** **** **** +19348 PNP_SHADOW_CONJURATION_QS1 **** **** **** **** **** **** **** **** +19349 PNP_SHADOW_CONJURATION_QS2 **** **** **** **** **** **** **** **** +19350 PNP_SHADOW_CONJURATION_QS3 **** **** **** **** **** **** **** **** +19351 PNP_SHADOW_CONJURATION_QS4 **** **** **** **** **** **** **** **** +19352 PNP_SHADOW_CONJURATION_QS5 **** **** **** **** **** **** **** **** +19353 PNP_GREATER_SHADOW_CONJURATION **** **** **** **** **** **** **** **** +19354 PNP_GREATER_SHADOW_CONJURATION_QS1 **** **** **** **** **** **** **** **** +19355 PNP_GREATER_SHADOW_CONJURATION_QS2 **** **** **** **** **** **** **** **** +19356 PNP_GREATER_SHADOW_CONJURATION_QS3 **** **** **** **** **** **** **** **** +19357 PNP_GREATER_SHADOW_CONJURATION_QS4 **** **** **** **** **** **** **** **** +19358 PNP_GREATER_SHADOW_CONJURATION_QS5 **** **** **** **** **** **** **** **** +19359 SPELL_MYSTIC_BACKLASH **** **** **** **** **** **** **** **** +19360 SPELL_ACIDIC_SPLATTER **** **** **** **** **** **** **** **** +19361 SPELL_FIERY_BURST **** **** **** **** **** **** **** **** +19362 SPELL_STORM_BOLT **** **** **** **** **** **** **** **** +19363 SPELL_WINTERS_BLAST **** **** **** **** **** **** **** **** +19364 SPELL_CLAP_OF_THUNDER **** **** **** **** **** **** **** **** +19365 SPELL_SICKENING_GRASP **** **** **** **** **** **** **** **** +19366 SPELL_TOUCH_OF_HEALING **** **** **** **** **** **** **** **** +19367 SPELL_DIMENSIONAL_JAUNT **** **** **** **** **** **** **** **** +19368 SPELL_CLUTCH_OF_EARTH **** **** **** **** **** **** **** **** +19369 SPELL_BORNE_ALOFT **** **** **** **** **** **** **** **** +19370 SPELL_PROTECTIVE_WARD **** **** **** **** **** **** **** **** +19371 SPELL_SHADOW_VEIL **** **** **** **** **** **** **** **** +19372 SPELL_SUNLIGHT_EYES **** **** **** **** **** **** **** **** +19373 SPELL_TOUCH_OF_DISTRACTION **** **** **** **** **** **** **** **** +19374 SPELL_UMBRAL_SHROUD **** **** **** **** **** **** **** **** +19375 SPELL_CHARNEL_MIASMA **** **** **** **** **** **** **** **** +19376 SPELL_DROWNING_GLANCE **** **** **** **** **** **** **** **** +19377 SPELL_INVISIBLE_NEEDLE **** **** **** **** **** **** **** **** +19378 SUMMON_ELEMENTAL_MASTER **** **** **** **** **** **** **** **** +19379 SPELL_SUMMON_ELEMENTAL_AIR **** **** **** **** **** **** **** **** +19380 SPELL_SUMMON_ELEMENTAL_EARTH **** **** **** **** **** **** **** **** +19381 SPELL_SUMMON_ELEMENTAL_FIRE **** **** **** **** **** **** **** **** +19382 SPELL_SUMMON_ELEMENTAL_WATER **** **** **** **** **** **** **** **** +19383 SPELL_DIMENSIONAL_REACH **** **** **** **** **** **** **** **** +19384 SPELL_HURRICANE_BREATH **** **** **** **** **** **** **** **** +19385 MINOR_SHAPESHIFT_MASTER **** **** **** **** **** **** **** **** +19386 SPELL_MINOR_SHAPESHIFT_MIGHT **** **** **** **** **** **** **** **** +19387 SPELL_MINOR_SHAPESHIFT_MOBILITY **** **** **** **** **** **** **** **** +19388 SPELL_MINOR_SHAPESHIFT_SAVAGERY **** **** **** **** **** **** **** **** +19389 SPELL_MINOR_SHAPESHIFT_SPEED **** **** **** **** **** **** **** **** +19390 SPELL_MINOR_SHAPESHIFT_VIGOR **** **** **** **** **** **** **** **** +19391 FACECHANGER_MASTER **** **** **** **** **** **** **** **** +19392 Disguise_Self_Learn **** **** **** **** **** **** **** **** +19393 SPELL_FACECHANGER_OPTIONS **** **** **** **** **** **** **** **** +19394 SPELL_FACECHANGER_QS1 **** **** **** **** **** **** **** **** +19395 SPELL_FACECHANGER_QS2 **** **** **** **** **** **** **** **** +19396 SPELL_FACECHANGER_QS3 **** **** **** **** **** **** **** **** diff --git a/src/hakpak/peps_prc8/tga/armor_pallet.tga b/src/hakpak/peps_prc8/tga/armor_pallet.tga new file mode 100644 index 0000000..7fae6b2 Binary files /dev/null and b/src/hakpak/peps_prc8/tga/armor_pallet.tga differ diff --git a/src/hakpak/peps_prc8/tga/gui_pal_tattoo.tga b/src/hakpak/peps_prc8/tga/gui_pal_tattoo.tga new file mode 100644 index 0000000..c8e2a27 Binary files /dev/null and b/src/hakpak/peps_prc8/tga/gui_pal_tattoo.tga differ diff --git a/src/prc8/include/bnd_inc_bndfunc.nss b/src/include/bnd_inc_bndfunc.nss similarity index 100% rename from src/prc8/include/bnd_inc_bndfunc.nss rename to src/include/bnd_inc_bndfunc.nss diff --git a/src/prc8/include/bnd_vestig_const.nss b/src/include/bnd_vestig_const.nss similarity index 100% rename from src/prc8/include/bnd_vestig_const.nss rename to src/include/bnd_vestig_const.nss diff --git a/src/prc8/include/inc_2dacache.nss b/src/include/inc_2dacache.nss similarity index 100% rename from src/prc8/include/inc_2dacache.nss rename to src/include/inc_2dacache.nss diff --git a/src/prc8/include/inc_abil_damage.nss b/src/include/inc_abil_damage.nss similarity index 100% rename from src/prc8/include/inc_abil_damage.nss rename to src/include/inc_abil_damage.nss diff --git a/src/prc8/include/inc_acp.nss b/src/include/inc_acp.nss similarity index 100% rename from src/prc8/include/inc_acp.nss rename to src/include/inc_acp.nss diff --git a/src/prc8/include/inc_addragebonus.nss b/src/include/inc_addragebonus.nss similarity index 100% rename from src/prc8/include/inc_addragebonus.nss rename to src/include/inc_addragebonus.nss diff --git a/src/prc8/include/inc_area.nss b/src/include/inc_area.nss similarity index 100% rename from src/prc8/include/inc_area.nss rename to src/include/inc_area.nss diff --git a/src/prc8/include/inc_array_sort.nss b/src/include/inc_array_sort.nss similarity index 100% rename from src/prc8/include/inc_array_sort.nss rename to src/include/inc_array_sort.nss diff --git a/src/prc8/include/inc_cache_setup.nss b/src/include/inc_cache_setup.nss similarity index 100% rename from src/prc8/include/inc_cache_setup.nss rename to src/include/inc_cache_setup.nss diff --git a/src/prc8/include/inc_debug.nss b/src/include/inc_debug.nss similarity index 100% rename from src/prc8/include/inc_debug.nss rename to src/include/inc_debug.nss diff --git a/src/prc8/include/inc_dispel.nss b/src/include/inc_dispel.nss similarity index 100% rename from src/prc8/include/inc_dispel.nss rename to src/include/inc_dispel.nss diff --git a/src/prc8/include/inc_draw.nss b/src/include/inc_draw.nss similarity index 100% rename from src/prc8/include/inc_draw.nss rename to src/include/inc_draw.nss diff --git a/src/prc8/include/inc_draw_prc.nss b/src/include/inc_draw_prc.nss similarity index 100% rename from src/prc8/include/inc_draw_prc.nss rename to src/include/inc_draw_prc.nss diff --git a/src/prc8/include/inc_draw_text.nss b/src/include/inc_draw_text.nss similarity index 100% rename from src/prc8/include/inc_draw_text.nss rename to src/include/inc_draw_text.nss diff --git a/src/prc8/include/inc_draw_tools.nss b/src/include/inc_draw_tools.nss similarity index 100% rename from src/prc8/include/inc_draw_tools.nss rename to src/include/inc_draw_tools.nss diff --git a/src/prc8/include/inc_dynconv.nss b/src/include/inc_dynconv.nss similarity index 100% rename from src/prc8/include/inc_dynconv.nss rename to src/include/inc_dynconv.nss diff --git a/src/prc8/include/inc_ecl.nss b/src/include/inc_ecl.nss similarity index 100% rename from src/prc8/include/inc_ecl.nss rename to src/include/inc_ecl.nss diff --git a/src/prc8/include/inc_epicspellai.nss b/src/include/inc_epicspellai.nss similarity index 100% rename from src/prc8/include/inc_epicspellai.nss rename to src/include/inc_epicspellai.nss diff --git a/src/prc8/include/inc_epicspelldef.nss b/src/include/inc_epicspelldef.nss similarity index 100% rename from src/prc8/include/inc_epicspelldef.nss rename to src/include/inc_epicspelldef.nss diff --git a/src/prc8/include/inc_epicspellfnc.nss b/src/include/inc_epicspellfnc.nss similarity index 99% rename from src/prc8/include/inc_epicspellfnc.nss rename to src/include/inc_epicspellfnc.nss index 59f4dd6..7fb6054 100644 --- a/src/prc8/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/prc8/include/inc_epicspells.nss b/src/include/inc_epicspells.nss similarity index 100% rename from src/prc8/include/inc_epicspells.nss rename to src/include/inc_epicspells.nss diff --git a/src/prc8/include/inc_eventhook.nss b/src/include/inc_eventhook.nss similarity index 100% rename from src/prc8/include/inc_eventhook.nss rename to src/include/inc_eventhook.nss diff --git a/src/prc8/include/inc_heap.nss b/src/include/inc_heap.nss similarity index 100% rename from src/prc8/include/inc_heap.nss rename to src/include/inc_heap.nss diff --git a/src/prc8/include/inc_item_props.nss b/src/include/inc_item_props.nss similarity index 100% rename from src/prc8/include/inc_item_props.nss rename to src/include/inc_item_props.nss diff --git a/src/prc8/include/inc_logmessage.nss b/src/include/inc_logmessage.nss similarity index 100% rename from src/prc8/include/inc_logmessage.nss rename to src/include/inc_logmessage.nss diff --git a/src/prc8/include/inc_lookups.nss b/src/include/inc_lookups.nss similarity index 99% rename from src/prc8/include/inc_lookups.nss rename to src/include/inc_lookups.nss index e5a5124..cc97622 100644 --- a/src/prc8/include/inc_lookups.nss +++ b/src/include/inc_lookups.nss @@ -242,7 +242,7 @@ 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 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; diff --git a/src/prc8/include/inc_metalocation.nss b/src/include/inc_metalocation.nss similarity index 100% rename from src/prc8/include/inc_metalocation.nss rename to src/include/inc_metalocation.nss diff --git a/src/prc8/include/inc_newspellbook.nss b/src/include/inc_newspellbook.nss similarity index 99% rename from src/prc8/include/inc_newspellbook.nss rename to src/include/inc_newspellbook.nss index 909b93d..1cdc8a2 100644 --- a/src/prc8/include/inc_newspellbook.nss +++ b/src/include/inc_newspellbook.nss @@ -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: diff --git a/src/prc8/include/inc_npc.nss b/src/include/inc_npc.nss similarity index 100% rename from src/prc8/include/inc_npc.nss rename to src/include/inc_npc.nss diff --git a/src/prc8/include/inc_nwnx_funcs.nss b/src/include/inc_nwnx_funcs.nss similarity index 100% rename from src/prc8/include/inc_nwnx_funcs.nss rename to src/include/inc_nwnx_funcs.nss diff --git a/src/prc8/include/inc_pers_array.nss b/src/include/inc_pers_array.nss similarity index 100% rename from src/prc8/include/inc_pers_array.nss rename to src/include/inc_pers_array.nss diff --git a/src/prc8/include/inc_persist_loca.nss b/src/include/inc_persist_loca.nss similarity index 100% rename from src/prc8/include/inc_persist_loca.nss rename to src/include/inc_persist_loca.nss diff --git a/src/prc8/include/inc_persistsql.nss b/src/include/inc_persistsql.nss similarity index 100% rename from src/prc8/include/inc_persistsql.nss rename to src/include/inc_persistsql.nss diff --git a/src/prc8/include/inc_poison.nss b/src/include/inc_poison.nss similarity index 100% rename from src/prc8/include/inc_poison.nss rename to src/include/inc_poison.nss diff --git a/src/prc8/include/inc_prc_npc.nss b/src/include/inc_prc_npc.nss similarity index 100% rename from src/prc8/include/inc_prc_npc.nss rename to src/include/inc_prc_npc.nss diff --git a/src/prc8/include/inc_prc_poly.nss b/src/include/inc_prc_poly.nss similarity index 100% rename from src/prc8/include/inc_prc_poly.nss rename to src/include/inc_prc_poly.nss diff --git a/src/prc8/include/inc_rand_equip.nss b/src/include/inc_rand_equip.nss similarity index 100% rename from src/prc8/include/inc_rand_equip.nss rename to src/include/inc_rand_equip.nss diff --git a/src/prc8/include/inc_ravage.nss b/src/include/inc_ravage.nss similarity index 100% rename from src/prc8/include/inc_ravage.nss rename to src/include/inc_ravage.nss diff --git a/src/prc8/include/inc_rend.nss b/src/include/inc_rend.nss similarity index 100% rename from src/prc8/include/inc_rend.nss rename to src/include/inc_rend.nss diff --git a/src/prc8/include/inc_sbr_readme.nss b/src/include/inc_sbr_readme.nss similarity index 100% rename from src/prc8/include/inc_sbr_readme.nss rename to src/include/inc_sbr_readme.nss diff --git a/src/prc8/include/inc_set.nss b/src/include/inc_set.nss similarity index 100% rename from src/prc8/include/inc_set.nss rename to src/include/inc_set.nss diff --git a/src/prc8/include/inc_sp_gain_mem.nss b/src/include/inc_sp_gain_mem.nss similarity index 100% rename from src/prc8/include/inc_sp_gain_mem.nss rename to src/include/inc_sp_gain_mem.nss diff --git a/src/prc8/include/inc_spirit_weapn.nss b/src/include/inc_spirit_weapn.nss similarity index 100% rename from src/prc8/include/inc_spirit_weapn.nss rename to src/include/inc_spirit_weapn.nss diff --git a/src/prc8/include/inc_sql.nss b/src/include/inc_sql.nss similarity index 100% rename from src/prc8/include/inc_sql.nss rename to src/include/inc_sql.nss diff --git a/src/prc8/include/inc_switch_setup.nss b/src/include/inc_switch_setup.nss similarity index 99% rename from src/prc8/include/inc_switch_setup.nss rename to src/include/inc_switch_setup.nss index afffaae..e8384a2 100644 --- a/src/prc8/include/inc_switch_setup.nss +++ b/src/include/inc_switch_setup.nss @@ -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,11 +1069,11 @@ 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_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); diff --git a/src/prc8/include/inc_target_list.nss b/src/include/inc_target_list.nss similarity index 100% rename from src/prc8/include/inc_target_list.nss rename to src/include/inc_target_list.nss diff --git a/src/prc8/include/inc_threads.nss b/src/include/inc_threads.nss similarity index 100% rename from src/prc8/include/inc_threads.nss rename to src/include/inc_threads.nss diff --git a/src/prc8/include/inc_time.nss b/src/include/inc_time.nss similarity index 100% rename from src/prc8/include/inc_time.nss rename to src/include/inc_time.nss diff --git a/src/prc8/include/inc_timestop.nss b/src/include/inc_timestop.nss similarity index 100% rename from src/prc8/include/inc_timestop.nss rename to src/include/inc_timestop.nss diff --git a/src/prc8/include/inc_uniqueid.nss b/src/include/inc_uniqueid.nss similarity index 100% rename from src/prc8/include/inc_uniqueid.nss rename to src/include/inc_uniqueid.nss diff --git a/src/prc8/include/inc_utility.nss b/src/include/inc_utility.nss similarity index 100% rename from src/prc8/include/inc_utility.nss rename to src/include/inc_utility.nss diff --git a/src/prc8/include/inc_vfx_const.nss b/src/include/inc_vfx_const.nss similarity index 100% rename from src/prc8/include/inc_vfx_const.nss rename to src/include/inc_vfx_const.nss diff --git a/src/prc8/include/inv_inc_blast.nss b/src/include/inv_inc_blast.nss similarity index 100% rename from src/prc8/include/inv_inc_blast.nss rename to src/include/inv_inc_blast.nss diff --git a/src/prc8/include/inv_inc_invfunc.nss b/src/include/inv_inc_invfunc.nss similarity index 100% rename from src/prc8/include/inv_inc_invfunc.nss rename to src/include/inv_inc_invfunc.nss diff --git a/src/prc8/include/inv_inc_invknown.nss b/src/include/inv_inc_invknown.nss similarity index 100% rename from src/prc8/include/inv_inc_invknown.nss rename to src/include/inv_inc_invknown.nss diff --git a/src/prc8/include/inv_inc_invoke.nss b/src/include/inv_inc_invoke.nss similarity index 100% rename from src/prc8/include/inv_inc_invoke.nss rename to src/include/inv_inc_invoke.nss diff --git a/src/prc8/include/inv_invoc_const.nss b/src/include/inv_invoc_const.nss similarity index 100% rename from src/prc8/include/inv_invoc_const.nss rename to src/include/inv_invoc_const.nss diff --git a/src/prc8/include/inv_invokehook.nss b/src/include/inv_invokehook.nss similarity index 100% rename from src/prc8/include/inv_invokehook.nss rename to src/include/inv_invokehook.nss diff --git a/src/prc8/include/lookup_2da_spell.nss b/src/include/lookup_2da_spell.nss similarity index 100% rename from src/prc8/include/lookup_2da_spell.nss rename to src/include/lookup_2da_spell.nss diff --git a/src/prc8/include/moi_inc_moifunc.nss b/src/include/moi_inc_moifunc.nss similarity index 100% rename from src/prc8/include/moi_inc_moifunc.nss rename to src/include/moi_inc_moifunc.nss diff --git a/src/prc8/include/moi_meld_const.nss b/src/include/moi_meld_const.nss similarity index 100% rename from src/prc8/include/moi_meld_const.nss rename to src/include/moi_meld_const.nss 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 new file mode 100644 index 0000000..a37f13f --- /dev/null +++ b/src/include/nw_inc_nui.nss @@ -0,0 +1,1199 @@ +const int NUI_DIRECTION_HORIZONTAL = 0; +const int NUI_DIRECTION_VERTICAL = 1; + +const int NUI_MOUSE_BUTTON_LEFT = 0; +const int NUI_MOUSE_BUTTON_MIDDLE = 1; +const int NUI_MOUSE_BUTTON_RIGHT = 2; + +const int NUI_SCROLLBARS_NONE = 0; +const int NUI_SCROLLBARS_X = 1; +const int NUI_SCROLLBARS_Y = 2; +const int NUI_SCROLLBARS_BOTH = 3; +const int NUI_SCROLLBARS_AUTO = 4; + +const int NUI_ASPECT_FIT = 0; +const int NUI_ASPECT_FILL = 1; +const int NUI_ASPECT_FIT100 = 2; +const int NUI_ASPECT_EXACT = 3; +const int NUI_ASPECT_EXACTSCALED = 4; +const int NUI_ASPECT_STRETCH = 5; + +const int NUI_HALIGN_CENTER = 0; +const int NUI_HALIGN_LEFT = 1; +const int NUI_HALIGN_RIGHT = 2; + +const int NUI_VALIGN_MIDDLE = 0; +const int NUI_VALIGN_TOP = 1; +const int NUI_VALIGN_BOTTOM = 2; + +// ----------------------- +// Style + +const float NUI_STYLE_PRIMARY_WIDTH = 150.0; +const float NUI_STYLE_PRIMARY_HEIGHT = 50.0; + +const float NUI_STYLE_SECONDARY_WIDTH = 150.0; +const float NUI_STYLE_SECONDARY_HEIGHT = 35.0; + +const float NUI_STYLE_TERTIARY_WIDTH = 100.0; +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 + +// Special cases: +// * 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. +// * 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 + +// Create a dynamic bind. Unlike static values, these can change at runtime: +// NuiBind("mybindlabel"); +// NuiSetBind(.., "mybindlabel", JsonString("hi")); +// To create static values, just use the json types directly: +// JsonString("hi"); +// +// 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 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); + +// ----------------------- +// Layout + +// A column will auto-space all elements inside of it and advise the parent +// about it's desired size. +// - 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. +// - 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. +// - 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. + +// - jElem: Element +// - fWidth: Float: Element width in pixels (strength=required). +json NuiWidth(json jElem, float fWidth); + +// - jElem: Element +// - fHeight: Float: Height in pixels (strength=required). +json NuiHeight(json jElem, float fHeight); + +// - 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 NuiMargin(json jElem, float fMargin); + +// Set padding on the widget. The margin is the spacing inside of the widget. +json NuiPadding(json jElem, float fPadding); + +// Disabled elements are non-interactive and greyed out. +// - jElem: Element +// - jEnabled: Bind:Bool +json NuiEnabled(json jElem, json jEnabler); + +// Invisible elements do not render at all, but still take up layout space. +// - jElem: Element +// - jVisible: Bind:Bool +json NuiVisible(json jElem, json jVisible); + +// Tooltips show on mouse hover. +// - jElem: Element +// - jTooltip: Bind:String +json NuiTooltip(json jElem, json jTooltip); + +// Tooltips for disabled elements show on mouse hover. +// - jElem: Element +// - jTooltip: Bind:String +json NuiDisabledTooltip(json jElem, json jTooltip); + +// Encouraged elements have a breathing animated glow inside of it. +// - jElem: Element +// - jEncouraged: Bind:Bool +json NuiEncouraged(json jElem, json jEncouraged); + +// ----------------------- +// Props & Style + +json NuiVec(float x, float y); + +json NuiRect(float x, float y, float w, float h); + +json NuiColor(int r, int g, int b, int a = 255); + +// 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. +// - 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 + +// 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 NuiSpacer(); + +// Create a label field. Labels are single-line stylable non-editable text fields. +// - 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. +// - 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. +// - jLabel: Bind:String +json NuiButton(json jLabel); + +// A clickable button with an image as the label. +// Sends "click" events on click. +// - 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. +// - jLabel: Bind:String +// - jValue: Bind:Bool +json NuiButtonSelect(json jLabel, json jValue); + +// A checkbox with a label to the right of it. +// - jLabel: Bind:String +// - jBool: Bind:Bool +json NuiCheck(json jLabel, json jBool); + +// A image, with no border or padding. +// - 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. 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 NuiImageRegion(json jImage, json jRegion); + +// A combobox/dropdown. +// - jElements: Bind:ComboEntry[] +// - jSelected: Bind:Int (index into jElements) +json NuiCombo(json jElements, json jSelected); + +json NuiComboEntry(string sLabel, int nValue); + +// A floating-point slider. A good step size for normal-sized sliders is 0.01. +// - 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. +// - 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. +// - jValue: Bind:Float (0.0->1.0 +json NuiProgress(json jValue); + +// A editable text field. +// - 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. +// All binds referenced in jTemplate should be arrays of rRowCount size; +// 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. +// 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); + +// - 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. +// - 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". +// - 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 +// value -1 means "nothing". +// - 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; + +// - 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. +// - jSlots: NuiChartSlot[] +json NuiChart( json jSlots); + +// ----------------------- +// Draw Lists + +// Draw lists are raw painting primitives on top of widgets. +// They are anchored to the widget x/y coordinates, and are always +// painted in order of definition, without culling. You cannot bind +// the draw_list itself, but most parameters on individual draw_list +// entries can be bound. + +const int NUI_DRAW_LIST_ITEM_TYPE_POLYLINE = 0; +const int NUI_DRAW_LIST_ITEM_TYPE_CURVE = 1; +const int NUI_DRAW_LIST_ITEM_TYPE_CIRCLE = 2; +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" +// a widget. + +const int NUI_DRAW_LIST_ITEM_ORDER_BEFORE = -1; +const int NUI_DRAW_LIST_ITEM_ORDER_AFTER = 1; + +// Always render draw list item (default). +const int NUI_DRAW_LIST_ITEM_RENDER_ALWAYS = 0; +// Only render when NOT hovering. +const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_OFF = 1; +// Only render when mouse is hovering. +const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_HOVER = 2; +// Only render while LMB is held down. +const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_LEFT = 3; +// Only render while RMB is held down. +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; + +// - 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); + +// - 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); + +// - 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); + +// - 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); + +// - 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); + +// - 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); + +// - jDrawListImage: DrawListItemImage +// - jRegion: Bind:NuiRect +json NuiDrawListImageRegion(json jDrawListImage, json jRegion); + +// - 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); + +// - 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 + +json +NuiWindow( + json jRoot, + json jTitle, + json jGeometry, + json jResizable, + json jCollapsed, + json jClosable, + json jTransparent, + json jBorder, + 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. + 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; +} + +json +NuiElement( + string sType, + json jLabel, + json jValue +) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "type", JsonString(sType)); + JsonObjectSetInplace(ret, "label", jLabel); + JsonObjectSetInplace(ret, "value", jValue); + return ret; +} + +json +NuiBind( + string sId, + int nNumberFlags = 0, + int nNumberPrecision = 0, + int nTextFlags = 0 +) +{ + 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 +NuiId( + json jElem, + string sId +) +{ + return JsonObjectSet(jElem, "id", JsonString(sId)); +} + +json +NuiStrRef( + int nStrRef +) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "strref", JsonInt(nStrRef)); + return ret; +} + +json +NuiCol( + json jList +) +{ + return JsonObjectSet(NuiElement("col", JsonNull(), JsonNull()), "children", jList); +} + +json +NuiRow( + json jList +) +{ + return JsonObjectSet(NuiElement("row", JsonNull(), JsonNull()), "children", jList); +} + +json +NuiGroup( + json jChild, + int bBorder = TRUE, + int nScroll = NUI_SCROLLBARS_AUTO +) +{ + json ret = NuiElement("group", JsonNull(), JsonNull()); + JsonObjectSetInplace(ret, "children", JsonArrayInsert(JsonArray(), jChild)); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); + return ret; +} + +json +NuiWidth(json jElem, float fWidth) +{ + return JsonObjectSet(jElem, "width", JsonFloat(fWidth)); +} + +json +NuiHeight(json jElem, float fHeight) +{ + return JsonObjectSet(jElem, "height", JsonFloat(fHeight)); +} + +json +NuiAspect(json jElem, float fAspect) +{ + return JsonObjectSet(jElem, "aspect", JsonFloat(fAspect)); +} + +json +NuiMargin( + json jElem, + float fMargin +) +{ + return JsonObjectSet(jElem, "margin", JsonFloat(fMargin)); +} + +json +NuiPadding( + json jElem, + float fPadding +) +{ + return JsonObjectSet(jElem, "padding", JsonFloat(fPadding)); +} + +json +NuiEnabled( + json jElem, + json jEnabler +) +{ + return JsonObjectSet(jElem, "enabled", jEnabler); +} + +json +NuiVisible( + json jElem, + json jVisible +) +{ + return JsonObjectSet(jElem, "visible", jVisible); +} + +json +NuiTooltip( + json jElem, + json jTooltip +) +{ + return JsonObjectSet(jElem, "tooltip", jTooltip); +} + +json +NuiDisabledTooltip( + json jElem, + json jTooltip +) +{ + return JsonObjectSet(jElem, "disabled_tooltip", jTooltip); +} + +json +NuiEncouraged( + json jElem, + json jEncouraged +) +{ + return JsonObjectSet(jElem, "encouraged", jEncouraged); +} + +json +NuiVec(float x, float y) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); + return ret; +} + +json +NuiRect(float x, float y, float w, float h) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "x", JsonFloat(x)); + JsonObjectSetInplace(ret, "y", JsonFloat(y)); + JsonObjectSetInplace(ret, "w", JsonFloat(w)); + JsonObjectSetInplace(ret, "h", JsonFloat(h)); + return ret; +} + +json +NuiColor(int r, int g, int b, int a = 255) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "r", JsonInt(r)); + JsonObjectSetInplace(ret, "g", JsonInt(g)); + JsonObjectSetInplace(ret, "b", JsonInt(b)); + JsonObjectSetInplace(ret, "a", JsonInt(a)); + return ret; +} + +json +NuiStyleForegroundColor( + json jElem, + json jColor +) +{ + return JsonObjectSet(jElem, "foreground_color", jColor); +} + +json +NuiStyleFont( + json jElem, + json jFont +) +{ + return JsonObjectSet(jElem, "font", jFont); +} + +json +NuiSpacer() +{ + return NuiElement("spacer", JsonNull(), JsonNull()); +} + +json +NuiLabel( + json jValue, + json jHAlign, + json jVAlign +) +{ + json ret = NuiElement("label", JsonNull(), jValue); + JsonObjectSetInplace(ret, "text_halign", jHAlign); + JsonObjectSetInplace(ret, "text_valign", jVAlign); + return ret; +} + +json +NuiText( + json jValue, + int bBorder = TRUE, + int nScroll = NUI_SCROLLBARS_AUTO +) +{ + json ret = NuiElement("text", JsonNull(), jValue); + JsonObjectSetInplace(ret, "border", JsonBool(bBorder)); + JsonObjectSetInplace(ret, "scrollbars", JsonInt(nScroll)); + return ret; +} + +json +NuiButton( + json jLabel +) +{ + return NuiElement("button", jLabel, JsonNull()); +} + +json +NuiButtonImage( + json jResRef +) +{ + return NuiElement("button_image", jResRef, JsonNull()); +} + +json +NuiButtonSelect( + json jLabel, + json jValue +) +{ + return NuiElement("button_select", jLabel, jValue); +} + +json +NuiCheck( + json jLabel, + json jBool +) +{ + return NuiElement("check", jLabel, jBool); +} + +json +NuiImage( + json jResRef, + json jAspect, + json jHAlign, + json jVAlign +) +{ + json img = NuiElement("image", JsonNull(), jResRef); + JsonObjectSetInplace(img, "image_aspect", jAspect); + JsonObjectSetInplace(img, "image_halign", jHAlign); + JsonObjectSetInplace(img, "image_valign", jVAlign); + return img; +} + +json +NuiImageRegion( + json jImage, + json jRegion +) +{ + return JsonObjectSet(jImage, "image_region", jRegion); +} + +json +NuiCombo( + json jElements, + json jSelected +) +{ + return JsonObjectSet(NuiElement("combo", JsonNull(), jSelected), "elements", jElements); +} + +json +NuiComboEntry( + string sLabel, + int nValue +) +{ + return JsonArrayInsert(JsonArrayInsert(JsonArray(), JsonString(sLabel)), JsonInt(nValue)); +} + +json +NuiSliderFloat( + json jValue, + json jMin, + json jMax, + json jStepSize +) +{ + json ret = NuiElement("sliderf", JsonNull(), jValue); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); + return ret; +} + +json +NuiSlider( + json jValue, + json jMin, + json jMax, + json jStepSize +) +{ + json ret = NuiElement("slider", JsonNull(), jValue); + JsonObjectSetInplace(ret, "min", jMin); + JsonObjectSetInplace(ret, "max", jMax); + JsonObjectSetInplace(ret, "step", jStepSize); + return ret; +} + +json +NuiProgress( + json jValue +) +{ + return NuiElement("progress", JsonNull(), jValue); +} + +json +NuiTextEdit( + json jPlaceholder, + json jValue, + int nMaxLength, + int bMultiline, + int bWordWrap = TRUE +) +{ + json ret = NuiElement("textedit", jPlaceholder, jValue); + JsonObjectSetInplace(ret, "max", JsonInt(nMaxLength)); + JsonObjectSetInplace(ret, "multiline", JsonBool(bMultiline)); + JsonObjectSetInplace(ret, "wordwrap", JsonBool(bWordWrap)); + return ret; +} + +json +NuiList( + json jTemplate, + json jRowCount, + float fRowHeight = NUI_STYLE_ROW_HEIGHT, + int bBorder = TRUE, + int nScroll = NUI_SCROLLBARS_Y +) +{ + json ret = NuiElement("list", JsonNull(), JsonNull()); + 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; +} + +json +NuiListTemplateCell( + json jElem, + float fWidth, + int bVariable +) +{ + json ret = JsonArray(); + JsonArrayInsertInplace(ret, jElem); + JsonArrayInsertInplace(ret, JsonFloat(fWidth)); + JsonArrayInsertInplace(ret, JsonBool(bVariable)); + return ret; +} + +json +NuiColorPicker( + json jColor +) +{ + json ret = NuiElement("color_picker", JsonNull(), jColor); + return ret; +} + +json +NuiOptions( + int nDirection, + json jElements, + json jValue +) +{ + json ret = NuiElement("options", JsonNull(), jValue); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); + return ret; +} + +json +NuiToggles( + int nDirection, + json jElements, + json jValue +) +{ + json ret = NuiElement("tabbar", JsonNull(), jValue); + JsonObjectSetInplace(ret, "direction", JsonInt(nDirection)); + JsonObjectSetInplace(ret, "elements", jElements); + return ret; +} + +json +NuiChartSlot( + int nType, + json jLegend, + json jColor, + json jData +) +{ + json ret = JsonObject(); + JsonObjectSetInplace(ret, "type", JsonInt(nType)); + JsonObjectSetInplace(ret, "legend", jLegend); + JsonObjectSetInplace(ret, "color", jColor); + JsonObjectSetInplace(ret, "data", jData); + return ret; +} + +json +NuiChart( + json jSlots +) +{ + json ret = NuiElement("chart", JsonNull(), jSlots); + return ret; +} + +json +NuiDrawListItem( + int nType, + json jEnabled, + json jColor, + json jFill, + json jLineThickness, + int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, + int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS, + int nBindArrays = FALSE +) +{ + json ret = JsonObject(); + 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; +} + +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 ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "points", jPoints); + return ret; +} + +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 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; +} + +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 ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender, nBindArrays); + JsonObjectSetInplace(ret, "rect", jRect); + return ret; +} + +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 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; +} + +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 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; +} + +json +NuiDrawListImage( + json jEnabled, + json jResRef, + json jRect, + 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 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; +} + +json +NuiDrawListImageRegion( + json jDrawListImage, + json jRegion +) +{ + return JsonObjectSet(jDrawListImage, "image_region", jRegion); +} + +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 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; +} + +json +NuiDrawList( + json jElem, + json jScissor, + json jList +) +{ + json ret = JsonObjectSet(jElem, "draw_list", jList); + JsonObjectSetInplace(ret, "draw_list_scissor", jScissor); + return ret; +} + +// json +// NuiCanvas( +// json jList +// ) +// { +// json ret = NuiElement("canvas", JsonNull(), jList); +// return ret; +// } diff --git a/src/prc8/include/nw_o2_coninclude.nss b/src/include/nw_o2_coninclude.nss similarity index 93% rename from src/prc8/include/nw_o2_coninclude.nss rename to src/include/nw_o2_coninclude.nss index e2fd1d7..4a250bd 100644 --- a/src/prc8/include/nw_o2_coninclude.nss +++ b/src/include/nw_o2_coninclude.nss @@ -11,6 +11,8 @@ //::////////////////////////////////////////////// //:: Created By: Brent, Andrew //:: Created On: November - May +//:: +//:: Updated for .35 by Jaysyn 2023/03/10 //::////////////////////////////////////////////// // :: MODS // April 23 2002: Removed animal parts. They were silly. @@ -22,64 +24,65 @@ // Moved nymph cloak +4 to treasure bracket 6 // Added Monk Enhancement items to random treasure +#include "prc_class_const" + // * --------- // * CONSTANTS // * --------- - // * tweaking constants // * SIX LEVEL RANGES - int RANGE_1_MIN = 0; - int RANGE_1_MAX = 5; - int RANGE_2_MIN = 6; - int RANGE_2_MAX = 8; + const int RANGE_1_MIN = 0; + const int RANGE_1_MAX = 5; + const int RANGE_2_MIN = 6; + const int RANGE_2_MAX = 8; - int RANGE_3_MIN = 9; - int RANGE_3_MAX = 10; + const int RANGE_3_MIN = 9; + const int RANGE_3_MAX = 10; - int RANGE_4_MIN = 11; - int RANGE_4_MAX = 13; + const int RANGE_4_MIN = 11; + const int RANGE_4_MAX = 13; - int RANGE_5_MIN = 14; - int RANGE_5_MAX = 16; + const int RANGE_5_MIN = 14; + const int RANGE_5_MAX = 16; - int RANGE_6_MIN = 17; - int RANGE_6_MAX = 100; + const int RANGE_6_MIN = 17; + const int RANGE_6_MAX = 100; // * NUMBER OF ITEMS APPEARING - int NUMBER_LOW_ONE = 100; int NUMBER_MED_ONE = 60; int NUMBER_HIGH_ONE = 40; int NUMBER_BOSS_ONE = 100; - int NUMBER_LOW_TWO = 0; int NUMBER_MED_TWO = 30; int NUMBER_HIGH_TWO = 40; int NUMBER_BOSS_TWO = 0; - int NUMBER_LOW_THREE = 0; int NUMBER_MED_THREE = 10; int NUMBER_HIGH_THREE = 20; int NUMBER_BOSS_THREE = 0; + const int NUMBER_LOW_ONE = 100; const int NUMBER_MED_ONE = 60; const int NUMBER_HIGH_ONE = 40; const int NUMBER_BOSS_ONE = 100; + const int NUMBER_LOW_TWO = 0; const int NUMBER_MED_TWO = 30; const int NUMBER_HIGH_TWO = 40; const int NUMBER_BOSS_TWO = 0; + const int NUMBER_LOW_THREE = 0; const int NUMBER_MED_THREE = 10; const int NUMBER_HIGH_THREE = 20; const int NUMBER_BOSS_THREE = 0; - int NUMBER_BOOK_ONE = 75; - int NUMBER_BOOK_TWO = 20; - int NUMBER_BOOK_THREE = 5; + const int NUMBER_BOOK_ONE = 75; + const int NUMBER_BOOK_TWO = 20; + const int NUMBER_BOOK_THREE = 5; // * AMOUNT OF GOLD BY VALUE - float LOW_MOD_GOLD = 0.5; float MEDIUM_MOD_GOLD = 1.0; float HIGH_MOD_GOLD = 3.0; + const float LOW_MOD_GOLD = 0.5; const float MEDIUM_MOD_GOLD = 1.0; const float HIGH_MOD_GOLD = 3.0; // * FREQUENCY OF ITEM TYPE APPEARING BY TREASURE TYPE - int LOW_PROB_BOOK = 1; int MEDIUM_PROB_BOOK = 1; int HIGH_PROB_BOOK =1; - int LOW_PROB_ANIMAL = 0; int MEDIUM_PROB_ANIMAL = 0; int HIGH_PROB_ANIMAL = 0; - int LOW_PROB_JUNK = 2; int MEDIUM_PROB_JUNK = 1; int HIGH_PROB_JUNK = 1; - int LOW_PROB_GOLD = 43; int MEDIUM_PROB_GOLD = 38; int HIGH_PROB_GOLD = 15; - int LOW_PROB_GEM = 9; int MEDIUM_PROB_GEM = 15; int HIGH_PROB_GEM = 15; - int LOW_PROB_JEWEL = 4; int MEDIUM_PROB_JEWEL = 6; int HIGH_PROB_JEWEL = 15; - int LOW_PROB_ARCANE = 3; int MEDIUM_PROB_ARCANE = 3; int HIGH_PROB_ARCANE = 3; - int LOW_PROB_DIVINE = 3; int MEDIUM_PROB_DIVINE = 3; int HIGH_PROB_DIVINE = 3; - int LOW_PROB_AMMO = 10; int MEDIUM_PROB_AMMO = 5; int HIGH_PROB_AMMO = 3; - int LOW_PROB_KIT = 5; int MEDIUM_PROB_KIT = 5; int HIGH_PROB_KIT = 5; - int LOW_PROB_POTION =17; int MEDIUM_PROB_POTION = 20; int HIGH_PROB_POTION= 9; - int LOW_PROB_TABLE2 = 3; int MEDIUM_PROB_TABLE2 = 3; int HIGH_PROB_TABLE2= 30; + const int LOW_PROB_BOOK = 1; const int MEDIUM_PROB_BOOK = 1; const int HIGH_PROB_BOOK =1; + const int LOW_PROB_ANIMAL = 0; const int MEDIUM_PROB_ANIMAL = 0; const int HIGH_PROB_ANIMAL = 0; + const int LOW_PROB_JUNK = 2; const int MEDIUM_PROB_JUNK = 1; const int HIGH_PROB_JUNK = 1; + const int LOW_PROB_GOLD = 43; const int MEDIUM_PROB_GOLD = 38; const int HIGH_PROB_GOLD = 15; + const int LOW_PROB_GEM = 9; const int MEDIUM_PROB_GEM = 15; const int HIGH_PROB_GEM = 15; + const int LOW_PROB_JEWEL = 4; const int MEDIUM_PROB_JEWEL = 6; const int HIGH_PROB_JEWEL = 15; + const int LOW_PROB_ARCANE = 3; const int MEDIUM_PROB_ARCANE = 3; const int HIGH_PROB_ARCANE = 3; + const int LOW_PROB_DIVINE = 3; const int MEDIUM_PROB_DIVINE = 3; const int HIGH_PROB_DIVINE = 3; + const int LOW_PROB_AMMO = 10; const int MEDIUM_PROB_AMMO = 5; const int HIGH_PROB_AMMO = 3; + const int LOW_PROB_KIT = 5; const int MEDIUM_PROB_KIT = 5; const int HIGH_PROB_KIT = 5; + const int LOW_PROB_POTION =17; const int MEDIUM_PROB_POTION = 20; const int HIGH_PROB_POTION= 9; + const int LOW_PROB_TABLE2 = 3; const int MEDIUM_PROB_TABLE2 = 3; const int HIGH_PROB_TABLE2= 30; // * readability constants -int TREASURE_LOW = 1; -int TREASURE_MEDIUM = 2; -int TREASURE_HIGH = 3; -int TREASURE_BOSS = 4; -int TREASURE_BOOK = 5; +const int TREASURE_LOW = 1; +const int TREASURE_MEDIUM = 2; +const int TREASURE_HIGH = 3; +const int TREASURE_BOSS = 4; +const int TREASURE_BOOK = 5; // * JUMP_LEVEL is used in a Specific item function @@ -88,7 +91,7 @@ int TREASURE_BOOK = 5; // * hit die for the purposes of the treasure evaluation. // * May 2002: Lowered JUMP_LEVEL from 3 to 2 -int JUMP_LEVEL = 2; +const int JUMP_LEVEL = 2; //* Declarations @@ -115,11 +118,13 @@ void dbSpeak(string s) //* made this function to help with debugging void dbCreateItemOnObject(string sItemTemplate, object oTarget = OBJECT_SELF, int nStackSize = 1) { +/* if (sItemTemplate == "") { PrintString("blank item passed into dbCreateItemOnObject. Please report as bug to Brent."); } dbSpeak(sItemTemplate); +*/ //sItemTemplate = GetStringLowerCase @@ -129,13 +134,14 @@ void dbCreateItemOnObject(string sItemTemplate, object oTarget = OBJECT_SELF, in // * it creates more string sRoot = GetSubString(sItemTemplate, 0, 6); - dbSpeak("ROOT: " + sRoot); + //dbSpeak("ROOT: " + sRoot); if (GetStringLowerCase(sRoot) == "nw_wth") { nStackSize = Random(30) + 1; } } object oItem = CreateItemOnObject(sItemTemplate, oTarget, nStackSize); +/* if (GetIsObjectValid(oItem) == FALSE && sItemTemplate != "NW_IT_GOLD001") { @@ -148,6 +154,7 @@ void dbCreateItemOnObject(string sItemTemplate, object oTarget = OBJECT_SELF, in PrintString("*******"); } } +*/ } @@ -160,16 +167,16 @@ object GetLastOpener() { if (GetIsObjectValid(GetLastOpenedBy()) == TRUE) { - dbSpeak("LastOpener: GetLastOpenedBy " + GetTag(GetLastOpenedBy())); + //dbSpeak("LastOpener: GetLastOpenedBy " + GetTag(GetLastOpenedBy())); return GetLastOpenedBy(); } else if (GetIsObjectValid(GetLastKiller()) == TRUE) { - dbSpeak("LastOpener: GetLastAttacker"); + //dbSpeak("LastOpener: GetLastAttacker"); return GetLastKiller(); } - dbSpeak("LastOpener: The Object is Invalid you weenie!"); + //dbSpeak("LastOpener: The Object is Invalid you weenie!"); return OBJECT_INVALID; } @@ -200,9 +207,9 @@ int GetRange(int nCategory, int nHD) case 1: nMin = RANGE_1_MIN; nMax = RANGE_1_MAX; break; } - dbSpeak("nMin = " + IntToString(nMin)); - dbSpeak("nMax = " + IntToString(nMax)); - dbSpeak("GetRange.nHD = " + IntToString(nHD)); + //dbSpeak("nMin = " + IntToString(nMin)); + //dbSpeak("nMax = " + IntToString(nMax)); + //dbSpeak("GetRange.nHD = " + IntToString(nHD)); if (nHD >= nMin && nHD <= nMax) { return TRUE; @@ -312,7 +319,7 @@ int GetNumberOfItems(int nTreasureType) { sRes = "NW_IT_BOOK0" + IntToString(nBook1); } - dbSpeak("Create book"); + //dbSpeak("Create book"); dbCreateItemOnObject(sRes, oTarget); } @@ -327,7 +334,7 @@ int GetNumberOfItems(int nTreasureType) case 2: sRes = "NW_IT_MMIDMISC05"; break; case 3: sRes = "NW_IT_MMIDMISC06"; break; } - dbSpeak("animal"); + //dbSpeak("animal"); dbCreateItemOnObject(sRes, oTarget); } @@ -346,7 +353,7 @@ int GetNumberOfItems(int nTreasureType) case 5: sRes = "NW_IT_MPOTION022"; break; // spirits case 6: sRes = "NW_IT_TORCH001"; break; //torch } - dbSpeak("CreateJunk"); + //dbSpeak("CreateJunk"); dbCreateItemOnObject(sRes, oTarget); } // * @@ -392,7 +399,7 @@ int GetNumberOfItems(int nTreasureType) { nAmount = 1; } - dbSpeak("gold"); + //dbSpeak("gold"); dbCreateItemOnObject("NW_IT_GOLD001", oTarget, nAmount); } void CreateGem(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) @@ -476,7 +483,7 @@ int GetNumberOfItems(int nTreasureType) case 8: sGem = "nw_it_gem012"; break; } } - dbSpeak("Create Gem"); + //dbSpeak("Create Gem"); dbCreateItemOnObject(sGem, oTarget, 1); } void CreateJewel(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) @@ -547,7 +554,7 @@ int GetNumberOfItems(int nTreasureType) case 5: case 6: sJewel = "nw_it_mneck022"; break; } } - dbSpeak("Create Jewel"); + //dbSpeak("Create Jewel"); dbCreateItemOnObject(sJewel, oTarget, 1); @@ -697,7 +704,7 @@ int GetNumberOfItems(int nTreasureType) case 7: sScroll = "nw_it_spdvscr702"; break; } } - dbSpeak("Divine Scroll"); + //dbSpeak("Divine Scroll"); dbCreateItemOnObject(sScroll, oTarget, 1); @@ -784,7 +791,7 @@ int GetNumberOfItems(int nTreasureType) case 20: sAmmo = "nw_wammbu007"; break; } } - dbSpeak("ammo"); + //dbSpeak("ammo"); dbCreateItemOnObject(sAmmo, oTarget, Random(30) + 1); // create up to 30 of the specified ammo type } @@ -935,7 +942,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Trapkit"); + //dbSpeak("Create Trapkit"); dbCreateItemOnObject(sKit, oTarget, 1); } @@ -1001,7 +1008,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Healing Kit"); + //dbSpeak("Create Healing Kit"); dbCreateItemOnObject(sKit, oTarget, 1); @@ -1076,7 +1083,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Lockpick"); + //dbSpeak("Create Lockpick"); dbCreateItemOnObject(sKit, oTarget, 1); @@ -1213,7 +1220,7 @@ int GetNumberOfItems(int nTreasureType) case 29: sPotion = "nw_it_mpotion006"; break; } } - dbSpeak("Create Potion"); + //dbSpeak("Create Potion"); dbCreateItemOnObject(sPotion, oTarget, 1); } //:://///////////////////////////////////////////// @@ -1476,7 +1483,7 @@ int GetNumberOfItems(int nTreasureType) case 30: sItem = "nw_it_mneck018"; break; } } - dbSpeak("Create Misc"); + //dbSpeak("Create Misc"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -1536,7 +1543,7 @@ int GetNumberOfItems(int nTreasureType) else if (GetLevelByClass(CLASS_TYPE_MONK, oAdventurer)>= 1) { - dbSpeak("in monk function"); + //dbSpeak("in monk function"); if (nSpecific == 0) { CreateGenericMonkWeapon(oTarget, oAdventurer); @@ -1631,7 +1638,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Generic Rod staff wand"); + //dbSpeak("Generic Rod staff wand"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -1747,7 +1754,7 @@ int GetNumberOfItems(int nTreasureType) case 13: sItem = "nw_waxmhn011"; break; } } - dbSpeak("Generic Monk Weapon"); + //dbSpeak("Generic Monk Weapon"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -1888,7 +1895,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Specific Monk Weapon"); + //dbSpeak("Specific Monk Weapon"); dbCreateItemOnObject(sItem, oTarget, 1); @@ -2004,7 +2011,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Generic Druid weapon"); + //dbSpeak("Generic Druid weapon"); dbCreateItemOnObject(sItem, oTarget, 1); @@ -2082,7 +2089,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("specific druid weapon"); + //dbSpeak("specific druid weapon"); dbCreateItemOnObject(sItem, oTarget, 1); @@ -2168,7 +2175,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Generic Wizard or Sorcerer Weapon"); + //dbSpeak("Generic Wizard or Sorcerer Weapon"); dbCreateItemOnObject(sItem, oTarget, 1); @@ -2241,7 +2248,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Specific Wizard or Sorcerer Weapon"); + //dbSpeak("Specific Wizard or Sorcerer Weapon"); dbCreateItemOnObject(sItem, oTarget, 1); @@ -2410,7 +2417,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Generic SImple; Specific = " + IntToString(nModifier)); + //dbSpeak("Create Generic SImple; Specific = " + IntToString(nModifier)); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -2594,7 +2601,7 @@ int GetNumberOfItems(int nTreasureType) } - dbSpeak("Create Generic Martial"); + //dbSpeak("Create Generic Martial"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -2726,7 +2733,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create generic exotic"); + //dbSpeak("Create generic exotic"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -2825,7 +2832,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Generic light"); + //dbSpeak("Create Generic light"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -2952,7 +2959,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Generic medium"); + //dbSpeak("Create Generic medium"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -3058,7 +3065,7 @@ int GetNumberOfItems(int nTreasureType) } } - dbSpeak("Create Generic heavy"); + // dbSpeak("Create Generic heavy"); dbCreateItemOnObject(sItem, oTarget, 1); } @@ -3124,7 +3131,7 @@ int GetNumberOfItems(int nTreasureType) case 10: sItem = "nw_it_mbelt006"; break; case 11: sItem = "nw_it_mbelt002"; break; case 12: sItem = "nw_it_mmidmisc03"; break; - case 13: sItem = "nw_it_resistring"; break; + case 13: sItem = "nw_it_mring002"; break; case 14: sItem = "nw_it_mbelt004"; break; case 15: sItem = "nw_it_mring005"; break; case 16: sItem = "nw_it_mboots005"; break; @@ -3142,7 +3149,7 @@ int GetNumberOfItems(int nTreasureType) case 1: sItem = "nw_it_mbelt002"; break; case 2: sItem = "nw_it_mbelt002"; break; case 3: sItem = "nw_it_mmidmisc03"; break; - case 4: sItem = "nw_it_resistring"; break; + case 4: sItem = "nw_it_mring002"; break; case 5: sItem = "nw_it_mbelt004"; break; case 6: sItem = "nw_it_mring005"; break; case 7: sItem = "nw_it_mboots005"; break; @@ -3253,7 +3260,7 @@ int GetNumberOfItems(int nTreasureType) case 1: sItem = "nw_wmgmrd004"; break; case 2: sItem = "nw_wmgst002"; break; case 3: sItem = "nw_wmgmrd005"; break; - case 4: sItem = "rezrod"; break; + case 4: sItem = "nw_wmgmrd002"; break; case 5: sItem = "nw_wmgst003"; break; case 6: sItem = "nw_wblmcl012"; break; } @@ -4007,7 +4014,7 @@ int GetNumberOfItems(int nTreasureType) // * if nSpecific is = 1 then spawn in 'named' items at the higher levels void CreateTable2Item(object oTarget, object oAdventurer, int nSpecific=0) { - dbSpeak("In CreateTable2Item"); + //dbSpeak("In CreateTable2Item"); string sItem = ""; int nProbMisc = 0; int nProbClass = 0; @@ -4042,9 +4049,12 @@ int GetNumberOfItems(int nTreasureType) //* SETUP probabilities based on Class - if ( nClass == CLASS_TYPE_FIGHTER || nClass == CLASS_TYPE_PALADIN || nSpecialRanger == 1) + if ( nClass == CLASS_TYPE_FIGHTER || nClass == CLASS_TYPE_PALADIN || nSpecialRanger == 1 + || nClass == CLASS_TYPE_ANTI_PALADIN || nClass == CLASS_TYPE_BRAWLER || nClass == CLASS_TYPE_CRUSADER + || nClass == CLASS_TYPE_DUSKBLADE || nClass == CLASS_TYPE_KNIGHT || nClass == CLASS_TYPE_MARSHAL + || nClass == CLASS_TYPE_PSYWAR || nClass == CLASS_TYPE_SOHEI) { - dbSpeak("I am fighter or paladin or heavy ranger"); + //dbSpeak("I am fighter or paladin or heavy ranger"); nProbMisc = 20; nProbClass = 0; nProbRodStaffWand = 5; @@ -4058,7 +4068,7 @@ int GetNumberOfItems(int nTreasureType) else if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER) { - dbSpeak("I am wizard or sorcerer"); + //dbSpeak("I am wizard or sorcerer"); nProbMisc = 40; nProbClass = 30; nProbRodStaffWand = 15; @@ -4070,9 +4080,10 @@ int GetNumberOfItems(int nTreasureType) nProbHeavy = 2; } else - if (nClass == CLASS_TYPE_BARBARIAN || nSpecialRanger == 2) + if (nClass == CLASS_TYPE_BARBARIAN || nSpecialRanger == 2 || nClass == CLASS_TYPE_BOWMAN + || nClass == CLASS_TYPE_HEXBLADE || nClass == CLASS_TYPE_WARBLADE) { - dbSpeak("I am barbarian or light ranger"); + //dbSpeak("I am barbarian or light ranger"); nProbMisc = 20; nProbClass = 0; @@ -4085,9 +4096,97 @@ int GetNumberOfItems(int nTreasureType) nProbHeavy = 3; } else + if (nClass == CLASS_TYPE_ARCHIVIST || nClass == CLASS_TYPE_DRAGON_SHAMAN || nClass == CLASS_TYPE_FAVOURED_SOUL + || nClass == CLASS_TYPE_MYSTIC || nClass == CLASS_TYPE_WARMAGE || nClass == CLASS_TYPE_TEMPLAR) + { + //type 1 + nProbMisc = 25; + nProbClass = 0; + nProbRodStaffWand = 15; + nProbSimple = 15; + nProbMartial = 8; + nProbExotic = 6; + nProbLight = 15; + nProbMedium = 10; + nProbHeavy = 6; + } + else + if (nClass == CLASS_TYPE_NOBLE || nClass == CLASS_TYPE_SWASHBUCKLER || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_ULTIMATE_RANGER) + { + //type 2 + nProbMisc = 27; + nProbClass = 0; + nProbRodStaffWand = 5; + nProbSimple = 15; + nProbMartial = 20; + nProbExotic = 10; + nProbLight = 10; + nProbMedium = 8; + nProbHeavy = 5; + } + else + if (nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER || nClass == CLASS_TYPE_HEALER + || nClass == CLASS_TYPE_SCOUT || nClass == CLASS_TYPE_SHAMAN || nClass == CLASS_TYPE_SOULKNIFE + || nClass == CLASS_TYPE_TRUENAMER || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_WILDER) + { + //type 3 + nProbMisc = 45; + nProbClass = 0; + nProbRodStaffWand = 7; + nProbSimple = 15; + nProbMartial = 5; + nProbExotic = 5; + nProbLight = 15; + nProbMedium = 4; + nProbHeavy = 4; + } + else + if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_PSION || nClass == CLASS_TYPE_WITCH) + { + //type 4 + nProbMisc = 50; + nProbClass = 0; + nProbRodStaffWand = 10; + nProbSimple = 20; + nProbMartial = 5; + nProbExotic = 5; + nProbLight = 4; + nProbMedium = 3; + nProbHeavy = 3; + } + else + if (nClass == CLASS_TYPE_NINJA) + { + //type 5 + nProbMisc = 45; + nProbClass = 0; + nProbRodStaffWand = 2; + nProbSimple = 12; + nProbMartial = 6; + nProbExotic = 26; + nProbLight = 3; + nProbMedium = 3; + nProbHeavy = 3; + } + else + if (nClass == CLASS_TYPE_CW_SAMURAI || nClass == CLASS_TYPE_SAMURAI) + { + //type 6 + nProbMisc = 25; + nProbClass = 0; + nProbRodStaffWand = 5; + nProbSimple = 5; + nProbMartial = 10; + nProbExotic = 20; + nProbLight = 10; + nProbMedium = 20; + nProbHeavy = 5; + } + else if (nClass == CLASS_TYPE_CLERIC) { - dbSpeak("I am cleric"); + //dbSpeak("I am cleric"); nProbMisc = 20; nProbClass = 10; @@ -4102,7 +4201,7 @@ int GetNumberOfItems(int nTreasureType) else if (nClass == CLASS_TYPE_DRUID) { - dbSpeak("I am druid"); + //dbSpeak("I am druid"); nProbMisc = 20; nProbClass = 25; @@ -4117,7 +4216,7 @@ int GetNumberOfItems(int nTreasureType) else if (nClass == CLASS_TYPE_MONK) { - dbSpeak("I am monk"); + //dbSpeak("I am monk"); nProbMisc = 20; nProbClass = 50; nProbRodStaffWand = 2; @@ -4129,9 +4228,9 @@ int GetNumberOfItems(int nTreasureType) nProbHeavy = 4; } else - if (nClass == CLASS_TYPE_ROGUE) + if (nClass == CLASS_TYPE_ROGUE || nClass == CLASS_TYPE_PSYCHIC_ROGUE) { - dbSpeak("I am rogue"); + //dbSpeak("I am rogue"); nProbMisc = 25; nProbClass = 10; @@ -4146,7 +4245,7 @@ int GetNumberOfItems(int nTreasureType) else if (nClass == CLASS_TYPE_BARD) { - dbSpeak("I am bard"); + //dbSpeak("I am bard"); nProbMisc = 25; nProbClass = 5; @@ -4158,11 +4257,11 @@ int GetNumberOfItems(int nTreasureType) nProbMedium = 5; nProbHeavy = 5; } - else - { - dbSpeak("No Valid Class"); - } - dbSpeak("Table2Item: After Class Distribution"); + //else + //{ + // dbSpeak("No Valid Class"); + //} + //dbSpeak("Table2Item: After Class Distribution"); //* Create Items based on Probabilities int nRandom = d100(); if (nRandom <= nProbMisc) @@ -4219,10 +4318,10 @@ int GetNumberOfItems(int nTreasureType) if (nSpecific == 0) CreateGenericHeavyArmor(oTarget, oAdventurer); else CreateSpecificHeavyArmor(oTarget, oAdventurer); } - else - { - dbSpeak("Generic Generic or Specific; error: 3524"); - } + //else + //{ + // dbSpeak("Generic Generic or Specific; error: 3524"); + //} } //:://///////////////////////////////////////////// @@ -4251,12 +4350,12 @@ int GetNumberOfItems(int nTreasureType) void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) { - dbSpeak("*********************NEW TREASURE*************************"); + //dbSpeak("*********************NEW TREASURE*************************"); // * abort treasure if no one opened the container if (GetIsObjectValid(oLastOpener) == FALSE) { - dbSpeak("Aborted. No valid Last Opener"); + //dbSpeak("Aborted. No valid Last Opener"); return; } @@ -4334,7 +4433,7 @@ void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) nProbTable2 = HIGH_PROB_TABLE2; } else if (nTreasureType == TREASURE_BOSS) - { dbSpeak("boss"); + { //dbSpeak("boss"); nProbTable2 = 100; nSpecific = 1; } @@ -4345,7 +4444,7 @@ void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) nProbDivine = 4; } - dbSpeak("Generate Treasure nSpecific = " + IntToString(nSpecific)); + //dbSpeak("Generate Treasure nSpecific = " + IntToString(nSpecific)); for (i = 1; i <= nNumberItems; i++) { @@ -4376,8 +4475,8 @@ void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) { CreateTable2Item(oCreateOn, oLastOpener, nSpecific); // * Weapons, Armor, Misc - Class based } - else - dbSpeak("other stuff"); + //else + // dbSpeak("other stuff"); @@ -4518,6 +4617,47 @@ void ShoutDisturbed() } } +int nGetIsBaseClass(int nClass) +{ + return (nClass <= CLASS_TYPE_WIZARD || + nClass == CLASS_TYPE_ANTI_PALADIN || + nClass == CLASS_TYPE_ARCHIVIST || + nClass == CLASS_TYPE_BEGUILER || + nClass == CLASS_TYPE_BOWMAN || + nClass == CLASS_TYPE_BRAWLER || + nClass == CLASS_TYPE_CRUSADER || + nClass == CLASS_TYPE_DRAGON_SHAMAN || + nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || + nClass == CLASS_TYPE_DREAD_NECROMANCER || + nClass == CLASS_TYPE_DUSKBLADE || + nClass == CLASS_TYPE_FAVOURED_SOUL || + nClass == CLASS_TYPE_HEALER || + nClass == CLASS_TYPE_HEXBLADE || + nClass == CLASS_TYPE_KNIGHT || + nClass == CLASS_TYPE_MARSHAL || + nClass == CLASS_TYPE_MYSTIC || + nClass == CLASS_TYPE_NINJA || + nClass == CLASS_TYPE_NOBLE || + nClass == CLASS_TYPE_PSION || + nClass == CLASS_TYPE_PSYWAR || + nClass == CLASS_TYPE_PSYCHIC_ROGUE || + nClass == CLASS_TYPE_SAMURAI || + nClass == CLASS_TYPE_CW_SAMURAI || + nClass == CLASS_TYPE_SCOUT || + nClass == CLASS_TYPE_SHAMAN || + nClass == CLASS_TYPE_SOHEI || + nClass == CLASS_TYPE_SOULKNIFE || + nClass == CLASS_TYPE_SWASHBUCKLER || + nClass == CLASS_TYPE_SWORDSAGE || + nClass == CLASS_TYPE_TRUENAMER || + nClass == CLASS_TYPE_ULTIMATE_RANGER || + nClass == CLASS_TYPE_WARBLADE || + nClass == CLASS_TYPE_WARLOCK || + nClass == CLASS_TYPE_WARMAGE || + nClass == CLASS_TYPE_WILDER || + nClass == CLASS_TYPE_WITCH || + nClass == CLASS_TYPE_TEMPLAR); +} //:://///////////////////////////////////////////// //:: Determine Class to Use @@ -4536,34 +4676,96 @@ int nDetermineClassToUse(object oCharacter) { int nClass; int nTotal = GetHitDice(oCharacter); - dbSpeak("Hit dice " + IntToString(nTotal)); + //dbSpeak("Hit dice " + IntToString(nTotal)); if (nTotal < 1) { nTotal = 1; } +/* float fTotal = IntToFloat(nTotal); - if (GetIsObjectValid(oCharacter) == FALSE) - { - dbSpeak("DetermineClassToUse: This character is invalid"); - } + //if (GetIsObjectValid(oCharacter) == FALSE) + //{ + // dbSpeak("DetermineClassToUse: This character is invalid"); + //} + int nClass1 = GetClassByPosition(1, oCharacter); int nState1 = FloatToInt((IntToFloat(GetLevelByClass(nClass1, oCharacter)) / fTotal) * 100); - dbSpeak("Level 1 Class Level = " + IntToString(GetLevelByClass(nClass1,oCharacter))); - dbSpeak("State 1 " + IntToString(nState1)); + //dbSpeak("Level 1 Class Level = " + IntToString(GetLevelByClass(nClass1,oCharacter))); + //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + GetTag(oCharacter) + "Class 1 " + IntToString(nState1)); + //dbSpeak("State 1 " + IntToString(nState1)); int nClass2 = GetClassByPosition(2, oCharacter); int nState2 = FloatToInt((IntToFloat(GetLevelByClass(nClass2, oCharacter)) / fTotal) * 100) + nState1; - dbSpeak("Level 2 Class Level = " + IntToString(GetLevelByClass(nClass2,oCharacter))); - dbSpeak("State 2 " + IntToString(nState2)); + //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + GetTag(oCharacter) + "Class 2 " + IntToString(nState2)); int nClass3 = GetClassByPosition(3, oCharacter); int nState3 = FloatToInt((IntToFloat(GetLevelByClass(nClass3, oCharacter)) / fTotal) * 100) + nState2; - dbSpeak("Level 3 Class Level = " + IntToString(GetLevelByClass(nClass3,oCharacter))); - dbSpeak("State 3 " + IntToString(nState3)); + //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + GetTag(oCharacter) + "Class 3 " + IntToString(nState3)); +*/ + int nClass1 = GetClassByPosition(1, oCharacter); + int nClass2 = GetClassByPosition(2, oCharacter); + int nClass3 = GetClassByPosition(3, oCharacter); + int nClass4 = GetClassByPosition(4, oCharacter); + int nClass5 = GetClassByPosition(5, oCharacter); + int nClass6 = GetClassByPosition(6, oCharacter); + int nClass7 = GetClassByPosition(7, oCharacter); + int nClass8 = GetClassByPosition(8, oCharacter); + + int nState1 = GetLevelByClass(nClass1, oCharacter) * 100 / nTotal; + int nState2 = GetLevelByClass(nClass2, oCharacter) * 100 / nTotal + nState1; + int nState3 = GetLevelByClass(nClass3, oCharacter) * 100 / nTotal + nState2; + int nState4 = GetLevelByClass(nClass4, oCharacter) * 100 / nTotal + nState3; + int nState5 = GetLevelByClass(nClass5, oCharacter) * 100 / nTotal + nState4; + int nState6 = GetLevelByClass(nClass6, oCharacter) * 100 / nTotal + nState5; + int nState7 = GetLevelByClass(nClass7, oCharacter) * 100 / nTotal + nState6; + + // nState8 will always be 100 if there is an eigth class, or 0 if there isn't + //int nState8 = GetLevelByClass(nClass3, oCharacter) * 100 / nTotal + nState7; + + // correct for unrecognized classes - assumes the first class will be a non-prestige player class + if(nClass2 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass2)) + { + nClass2 = CLASS_TYPE_INVALID; + nState1 = nState2; + } + if(nClass3 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass3)) + { + nClass3 = CLASS_TYPE_INVALID; + nState1 = nState3; + } + if(nClass4 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass4)) + { + nClass4 = CLASS_TYPE_INVALID; + nState1 = nState4; + } + if(nClass5 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass5)) + { + nClass5 = CLASS_TYPE_INVALID; + nState1 = nState5; + } + if(nClass6 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass6)) + { + nClass6 = CLASS_TYPE_INVALID; + nState1 = nState6; + } + if(nClass7 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass7)) + { + nClass7 = CLASS_TYPE_INVALID; + nState1 = nState7; + } + if(nClass8 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass8)) + { + nClass8 = CLASS_TYPE_INVALID; + if(nClass7 != CLASS_TYPE_INVALID) + nState7 = 100; + else nState1 = 100; + } int nUseClass = d100(); + //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + "D100 Roll " +IntToString(nUseClass)); - dbSpeak("Before comparison : " + IntToString(nClass1)); + + //dbSpeak("Before comparison : " + IntToString(nClass1)); if(nUseClass <= nState1) { nClass = nClass1; @@ -4574,11 +4776,16 @@ int nDetermineClassToUse(object oCharacter) } else { - nClass = nClass3; + // might be possible to end up here by accident because of a rounding error + // so just in case... + if(nClass3 == CLASS_TYPE_INVALID) nClass = nClass1; + else nClass = nClass3; } - dbSpeak("Class from determineClass " + IntToString(nClass)); + + //dbSpeak("Class from determineClass " + IntToString(nClass)); return nClass; } - +//:: Test Void +//void main () {} diff --git a/src/prc8/include/pnp_lich_inc.nss b/src/include/pnp_lich_inc.nss similarity index 100% rename from src/prc8/include/pnp_lich_inc.nss rename to src/include/pnp_lich_inc.nss diff --git a/src/prc8/include/pnp_shft_main.nss b/src/include/pnp_shft_main.nss similarity index 100% rename from src/prc8/include/pnp_shft_main.nss rename to src/include/pnp_shft_main.nss diff --git a/src/prc8/include/pnp_shft_poly.nss b/src/include/pnp_shft_poly.nss similarity index 100% rename from src/prc8/include/pnp_shft_poly.nss rename to src/include/pnp_shft_poly.nss diff --git a/src/prc8/include/prc_add_spell_dc.nss b/src/include/prc_add_spell_dc.nss similarity index 100% rename from src/prc8/include/prc_add_spell_dc.nss rename to src/include/prc_add_spell_dc.nss diff --git a/src/prc8/include/prc_add_spl_pen.nss b/src/include/prc_add_spl_pen.nss similarity index 100% rename from src/prc8/include/prc_add_spl_pen.nss rename to src/include/prc_add_spl_pen.nss diff --git a/src/prc8/include/prc_allow_const.nss b/src/include/prc_allow_const.nss similarity index 100% rename from src/prc8/include/prc_allow_const.nss rename to src/include/prc_allow_const.nss diff --git a/src/prc8/include/prc_alterations.nss b/src/include/prc_alterations.nss similarity index 100% rename from src/prc8/include/prc_alterations.nss rename to src/include/prc_alterations.nss diff --git a/src/prc8/include/prc_ccc_const.nss b/src/include/prc_ccc_const.nss similarity index 100% rename from src/prc8/include/prc_ccc_const.nss rename to src/include/prc_ccc_const.nss diff --git a/src/prc8/include/prc_ccc_readme.nss b/src/include/prc_ccc_readme.nss similarity index 100% rename from src/prc8/include/prc_ccc_readme.nss rename to src/include/prc_ccc_readme.nss diff --git a/src/prc8/include/prc_class_const.nss b/src/include/prc_class_const.nss similarity index 100% rename from src/prc8/include/prc_class_const.nss rename to src/include/prc_class_const.nss diff --git a/src/prc8/include/prc_compan_inc.nss b/src/include/prc_compan_inc.nss similarity index 100% rename from src/prc8/include/prc_compan_inc.nss rename to src/include/prc_compan_inc.nss diff --git a/src/prc8/include/prc_craft_inc.nss b/src/include/prc_craft_inc.nss similarity index 100% rename from src/prc8/include/prc_craft_inc.nss rename to src/include/prc_craft_inc.nss diff --git a/src/prc8/include/prc_effect_inc.nss b/src/include/prc_effect_inc.nss similarity index 100% rename from src/prc8/include/prc_effect_inc.nss rename to src/include/prc_effect_inc.nss diff --git a/src/prc8/include/prc_feat_const.nss b/src/include/prc_feat_const.nss similarity index 99% rename from src/prc8/include/prc_feat_const.nss rename to src/include/prc_feat_const.nss index c961dab..0728224 100644 --- a/src/prc8/include/prc_feat_const.nss +++ b/src/include/prc_feat_const.nss @@ -1549,7 +1549,7 @@ 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; +const int FEAT_VOWOFPOVERTY = 26002; //Vile Feat const int FEAT_LICHLOVED = 3395; @@ -1868,12 +1868,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; @@ -3933,6 +3933,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; diff --git a/src/prc8/include/prc_getbest_inc.nss b/src/include/prc_getbest_inc.nss similarity index 100% rename from src/prc8/include/prc_getbest_inc.nss rename to src/include/prc_getbest_inc.nss diff --git a/src/prc8/include/prc_inc_actions.nss b/src/include/prc_inc_actions.nss similarity index 100% rename from src/prc8/include/prc_inc_actions.nss rename to src/include/prc_inc_actions.nss diff --git a/src/prc8/include/prc_inc_array.nss b/src/include/prc_inc_array.nss similarity index 100% rename from src/prc8/include/prc_inc_array.nss rename to src/include/prc_inc_array.nss diff --git a/src/prc8/include/prc_inc_assoc.nss b/src/include/prc_inc_assoc.nss similarity index 100% rename from src/prc8/include/prc_inc_assoc.nss rename to src/include/prc_inc_assoc.nss diff --git a/src/prc8/include/prc_inc_breath.nss b/src/include/prc_inc_breath.nss similarity index 100% rename from src/prc8/include/prc_inc_breath.nss rename to src/include/prc_inc_breath.nss diff --git a/src/prc8/include/prc_inc_burn.nss b/src/include/prc_inc_burn.nss similarity index 100% rename from src/prc8/include/prc_inc_burn.nss rename to src/include/prc_inc_burn.nss diff --git a/src/prc8/include/prc_inc_castlvl.nss b/src/include/prc_inc_castlvl.nss similarity index 99% rename from src/prc8/include/prc_inc_castlvl.nss rename to src/include/prc_inc_castlvl.nss index 876ac84..bffffee 100644 --- a/src/prc8/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); diff --git a/src/prc8/include/prc_inc_chat.nss b/src/include/prc_inc_chat.nss similarity index 100% rename from src/prc8/include/prc_inc_chat.nss rename to src/include/prc_inc_chat.nss diff --git a/src/prc8/include/prc_inc_chat_dm.nss b/src/include/prc_inc_chat_dm.nss similarity index 100% rename from src/prc8/include/prc_inc_chat_dm.nss rename to src/include/prc_inc_chat_dm.nss diff --git a/src/prc8/include/prc_inc_chat_pow.nss b/src/include/prc_inc_chat_pow.nss similarity index 100% rename from src/prc8/include/prc_inc_chat_pow.nss rename to src/include/prc_inc_chat_pow.nss diff --git a/src/prc8/include/prc_inc_chat_shf.nss b/src/include/prc_inc_chat_shf.nss similarity index 100% rename from src/prc8/include/prc_inc_chat_shf.nss rename to src/include/prc_inc_chat_shf.nss diff --git a/src/prc8/include/prc_inc_clsfunc.nss b/src/include/prc_inc_clsfunc.nss similarity index 99% rename from src/prc8/include/prc_inc_clsfunc.nss rename to src/include/prc_inc_clsfunc.nss index 3a6c251..4d1ffcb 100644 --- a/src/prc8/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/prc8/include/prc_inc_combat.nss b/src/include/prc_inc_combat.nss similarity index 99% rename from src/prc8/include/prc_inc_combat.nss rename to src/include/prc_inc_combat.nss index f5a2411..df4a5b7 100644 --- a/src/prc8/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/prc8/include/prc_inc_combmove.nss b/src/include/prc_inc_combmove.nss similarity index 100% rename from src/prc8/include/prc_inc_combmove.nss rename to src/include/prc_inc_combmove.nss diff --git a/src/prc8/include/prc_inc_core.nss b/src/include/prc_inc_core.nss similarity index 100% rename from src/prc8/include/prc_inc_core.nss rename to src/include/prc_inc_core.nss diff --git a/src/prc8/include/prc_inc_damage.nss b/src/include/prc_inc_damage.nss similarity index 100% rename from src/prc8/include/prc_inc_damage.nss rename to src/include/prc_inc_damage.nss diff --git a/src/prc8/include/prc_inc_descrptr.nss b/src/include/prc_inc_descrptr.nss similarity index 100% rename from src/prc8/include/prc_inc_descrptr.nss rename to src/include/prc_inc_descrptr.nss diff --git a/src/prc8/include/prc_inc_domain.nss b/src/include/prc_inc_domain.nss similarity index 100% rename from src/prc8/include/prc_inc_domain.nss rename to src/include/prc_inc_domain.nss diff --git a/src/prc8/include/prc_inc_dragsham.nss b/src/include/prc_inc_dragsham.nss similarity index 100% rename from src/prc8/include/prc_inc_dragsham.nss rename to src/include/prc_inc_dragsham.nss diff --git a/src/prc8/include/prc_inc_drugfunc.nss b/src/include/prc_inc_drugfunc.nss similarity index 100% rename from src/prc8/include/prc_inc_drugfunc.nss rename to src/include/prc_inc_drugfunc.nss diff --git a/src/prc8/include/prc_inc_effect.nss b/src/include/prc_inc_effect.nss similarity index 100% rename from src/prc8/include/prc_inc_effect.nss rename to src/include/prc_inc_effect.nss diff --git a/src/prc8/include/prc_inc_factotum.nss b/src/include/prc_inc_factotum.nss similarity index 100% rename from src/prc8/include/prc_inc_factotum.nss rename to src/include/prc_inc_factotum.nss diff --git a/src/prc8/include/prc_inc_fork.nss b/src/include/prc_inc_fork.nss similarity index 98% rename from src/prc8/include/prc_inc_fork.nss rename to src/include/prc_inc_fork.nss index 3e46b83..b6b672e 100644 --- a/src/prc8/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/prc8/include/prc_inc_function.nss b/src/include/prc_inc_function.nss similarity index 99% rename from src/prc8/include/prc_inc_function.nss rename to src/include/prc_inc_function.nss index 93f7aa1..cf05967 100644 --- a/src/prc8/include/prc_inc_function.nss +++ b/src/include/prc_inc_function.nss @@ -108,7 +108,7 @@ 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_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; diff --git a/src/prc8/include/prc_inc_hextor.nss b/src/include/prc_inc_hextor.nss similarity index 100% rename from src/prc8/include/prc_inc_hextor.nss rename to src/include/prc_inc_hextor.nss diff --git a/src/prc8/include/prc_inc_itmrstr.nss b/src/include/prc_inc_itmrstr.nss similarity index 100% rename from src/prc8/include/prc_inc_itmrstr.nss rename to src/include/prc_inc_itmrstr.nss diff --git a/src/prc8/include/prc_inc_leadersh.nss b/src/include/prc_inc_leadersh.nss similarity index 100% rename from src/prc8/include/prc_inc_leadersh.nss rename to src/include/prc_inc_leadersh.nss diff --git a/src/prc8/include/prc_inc_listener.nss b/src/include/prc_inc_listener.nss similarity index 100% rename from src/prc8/include/prc_inc_listener.nss rename to src/include/prc_inc_listener.nss diff --git a/src/prc8/include/prc_inc_material.nss b/src/include/prc_inc_material.nss similarity index 100% rename from src/prc8/include/prc_inc_material.nss rename to src/include/prc_inc_material.nss diff --git a/src/prc8/include/prc_inc_nat_hb.nss b/src/include/prc_inc_nat_hb.nss similarity index 100% rename from src/prc8/include/prc_inc_nat_hb.nss rename to src/include/prc_inc_nat_hb.nss diff --git a/src/prc8/include/prc_inc_natweap.nss b/src/include/prc_inc_natweap.nss similarity index 100% rename from src/prc8/include/prc_inc_natweap.nss rename to src/include/prc_inc_natweap.nss diff --git a/src/prc8/include/prc_inc_newip.nss b/src/include/prc_inc_newip.nss similarity index 100% rename from src/prc8/include/prc_inc_newip.nss rename to src/include/prc_inc_newip.nss diff --git a/src/prc8/include/prc_inc_nwscript.nss b/src/include/prc_inc_nwscript.nss similarity index 100% rename from src/prc8/include/prc_inc_nwscript.nss rename to src/include/prc_inc_nwscript.nss diff --git a/src/prc8/include/prc_inc_onhit.nss b/src/include/prc_inc_onhit.nss similarity index 100% rename from src/prc8/include/prc_inc_onhit.nss rename to src/include/prc_inc_onhit.nss diff --git a/src/prc8/include/prc_inc_racial.nss b/src/include/prc_inc_racial.nss similarity index 100% rename from src/prc8/include/prc_inc_racial.nss rename to src/include/prc_inc_racial.nss diff --git a/src/prc8/include/prc_inc_s_det.nss b/src/include/prc_inc_s_det.nss similarity index 100% rename from src/prc8/include/prc_inc_s_det.nss rename to src/include/prc_inc_s_det.nss diff --git a/src/prc8/include/prc_inc_sb_const.nss b/src/include/prc_inc_sb_const.nss similarity index 100% rename from src/prc8/include/prc_inc_sb_const.nss rename to src/include/prc_inc_sb_const.nss diff --git a/src/prc8/include/prc_inc_sbheir.nss b/src/include/prc_inc_sbheir.nss similarity index 100% rename from src/prc8/include/prc_inc_sbheir.nss rename to src/include/prc_inc_sbheir.nss diff --git a/src/prc8/include/prc_inc_scry.nss b/src/include/prc_inc_scry.nss similarity index 100% rename from src/prc8/include/prc_inc_scry.nss rename to src/include/prc_inc_scry.nss diff --git a/src/prc8/include/prc_inc_shifting.nss b/src/include/prc_inc_shifting.nss similarity index 100% rename from src/prc8/include/prc_inc_shifting.nss rename to src/include/prc_inc_shifting.nss diff --git a/src/prc8/include/prc_inc_skills.nss b/src/include/prc_inc_skills.nss similarity index 97% rename from src/prc8/include/prc_inc_skills.nss rename to src/include/prc_inc_skills.nss index bbca299..0674604 100644 --- a/src/prc8/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/prc8/include/prc_inc_skin.nss b/src/include/prc_inc_skin.nss similarity index 100% rename from src/prc8/include/prc_inc_skin.nss rename to src/include/prc_inc_skin.nss diff --git a/src/prc8/include/prc_inc_smite.nss b/src/include/prc_inc_smite.nss similarity index 100% rename from src/prc8/include/prc_inc_smite.nss rename to src/include/prc_inc_smite.nss diff --git a/src/prc8/include/prc_inc_sneak.nss b/src/include/prc_inc_sneak.nss similarity index 100% rename from src/prc8/include/prc_inc_sneak.nss rename to src/include/prc_inc_sneak.nss diff --git a/src/prc8/include/prc_inc_sp_tch.nss b/src/include/prc_inc_sp_tch.nss similarity index 100% rename from src/prc8/include/prc_inc_sp_tch.nss rename to src/include/prc_inc_sp_tch.nss diff --git a/src/include/prc_inc_spells.ncs b/src/include/prc_inc_spells.ncs new file mode 100644 index 0000000..947f7b5 Binary files /dev/null and b/src/include/prc_inc_spells.ncs differ diff --git a/src/prc8/include/prc_inc_spells.nss b/src/include/prc_inc_spells.nss similarity index 97% rename from src/prc8/include/prc_inc_spells.nss rename to src/include/prc_inc_spells.nss index 19e73d7..d967186 100644 --- a/src/prc8/include/prc_inc_spells.nss +++ b/src/include/prc_inc_spells.nss @@ -20,6 +20,9 @@ /* 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); @@ -382,17 +385,17 @@ int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF) // 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); @@ -2223,6 +2226,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 +2350,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/prc8/include/prc_inc_stunfist.nss b/src/include/prc_inc_stunfist.nss similarity index 100% rename from src/prc8/include/prc_inc_stunfist.nss rename to src/include/prc_inc_stunfist.nss diff --git a/src/prc8/include/prc_inc_switch.nss b/src/include/prc_inc_switch.nss similarity index 99% rename from src/prc8/include/prc_inc_switch.nss rename to src/include/prc_inc_switch.nss index 4913e3d..8819a4b 100644 --- a/src/prc8/include/prc_inc_switch.nss +++ b/src/include/prc_inc_switch.nss @@ -1961,45 +1961,46 @@ 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"; /* * 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/prc8/include/prc_inc_teleport.nss b/src/include/prc_inc_teleport.nss similarity index 100% rename from src/prc8/include/prc_inc_teleport.nss rename to src/include/prc_inc_teleport.nss diff --git a/src/prc8/include/prc_inc_template.nss b/src/include/prc_inc_template.nss similarity index 100% rename from src/prc8/include/prc_inc_template.nss rename to src/include/prc_inc_template.nss diff --git a/src/prc8/include/prc_inc_turning.nss b/src/include/prc_inc_turning.nss similarity index 100% rename from src/prc8/include/prc_inc_turning.nss rename to src/include/prc_inc_turning.nss diff --git a/src/prc8/include/prc_inc_unarmed.nss b/src/include/prc_inc_unarmed.nss similarity index 100% rename from src/prc8/include/prc_inc_unarmed.nss rename to src/include/prc_inc_unarmed.nss diff --git a/src/prc8/include/prc_inc_util.nss b/src/include/prc_inc_util.nss similarity index 100% rename from src/prc8/include/prc_inc_util.nss rename to src/include/prc_inc_util.nss diff --git a/src/prc8/include/prc_inc_wpnrest.nss b/src/include/prc_inc_wpnrest.nss similarity index 91% rename from src/prc8/include/prc_inc_wpnrest.nss rename to src/include/prc_inc_wpnrest.nss index 401b323..9dcf65a 100644 --- a/src/prc8/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/prc8/include/prc_ip_srcost.nss b/src/include/prc_ip_srcost.nss similarity index 100% rename from src/prc8/include/prc_ip_srcost.nss rename to src/include/prc_ip_srcost.nss diff --git a/src/prc8/include/prc_ipfeat_const.nss b/src/include/prc_ipfeat_const.nss similarity index 100% rename from src/prc8/include/prc_ipfeat_const.nss rename to src/include/prc_ipfeat_const.nss diff --git a/src/prc8/include/prc_misc_const.nss b/src/include/prc_misc_const.nss similarity index 100% rename from src/prc8/include/prc_misc_const.nss rename to src/include/prc_misc_const.nss 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 new file mode 100644 index 0000000..e1e9c5c --- /dev/null +++ b/src/include/prc_nui_consts.nss @@ -0,0 +1,158 @@ +//:://///////////////////////////////////////////// +//:: NUI Constants +//:: prc_nui_consts +//::////////////////////////////////////////////// +/* + This file holds all the constants used by the various PRC NUI scripts. +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 24.05.2005 +//::////////////////////////////////////////////// + +const int NUI_PAYLOAD_BUTTON_LEFT_CLICK = 0; +const int NUI_PAYLOAD_BUTTON_MIDDLE_CLICK = 1; +const int NUI_PAYLOAD_BUTTON_RIGHT_CLICK = 2; + + +////////////////////////////////////////////////// +// // +// NUI Spellbook // +// // +////////////////////////////////////////////////// + +// This is the NUI Spellbook window ID +const string PRC_SPELLBOOK_NUI_WINDOW_ID = "prcSpellbookNui"; + +// This is the base Id for the Class buttons in the NUI Spellbook, the ID will +// have the ClassID attached to it (i.e. spellbookClassButton_123) +const string PRC_SPELLBOOK_NUI_CLASS_BUTTON_BASEID = "spellbookClassButton_"; + +// This is the base Id for the Spell Circle buttons in the NUI Spellbook, the ID will +// have the Circle attached to it (i.e. spellbookCircleButton__6) +const string PRC_SPELLBOOK_NUI_CIRCLE_BUTTON_BASEID = "spellbookCircleButton_"; + +// This is the base Id for the Spell Buttons in the NUI Spellbook, the ID will +// have the SpellbookId (the row of the class's spell's 2da or equivalent) +// attached to it (i.e. spellbookSpellButton_6) +const string PRC_SPELLBOOK_NUI_SPELL_BUTTON_BASEID = "spellbookSpellButton_"; + +// This is the base Id for the Meta Feat buttons in the NUI Spellbook, the ID will +// have the FeatID attached to it (i.e. spellbookMetaButton_12345) +const string PRC_SPELLBOOK_NUI_META_BUTTON_BASEID = "spellbookMetaButton_"; + +// This is the selected ClassID var used to store what class was selected to the Player +// locally +const string PRC_SPELLBOOK_SELECTED_CLASSID_VAR = "prcSpellbookSelectedClassID"; + +// This is the selected Circle var used to store what spell circle was selected +// to the Player locally +const string PRC_SPELLBOOK_SELECTED_CIRCLE_VAR = "prcSpellbookSelectedCircle"; + +// This is the Spellbook NUI geomeotry var, used to allow the location and sizing +// of the NUI to be remembered if it is ever rerendered. +const string PRC_SPELLBOOK_NUI_GEOMETRY_VAR = "sbNuiGeometry"; + +// This is the Selected SpellID Var, used to tell the OnTarget script what spell +// we are using after manual targetting +const string NUI_SPELLBOOK_SELECTED_SPELLID_VAR = "NUI_Spellbook_SpellId"; + +// This is the Selected FeatID Var, used to tell the OnTarget script what feat +// we are using after manual targetting +const string NUI_SPELLBOOK_SELECTED_FEATID_VAR = "NUI_Spellbook_FeatID"; + +// This is the Selected SubSpellID Var, used in conjuncture with the Selected FeatID +// to allow radial spells to work (it needs the master spell's featID and the sub spell's +// SpellID for it to work. +const string NUI_SPELLBOOK_SELECTED_SUBSPELL_SPELLID_VAR = "NUI_Spellbook_SubSpellID"; + +// This is the OnTarget action var saved to the player locally to say if we are +// using the NUI Spellbook spell or not. +const string NUI_SPELLBOOK_ON_TARGET_ACTION_VAR = "ONPLAYERTARGET_ACTION"; + +// This is a Boolean to tell the target script if the selected feat is a persoanl feat +// and can only be used on the executing object. +const string NUI_SPELLBOOK_ON_TARGET_IS_PERSONAL_FEAT = "NUI_Spellbook_IsPersonalFeat"; + +const string NUI_SPELL_DESCRIPTION_WINDOW_ID = "NUI_Spell_Description"; +const string NUI_SPELL_DESCRIPTION_OK_BUTTON = "NUIDescriptionOKButton"; + +// This is the limit of how many spell buttons we can have in a row before we +// need to start a new row on the NUI Spellbook. +const int NUI_SPELLBOOK_SPELL_BUTTON_LENGTH = 9; + +const string NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR = "NUI_Spellbook_GetBinderSpellToFeatDictionaryCache"; +const string NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR = "NUI_Spellbook_GetToBStanceSpellListCache_"; +const string NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR = "NUI_Spellbook_GetInvokerShapeSpellListCache_"; +const string NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR = "NUISpellbookClassEssence_"; + + + +////////////////////////////////////////////////// +// // +// NUI Power Attack // +// // +////////////////////////////////////////////////// + +// The Window ID for the Power Attack NUI +const string NUI_PRC_POWER_ATTACK_WINDOW = "nui_prc_power_attack_window"; + +// LocalVar for the geometry of the Power Attack NUI window +const string NUI_PRC_PA_GEOMETRY_VAR = "paNuiGeometry"; + +// Event For Left "-" button of the Power Attack NUI +const string NUI_PRC_PA_LEFT_BUTTON_EVENT = "nui_prc_pa_left_button_event"; +// Event For Right "+" Button of the Power Attack NUI +const string NUI_PRC_PA_RIGHT_BUTTON_EVENT = "nui_prc_pa_right_button_event"; + +// Bind for Text of the Power Attack NUI saying what the current Power Attack level is +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"; + +////////////////////////////////////////////////// +// // +// 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..9deed81 --- /dev/null +++ b/src/include/prc_nui_lv_inc.nss @@ -0,0 +1,3342 @@ +//:://///////////////////////////////////////////// +//:: 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); + } + if (GetIsBladeMagicClass(nClass)) + { + DeletePersistantLocalInt(oPC, "AllowedDisciplines"); + } + 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))); + if (nManCount >= prereqs) + return TRUE; + } + + return FALSE; +} + +int GetMaxInitiatorCircle(int nClass, object oPC=OBJECT_SELF) +{ + int initiatorLevel = GetInitiatorLevel(oPC, nClass); + // initiators learn by ceiling(classLevel) + int highestCircle = (initiatorLevel + 1) / 2; + if (highestCircle > 9) + return 9; + return highestCircle; +} + +int GetRemainingManeuverChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jManAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_MANEUVER_TOTAL); + int nManAmount = 0; + if (jManAmount != JsonNull()) + nManAmount = JsonGetInt(jManAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER); + + return maxAmount - nManAmount; +} + +int GetRemainingStanceChoices(int nClass, object oPC=OBJECT_SELF) +{ + json discInfo = GetDisciplineInfoObject(nClass, oPC); + + json jStanceAmount = JsonObjectGet(discInfo, NUI_LEVEL_UP_STANCE_TOTAL); + int nStanceAmount = 0; + if (jStanceAmount != JsonNull()) + nStanceAmount = JsonGetInt(jStanceAmount); + + int maxAmount = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE); + + return maxAmount - nStanceAmount; +} + +int IsAllowedDiscipline(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + // logic carried over from private function in discipline inc functions + // uses bitwise matching to tell if the discipline is allowed or not + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + int nOverride = GetPersistantLocalInt(oPC, "AllowedDisciplines"); + if(nOverride == 0) + { + switch(nClass) + { + case CLASS_TYPE_CRUSADER: nOverride = 322; break;//DISCIPLINE_DEVOTED_SPIRIT + DISCIPLINE_STONE_DRAGON + DISCIPLINE_WHITE_RAVEN + case CLASS_TYPE_SWORDSAGE: nOverride = 245; break;//DISCIPLINE_DESERT_WIND + DISCIPLINE_DIAMOND_MIND + DISCIPLINE_SETTING_SUN + DISCIPLINE_SHADOW_HAND + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + case CLASS_TYPE_WARBLADE: nOverride = 460; break;//DISCIPLINE_DIAMOND_MIND + DISCIPLINE_IRON_HEART + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + DISCIPLINE_WHITE_RAVEN + } + } + return nOverride & discipline; +} + +int IsRequiredForToBPRCClass(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + int currentClassPos = 1; + // loop through all the classes and look for a PRC + while (currentClassPos) + { + int currentClass = GetClassByPosition(currentClassPos, oPC); + // if we reached a non existant class, we reached the end. + if (currentClass != CLASS_TYPE_INVALID) + { + string sFile = GetClassSpellbookFile(nClass); + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + + // check if the class is a ToB PRC Class and if the current spell's + // discipline is used for it. + int isUsed = FALSE; + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL + && (discipline == DISCIPLINE_STONE_DRAGON)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER + && (discipline == DISCIPLINE_TIGER_CLAW)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR + && (discipline == DISCIPLINE_DEVOTED_SPIRIT)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_ETERNAL_BLADE + && (discipline == DISCIPLINE_DEVOTED_SPIRIT + || discipline == DISCIPLINE_DIAMOND_MIND)) + isUsed = TRUE; + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA + && (discipline == DISCIPLINE_SETTING_SUN + || discipline == DISCIPLINE_SHADOW_HAND)) + isUsed = TRUE; + + // if any of the above was true than we need to check if this spell + // is required for a PRC + if (isUsed) + { + // get the discipline info for all BladeMagic classes if we have them. + json discInfo = GetDisciplineInfoObject(nClass, oPC); + json classDisc2Info = JsonObject(); + json classDisc3Info = JsonObject(); + if (nClass == CLASS_TYPE_SWORDSAGE) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + } + if (nClass == CLASS_TYPE_CRUSADER) + { + if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_WARBLADE, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + if (nClass == CLASS_TYPE_WARBLADE) + { + if (GetLevelByClass(CLASS_TYPE_CRUSADER, oPC)) + classDisc2Info = GetDisciplineInfoObject(CLASS_TYPE_CRUSADER, oPC); + if (GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC)) + classDisc3Info = GetDisciplineInfoObject(CLASS_TYPE_SWORDSAGE, oPC); + } + + // Time to begin checking the PRCs + // this should follow the same logic as here + // https://gitea.raptio.us/Jaysyn/PRC8/src/commit/797442d3da7c9c8e1fcf585b97e2ff1cbe56045b/nwn/nwnprc/trunk/scripts/prc_prereq.nss#L991 + + // Check Deepstone Sentinel + if (currentClass == CLASS_TYPE_DEEPSTONE_SENTINEL) + { + // we need to look for 2 Stone Dragon Maneuvers and 1 Stone Dragon + // Stance. So add up the other MagicBlade classes and see if it is satisfied. + int stoneDMan, stoneDStance = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (stoneDMan >= 2 && stoneDStance >= 1) + return FALSE; + } + // if it still isn't satisfied than the current class is required + // for it to exist. Check to see if it is safe to remove the maneuever + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stoneDMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + stoneDStance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + //if the current maneuver is a stance, check to see if it is safe to remove + if (type == MANEUVER_TYPE_STANCE) + { + if (stoneDStance - 1 >= 1) + return FALSE; + } + else + { + // if it is not a stance we can just check the maneuevers in general + if (stoneDMan - 1 >= 2) + return FALSE; + } + + // this maneuver is required and should not be removed. + return TRUE; + } + } + + // Check Bloodclaw Master + if (currentClass == CLASS_TYPE_BLOODCLAW_MASTER) + { + // bloodclaw needs 3 Tiger Claw maneuevers + int tigerCMan = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan >= 3) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + tigerCMan += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + if (tigerCMan-1 >= 3) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_RUBY_VINDICATOR) + { + // Ruby Vindicator needs 1 stance and 1 maneuever from Devoted Spirit + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 1) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if (stance - 1 >= 1) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 1) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_JADE_PHOENIX_MAGE) + { + // Jade Phoenix needs 1 stance and 2 maneuvers of any type + int stance = 0; + int maneuver = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if (stance >= 1 && maneuver >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + stance += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + maneuver += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + if (type == MANEUVER_TYPE_STANCE) + { + if ((stance - 1 >= 1) && (maneuver -1 >= 2)) + return FALSE; + return TRUE; + } + if (maneuver - 1 >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_MASTER_OF_NINE) + { + // master of nine needs 1 maneuever from 6 different disciplines + + int totalDiscCount = 0; + int currentClassAndDiscUsed = 0; + int i; + // loop through each possible discipline + for (i = 0; i <= 256; i++) + { + int found = 0; + // only disciplines that exist are stored, and only those + // that are used are stored, so we can loop through and + // find what disciplines we do or don't know. + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + + if (!found) + { + json currentDisc = JsonObjectGet(classDisc3Info, IntToString(i)); + if (currentDisc != JsonNull()) + found = 1; + } + + if (!found) + { + json currentDisc = JsonObjectGet(discInfo, IntToString(i)); + if (currentDisc != JsonNull()) + { + if (i == discipline) + currentClassAndDiscUsed = 1; + found = 1; + } + } + + totalDiscCount += found; + } + // if we have more maneuevers than 6, it is not required + if (totalDiscCount > 6) + return FALSE; + // however if we have 6 and this discipline was grabbed we need to make sure it is safe to remove + if (currentClassAndDiscUsed) + { + // if we were to remove this discipline and it is 5 or less total disciplines we have now + // it is important + if (totalDiscCount - 1 >= 6) + return FALSE; + json currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + int stance = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + int maneuver = JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // if we were to remove this discipline and are left with no more than + // this was important and it can't be removed + if ((stance + maneuver - 1) >= 1) + return FALSE; + return TRUE; + } + return FALSE; + } + + if (currentClass == CLASS_TYPE_ETERNAL_BLADE) + { + //Eternal blade 2 Devoted Spirits OR 2 Diamond Mind + int nTotal = 0; + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DEVOTED_SPIRIT)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_DIAMOND_MIND)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nTotal >= 2) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(discipline)); + if (currentDisc != JsonNull()) + { + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + nTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + if ((nTotal - 1) >= 2) + return FALSE; + return TRUE; + } + } + + if (currentClass == CLASS_TYPE_SHADOW_SUN_NINJA) + { + // Shadow Sun Ninja needs 1 lvl2 Setting Sun OR Shadow Hand maneuever + // 1 Setting Sun maneuver AND 1 Shadow Hand maneuver + int nLvl2 = 0; + int shadowHTotal; + int settingSTotal; + + json currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc3Info, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(classDisc2Info, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + // stances here count as a maneuver so we need to count 2 + // to account for that + if (nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)) + return FALSE; + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SHADOW_HAND)); + if (currentDisc != JsonNull()) + { + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + shadowHTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + currentDisc = JsonObjectGet(discInfo, IntToString(DISCIPLINE_SETTING_SUN)); + if (currentDisc != JsonNull()) + { + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_STANCE))); + settingSTotal += JsonGetInt(JsonObjectGet(currentDisc, IntToString(MANEUVER_TYPE_MANEUVER))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_STANCE))); + nLvl2 += JsonGetInt(JsonObjectGet(currentDisc, "Level2_" + IntToString(MANEUVER_TYPE_MANEUVER))); + } + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + if (level == 2) + nLvl2 -= 1; + if (discipline == DISCIPLINE_SHADOW_HAND) + shadowHTotal -= 1; + else + settingSTotal -= 1; + + return !(nLvl2 && shadowHTotal && settingSTotal && (shadowHTotal >= 2 || settingSTotal >= 2)); + } + } + + currentClassPos += 1; + } + else + currentClassPos = 0; + } + + return FALSE; +} + +json AddSpellDisciplineInfo(string sFile, int spellbookId, json classDisc) +{ + json classDiscCopy = classDisc; + int discipline = StringToInt(Get2DACache(sFile, "Discipline", spellbookId)); + int type = StringToInt(Get2DACache(sFile, "Type", spellbookId)); + int level = StringToInt(Get2DACache(sFile, "Level", spellbookId)); + int prereq = StringToInt(Get2DACache(sFile, "Prereqs", spellbookId)); + + json jDisc = JsonObjectGet(classDisc, IntToString(discipline)); + if (jDisc == JsonNull()) + jDisc = JsonObject(); + + string levelKey = "Level" + IntToString(level) + "_" + IntToString(type); + int nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(type))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(type), JsonInt(nTypeTotal)); + + if (type != MANEUVER_TYPE_MANEUVER + && type != MANEUVER_TYPE_STANCE) + { + levelKey = "Level" + IntToString(level) + "_" + IntToString(MANEUVER_TYPE_MANEUVER); + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, levelKey)) + 1); + jDisc = JsonObjectSet(jDisc, levelKey, JsonInt(nTypeTotal)); + + nTypeTotal = (JsonGetInt(JsonObjectGet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER))) + 1); + jDisc = JsonObjectSet(jDisc, IntToString(MANEUVER_TYPE_MANEUVER), JsonInt(nTypeTotal)); + } + + string prereqKey = "Prereq_" + IntToString(prereq); + int nPrereqTotal = (JsonGetInt(JsonObjectGet(jDisc, prereqKey)) + 1); + jDisc = JsonObjectSet(jDisc, prereqKey, JsonInt(nPrereqTotal)); + + if (type == MANEUVER_TYPE_STANCE) + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_STANCE_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_STANCE_TOTAL, JsonInt(nTypeTotal)); + } + else + { + nTypeTotal = (JsonGetInt(JsonObjectGet(classDisc, NUI_LEVEL_UP_MANEUVER_TOTAL)) + 1); + classDiscCopy = JsonObjectSet(classDiscCopy, NUI_LEVEL_UP_MANEUVER_TOTAL, JsonInt(nTypeTotal)); + } + + return JsonObjectSet(classDiscCopy, IntToString(discipline), jDisc); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Invokers /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetInvokerKnownListObject(int nClass, object oPC=OBJECT_SELF) +{ + json knownObject = GetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass)); + if (knownObject == JsonNull()) + knownObject = JsonObject(); + else + return knownObject; + + string sFile = GetAMSKnownFileName(nClass); + int totalRows = Get2DARowCount(sFile); + int maxInvocLevel = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", totalRows-1)); + json previousInvocList = JsonObject(); + + int i; + for (i = 1; i <= maxInvocLevel; i++) + { + previousInvocList = JsonObjectSet(previousInvocList, IntToString(i), JsonInt(0)); + } + + for (i = 0; i < totalRows; i++) + { + int maxInvocation = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", i)); + int invocationKnown = StringToInt(Get2DACache(sFile, "InvocationKnown", i)); + json invocList = previousInvocList; + + int previousInvocTotal = 0; + if (i > 0) + previousInvocTotal = StringToInt(Get2DACache(sFile, "InvocationKnown", i-1)); + int previousInvocAmount = JsonGetInt(JsonObjectGet(previousInvocList, IntToString(maxInvocation))); + int currentInvocationAmount = (invocationKnown - previousInvocTotal + previousInvocAmount); + + invocList = JsonObjectSet(invocList, IntToString(maxInvocation), JsonInt(currentInvocationAmount)); + knownObject = JsonObjectSet(knownObject, IntToString(i+1), invocList); + previousInvocList = invocList; + } + + SetLocalJson(oPC, NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR + IntToString(nClass), knownObject); + return knownObject; +} + +int GetRemainingInvocationChoices(int nClass, int chosenCircle, object oPC=OBJECT_SELF, int extra=TRUE) +{ + int remaining = 0; + int nLevel = GetInvokerLevel(oPC, nClass); + + json knownObject = GetInvokerKnownListObject(nClass, oPC); + json chosenInv = GetChosenSpellListObject(nClass, oPC); + json currentLevelKnown = JsonObjectGet(knownObject, IntToString(nLevel)); + + int totalCircles = JsonGetLength(JsonObjectKeys(currentLevelKnown)); + + // logic goes we are given a set amount of invocations at each circle. We can + // take from a circle above us, but not below us. So we need to make sure + // we have a legal amount of choices + int i; + for (i = 1; i <= totalCircles; i++) + { + int currentChosen = 0; + json chosenSpells = JsonObjectGet(chosenInv, IntToString(i)); + if (chosenSpells != JsonNull()) + { + int totalChosen = JsonGetLength(chosenSpells); + int j; + for (j = 0; j < totalChosen; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(chosenSpells, j)); + // only count non extra invocation choices + if (!IsExtraChoiceInvocation(nClass, spellbookId, oPC)) + currentChosen += 1; + } + } + + int allowedAtCircle = JsonGetInt(JsonObjectGet(currentLevelKnown, IntToString(i))); + + remaining = (allowedAtCircle - currentChosen + remaining); + // if the circle is below the chosen circle and we have a positive remaining, + // we set it to 0 because we cannot use lower circle spells on higher circle. + // however if thge value is negative then we carry it over because we + // have a deficit and need to account for it by using the spells of the + // next circle. + if (i < chosenCircle && remaining > 0) + remaining = 0; + } + + + // count extra and epic invocation choices + if (extra) + { + string sFile = GetAMSKnownFileName(nClass); + int maxCircle = StringToInt(Get2DACache(sFile, "MaxInvocationLevel", nLevel-1)); + + if (GetHasFeat(FEAT_EXTRA_INVOCATION_I, oPC) && (chosenCircle <= (maxCircle-1))) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA); + json expChoices = GetExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + if (GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I, oPC)) + { + int totalExp = GetMaxInvocationCount(oPC, INVOCATION_LIST_EXTRA_EPIC); + json expChoices = GetEpicExpandedChoicesList(nClass, oPC); + int choicesCount = JsonGetLength(JsonObjectKeys(expChoices)); + remaining += (totalExp - choicesCount); + } + } + + return remaining; +} + +int IsExtraChoiceInvocation(int nClass, int spellbookId, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + string spellId = Get2DACache(sFile, "SpellID", spellbookId); + json extraChoices = GetExpandedChoicesList(nClass, oPC); + json chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + extraChoices = GetEpicExpandedChoicesList(nClass, oPC); + chosenSpell = JsonObjectGet(extraChoices, spellId); + if (chosenSpell != JsonNull()) + return TRUE; + + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Truenamer /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +int GetRemainingTruenameChoices(int nClass, int nType, object oPC=OBJECT_SELF) +{ + string sFile = GetClassSpellbookFile(nClass); + json chosenSpells = GetChosenSpellListObject(nClass, oPC); + json circles = JsonObjectKeys(chosenSpells); + int totalCircles = JsonGetLength(circles); + + int remainingChoices = 0; + + int i; + for (i = 0; i < totalCircles; i++) + { + json spellList = JsonObjectGet(chosenSpells, JsonGetString(JsonArrayGet(circles, i))); + if (spellList != JsonNull()) + { + int totalChoices = JsonGetLength(spellList); + + int j; + for (j = 0; j < totalChoices; j++) + { + int spellbookId = JsonGetInt(JsonArrayGet(spellList, j)); + int lexicon = StringToInt(Get2DACache(sFile, "Lexicon", spellbookId)); + // -1 means count all lexicons + if (nType == -1 || lexicon == nType) + remainingChoices += 1; + } + } + } + + int maxChoices; + // if -1 we count all lexicons to get total remaining + if (nType == -1) + maxChoices = (GetMaxUtteranceCount(oPC, nClass, LEXICON_CRAFTED_TOOL) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_EVOLVING_MIND) + + GetMaxUtteranceCount(oPC, nClass, LEXICON_PERFECTED_MAP)); + else + maxChoices = GetMaxUtteranceCount(oPC, nClass, nType); + return (maxChoices - remainingChoices); +} + +int GetLexiconCircleKnownAtLevel(int nLevel, int nType) +{ + + string sFile = "cls_true_maxlvl"; + + string columnName; + if (nType == LEXICON_EVOLVING_MIND) + columnName = "EvolvingMind"; + else if (nType == LEXICON_CRAFTED_TOOL) + columnName = "CraftedTool"; + else + columnName = "PerfectedMap"; + + return StringToInt(Get2DACache(sFile, columnName, nLevel-1)); +} + +//////////////////////////////////////////////////////////////////////////// +/// /// +/// Archivist /// +/// /// +//////////////////////////////////////////////////////////////////////////// + +json GetArchivistNewSpellsList(object oPC=OBJECT_SELF) +{ + json retValue = GetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR); + if (retValue == JsonNull()) + retValue = JsonArray(); + else + return retValue; + + SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue); + return retValue; +} + +//:: void main(){} \ No newline at end of file diff --git a/src/include/prc_nui_sb_inc.nss b/src/include/prc_nui_sb_inc.nss new file mode 100644 index 0000000..3f901d3 --- /dev/null +++ b/src/include/prc_nui_sb_inc.nss @@ -0,0 +1,845 @@ +//:://///////////////////////////////////////////// +//:: PRC Spellbook Script +//:: prc_nui_sb_inc +//::////////////////////////////////////////////// +/* + This is the script that handles some backend work for the PRC Spellbook + NUI View +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 24.05.2005 +//::////////////////////////////////////////////// + +#include "prc_nui_com_inc" + +// +// GetSpellListForCircle +// Gets the spell list for a specified class at the specified circle. +// +// Arguments: +// oPlayer:object the player +// nClass:int the ClassID +// circle:int the circle we want to grab for +// +// Returns: +// json:Array a list of all the spellIDs of the given circle +// +json GetSpellListForCircle(object oPlayer, int nClass, int circle); + +// +// GetSupportedNUISpellbookClasses +// Gets the list of support PRC classes that can use the NUi spellbook that +// the player has. +// +// Arguments: +// oPlayer:object the player this is being determined for +// +// Returns: +// json:int list of class ids that have the player has that can use the +// NUI spellbook. +// +json GetSupportedNUISpellbookClasses(object oPlayer); + +// +// IsSpellKnown +// Returns whether the player with the given class, spell file, and spellbook id +// knows the spell or not +// +// Arguments: +// oPlayer;Object the player +// nClass:int the class ID +// spellId:int the spell ID to check +// +// Returns: +// int:Boolean TRUE if spell is known, FALSE otherwise +// +int IsSpellKnown(object oPlayer, int nClass, int spellId); + +// +// IsClassAllowedToUseNUISpellbook +// Takes a player and a classId and determines if thee class is allowed to +// be using the NUI spellbook. +// +// Arguments: +// oPlayer:Object the player +// nClass:int the ClassID +// +// Returns: +// int:Boolean TRUE if allowed to use the spellbook, FALSE otherwise +// +int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass); + +// +// CanClassUseMetamagicFeats +// Given a class id determines if it is allowed to use the Metamagic feats +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise +// +int CanClassUseMetamagicFeats(int nClass); + +// +// CanClassUseSuddenMetamagicFeats +// Given a class id determines if it is allowed to use the Sudden Metamagic feats +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise +// +int CanClassUseSuddenMetamagicFeats(int nClass); + +// +// CanClassUseMetaPsionicFeats +// Given a class id determines if it is allowed to use the MetaPsionic feats +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise +// +int CanClassUseMetaPsionicFeats(int nClass); + +// +// CanClassUseMetaMysteryFeats +// Given a class id determines if it is allowed to use the MetaMystery feats +// +// Arguments: +// nClass:int the ClassID +// +// Returns: +// int:Boolean TRUE if allowed to use the set of feats, FALSE otherwise +// +int CanClassUseMetaMysteryFeats(int nClass); + +// +// GetMetaMagicFeatList +// Gets the list of MetaMagic featIDs +// +// Returns: +// json:Array the list of FeatIDs associated with the meta feats +// +json GetMetaMagicFeatList(); + +// +// GetSuddenMetaMagicFeatList +// Gets the list of Sudden MetaMagic featIDs +// +// Returns: +// json:Array the list of FeatIDs associated with the meta feats +// +json GetSuddenMetaMagicFeatList(); + +// +// GetMetaPsionicFeatList +// Gets the list of MetaPsionic featIDs +// +// Returns: +// json:Array the list of FeatIDs associated with the meta feats +// +json GetMetaPsionicFeatList(); + +// +// GetMetaMagicMysteryList +// Gets the list of MetaMystery featIDs +// +// Returns: +// json:Array the list of FeatIDs associated with the meta feats +// +json GetMetaMysteryFeatList(); + +// +// GetTrueClassIfRHD +// Checks to make sure if the provided RHD class and player's race +// match up to give them their proper spell caster class (ie Glouras have +// bard spells and thus should be treated like a bard class) +// +// Arguments: +// oPlayer:object the player +// nClass:int the ClassID +// +// Returns: +// int the true ClassID to use, otherwise nClass +// +int GetTrueClassIfRHD(object oPlayer, int nClass); + +// +// ShouldAddSpell +// Given a spellId and a class, determines if the spell should be added to the +// spellbook (as some are added in it's own special row or for other reasons) +// +// Arguments: +// nClass:int the ClassID +// spellId:int the SpellID +// oPlayer:object the player +// +// Returns: +// int:Boolean TRUE if the spell should be added, FALSE otherwise +// +int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF); + +// +// GetToBStanceSpellList +// Gets the ToB Stance Spell List for the given class +// +// Arguments: +// nClass:int ClassID +// oPlayer:object the player +// +// Returns: +// json:Array the list of stances' SpellIDs +// +json GetToBStanceSpellList(int nClass, object oPlayer=OBJECT_SELF); + +// +// GetInvokerShapeSpellList +// Gets the Invoker Shapes Spell List for the given class +// +// Arguments: +// nClass:int ClassID +// oPlayer:object the player +// +// Returns: +// json:Array the list of shapes' SpellIDs +// +json GetInvokerShapeSpellList(int nClass, object oPlayer=OBJECT_SELF); + +// +// GetInvokerEssenceSpellList +// Gets the Invoker Essences Spell List for the given class +// +// Arguments: +// nClass:int ClassID +// oPlayer:object the player +// +// Returns: +// json:Array the list of essences' SpellIDs +// +json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF); + +// +// JsonArrayContainsInt +// A helper function that takes a json array list and sees if the int item is within i +// +// Arguments: +// list:json:Array the list of ints +// item:int the item we are looking for +// +// Returns: +// int:Boolean TRUE if item is found, FALSE otherwise +// +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(); + string sFile = GetClassSpellbookFile(nClass); + int totalSpells; + json binderDictKeys; + //Special case for Binder since they don't have their own spellbook 2da + if (nClass == CLASS_TYPE_BINDER) + { + json binderDict = GetBinderSpellToFeatDictionary(oPlayer); + + // we loop through the list of SpellIDs + binderDictKeys = JsonObjectKeys(binderDict); + totalSpells = JsonGetLength(binderDictKeys); + } + else + totalSpells = Get2DARowCount(sFile); + + int i; + for (i = 0; i < totalSpells; i++) + { + int currentSpell; + if (nClass == CLASS_TYPE_BINDER) + currentSpell = StringToInt(JsonGetString(JsonArrayGet(binderDictKeys, i))); + else + currentSpell = StringToInt(Get2DACache(sFile, "SpellID", i)); + + if (ShouldAddSpell(nClass, currentSpell, oPlayer)) + { + string sSpellLevel = Get2DACache("spells", "Innate", currentSpell); + int iSpellLevel = StringToInt(sSpellLevel); + + if (nClass == CLASS_TYPE_BINDER && IsSpellKnown(oPlayer, nClass, currentSpell)) + { + retValue = JsonArrayInsert(retValue, JsonInt(currentSpell)); + } + else if ((iSpellLevel == circle && IntToString(iSpellLevel) == sSpellLevel)) + { + // We add the spell if it is known and is not a radial master spell (since those don't work) + if (IsSpellKnown(oPlayer, nClass, currentSpell)) + retValue = JsonArrayInsert(retValue, JsonInt(i)); + } + } + } + + return retValue; +} + +int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF) +{ + int isRadialMasterSpell = StringToInt(Get2DACache("spells", "SubRadSpell1", spellId)); + // We don't add radial master spells + if (isRadialMasterSpell) + return FALSE; + // we don't add essences and shapes + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT + || nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + json ignoreList = GetInvokerShapeSpellList(nClass, oPlayer); + if (JsonArrayContainsInt(ignoreList, spellId)) + return FALSE; + ignoreList = GetInvokerEssenceSpellList(nClass, oPlayer); + if (JsonArrayContainsInt(ignoreList, spellId)) + return FALSE; + } + // we don't add stances + if (nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER) + { + json ignoreList = GetToBStanceSpellList(nClass, oPlayer); + if (JsonArrayContainsInt(ignoreList, spellId)) + return FALSE; + } + + return TRUE; +} + +json GetSupportedNUISpellbookClasses(object oPlayer) +{ + json retValue = JsonArray(); + int i = 1; + while(i >= 1) + { + int classId = GetClassByPosition(i, oPlayer); + if (classId != CLASS_TYPE_INVALID) + { + if (IsClassAllowedToUseNUISpellbook(oPlayer, classId)) + { + classId = GetTrueClassIfRHD(oPlayer, classId); + retValue = JsonArrayInsert(retValue, JsonInt(classId)); + } + i++; + } + else + { + i = -1; + } + } + + return retValue; +} + +int IsSpellKnown(object oPlayer, int nClass, int spellId) +{ + // special case for Binders since they don't have a spell book 2da. + if (nClass == CLASS_TYPE_BINDER) + { + json binderDict = GetBinderSpellToFeatDictionary(oPlayer); + int featID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId))); + return GetHasFeat(featID, oPlayer); + } + + int currentSpell = spellId; + int masterSpell = StringToInt(Get2DACache("spells", "Master", currentSpell)); + if (masterSpell) // If this is not 0 then this is a radial spell, check the radial master + currentSpell = masterSpell; + + string sFeatID = Get2DACache("spells", "FeatID", currentSpell); + int iFeatID = StringToInt(sFeatID); + + if (IntToString(iFeatID) == sFeatID) + return GetHasFeat(iFeatID, oPlayer); + + return FALSE; +} + +int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass) +{ + // This controls who can use the Spellbook NUI, if for some reason you don't + // want a class to be allowed to use this you can comment out their line here + + // Bard and Sorc are allowed if they took a PRC that makes them use the spellbook + if ((nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER) + && GetPrCAdjustedClassLevel(nClass, oPlayer) > GetLevelByClass(nClass, oPlayer)) + return TRUE; + + // Arcane Spont + if (nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_CELEBRANT_SHARESS + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_DUSKBLADE + || nClass == CLASS_TYPE_HARPER + || nClass == CLASS_TYPE_HEXBLADE + || nClass == CLASS_TYPE_KNIGHT_WEAVE + || nClass == CLASS_TYPE_SHADOWLORD + || nClass == CLASS_TYPE_SUBLIME_CHORD + || nClass == CLASS_TYPE_SUEL_ARCHANAMACH + || nClass == CLASS_TYPE_WARMAGE) + return TRUE; + + // Psionics + 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) + return TRUE; + + // Invokers + if (nClass == CLASS_TYPE_WARLOCK + || nClass == CLASS_TYPE_DRAGON_SHAMAN + || nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + return TRUE; + + // Divine Spont + if (nClass == CLASS_TYPE_ARCHIVIST //while technically prepared, they use the spont system of casting + || nClass == CLASS_TYPE_FAVOURED_SOUL + || nClass == CLASS_TYPE_JUSTICEWW) + return TRUE; + + // ToB Classes + if (nClass == CLASS_TYPE_WARBLADE + || nClass == CLASS_TYPE_SWORDSAGE + || nClass == CLASS_TYPE_CRUSADER) + return TRUE; + + // Mystery Classes + if (nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH) + return TRUE; + + // Truenamers + if (nClass == CLASS_TYPE_TRUENAMER) + return TRUE; + + // RHD Casters + if ((nClass == CLASS_TYPE_SHAPECHANGER + && GetRacialType(oPlayer) == RACIAL_TYPE_ARANEA + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_OUTSIDER + && GetRacialType(oPlayer) == RACIAL_TYPE_RAKSHASA + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_ABERRATION + && GetRacialType(oPlayer) == RACIAL_TYPE_DRIDER + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_ARKAMOI + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_HOBGOBLIN_WARSOUL + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_REDSPAWN_ARCANISS + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_MARRUTACT + && !GetLevelByClass(CLASS_TYPE_SORCERER)) + || (nClass == CLASS_TYPE_FEY + && GetRacialType(oPlayer) == RACIAL_TYPE_GLOURA + && !GetLevelByClass(CLASS_TYPE_BARD))) + return TRUE; + + // Binders + if (nClass == CLASS_TYPE_BINDER) + return TRUE; + + return FALSE; +} + +int GetTrueClassIfRHD(object oPlayer, int nClass) +{ + if (nClass == CLASS_TYPE_SHAPECHANGER + && GetRacialType(oPlayer) == RACIAL_TYPE_ARANEA) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_OUTSIDER + && GetRacialType(oPlayer) == RACIAL_TYPE_RAKSHASA) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_ABERRATION + && GetRacialType(oPlayer) == RACIAL_TYPE_DRIDER) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_ARKAMOI) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_HOBGOBLIN_WARSOUL) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_REDSPAWN_ARCANISS) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_MONSTROUS + && GetRacialType(oPlayer) == RACIAL_TYPE_MARRUTACT) + return CLASS_TYPE_SORCERER; + if (nClass == CLASS_TYPE_FEY + && GetRacialType(oPlayer) == RACIAL_TYPE_GLOURA) + return CLASS_TYPE_BARD; + + return nClass; +} + +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_BARD + || nClass == CLASS_TYPE_SORCERER + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_DUSKBLADE + || nClass == CLASS_TYPE_HEXBLADE + || nClass == CLASS_TYPE_JUSTICEWW + || nClass == CLASS_TYPE_SUBLIME_CHORD + || nClass == CLASS_TYPE_SUEL_ARCHANAMACH + || nClass == CLASS_TYPE_FAVOURED_SOUL + || nClass == CLASS_TYPE_WARMAGE); +} + +int CanClassUseSuddenMetamagicFeats(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 Sudden Metamagic + return (nClass == CLASS_TYPE_SHADOWLORD + || nClass == CLASS_TYPE_ARCHIVIST + || nClass == CLASS_TYPE_BARD + || nClass == CLASS_TYPE_BEGUILER + || nClass == CLASS_TYPE_DREAD_NECROMANCER + || nClass == CLASS_TYPE_DUSKBLADE + || nClass == CLASS_TYPE_FAVOURED_SOUL + || nClass == CLASS_TYPE_HEXBLADE + || nClass == CLASS_TYPE_JUSTICEWW + || nClass == CLASS_TYPE_KNIGHT_WEAVE + || nClass == CLASS_TYPE_SUBLIME_CHORD + || nClass == CLASS_TYPE_SORCERER + || nClass == CLASS_TYPE_SUEL_ARCHANAMACH + || nClass == CLASS_TYPE_WARMAGE); +} + +int CanClassUseMetaPsionicFeats(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 Metapsionics + return (nClass == CLASS_TYPE_FIST_OF_ZUOKEN + || nClass == CLASS_TYPE_PSION + || nClass == CLASS_TYPE_PSYCHIC_ROGUE + || nClass == CLASS_TYPE_PSYWAR + || nClass == CLASS_TYPE_WARMIND + || nClass == CLASS_TYPE_WILDER); +} + +int CanClassUseMetaMysteryFeats(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 Metamysteries + return (nClass == CLASS_TYPE_SHADOWCASTER + || nClass == CLASS_TYPE_SHADOWSMITH); +} + +json GetMetaMagicFeatList() +{ + json metaFeats = JsonArray(); + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_STILL_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SILENT_SPELL_ABILITY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + + return metaFeats; +} + +json GetSuddenMetaMagicFeatList() +{ + json metaFeats = JsonArray(); + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_EXTEND)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_EMPOWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_MAXIMIZE)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SUDDEN_WIDEN)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + + return metaFeats; +} + +json GetMetaPsionicFeatList() +{ + json metaFeats = JsonArray(); + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_WIDEN_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_CHAIN_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_TWIN_POWER)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SPLIT_PSIONIC_RAY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + + return metaFeats; +} + +json GetMetaMysteryFeatList() +{ + json metaFeats = JsonArray(); + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EXTEND_MYSTERY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_EMPOWER_MYSTERY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_MAXIMIZE_MYSTERY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_QUICKEN_MYSTERY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_STILL_MYSTERY)); + metaFeats = JsonArrayInsert(metaFeats, JsonInt(spellId)); + + return metaFeats; +} + +json GetToBStanceSpellList(int nClass, object oPlayer=OBJECT_SELF) +{ + // caching + json stanceSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR + IntToString(nClass)); + if (stanceSpells == JsonNull()) + stanceSpells = JsonArray(); + else + return stanceSpells; + + string sFile = GetClassSpellbookFile(nClass); + int totalRows = Get2DARowCount(sFile); + + int i; + for (i = 0; i < totalRows; i++) + { + int Type = StringToInt(Get2DACache(sFile, "Type", i)); + if (Type == 1) + { + int spellId = StringToInt(Get2DACache(sFile, "SpellID", i)); + stanceSpells = JsonArrayInsert(stanceSpells, JsonInt(spellId)); + } + } + + SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_STANCES_CACHE_BASE_VAR + IntToString(nClass), stanceSpells); + return stanceSpells; +} + +json GetInvokerShapeSpellList(int nClass, object oPlayer=OBJECT_SELF) +{ + // caching + json shapeSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR + IntToString(nClass)); + if (shapeSpells == JsonNull()) + shapeSpells = JsonArray(); + else + return shapeSpells; + + string sFile = GetClassSpellbookFile(nClass); + int totalRows = Get2DARowCount(sFile); + + if (nClass == CLASS_TYPE_WARLOCK) + { + // Add the ELdritch Blast shapes + // TODO: Replace these magic SpellID ints with consts + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(INVOKE_ELDRITCH_BLAST)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18216)); // Eldritch Chain + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18245)); // Eldritch Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18261)); // Eldritch Doom + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18172)); // Glaive + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18246)); // Eldritch Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(18173)); // Eldritch Spear + } + + if (nClass == CLASS_TYPE_DRAGON_SHAMAN) + { + // Add the Dragon Shaman Auras + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_ENERGY)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_ENERGYSHLD)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_INSIGHT)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_MAGICPOWER)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_POWER)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_PRESENCE)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_RESISTANCE)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_RESOLVE)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_SENSES)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_STAMINA)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_SWIFTNESS)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_TOUGHNESS)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_DRAGONSHAMAN_AURA_VIGOR)); + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(spellId)); + } + + if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + { + // Add Dragon Adept Breaths + // TODO: Replace these magic SpellID ints with consts + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2102)); // Fire Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2103)); // Fire Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2104)); // Frost Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2105)); // Electric Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2106)); // Sickness Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2108)); // Acid Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2109)); // Acid Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2111)); // Slow Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2112)); // Weakening Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2115)); // Sleep Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2116)); // Thunder Cone + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2117)); // Bahamut Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2118)); // Force Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2119)); // Paralyzation Line + shapeSpells = JsonArrayInsert(shapeSpells, JsonInt(2120)); // Tiamat Breath + } + + + SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_SHAPES_CACHE_BASE_VAR + IntToString(nClass), shapeSpells); + return shapeSpells; +} + +json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF) +{ + //caching + json essenceSpells = GetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR + IntToString(nClass)); + if (essenceSpells == JsonNull()) + essenceSpells = JsonArray(); + else + return essenceSpells; + + if (nClass == CLASS_TYPE_WARLOCK) + { + // Add Eldritch Essences + // TODO: Replace these magic SpellID ints with consts + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18177)); // Hideous Blow + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18189)); // Baneful Abberation + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18190)); // Baneful Beast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18191)); // Baneful Construct + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18192)); // Baneful Dragon + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18193)); // Baneful Dwarf + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18194)); // Baneful Elemental + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18195)); // Baneful Elf + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18196)); // baneful Fey + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18197)); // Baneful Giant + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18198)); // Baneful Goblinoid + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18199)); // Baneful Gnome + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18200)); // Baneful Halfling + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18201)); // Baneful Human + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18202)); // Baneful Monsterous + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18203)); // Baneful Orc + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18204)); // Baneful Outsider + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18205)); // Baneful Plant + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18206)); // Baneful Reptilian + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18207)); // Baneful Shapechanger + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18208)); // Baneful Undead + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18209)); // Baneful Vermin + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18210)); // Beshadowed Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18240)); // Bewitching Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18257)); // Binding Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18211)); // Brimstone Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18175)); // Frightful Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18176)); // Hammer Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18183)); // Sickening Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HEALING_BLAST)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_BLAST)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_BLOW)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_CHAIN)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_CONE)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_DOOM)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_GLAIVE)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_LINE)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(INVOKE_HELLFIRE_SPEAR)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18220)); // Hellrime Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18177)); // Hideous Blow + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18249)); // Hindering Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18251)); // Noxious Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18253)); // Penetrating Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18267)); // Utterdark Blast + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(18255)); // Vitriolic Blast + } + + if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT) + { + // Add the Dragonfire Adept Shapes + int spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_SHAPED_ADEPTBREATH)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_CLOUD_ADEPTBREATH)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); + spellId = StringToInt(Get2DACache("feat", "SPELLID", FEAT_ENDURE_ADEPTBREATH)); + essenceSpells = JsonArrayInsert(essenceSpells, JsonInt(spellId)); + } + + SetLocalJson(oPlayer, NUI_SPELLBOOK_CLASS_ESSENCE_CACHE_BASE_VAR + IntToString(nClass), essenceSpells); + return essenceSpells; +} + +int JsonArrayContainsInt(json list, int item) +{ + int totalCount = JsonGetLength(list); + + int i; + for (i = 0; i < totalCount; i++) + { + if (JsonGetInt(JsonArrayGet(list, i)) == 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; +} diff --git a/src/prc8/include/prc_nui_sbd_inc.nss b/src/include/prc_nui_sbd_inc.nss similarity index 100% rename from src/prc8/include/prc_nui_sbd_inc.nss rename to src/include/prc_nui_sbd_inc.nss diff --git a/src/prc8/include/prc_racial_const.nss b/src/include/prc_racial_const.nss similarity index 100% rename from src/prc8/include/prc_racial_const.nss rename to src/include/prc_racial_const.nss diff --git a/src/prc8/include/prc_shifter_info.nss b/src/include/prc_shifter_info.nss similarity index 100% rename from src/prc8/include/prc_shifter_info.nss rename to src/include/prc_shifter_info.nss diff --git a/src/prc8/include/prc_sp_func.nss b/src/include/prc_sp_func.nss similarity index 100% rename from src/prc8/include/prc_sp_func.nss rename to src/include/prc_sp_func.nss diff --git a/src/prc8/include/prc_spell_const.nss b/src/include/prc_spell_const.nss similarity index 99% rename from src/prc8/include/prc_spell_const.nss rename to src/include/prc_spell_const.nss index bb8b1cd..b90a3dc 100644 --- a/src/prc8/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; diff --git a/src/prc8/include/prc_spellf_inc.nss b/src/include/prc_spellf_inc.nss similarity index 100% rename from src/prc8/include/prc_spellf_inc.nss rename to src/include/prc_spellf_inc.nss diff --git a/src/prc8/include/prc_spellhook.nss b/src/include/prc_spellhook.nss similarity index 100% rename from src/prc8/include/prc_spellhook.nss rename to src/include/prc_spellhook.nss diff --git a/src/prc8/include/prc_string_inc.nss b/src/include/prc_string_inc.nss similarity index 100% rename from src/prc8/include/prc_string_inc.nss rename to src/include/prc_string_inc.nss diff --git a/src/prc8/include/prc_template_con.nss b/src/include/prc_template_con.nss similarity index 100% rename from src/prc8/include/prc_template_con.nss rename to src/include/prc_template_con.nss diff --git a/src/prc8/include/prc_weap_apt.nss b/src/include/prc_weap_apt.nss similarity index 100% rename from src/prc8/include/prc_weap_apt.nss rename to src/include/prc_weap_apt.nss diff --git a/src/prc8/include/prc_x2_craft.nss b/src/include/prc_x2_craft.nss similarity index 99% rename from src/prc8/include/prc_x2_craft.nss rename to src/include/prc_x2_craft.nss index 5834f63..ddcaf9a 100644 --- a/src/prc8/include/prc_x2_craft.nss +++ b/src/include/prc_x2_craft.nss @@ -44,14 +44,14 @@ 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; @@ -593,7 +593,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 +624,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 +728,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 +884,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 +896,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 +1027,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 +1175,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)); diff --git a/src/prc8/include/prc_x2_itemprop.nss b/src/include/prc_x2_itemprop.nss similarity index 99% rename from src/prc8/include/prc_x2_itemprop.nss rename to src/include/prc_x2_itemprop.nss index e4a1be0..1ccb454 100644 --- a/src/prc8/include/prc_x2_itemprop.nss +++ b/src/include/prc_x2_itemprop.nss @@ -1883,7 +1883,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/prc8/include/prcsp_archmaginc.nss b/src/include/prcsp_archmaginc.nss similarity index 100% rename from src/prc8/include/prcsp_archmaginc.nss rename to src/include/prcsp_archmaginc.nss diff --git a/src/prc8/include/prcsp_engine.nss b/src/include/prcsp_engine.nss similarity index 100% rename from src/prc8/include/prcsp_engine.nss rename to src/include/prcsp_engine.nss diff --git a/src/prc8/include/prcsp_reputation.nss b/src/include/prcsp_reputation.nss similarity index 100% rename from src/prc8/include/prcsp_reputation.nss rename to src/include/prcsp_reputation.nss diff --git a/src/prc8/include/prgt_inc.nss b/src/include/prgt_inc.nss similarity index 100% rename from src/prc8/include/prgt_inc.nss rename to src/include/prgt_inc.nss diff --git a/src/prc8/include/prgt_inc_trap.nss b/src/include/prgt_inc_trap.nss similarity index 100% rename from src/prc8/include/prgt_inc_trap.nss rename to src/include/prgt_inc_trap.nss diff --git a/src/prc8/include/psi_inc_ac_const.nss b/src/include/psi_inc_ac_const.nss similarity index 100% rename from src/prc8/include/psi_inc_ac_const.nss rename to src/include/psi_inc_ac_const.nss diff --git a/src/prc8/include/psi_inc_ac_convo.nss b/src/include/psi_inc_ac_convo.nss similarity index 100% rename from src/prc8/include/psi_inc_ac_convo.nss rename to src/include/psi_inc_ac_convo.nss diff --git a/src/prc8/include/psi_inc_ac_manif.nss b/src/include/psi_inc_ac_manif.nss similarity index 100% rename from src/prc8/include/psi_inc_ac_manif.nss rename to src/include/psi_inc_ac_manif.nss diff --git a/src/prc8/include/psi_inc_ac_spawn.nss b/src/include/psi_inc_ac_spawn.nss similarity index 100% rename from src/prc8/include/psi_inc_ac_spawn.nss rename to src/include/psi_inc_ac_spawn.nss diff --git a/src/prc8/include/psi_inc_augment.nss b/src/include/psi_inc_augment.nss similarity index 100% rename from src/prc8/include/psi_inc_augment.nss rename to src/include/psi_inc_augment.nss diff --git a/src/prc8/include/psi_inc_const.nss b/src/include/psi_inc_const.nss similarity index 100% rename from src/prc8/include/psi_inc_const.nss rename to src/include/psi_inc_const.nss diff --git a/src/prc8/include/psi_inc_core.nss b/src/include/psi_inc_core.nss similarity index 100% rename from src/prc8/include/psi_inc_core.nss rename to src/include/psi_inc_core.nss diff --git a/src/prc8/include/psi_inc_enrgypow.nss b/src/include/psi_inc_enrgypow.nss similarity index 100% rename from src/prc8/include/psi_inc_enrgypow.nss rename to src/include/psi_inc_enrgypow.nss diff --git a/src/prc8/include/psi_inc_metapsi.nss b/src/include/psi_inc_metapsi.nss similarity index 100% rename from src/prc8/include/psi_inc_metapsi.nss rename to src/include/psi_inc_metapsi.nss diff --git a/src/prc8/include/psi_inc_onhit.nss b/src/include/psi_inc_onhit.nss similarity index 100% rename from src/prc8/include/psi_inc_onhit.nss rename to src/include/psi_inc_onhit.nss diff --git a/src/prc8/include/psi_inc_powknown.nss b/src/include/psi_inc_powknown.nss similarity index 100% rename from src/prc8/include/psi_inc_powknown.nss rename to src/include/psi_inc_powknown.nss diff --git a/src/prc8/include/psi_inc_ppoints.nss b/src/include/psi_inc_ppoints.nss similarity index 100% rename from src/prc8/include/psi_inc_ppoints.nss rename to src/include/psi_inc_ppoints.nss diff --git a/src/prc8/include/psi_inc_psicraft.nss b/src/include/psi_inc_psicraft.nss similarity index 100% rename from src/prc8/include/psi_inc_psicraft.nss rename to src/include/psi_inc_psicraft.nss diff --git a/src/prc8/include/psi_inc_psifunc.nss b/src/include/psi_inc_psifunc.nss similarity index 100% rename from src/prc8/include/psi_inc_psifunc.nss rename to src/include/psi_inc_psifunc.nss diff --git a/src/prc8/include/psi_inc_pwresist.nss b/src/include/psi_inc_pwresist.nss similarity index 100% rename from src/prc8/include/psi_inc_pwresist.nss rename to src/include/psi_inc_pwresist.nss diff --git a/src/prc8/include/psi_inc_soulkn.nss b/src/include/psi_inc_soulkn.nss similarity index 100% rename from src/prc8/include/psi_inc_soulkn.nss rename to src/include/psi_inc_soulkn.nss diff --git a/src/prc8/include/psi_power_const.nss b/src/include/psi_power_const.nss similarity index 100% rename from src/prc8/include/psi_power_const.nss rename to src/include/psi_power_const.nss diff --git a/src/prc8/include/psi_spellhook.nss b/src/include/psi_spellhook.nss similarity index 100% rename from src/prc8/include/psi_spellhook.nss rename to src/include/psi_spellhook.nss diff --git a/src/prc8/include/sbr_include.nss b/src/include/sbr_include.nss similarity index 100% rename from src/prc8/include/sbr_include.nss rename to src/include/sbr_include.nss diff --git a/src/prc8/include/shd_inc_metashd.nss b/src/include/shd_inc_metashd.nss similarity index 100% rename from src/prc8/include/shd_inc_metashd.nss rename to src/include/shd_inc_metashd.nss diff --git a/src/prc8/include/shd_inc_myst.nss b/src/include/shd_inc_myst.nss similarity index 100% rename from src/prc8/include/shd_inc_myst.nss rename to src/include/shd_inc_myst.nss diff --git a/src/prc8/include/shd_inc_mystknwn.nss b/src/include/shd_inc_mystknwn.nss similarity index 99% rename from src/prc8/include/shd_inc_mystknwn.nss rename to src/include/shd_inc_mystknwn.nss index bc6ecc5..b335485 100644 --- a/src/prc8/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/prc8/include/shd_inc_shdfunc.nss b/src/include/shd_inc_shdfunc.nss similarity index 100% rename from src/prc8/include/shd_inc_shdfunc.nss rename to src/include/shd_inc_shdfunc.nss diff --git a/src/prc8/include/shd_myst_const.nss b/src/include/shd_myst_const.nss similarity index 100% rename from src/prc8/include/shd_myst_const.nss rename to src/include/shd_myst_const.nss diff --git a/src/prc8/include/shd_mysthook.nss b/src/include/shd_mysthook.nss similarity index 100% rename from src/prc8/include/shd_mysthook.nss rename to src/include/shd_mysthook.nss diff --git a/src/prc8/include/spinc_bolt.nss b/src/include/spinc_bolt.nss similarity index 100% rename from src/prc8/include/spinc_bolt.nss rename to src/include/spinc_bolt.nss diff --git a/src/prc8/include/spinc_burst.nss b/src/include/spinc_burst.nss similarity index 100% rename from src/prc8/include/spinc_burst.nss rename to src/include/spinc_burst.nss diff --git a/src/prc8/include/spinc_cone.nss b/src/include/spinc_cone.nss similarity index 100% rename from src/prc8/include/spinc_cone.nss rename to src/include/spinc_cone.nss diff --git a/src/prc8/include/spinc_dimdoor.nss b/src/include/spinc_dimdoor.nss similarity index 100% rename from src/prc8/include/spinc_dimdoor.nss rename to src/include/spinc_dimdoor.nss diff --git a/src/prc8/include/spinc_engimm.nss b/src/include/spinc_engimm.nss similarity index 100% rename from src/prc8/include/spinc_engimm.nss rename to src/include/spinc_engimm.nss diff --git a/src/prc8/include/spinc_fdisk.nss b/src/include/spinc_fdisk.nss similarity index 100% rename from src/prc8/include/spinc_fdisk.nss rename to src/include/spinc_fdisk.nss diff --git a/src/prc8/include/spinc_greenfire.nss b/src/include/spinc_greenfire.nss similarity index 100% rename from src/prc8/include/spinc_greenfire.nss rename to src/include/spinc_greenfire.nss diff --git a/src/prc8/include/spinc_lessorb.nss b/src/include/spinc_lessorb.nss similarity index 100% rename from src/prc8/include/spinc_lessorb.nss rename to src/include/spinc_lessorb.nss diff --git a/src/prc8/include/spinc_maze.nss b/src/include/spinc_maze.nss similarity index 100% rename from src/prc8/include/spinc_maze.nss rename to src/include/spinc_maze.nss diff --git a/src/prc8/include/spinc_necro_cyst.nss b/src/include/spinc_necro_cyst.nss similarity index 100% rename from src/prc8/include/spinc_necro_cyst.nss rename to src/include/spinc_necro_cyst.nss diff --git a/src/prc8/include/spinc_orb.nss b/src/include/spinc_orb.nss similarity index 100% rename from src/prc8/include/spinc_orb.nss rename to src/include/spinc_orb.nss diff --git a/src/prc8/include/spinc_remeffct.nss b/src/include/spinc_remeffct.nss similarity index 100% rename from src/prc8/include/spinc_remeffct.nss rename to src/include/spinc_remeffct.nss diff --git a/src/prc8/include/spinc_telecircle.nss b/src/include/spinc_telecircle.nss similarity index 100% rename from src/prc8/include/spinc_telecircle.nss rename to src/include/spinc_telecircle.nss diff --git a/src/prc8/include/spinc_teleport.nss b/src/include/spinc_teleport.nss similarity index 100% rename from src/prc8/include/spinc_teleport.nss rename to src/include/spinc_teleport.nss diff --git a/src/prc8/include/spinc_trans.nss b/src/include/spinc_trans.nss similarity index 100% rename from src/prc8/include/spinc_trans.nss rename to src/include/spinc_trans.nss diff --git a/src/prc8/include/tob_inc_martlore.nss b/src/include/tob_inc_martlore.nss similarity index 100% rename from src/prc8/include/tob_inc_martlore.nss rename to src/include/tob_inc_martlore.nss diff --git a/src/prc8/include/tob_inc_move.nss b/src/include/tob_inc_move.nss similarity index 100% rename from src/prc8/include/tob_inc_move.nss rename to src/include/tob_inc_move.nss diff --git a/src/prc8/include/tob_inc_moveknwn.nss b/src/include/tob_inc_moveknwn.nss similarity index 100% rename from src/prc8/include/tob_inc_moveknwn.nss rename to src/include/tob_inc_moveknwn.nss diff --git a/src/prc8/include/tob_inc_recovery.nss b/src/include/tob_inc_recovery.nss similarity index 100% rename from src/prc8/include/tob_inc_recovery.nss rename to src/include/tob_inc_recovery.nss diff --git a/src/prc8/include/tob_inc_tobfunc.nss b/src/include/tob_inc_tobfunc.nss similarity index 99% rename from src/prc8/include/tob_inc_tobfunc.nss rename to src/include/tob_inc_tobfunc.nss index 3d74cbd..d339082 100644 --- a/src/prc8/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/prc8/include/tob_move_const.nss b/src/include/tob_move_const.nss similarity index 100% rename from src/prc8/include/tob_move_const.nss rename to src/include/tob_move_const.nss diff --git a/src/prc8/include/tob_movehook.nss b/src/include/tob_movehook.nss similarity index 100% rename from src/prc8/include/tob_movehook.nss rename to src/include/tob_movehook.nss diff --git a/src/prc8/include/true_inc_metautr.nss b/src/include/true_inc_metautr.nss similarity index 100% rename from src/prc8/include/true_inc_metautr.nss rename to src/include/true_inc_metautr.nss diff --git a/src/prc8/include/true_inc_truespk.nss b/src/include/true_inc_truespk.nss similarity index 100% rename from src/prc8/include/true_inc_truespk.nss rename to src/include/true_inc_truespk.nss diff --git a/src/prc8/include/true_inc_trufunc.nss b/src/include/true_inc_trufunc.nss similarity index 100% rename from src/prc8/include/true_inc_trufunc.nss rename to src/include/true_inc_trufunc.nss diff --git a/src/prc8/include/true_inc_truknwn.nss b/src/include/true_inc_truknwn.nss similarity index 100% rename from src/prc8/include/true_inc_truknwn.nss rename to src/include/true_inc_truknwn.nss diff --git a/src/prc8/include/true_inc_utter.nss b/src/include/true_inc_utter.nss similarity index 100% rename from src/prc8/include/true_inc_utter.nss rename to src/include/true_inc_utter.nss diff --git a/src/prc8/include/true_utter_const.nss b/src/include/true_utter_const.nss similarity index 100% rename from src/prc8/include/true_utter_const.nss rename to src/include/true_utter_const.nss diff --git a/src/prc8/include/true_utterhook.nss b/src/include/true_utterhook.nss similarity index 100% rename from src/prc8/include/true_utterhook.nss rename to src/include/true_utterhook.nss diff --git a/src/prc8/include/utl_i_sqluuid.nss b/src/include/utl_i_sqluuid.nss similarity index 100% rename from src/prc8/include/utl_i_sqluuid.nss rename to src/include/utl_i_sqluuid.nss diff --git a/src/prc8/include/x0_i0_transport.nss b/src/include/x0_i0_transport.nss similarity index 100% rename from src/prc8/include/x0_i0_transport.nss rename to src/include/x0_i0_transport.nss diff --git a/src/prc8/include/x2_inc_cutscenep.nss b/src/include/x2_inc_cutscenep.nss similarity index 100% rename from src/prc8/include/x2_inc_cutscenep.nss rename to src/include/x2_inc_cutscenep.nss diff --git a/src/prc8/include/x2_inc_spellhook.nss b/src/include/x2_inc_spellhook.nss similarity index 97% rename from src/prc8/include/x2_inc_spellhook.nss rename to src/include/x2_inc_spellhook.nss index 2785789..c631c0e 100644 --- a/src/prc8/include/x2_inc_spellhook.nss +++ b/src/include/x2_inc_spellhook.nss @@ -1441,8 +1441,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 +1493,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 +1542,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 +1602,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 +1666,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 +1769,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) diff --git a/src/prc8/include/x3_inc_horse.nss b/src/include/x3_inc_horse.nss similarity index 100% rename from src/prc8/include/x3_inc_horse.nss rename to src/include/x3_inc_horse.nss diff --git a/src/prc8/include/xchst_inc.nss b/src/include/xchst_inc.nss similarity index 100% rename from src/prc8/include/xchst_inc.nss rename to src/include/xchst_inc.nss diff --git a/src/mod/are/a1.are.json b/src/module/are/a1.are.json similarity index 100% rename from src/mod/are/a1.are.json rename to src/module/are/a1.are.json diff --git a/src/mod/are/a1hall.are.json b/src/module/are/a1hall.are.json similarity index 100% rename from src/mod/are/a1hall.are.json rename to src/module/are/a1hall.are.json diff --git a/src/mod/are/a2.are.json b/src/module/are/a2.are.json similarity index 100% rename from src/mod/are/a2.are.json rename to src/module/are/a2.are.json diff --git a/src/mod/are/a2hall.are.json b/src/module/are/a2hall.are.json similarity index 100% rename from src/mod/are/a2hall.are.json rename to src/module/are/a2hall.are.json diff --git a/src/mod/are/a3.are.json b/src/module/are/a3.are.json similarity index 100% rename from src/mod/are/a3.are.json rename to src/module/are/a3.are.json diff --git a/src/mod/are/ancientmountainc.are.json b/src/module/are/ancientmountainc.are.json similarity index 100% rename from src/mod/are/ancientmountainc.are.json rename to src/module/are/ancientmountainc.are.json diff --git a/src/mod/are/ancientmtformian.are.json b/src/module/are/ancientmtformian.are.json similarity index 100% rename from src/mod/are/ancientmtformian.are.json rename to src/module/are/ancientmtformian.are.json diff --git a/src/mod/are/ancientmtruins.are.json b/src/module/are/ancientmtruins.are.json similarity index 100% rename from src/mod/are/ancientmtruins.are.json rename to src/module/are/ancientmtruins.are.json diff --git a/src/mod/are/ancientmtstinger.are.json b/src/module/are/ancientmtstinger.are.json similarity index 100% rename from src/mod/are/ancientmtstinger.are.json rename to src/module/are/ancientmtstinger.are.json diff --git a/src/mod/are/area.are.json b/src/module/are/area.are.json similarity index 100% rename from src/mod/are/area.are.json rename to src/module/are/area.are.json diff --git a/src/mod/are/area001.are.json b/src/module/are/area001.are.json similarity index 100% rename from src/mod/are/area001.are.json rename to src/module/are/area001.are.json diff --git a/src/mod/are/area002.are.json b/src/module/are/area002.are.json similarity index 100% rename from src/mod/are/area002.are.json rename to src/module/are/area002.are.json diff --git a/src/mod/are/area003.are.json b/src/module/are/area003.are.json similarity index 100% rename from src/mod/are/area003.are.json rename to src/module/are/area003.are.json diff --git a/src/mod/are/area004.are.json b/src/module/are/area004.are.json similarity index 100% rename from src/mod/are/area004.are.json rename to src/module/are/area004.are.json diff --git a/src/mod/are/area005.are.json b/src/module/are/area005.are.json similarity index 100% rename from src/mod/are/area005.are.json rename to src/module/are/area005.are.json diff --git a/src/mod/are/area006.are.json b/src/module/are/area006.are.json similarity index 100% rename from src/mod/are/area006.are.json rename to src/module/are/area006.are.json diff --git a/src/mod/are/area007.are.json b/src/module/are/area007.are.json similarity index 100% rename from src/mod/are/area007.are.json rename to src/module/are/area007.are.json diff --git a/src/mod/are/area008.are.json b/src/module/are/area008.are.json similarity index 100% rename from src/mod/are/area008.are.json rename to src/module/are/area008.are.json diff --git a/src/mod/are/area009.are.json b/src/module/are/area009.are.json similarity index 100% rename from src/mod/are/area009.are.json rename to src/module/are/area009.are.json diff --git a/src/mod/are/area010.are.json b/src/module/are/area010.are.json similarity index 100% rename from src/mod/are/area010.are.json rename to src/module/are/area010.are.json diff --git a/src/mod/are/area011.are.json b/src/module/are/area011.are.json similarity index 100% rename from src/mod/are/area011.are.json rename to src/module/are/area011.are.json diff --git a/src/mod/are/area012.are.json b/src/module/are/area012.are.json similarity index 100% rename from src/mod/are/area012.are.json rename to src/module/are/area012.are.json diff --git a/src/mod/are/area013.are.json b/src/module/are/area013.are.json similarity index 100% rename from src/mod/are/area013.are.json rename to src/module/are/area013.are.json diff --git a/src/mod/are/area014.are.json b/src/module/are/area014.are.json similarity index 100% rename from src/mod/are/area014.are.json rename to src/module/are/area014.are.json diff --git a/src/mod/are/area015.are.json b/src/module/are/area015.are.json similarity index 100% rename from src/mod/are/area015.are.json rename to src/module/are/area015.are.json diff --git a/src/mod/are/area016.are.json b/src/module/are/area016.are.json similarity index 100% rename from src/mod/are/area016.are.json rename to src/module/are/area016.are.json diff --git a/src/mod/are/area017.are.json b/src/module/are/area017.are.json similarity index 100% rename from src/mod/are/area017.are.json rename to src/module/are/area017.are.json diff --git a/src/mod/are/area018.are.json b/src/module/are/area018.are.json similarity index 100% rename from src/mod/are/area018.are.json rename to src/module/are/area018.are.json diff --git a/src/mod/are/area019.are.json b/src/module/are/area019.are.json similarity index 100% rename from src/mod/are/area019.are.json rename to src/module/are/area019.are.json diff --git a/src/mod/are/area022.are.json b/src/module/are/area022.are.json similarity index 100% rename from src/mod/are/area022.are.json rename to src/module/are/area022.are.json diff --git a/src/mod/are/area024.are.json b/src/module/are/area024.are.json similarity index 100% rename from src/mod/are/area024.are.json rename to src/module/are/area024.are.json diff --git a/src/mod/are/area027.are.json b/src/module/are/area027.are.json similarity index 100% rename from src/mod/are/area027.are.json rename to src/module/are/area027.are.json diff --git a/src/mod/are/area028.are.json b/src/module/are/area028.are.json similarity index 100% rename from src/mod/are/area028.are.json rename to src/module/are/area028.are.json diff --git a/src/mod/are/area029.are.json b/src/module/are/area029.are.json similarity index 100% rename from src/mod/are/area029.are.json rename to src/module/are/area029.are.json diff --git a/src/mod/are/arena.are.json b/src/module/are/arena.are.json similarity index 100% rename from src/mod/are/arena.are.json rename to src/module/are/arena.are.json diff --git a/src/mod/are/asyriancastle.are.json b/src/module/are/asyriancastle.are.json similarity index 100% rename from src/mod/are/asyriancastle.are.json rename to src/module/are/asyriancastle.are.json diff --git a/src/mod/are/asyriancastle001.are.json b/src/module/are/asyriancastle001.are.json similarity index 100% rename from src/mod/are/asyriancastle001.are.json rename to src/module/are/asyriancastle001.are.json diff --git a/src/mod/are/asyrianholyruins.are.json b/src/module/are/asyrianholyruins.are.json similarity index 100% rename from src/mod/are/asyrianholyruins.are.json rename to src/module/are/asyrianholyruins.are.json diff --git a/src/mod/are/asyriantreasurer.are.json b/src/module/are/asyriantreasurer.are.json similarity index 100% rename from src/mod/are/asyriantreasurer.are.json rename to src/module/are/asyriantreasurer.are.json diff --git a/src/mod/are/asyrianupper.are.json b/src/module/are/asyrianupper.are.json similarity index 100% rename from src/mod/are/asyrianupper.are.json rename to src/module/are/asyrianupper.are.json diff --git a/src/mod/are/atlantis.are.json b/src/module/are/atlantis.are.json similarity index 100% rename from src/mod/are/atlantis.are.json rename to src/module/are/atlantis.are.json diff --git a/src/mod/are/atlantiseast.are.json b/src/module/are/atlantiseast.are.json similarity index 100% rename from src/mod/are/atlantiseast.are.json rename to src/module/are/atlantiseast.are.json diff --git a/src/mod/are/atlantiseastbuil.are.json b/src/module/are/atlantiseastbuil.are.json similarity index 100% rename from src/mod/are/atlantiseastbuil.are.json rename to src/module/are/atlantiseastbuil.are.json diff --git a/src/mod/are/atlantisnorth.are.json b/src/module/are/atlantisnorth.are.json similarity index 100% rename from src/mod/are/atlantisnorth.are.json rename to src/module/are/atlantisnorth.are.json diff --git a/src/mod/are/atlantisnorthbui.are.json b/src/module/are/atlantisnorthbui.are.json similarity index 100% rename from src/mod/are/atlantisnorthbui.are.json rename to src/module/are/atlantisnorthbui.are.json diff --git a/src/mod/are/atlantissouth.are.json b/src/module/are/atlantissouth.are.json similarity index 100% rename from src/mod/are/atlantissouth.are.json rename to src/module/are/atlantissouth.are.json diff --git a/src/mod/are/atlantissouthbui.are.json b/src/module/are/atlantissouthbui.are.json similarity index 100% rename from src/mod/are/atlantissouthbui.are.json rename to src/module/are/atlantissouthbui.are.json diff --git a/src/mod/are/atlantiswest.are.json b/src/module/are/atlantiswest.are.json similarity index 100% rename from src/mod/are/atlantiswest.are.json rename to src/module/are/atlantiswest.are.json diff --git a/src/mod/are/atlantiswestbuil.are.json b/src/module/are/atlantiswestbuil.are.json similarity index 100% rename from src/mod/are/atlantiswestbuil.are.json rename to src/module/are/atlantiswestbuil.are.json diff --git a/src/mod/are/awabandonedlodge.are.json b/src/module/are/awabandonedlodge.are.json similarity index 100% rename from src/mod/are/awabandonedlodge.are.json rename to src/module/are/awabandonedlodge.are.json diff --git a/src/mod/are/awcavern.are.json b/src/module/are/awcavern.are.json similarity index 100% rename from src/mod/are/awcavern.are.json rename to src/module/are/awcavern.are.json diff --git a/src/mod/are/awdesertruins.are.json b/src/module/are/awdesertruins.are.json similarity index 100% rename from src/mod/are/awdesertruins.are.json rename to src/module/are/awdesertruins.are.json diff --git a/src/mod/are/awhome.are.json b/src/module/are/awhome.are.json similarity index 100% rename from src/mod/are/awhome.are.json rename to src/module/are/awhome.are.json diff --git a/src/mod/are/awillithidinner.are.json b/src/module/are/awillithidinner.are.json similarity index 100% rename from src/mod/are/awillithidinner.are.json rename to src/module/are/awillithidinner.are.json diff --git a/src/mod/are/awportaltoverasp.are.json b/src/module/are/awportaltoverasp.are.json similarity index 100% rename from src/mod/are/awportaltoverasp.are.json rename to src/module/are/awportaltoverasp.are.json diff --git a/src/mod/are/awtempleofvera.are.json b/src/module/are/awtempleofvera.are.json similarity index 100% rename from src/mod/are/awtempleofvera.are.json rename to src/module/are/awtempleofvera.are.json diff --git a/src/mod/are/awtrollcaves.are.json b/src/module/are/awtrollcaves.are.json similarity index 100% rename from src/mod/are/awtrollcaves.are.json rename to src/module/are/awtrollcaves.are.json diff --git a/src/mod/are/awtrollcaves2.are.json b/src/module/are/awtrollcaves2.are.json similarity index 100% rename from src/mod/are/awtrollcaves2.are.json rename to src/module/are/awtrollcaves2.are.json diff --git a/src/mod/are/b1.are.json b/src/module/are/b1.are.json similarity index 100% rename from src/mod/are/b1.are.json rename to src/module/are/b1.are.json diff --git a/src/mod/are/b1hall.are.json b/src/module/are/b1hall.are.json similarity index 100% rename from src/mod/are/b1hall.are.json rename to src/module/are/b1hall.are.json diff --git a/src/mod/are/b2.are.json b/src/module/are/b2.are.json similarity index 100% rename from src/mod/are/b2.are.json rename to src/module/are/b2.are.json diff --git a/src/mod/are/b3.are.json b/src/module/are/b3.are.json similarity index 100% rename from src/mod/are/b3.are.json rename to src/module/are/b3.are.json diff --git a/src/mod/are/bandithold001.are.json b/src/module/are/bandithold001.are.json similarity index 100% rename from src/mod/are/bandithold001.are.json rename to src/module/are/bandithold001.are.json diff --git a/src/mod/are/bandithouse.are.json b/src/module/are/bandithouse.are.json similarity index 100% rename from src/mod/are/bandithouse.are.json rename to src/module/are/bandithouse.are.json diff --git a/src/mod/are/barn.are.json b/src/module/are/barn.are.json similarity index 100% rename from src/mod/are/barn.are.json rename to src/module/are/barn.are.json diff --git a/src/mod/are/barn001.are.json b/src/module/are/barn001.are.json similarity index 100% rename from src/mod/are/barn001.are.json rename to src/module/are/barn001.are.json diff --git a/src/mod/are/barrieddesert.are.json b/src/module/are/barrieddesert.are.json similarity index 100% rename from src/mod/are/barrieddesert.are.json rename to src/module/are/barrieddesert.are.json diff --git a/src/mod/are/baylibrary.are.json b/src/module/are/baylibrary.are.json similarity index 100% rename from src/mod/are/baylibrary.are.json rename to src/module/are/baylibrary.are.json diff --git a/src/mod/are/bayvillage.are.json b/src/module/are/bayvillage.are.json similarity index 100% rename from src/mod/are/bayvillage.are.json rename to src/module/are/bayvillage.are.json diff --git a/src/mod/are/bayvillagetownha.are.json b/src/module/are/bayvillagetownha.are.json similarity index 100% rename from src/mod/are/bayvillagetownha.are.json rename to src/module/are/bayvillagetownha.are.json diff --git a/src/mod/are/beholdercaves.are.json b/src/module/are/beholdercaves.are.json similarity index 100% rename from src/mod/are/beholdercaves.are.json rename to src/module/are/beholdercaves.are.json diff --git a/src/mod/are/beholdercavestyr.are.json b/src/module/are/beholdercavestyr.are.json similarity index 100% rename from src/mod/are/beholdercavestyr.are.json rename to src/module/are/beholdercavestyr.are.json diff --git a/src/mod/are/bigginsville.are.json b/src/module/are/bigginsville.are.json similarity index 100% rename from src/mod/are/bigginsville.are.json rename to src/module/are/bigginsville.are.json diff --git a/src/mod/are/bluearena.are.json b/src/module/are/bluearena.are.json similarity index 100% rename from src/mod/are/bluearena.are.json rename to src/module/are/bluearena.are.json diff --git a/src/mod/are/blueteamcastl001.are.json b/src/module/are/blueteamcastl001.are.json similarity index 100% rename from src/mod/are/blueteamcastl001.are.json rename to src/module/are/blueteamcastl001.are.json diff --git a/src/mod/are/boudoirofthepurp.are.json b/src/module/are/boudoirofthepurp.are.json similarity index 100% rename from src/mod/are/boudoirofthepurp.are.json rename to src/module/are/boudoirofthepurp.are.json diff --git a/src/mod/are/bretheren1.are.json b/src/module/are/bretheren1.are.json similarity index 100% rename from src/mod/are/bretheren1.are.json rename to src/module/are/bretheren1.are.json diff --git a/src/mod/are/bretherenlivingq.are.json b/src/module/are/bretherenlivingq.are.json similarity index 100% rename from src/mod/are/bretherenlivingq.are.json rename to src/module/are/bretherenlivingq.are.json diff --git a/src/mod/are/bretherenlounge.are.json b/src/module/are/bretherenlounge.are.json similarity index 100% rename from src/mod/are/bretherenlounge.are.json rename to src/module/are/bretherenlounge.are.json diff --git a/src/mod/are/bretherenthroner.are.json b/src/module/are/bretherenthroner.are.json similarity index 100% rename from src/mod/are/bretherenthroner.are.json rename to src/module/are/bretherenthroner.are.json diff --git a/src/mod/are/burialchamber.are.json b/src/module/are/burialchamber.are.json similarity index 100% rename from src/mod/are/burialchamber.are.json rename to src/module/are/burialchamber.are.json diff --git a/src/mod/are/castleofcain.are.json b/src/module/are/castleofcain.are.json similarity index 100% rename from src/mod/are/castleofcain.are.json rename to src/module/are/castleofcain.are.json diff --git a/src/mod/are/castleoftheda001.are.json b/src/module/are/castleoftheda001.are.json similarity index 100% rename from src/mod/are/castleoftheda001.are.json rename to src/module/are/castleoftheda001.are.json diff --git a/src/mod/are/castleofthedarkq.are.json b/src/module/are/castleofthedarkq.are.json similarity index 100% rename from src/mod/are/castleofthedarkq.are.json rename to src/module/are/castleofthedarkq.are.json diff --git a/src/mod/are/caveoftheclanlea.are.json b/src/module/are/caveoftheclanlea.are.json similarity index 100% rename from src/mod/are/caveoftheclanlea.are.json rename to src/module/are/caveoftheclanlea.are.json diff --git a/src/mod/are/chamberofalignme.are.json b/src/module/are/chamberofalignme.are.json similarity index 100% rename from src/mod/are/chamberofalignme.are.json rename to src/module/are/chamberofalignme.are.json diff --git a/src/mod/are/cheatcentral.are.json b/src/module/are/cheatcentral.are.json similarity index 100% rename from src/mod/are/cheatcentral.are.json rename to src/module/are/cheatcentral.are.json diff --git a/src/mod/are/cityofdirth.are.json b/src/module/are/cityofdirth.are.json similarity index 100% rename from src/mod/are/cityofdirth.are.json rename to src/module/are/cityofdirth.are.json diff --git a/src/mod/are/cityofdirthbehol.are.json b/src/module/are/cityofdirthbehol.are.json similarity index 100% rename from src/mod/are/cityofdirthbehol.are.json rename to src/module/are/cityofdirthbehol.are.json diff --git a/src/mod/are/cityofdirthcore.are.json b/src/module/are/cityofdirthcore.are.json similarity index 100% rename from src/mod/are/cityofdirthcore.are.json rename to src/module/are/cityofdirthcore.are.json diff --git a/src/mod/are/cityofdirthdrowb.are.json b/src/module/are/cityofdirthdrowb.are.json similarity index 100% rename from src/mod/are/cityofdirthdrowb.are.json rename to src/module/are/cityofdirthdrowb.are.json diff --git a/src/mod/are/cityofdirthdrows.are.json b/src/module/are/cityofdirthdrows.are.json similarity index 100% rename from src/mod/are/cityofdirthdrows.are.json rename to src/module/are/cityofdirthdrows.are.json diff --git a/src/mod/are/cityofdirthoutsk.are.json b/src/module/are/cityofdirthoutsk.are.json similarity index 100% rename from src/mod/are/cityofdirthoutsk.are.json rename to src/module/are/cityofdirthoutsk.are.json diff --git a/src/mod/are/cityofdirthpoor.are.json b/src/module/are/cityofdirthpoor.are.json similarity index 100% rename from src/mod/are/cityofdirthpoor.are.json rename to src/module/are/cityofdirthpoor.are.json diff --git a/src/mod/are/cityofdirthpoorh.are.json b/src/module/are/cityofdirthpoorh.are.json similarity index 100% rename from src/mod/are/cityofdirthpoorh.are.json rename to src/module/are/cityofdirthpoorh.are.json diff --git a/src/mod/are/cityofdirthtempl.are.json b/src/module/are/cityofdirthtempl.are.json similarity index 100% rename from src/mod/are/cityofdirthtempl.are.json rename to src/module/are/cityofdirthtempl.are.json diff --git a/src/mod/are/cityofdirthupwiz.are.json b/src/module/are/cityofdirthupwiz.are.json similarity index 100% rename from src/mod/are/cityofdirthupwiz.are.json rename to src/module/are/cityofdirthupwiz.are.json diff --git a/src/mod/are/cityofdirthwhore.are.json b/src/module/are/cityofdirthwhore.are.json similarity index 100% rename from src/mod/are/cityofdirthwhore.are.json rename to src/module/are/cityofdirthwhore.are.json diff --git a/src/mod/are/cityofdirthwizto.are.json b/src/module/are/cityofdirthwizto.are.json similarity index 100% rename from src/mod/are/cityofdirthwizto.are.json rename to src/module/are/cityofdirthwizto.are.json diff --git a/src/mod/are/cityofoz.are.json b/src/module/are/cityofoz.are.json similarity index 100% rename from src/mod/are/cityofoz.are.json rename to src/module/are/cityofoz.are.json diff --git a/src/mod/are/cloaktowerheadli.are.json b/src/module/are/cloaktowerheadli.are.json similarity index 100% rename from src/mod/are/cloaktowerheadli.are.json rename to src/module/are/cloaktowerheadli.are.json diff --git a/src/mod/are/cloaktowerlevel1.are.json b/src/module/are/cloaktowerlevel1.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel1.are.json rename to src/module/are/cloaktowerlevel1.are.json diff --git a/src/mod/are/cloaktowerlevel2.are.json b/src/module/are/cloaktowerlevel2.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel2.are.json rename to src/module/are/cloaktowerlevel2.are.json diff --git a/src/mod/are/cloaktowerlevel3.are.json b/src/module/are/cloaktowerlevel3.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel3.are.json rename to src/module/are/cloaktowerlevel3.are.json diff --git a/src/mod/are/cloaktowerlevel4.are.json b/src/module/are/cloaktowerlevel4.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel4.are.json rename to src/module/are/cloaktowerlevel4.are.json diff --git a/src/mod/are/cloaktowerlevel5.are.json b/src/module/are/cloaktowerlevel5.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel5.are.json rename to src/module/are/cloaktowerlevel5.are.json diff --git a/src/mod/are/cloaktowerlevel6.are.json b/src/module/are/cloaktowerlevel6.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel6.are.json rename to src/module/are/cloaktowerlevel6.are.json diff --git a/src/mod/are/cloaktowerlevel7.are.json b/src/module/are/cloaktowerlevel7.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel7.are.json rename to src/module/are/cloaktowerlevel7.are.json diff --git a/src/mod/are/cloaktowerlevel8.are.json b/src/module/are/cloaktowerlevel8.are.json similarity index 100% rename from src/mod/are/cloaktowerlevel8.are.json rename to src/module/are/cloaktowerlevel8.are.json diff --git a/src/mod/are/coalmines.are.json b/src/module/are/coalmines.are.json similarity index 100% rename from src/mod/are/coalmines.are.json rename to src/module/are/coalmines.are.json diff --git a/src/mod/are/coastalcity.are.json b/src/module/are/coastalcity.are.json similarity index 100% rename from src/mod/are/coastalcity.are.json rename to src/module/are/coastalcity.are.json diff --git a/src/mod/are/coastalroad.are.json b/src/module/are/coastalroad.are.json similarity index 100% rename from src/mod/are/coastalroad.are.json rename to src/module/are/coastalroad.are.json diff --git a/src/mod/are/conciousroom.are.json b/src/module/are/conciousroom.are.json similarity index 100% rename from src/mod/are/conciousroom.are.json rename to src/module/are/conciousroom.are.json diff --git a/src/mod/are/cuyahogawilderne.are.json b/src/module/are/cuyahogawilderne.are.json similarity index 100% rename from src/mod/are/cuyahogawilderne.are.json rename to src/module/are/cuyahogawilderne.are.json diff --git a/src/mod/are/darkqueenchamb.are.json b/src/module/are/darkqueenchamb.are.json similarity index 100% rename from src/mod/are/darkqueenchamb.are.json rename to src/module/are/darkqueenchamb.are.json diff --git a/src/mod/are/dbi_pc_rooms.are.json b/src/module/are/dbi_pc_rooms.are.json similarity index 100% rename from src/mod/are/dbi_pc_rooms.are.json rename to src/module/are/dbi_pc_rooms.are.json diff --git a/src/mod/are/desertcavern.are.json b/src/module/are/desertcavern.are.json similarity index 100% rename from src/mod/are/desertcavern.are.json rename to src/module/are/desertcavern.are.json diff --git a/src/mod/are/desertdwarfruins.are.json b/src/module/are/desertdwarfruins.are.json similarity index 100% rename from src/mod/are/desertdwarfruins.are.json rename to src/module/are/desertdwarfruins.are.json diff --git a/src/mod/are/desertruins.are.json b/src/module/are/desertruins.are.json similarity index 100% rename from src/mod/are/desertruins.are.json rename to src/module/are/desertruins.are.json diff --git a/src/mod/are/desolateanddespa.are.json b/src/module/are/desolateanddespa.are.json similarity index 100% rename from src/mod/are/desolateanddespa.are.json rename to src/module/are/desolateanddespa.are.json diff --git a/src/mod/are/dirthtower1.are.json b/src/module/are/dirthtower1.are.json similarity index 100% rename from src/mod/are/dirthtower1.are.json rename to src/module/are/dirthtower1.are.json diff --git a/src/mod/are/dirthtransporter.are.json b/src/module/are/dirthtransporter.are.json similarity index 100% rename from src/mod/are/dirthtransporter.are.json rename to src/module/are/dirthtransporter.are.json diff --git a/src/mod/are/doctorsguild.are.json b/src/module/are/doctorsguild.are.json similarity index 100% rename from src/mod/are/doctorsguild.are.json rename to src/module/are/doctorsguild.are.json diff --git a/src/mod/are/doctorsmain.are.json b/src/module/are/doctorsmain.are.json similarity index 100% rename from src/mod/are/doctorsmain.are.json rename to src/module/are/doctorsmain.are.json diff --git a/src/mod/are/doctorsmain001.are.json b/src/module/are/doctorsmain001.are.json similarity index 100% rename from src/mod/are/doctorsmain001.are.json rename to src/module/are/doctorsmain001.are.json diff --git a/src/mod/are/downtherabbithol.are.json b/src/module/are/downtherabbithol.are.json similarity index 100% rename from src/mod/are/downtherabbithol.are.json rename to src/module/are/downtherabbithol.are.json diff --git a/src/mod/are/draculascrypt.are.json b/src/module/are/draculascrypt.are.json similarity index 100% rename from src/mod/are/draculascrypt.are.json rename to src/module/are/draculascrypt.are.json diff --git a/src/mod/are/dragonbackinn.are.json b/src/module/are/dragonbackinn.are.json similarity index 100% rename from src/mod/are/dragonbackinn.are.json rename to src/module/are/dragonbackinn.are.json diff --git a/src/mod/are/dragoncaverns.are.json b/src/module/are/dragoncaverns.are.json similarity index 100% rename from src/mod/are/dragoncaverns.are.json rename to src/module/are/dragoncaverns.are.json diff --git a/src/mod/are/dragoncaverntunn.are.json b/src/module/are/dragoncaverntunn.are.json similarity index 100% rename from src/mod/are/dragoncaverntunn.are.json rename to src/module/are/dragoncaverntunn.are.json diff --git a/src/mod/are/dragoncaves001.are.json b/src/module/are/dragoncaves001.are.json similarity index 100% rename from src/mod/are/dragoncaves001.are.json rename to src/module/are/dragoncaves001.are.json diff --git a/src/mod/are/dragoncultbarrak.are.json b/src/module/are/dragoncultbarrak.are.json similarity index 100% rename from src/mod/are/dragoncultbarrak.are.json rename to src/module/are/dragoncultbarrak.are.json diff --git a/src/mod/are/dragoncultcastle.are.json b/src/module/are/dragoncultcastle.are.json similarity index 100% rename from src/mod/are/dragoncultcastle.are.json rename to src/module/are/dragoncultcastle.are.json diff --git a/src/mod/are/dragoncultenergy.are.json b/src/module/are/dragoncultenergy.are.json similarity index 100% rename from src/mod/are/dragoncultenergy.are.json rename to src/module/are/dragoncultenergy.are.json diff --git a/src/mod/are/dreamweaver001.are.json b/src/module/are/dreamweaver001.are.json similarity index 100% rename from src/mod/are/dreamweaver001.are.json rename to src/module/are/dreamweaver001.are.json diff --git a/src/mod/are/drowbarraks.are.json b/src/module/are/drowbarraks.are.json similarity index 100% rename from src/mod/are/drowbarraks.are.json rename to src/module/are/drowbarraks.are.json diff --git a/src/mod/are/drowtemple.are.json b/src/module/are/drowtemple.are.json similarity index 100% rename from src/mod/are/drowtemple.are.json rename to src/module/are/drowtemple.are.json diff --git a/src/mod/are/durbonshire.are.json b/src/module/are/durbonshire.are.json similarity index 100% rename from src/mod/are/durbonshire.are.json rename to src/module/are/durbonshire.are.json diff --git a/src/mod/are/dwarvencaverns.are.json b/src/module/are/dwarvencaverns.are.json similarity index 100% rename from src/mod/are/dwarvencaverns.are.json rename to src/module/are/dwarvencaverns.are.json diff --git a/src/mod/are/dwarvencavernslv.are.json b/src/module/are/dwarvencavernslv.are.json similarity index 100% rename from src/mod/are/dwarvencavernslv.are.json rename to src/module/are/dwarvencavernslv.are.json diff --git a/src/mod/are/dwarvendungeons.are.json b/src/module/are/dwarvendungeons.are.json similarity index 100% rename from src/mod/are/dwarvendungeons.are.json rename to src/module/are/dwarvendungeons.are.json diff --git a/src/mod/are/dwarvendungeonsl.are.json b/src/module/are/dwarvendungeonsl.are.json similarity index 100% rename from src/mod/are/dwarvendungeonsl.are.json rename to src/module/are/dwarvendungeonsl.are.json diff --git a/src/mod/are/eleventoeddwarfs.are.json b/src/module/are/eleventoeddwarfs.are.json similarity index 100% rename from src/mod/are/eleventoeddwarfs.are.json rename to src/module/are/eleventoeddwarfs.are.json diff --git a/src/mod/are/elvendar.are.json b/src/module/are/elvendar.are.json similarity index 100% rename from src/mod/are/elvendar.are.json rename to src/module/are/elvendar.are.json diff --git a/src/mod/are/elvendargener001.are.json b/src/module/are/elvendargener001.are.json similarity index 100% rename from src/mod/are/elvendargener001.are.json rename to src/module/are/elvendargener001.are.json diff --git a/src/mod/are/elvendarnorth001.are.json b/src/module/are/elvendarnorth001.are.json similarity index 100% rename from src/mod/are/elvendarnorth001.are.json rename to src/module/are/elvendarnorth001.are.json diff --git a/src/mod/are/elvendarnorthern.are.json b/src/module/are/elvendarnorthern.are.json similarity index 100% rename from src/mod/are/elvendarnorthern.are.json rename to src/module/are/elvendarnorthern.are.json diff --git a/src/mod/are/elvendarouterfor.are.json b/src/module/are/elvendarouterfor.are.json similarity index 100% rename from src/mod/are/elvendarouterfor.are.json rename to src/module/are/elvendarouterfor.are.json diff --git a/src/mod/are/elvendarunder001.are.json b/src/module/are/elvendarunder001.are.json similarity index 100% rename from src/mod/are/elvendarunder001.are.json rename to src/module/are/elvendarunder001.are.json diff --git a/src/mod/are/elvendarunder002.are.json b/src/module/are/elvendarunder002.are.json similarity index 100% rename from src/mod/are/elvendarunder002.are.json rename to src/module/are/elvendarunder002.are.json diff --git a/src/mod/are/elvendarundergro.are.json b/src/module/are/elvendarundergro.are.json similarity index 100% rename from src/mod/are/elvendarundergro.are.json rename to src/module/are/elvendarundergro.are.json diff --git a/src/mod/are/elvendarweste001.are.json b/src/module/are/elvendarweste001.are.json similarity index 100% rename from src/mod/are/elvendarweste001.are.json rename to src/module/are/elvendarweste001.are.json diff --git a/src/mod/are/elvendarwesternb.are.json b/src/module/are/elvendarwesternb.are.json similarity index 100% rename from src/mod/are/elvendarwesternb.are.json rename to src/module/are/elvendarwesternb.are.json diff --git a/src/mod/are/evilclericceremo.are.json b/src/module/are/evilclericceremo.are.json similarity index 100% rename from src/mod/are/evilclericceremo.are.json rename to src/module/are/evilclericceremo.are.json diff --git a/src/mod/are/evilclericruins.are.json b/src/module/are/evilclericruins.are.json similarity index 100% rename from src/mod/are/evilclericruins.are.json rename to src/module/are/evilclericruins.are.json diff --git a/src/mod/are/ey_dpcon_erewood.are.json b/src/module/are/ey_dpcon_erewood.are.json similarity index 100% rename from src/mod/are/ey_dpcon_erewood.are.json rename to src/module/are/ey_dpcon_erewood.are.json diff --git a/src/mod/are/fareast001.are.json b/src/module/are/fareast001.are.json similarity index 100% rename from src/mod/are/fareast001.are.json rename to src/module/are/fareast001.are.json diff --git a/src/mod/are/fareastdesert.are.json b/src/module/are/fareastdesert.are.json similarity index 100% rename from src/mod/are/fareastdesert.are.json rename to src/module/are/fareastdesert.are.json diff --git a/src/mod/are/fareastdesertrui.are.json b/src/module/are/fareastdesertrui.are.json similarity index 100% rename from src/mod/are/fareastdesertrui.are.json rename to src/module/are/fareastdesertrui.are.json diff --git a/src/mod/are/followersofmorda.are.json b/src/module/are/followersofmorda.are.json similarity index 100% rename from src/mod/are/followersofmorda.are.json rename to src/module/are/followersofmorda.are.json diff --git a/src/mod/are/foresttemple001.are.json b/src/module/are/foresttemple001.are.json similarity index 100% rename from src/mod/are/foresttemple001.are.json rename to src/module/are/foresttemple001.are.json diff --git a/src/mod/are/frostedpits.are.json b/src/module/are/frostedpits.are.json similarity index 100% rename from src/mod/are/frostedpits.are.json rename to src/module/are/frostedpits.are.json diff --git a/src/mod/are/frozantundraeast.are.json b/src/module/are/frozantundraeast.are.json similarity index 100% rename from src/mod/are/frozantundraeast.are.json rename to src/module/are/frozantundraeast.are.json diff --git a/src/mod/are/frozedtundra.are.json b/src/module/are/frozedtundra.are.json similarity index 100% rename from src/mod/are/frozedtundra.are.json rename to src/module/are/frozedtundra.are.json diff --git a/src/mod/are/frozentimes.are.json b/src/module/are/frozentimes.are.json similarity index 100% rename from src/mod/are/frozentimes.are.json rename to src/module/are/frozentimes.are.json diff --git a/src/mod/are/frozentundranort.are.json b/src/module/are/frozentundranort.are.json similarity index 100% rename from src/mod/are/frozentundranort.are.json rename to src/module/are/frozentundranort.are.json diff --git a/src/mod/are/frozentundrawest.are.json b/src/module/are/frozentundrawest.are.json similarity index 100% rename from src/mod/are/frozentundrawest.are.json rename to src/module/are/frozentundrawest.are.json diff --git a/src/mod/are/granolalodge.are.json b/src/module/are/granolalodge.are.json similarity index 100% rename from src/mod/are/granolalodge.are.json rename to src/module/are/granolalodge.are.json diff --git a/src/mod/are/groundskeeper.are.json b/src/module/are/groundskeeper.are.json similarity index 100% rename from src/mod/are/groundskeeper.are.json rename to src/module/are/groundskeeper.are.json diff --git a/src/mod/are/halloftheancient.are.json b/src/module/are/halloftheancient.are.json similarity index 100% rename from src/mod/are/halloftheancient.are.json rename to src/module/are/halloftheancient.are.json diff --git a/src/mod/are/hallowedground1.are.json b/src/module/are/hallowedground1.are.json similarity index 100% rename from src/mod/are/hallowedground1.are.json rename to src/module/are/hallowedground1.are.json diff --git a/src/mod/are/healerhouse.are.json b/src/module/are/healerhouse.are.json similarity index 100% rename from src/mod/are/healerhouse.are.json rename to src/module/are/healerhouse.are.json diff --git a/src/mod/are/hillsidehome001.are.json b/src/module/are/hillsidehome001.are.json similarity index 100% rename from src/mod/are/hillsidehome001.are.json rename to src/module/are/hillsidehome001.are.json diff --git a/src/mod/are/hillsideinn.are.json b/src/module/are/hillsideinn.are.json similarity index 100% rename from src/mod/are/hillsideinn.are.json rename to src/module/are/hillsideinn.are.json diff --git a/src/mod/are/hillsidemysticto.are.json b/src/module/are/hillsidemysticto.are.json similarity index 100% rename from src/mod/are/hillsidemysticto.are.json rename to src/module/are/hillsidemysticto.are.json diff --git a/src/mod/are/hillsidetempl001.are.json b/src/module/are/hillsidetempl001.are.json similarity index 100% rename from src/mod/are/hillsidetempl001.are.json rename to src/module/are/hillsidetempl001.are.json diff --git a/src/mod/are/historywing.are.json b/src/module/are/historywing.are.json similarity index 100% rename from src/mod/are/historywing.are.json rename to src/module/are/historywing.are.json diff --git a/src/mod/are/holyground.are.json b/src/module/are/holyground.are.json similarity index 100% rename from src/mod/are/holyground.are.json rename to src/module/are/holyground.are.json diff --git a/src/mod/are/horrorwing.are.json b/src/module/are/horrorwing.are.json similarity index 100% rename from src/mod/are/horrorwing.are.json rename to src/module/are/horrorwing.are.json diff --git a/src/mod/are/ifm_pc_rooms.are.json b/src/module/are/ifm_pc_rooms.are.json similarity index 100% rename from src/mod/are/ifm_pc_rooms.are.json rename to src/module/are/ifm_pc_rooms.are.json diff --git a/src/mod/are/igloo.are.json b/src/module/are/igloo.are.json similarity index 100% rename from src/mod/are/igloo.are.json rename to src/module/are/igloo.are.json diff --git a/src/mod/are/illithidbridges.are.json b/src/module/are/illithidbridges.are.json similarity index 100% rename from src/mod/are/illithidbridges.are.json rename to src/module/are/illithidbridges.are.json diff --git a/src/mod/are/illithidresingch.are.json b/src/module/are/illithidresingch.are.json similarity index 100% rename from src/mod/are/illithidresingch.are.json rename to src/module/are/illithidresingch.are.json diff --git a/src/mod/are/ironclawbattlegr.are.json b/src/module/are/ironclawbattlegr.are.json similarity index 100% rename from src/mod/are/ironclawbattlegr.are.json rename to src/module/are/ironclawbattlegr.are.json diff --git a/src/mod/are/ironclawcastle.are.json b/src/module/are/ironclawcastle.are.json similarity index 100% rename from src/mod/are/ironclawcastle.are.json rename to src/module/are/ironclawcastle.are.json diff --git a/src/mod/are/ironclawcastleup.are.json b/src/module/are/ironclawcastleup.are.json similarity index 100% rename from src/mod/are/ironclawcastleup.are.json rename to src/module/are/ironclawcastleup.are.json diff --git a/src/mod/are/ironclawdungeons.are.json b/src/module/are/ironclawdungeons.are.json similarity index 100% rename from src/mod/are/ironclawdungeons.are.json rename to src/module/are/ironclawdungeons.are.json diff --git a/src/mod/are/ironclawhalltoto.are.json b/src/module/are/ironclawhalltoto.are.json similarity index 100% rename from src/mod/are/ironclawhalltoto.are.json rename to src/module/are/ironclawhalltoto.are.json diff --git a/src/mod/are/ironclawinnercas.are.json b/src/module/are/ironclawinnercas.are.json similarity index 100% rename from src/mod/are/ironclawinnercas.are.json rename to src/module/are/ironclawinnercas.are.json diff --git a/src/mod/are/ironclawtower.are.json b/src/module/are/ironclawtower.are.json similarity index 100% rename from src/mod/are/ironclawtower.are.json rename to src/module/are/ironclawtower.are.json diff --git a/src/mod/are/irongoblinleader.are.json b/src/module/are/irongoblinleader.are.json similarity index 100% rename from src/mod/are/irongoblinleader.are.json rename to src/module/are/irongoblinleader.are.json diff --git a/src/mod/are/ironmineslevel2.are.json b/src/module/are/ironmineslevel2.are.json similarity index 100% rename from src/mod/are/ironmineslevel2.are.json rename to src/module/are/ironmineslevel2.are.json diff --git a/src/mod/are/ironminesupper.are.json b/src/module/are/ironminesupper.are.json similarity index 100% rename from src/mod/are/ironminesupper.are.json rename to src/module/are/ironminesupper.are.json diff --git a/src/mod/are/isleofrepent.are.json b/src/module/are/isleofrepent.are.json similarity index 100% rename from src/mod/are/isleofrepent.are.json rename to src/module/are/isleofrepent.are.json diff --git a/src/mod/are/jerkinsbarn.are.json b/src/module/are/jerkinsbarn.are.json similarity index 100% rename from src/mod/are/jerkinsbarn.are.json rename to src/module/are/jerkinsbarn.are.json diff --git a/src/mod/are/keepofthefallinp.are.json b/src/module/are/keepofthefallinp.are.json similarity index 100% rename from src/mod/are/keepofthefallinp.are.json rename to src/module/are/keepofthefallinp.are.json diff --git a/src/mod/are/koboldcaves.are.json b/src/module/are/koboldcaves.are.json similarity index 100% rename from src/mod/are/koboldcaves.are.json rename to src/module/are/koboldcaves.are.json diff --git a/src/mod/are/lairofkluam.are.json b/src/module/are/lairofkluam.are.json similarity index 100% rename from src/mod/are/lairofkluam.are.json rename to src/module/are/lairofkluam.are.json diff --git a/src/mod/are/lethalweaponsgui.are.json b/src/module/are/lethalweaponsgui.are.json similarity index 100% rename from src/mod/are/lethalweaponsgui.are.json rename to src/module/are/lethalweaponsgui.are.json diff --git a/src/mod/are/limbo001.are.json b/src/module/are/limbo001.are.json similarity index 100% rename from src/mod/are/limbo001.are.json rename to src/module/are/limbo001.are.json diff --git a/src/mod/are/lithiuminfusionc.are.json b/src/module/are/lithiuminfusionc.are.json similarity index 100% rename from src/mod/are/lithiuminfusionc.are.json rename to src/module/are/lithiuminfusionc.are.json diff --git a/src/mod/are/livingforest.are.json b/src/module/are/livingforest.are.json similarity index 100% rename from src/mod/are/livingforest.are.json rename to src/module/are/livingforest.are.json diff --git a/src/mod/are/livingforesteast.are.json b/src/module/are/livingforesteast.are.json similarity index 100% rename from src/mod/are/livingforesteast.are.json rename to src/module/are/livingforesteast.are.json diff --git a/src/mod/are/livingforestnort.are.json b/src/module/are/livingforestnort.are.json similarity index 100% rename from src/mod/are/livingforestnort.are.json rename to src/module/are/livingforestnort.are.json diff --git a/src/mod/are/livingforestwest.are.json b/src/module/are/livingforestwest.are.json similarity index 100% rename from src/mod/are/livingforestwest.are.json rename to src/module/are/livingforestwest.are.json diff --git a/src/mod/are/manypaths.are.json b/src/module/are/manypaths.are.json similarity index 100% rename from src/mod/are/manypaths.are.json rename to src/module/are/manypaths.are.json diff --git a/src/mod/are/minihouse.are.json b/src/module/are/minihouse.are.json similarity index 100% rename from src/mod/are/minihouse.are.json rename to src/module/are/minihouse.are.json diff --git a/src/mod/are/minihouseupper.are.json b/src/module/are/minihouseupper.are.json similarity index 100% rename from src/mod/are/minihouseupper.are.json rename to src/module/are/minihouseupper.are.json diff --git a/src/mod/are/mithralmines.are.json b/src/module/are/mithralmines.are.json similarity index 100% rename from src/mod/are/mithralmines.are.json rename to src/module/are/mithralmines.are.json diff --git a/src/mod/are/mordmagman01.are.json b/src/module/are/mordmagman01.are.json similarity index 100% rename from src/mod/are/mordmagman01.are.json rename to src/module/are/mordmagman01.are.json diff --git a/src/mod/are/mordmagman02.are.json b/src/module/are/mordmagman02.are.json similarity index 100% rename from src/mod/are/mordmagman02.are.json rename to src/module/are/mordmagman02.are.json diff --git a/src/mod/are/mordmagman03.are.json b/src/module/are/mordmagman03.are.json similarity index 100% rename from src/mod/are/mordmagman03.are.json rename to src/module/are/mordmagman03.are.json diff --git a/src/mod/are/mordmagman04.are.json b/src/module/are/mordmagman04.are.json similarity index 100% rename from src/mod/are/mordmagman04.are.json rename to src/module/are/mordmagman04.are.json diff --git a/src/mod/are/mordmagman05.are.json b/src/module/are/mordmagman05.are.json similarity index 100% rename from src/mod/are/mordmagman05.are.json rename to src/module/are/mordmagman05.are.json diff --git a/src/mod/are/mordmagman06.are.json b/src/module/are/mordmagman06.are.json similarity index 100% rename from src/mod/are/mordmagman06.are.json rename to src/module/are/mordmagman06.are.json diff --git a/src/mod/are/mountianside.are.json b/src/module/are/mountianside.are.json similarity index 100% rename from src/mod/are/mountianside.are.json rename to src/module/are/mountianside.are.json diff --git a/src/mod/are/mountiansidenort.are.json b/src/module/are/mountiansidenort.are.json similarity index 100% rename from src/mod/are/mountiansidenort.are.json rename to src/module/are/mountiansidenort.are.json diff --git a/src/mod/are/nightofthunder.are.json b/src/module/are/nightofthunder.are.json similarity index 100% rename from src/mod/are/nightofthunder.are.json rename to src/module/are/nightofthunder.are.json diff --git a/src/mod/are/nodropitemsarea.are.json b/src/module/are/nodropitemsarea.are.json similarity index 100% rename from src/mod/are/nodropitemsarea.are.json rename to src/module/are/nodropitemsarea.are.json diff --git a/src/mod/are/nordicpolarpass.are.json b/src/module/are/nordicpolarpass.are.json similarity index 100% rename from src/mod/are/nordicpolarpass.are.json rename to src/module/are/nordicpolarpass.are.json diff --git a/src/mod/are/northernport.are.json b/src/module/are/northernport.are.json similarity index 100% rename from src/mod/are/northernport.are.json rename to src/module/are/northernport.are.json diff --git a/src/mod/are/northernroad001.are.json b/src/module/are/northernroad001.are.json similarity index 100% rename from src/mod/are/northernroad001.are.json rename to src/module/are/northernroad001.are.json diff --git a/src/mod/are/northernwoods.are.json b/src/module/are/northernwoods.are.json similarity index 100% rename from src/mod/are/northernwoods.are.json rename to src/module/are/northernwoods.are.json diff --git a/src/mod/are/oddbuilding.are.json b/src/module/are/oddbuilding.are.json similarity index 100% rename from src/mod/are/oddbuilding.are.json rename to src/module/are/oddbuilding.are.json diff --git a/src/mod/are/ogrecaves.are.json b/src/module/are/ogrecaves.are.json similarity index 100% rename from src/mod/are/ogrecaves.are.json rename to src/module/are/ogrecaves.are.json diff --git a/src/mod/are/ogrecaveslevel2.are.json b/src/module/are/ogrecaveslevel2.are.json similarity index 100% rename from src/mod/are/ogrecaveslevel2.are.json rename to src/module/are/ogrecaveslevel2.are.json diff --git a/src/mod/are/ogrecaveslevel3.are.json b/src/module/are/ogrecaveslevel3.are.json similarity index 100% rename from src/mod/are/ogrecaveslevel3.are.json rename to src/module/are/ogrecaveslevel3.are.json diff --git a/src/mod/are/oldhouse1.are.json b/src/module/are/oldhouse1.are.json similarity index 100% rename from src/mod/are/oldhouse1.are.json rename to src/module/are/oldhouse1.are.json diff --git a/src/mod/are/oldhouse2.are.json b/src/module/are/oldhouse2.are.json similarity index 100% rename from src/mod/are/oldhouse2.are.json rename to src/module/are/oldhouse2.are.json diff --git a/src/mod/are/oldhouse3.are.json b/src/module/are/oldhouse3.are.json similarity index 100% rename from src/mod/are/oldhouse3.are.json rename to src/module/are/oldhouse3.are.json diff --git a/src/mod/are/oldhouse4.are.json b/src/module/are/oldhouse4.are.json similarity index 100% rename from src/mod/are/oldhouse4.are.json rename to src/module/are/oldhouse4.are.json diff --git a/src/mod/are/oldhouse5.are.json b/src/module/are/oldhouse5.are.json similarity index 100% rename from src/mod/are/oldhouse5.are.json rename to src/module/are/oldhouse5.are.json diff --git a/src/mod/are/oldhouse6.are.json b/src/module/are/oldhouse6.are.json similarity index 100% rename from src/mod/are/oldhouse6.are.json rename to src/module/are/oldhouse6.are.json diff --git a/src/mod/are/oldhouse7.are.json b/src/module/are/oldhouse7.are.json similarity index 100% rename from src/mod/are/oldhouse7.are.json rename to src/module/are/oldhouse7.are.json diff --git a/src/mod/are/oldmanjerkinshou.are.json b/src/module/are/oldmanjerkinshou.are.json similarity index 100% rename from src/mod/are/oldmanjerkinshou.are.json rename to src/module/are/oldmanjerkinshou.are.json diff --git a/src/mod/are/oldmines.are.json b/src/module/are/oldmines.are.json similarity index 100% rename from src/mod/are/oldmines.are.json rename to src/module/are/oldmines.are.json diff --git a/src/mod/are/orcbarracks.are.json b/src/module/are/orcbarracks.are.json similarity index 100% rename from src/mod/are/orcbarracks.are.json rename to src/module/are/orcbarracks.are.json diff --git a/src/mod/are/orcbarrackslevel.are.json b/src/module/are/orcbarrackslevel.are.json similarity index 100% rename from src/mod/are/orcbarrackslevel.are.json rename to src/module/are/orcbarrackslevel.are.json diff --git a/src/mod/are/orcmasterbarrack.are.json b/src/module/are/orcmasterbarrack.are.json similarity index 100% rename from src/mod/are/orcmasterbarrack.are.json rename to src/module/are/orcmasterbarrack.are.json diff --git a/src/mod/are/orcsublevel.are.json b/src/module/are/orcsublevel.are.json similarity index 100% rename from src/mod/are/orcsublevel.are.json rename to src/module/are/orcsublevel.are.json diff --git a/src/mod/are/osu.are.json b/src/module/are/osu.are.json similarity index 100% rename from src/mod/are/osu.are.json rename to src/module/are/osu.are.json diff --git a/src/mod/are/outfitterspos001.are.json b/src/module/are/outfitterspos001.are.json similarity index 100% rename from src/mod/are/outfitterspos001.are.json rename to src/module/are/outfitterspos001.are.json diff --git a/src/mod/are/ozcastle.are.json b/src/module/are/ozcastle.are.json similarity index 100% rename from src/mod/are/ozcastle.are.json rename to src/module/are/ozcastle.are.json diff --git a/src/mod/are/ozcastleupper.are.json b/src/module/are/ozcastleupper.are.json similarity index 100% rename from src/mod/are/ozcastleupper.are.json rename to src/module/are/ozcastleupper.are.json diff --git a/src/mod/are/ozchamberofmysti.are.json b/src/module/are/ozchamberofmysti.are.json similarity index 100% rename from src/mod/are/ozchamberofmysti.are.json rename to src/module/are/ozchamberofmysti.are.json diff --git a/src/mod/are/ozeastwing.are.json b/src/module/are/ozeastwing.are.json similarity index 100% rename from src/mod/are/ozeastwing.are.json rename to src/module/are/ozeastwing.are.json diff --git a/src/mod/are/ozjail.are.json b/src/module/are/ozjail.are.json similarity index 100% rename from src/mod/are/ozjail.are.json rename to src/module/are/ozjail.are.json diff --git a/src/mod/are/ozmaincastle.are.json b/src/module/are/ozmaincastle.are.json similarity index 100% rename from src/mod/are/ozmaincastle.are.json rename to src/module/are/ozmaincastle.are.json diff --git a/src/mod/are/ozmainlibrary.are.json b/src/module/are/ozmainlibrary.are.json similarity index 100% rename from src/mod/are/ozmainlibrary.are.json rename to src/module/are/ozmainlibrary.are.json diff --git a/src/mod/are/ozwestwing.are.json b/src/module/are/ozwestwing.are.json similarity index 100% rename from src/mod/are/ozwestwing.are.json rename to src/module/are/ozwestwing.are.json diff --git a/src/mod/are/pathtoozcastle.are.json b/src/module/are/pathtoozcastle.are.json similarity index 100% rename from src/mod/are/pathtoozcastle.are.json rename to src/module/are/pathtoozcastle.are.json diff --git a/src/mod/are/pathtotheancient.are.json b/src/module/are/pathtotheancient.are.json similarity index 100% rename from src/mod/are/pathtotheancient.are.json rename to src/module/are/pathtotheancient.are.json diff --git a/src/mod/are/pleasantville.are.json b/src/module/are/pleasantville.are.json similarity index 100% rename from src/mod/are/pleasantville.are.json rename to src/module/are/pleasantville.are.json diff --git a/src/mod/are/prc_maze_01.are.json b/src/module/are/prc_maze_01.are.json similarity index 100% rename from src/mod/are/prc_maze_01.are.json rename to src/module/are/prc_maze_01.are.json diff --git a/src/mod/are/pvpexitingroom.are.json b/src/module/are/pvpexitingroom.are.json similarity index 100% rename from src/mod/are/pvpexitingroom.are.json rename to src/module/are/pvpexitingroom.are.json diff --git a/src/mod/are/pvppreparationro.are.json b/src/module/are/pvppreparationro.are.json similarity index 100% rename from src/mod/are/pvppreparationro.are.json rename to src/module/are/pvppreparationro.are.json diff --git a/src/mod/are/pvprespawn.are.json b/src/module/are/pvprespawn.are.json similarity index 100% rename from src/mod/are/pvprespawn.are.json rename to src/module/are/pvprespawn.are.json diff --git a/src/mod/are/rajashouse.are.json b/src/module/are/rajashouse.are.json similarity index 100% rename from src/mod/are/rajashouse.are.json rename to src/module/are/rajashouse.are.json diff --git a/src/mod/are/realmofcain.are.json b/src/module/are/realmofcain.are.json similarity index 100% rename from src/mod/are/realmofcain.are.json rename to src/module/are/realmofcain.are.json diff --git a/src/mod/are/realmofcain2.are.json b/src/module/are/realmofcain2.are.json similarity index 100% rename from src/mod/are/realmofcain2.are.json rename to src/module/are/realmofcain2.are.json diff --git a/src/mod/are/realmofcaincastl.are.json b/src/module/are/realmofcaincastl.are.json similarity index 100% rename from src/mod/are/realmofcaincastl.are.json rename to src/module/are/realmofcaincastl.are.json diff --git a/src/mod/are/realmofsubzeroes.are.json b/src/module/are/realmofsubzeroes.are.json similarity index 100% rename from src/mod/are/realmofsubzeroes.are.json rename to src/module/are/realmofsubzeroes.are.json diff --git a/src/mod/are/realmofthedarksi.are.json b/src/module/are/realmofthedarksi.are.json similarity index 100% rename from src/mod/are/realmofthedarksi.are.json rename to src/module/are/realmofthedarksi.are.json diff --git a/src/mod/are/reb.are.json b/src/module/are/reb.are.json similarity index 100% rename from src/mod/are/reb.are.json rename to src/module/are/reb.are.json diff --git a/src/mod/are/redarena.are.json b/src/module/are/redarena.are.json similarity index 100% rename from src/mod/are/redarena.are.json rename to src/module/are/redarena.are.json diff --git a/src/mod/are/redteamcastle002.are.json b/src/module/are/redteamcastle002.are.json similarity index 100% rename from src/mod/are/redteamcastle002.are.json rename to src/module/are/redteamcastle002.are.json diff --git a/src/mod/are/resident002.are.json b/src/module/are/resident002.are.json similarity index 100% rename from src/mod/are/resident002.are.json rename to src/module/are/resident002.are.json diff --git a/src/mod/are/resident003.are.json b/src/module/are/resident003.are.json similarity index 100% rename from src/mod/are/resident003.are.json rename to src/module/are/resident003.are.json diff --git a/src/mod/are/resident004.are.json b/src/module/are/resident004.are.json similarity index 100% rename from src/mod/are/resident004.are.json rename to src/module/are/resident004.are.json diff --git a/src/mod/are/riversidetrail.are.json b/src/module/are/riversidetrail.are.json similarity index 100% rename from src/mod/are/riversidetrail.are.json rename to src/module/are/riversidetrail.are.json diff --git a/src/mod/are/rollinghills001.are.json b/src/module/are/rollinghills001.are.json similarity index 100% rename from src/mod/are/rollinghills001.are.json rename to src/module/are/rollinghills001.are.json diff --git a/src/mod/are/rollingmeadows.are.json b/src/module/are/rollingmeadows.are.json similarity index 100% rename from src/mod/are/rollingmeadows.are.json rename to src/module/are/rollingmeadows.are.json diff --git a/src/mod/are/romancewing.are.json b/src/module/are/romancewing.are.json similarity index 100% rename from src/mod/are/romancewing.are.json rename to src/module/are/romancewing.are.json diff --git a/src/mod/are/ruinedminds001.are.json b/src/module/are/ruinedminds001.are.json similarity index 100% rename from src/mod/are/ruinedminds001.are.json rename to src/module/are/ruinedminds001.are.json diff --git a/src/mod/are/ruralfarms.are.json b/src/module/are/ruralfarms.are.json similarity index 100% rename from src/mod/are/ruralfarms.are.json rename to src/module/are/ruralfarms.are.json diff --git a/src/mod/are/scifiwing.are.json b/src/module/are/scifiwing.are.json similarity index 100% rename from src/mod/are/scifiwing.are.json rename to src/module/are/scifiwing.are.json diff --git a/src/mod/are/sector1.are.json b/src/module/are/sector1.are.json similarity index 100% rename from src/mod/are/sector1.are.json rename to src/module/are/sector1.are.json diff --git a/src/mod/are/sector2.are.json b/src/module/are/sector2.are.json similarity index 100% rename from src/mod/are/sector2.are.json rename to src/module/are/sector2.are.json diff --git a/src/mod/are/sector3.are.json b/src/module/are/sector3.are.json similarity index 100% rename from src/mod/are/sector3.are.json rename to src/module/are/sector3.are.json diff --git a/src/mod/are/sexyfreakguildho.are.json b/src/module/are/sexyfreakguildho.are.json similarity index 100% rename from src/mod/are/sexyfreakguildho.are.json rename to src/module/are/sexyfreakguildho.are.json diff --git a/src/mod/are/shadowlegionmain.are.json b/src/module/are/shadowlegionmain.are.json similarity index 100% rename from src/mod/are/shadowlegionmain.are.json rename to src/module/are/shadowlegionmain.are.json diff --git a/src/mod/are/shadowlegionreal.are.json b/src/module/are/shadowlegionreal.are.json similarity index 100% rename from src/mod/are/shadowlegionreal.are.json rename to src/module/are/shadowlegionreal.are.json diff --git a/src/mod/are/shadyladypub.are.json b/src/module/are/shadyladypub.are.json similarity index 100% rename from src/mod/are/shadyladypub.are.json rename to src/module/are/shadyladypub.are.json diff --git a/src/mod/are/shogunforesteast.are.json b/src/module/are/shogunforesteast.are.json similarity index 100% rename from src/mod/are/shogunforesteast.are.json rename to src/module/are/shogunforesteast.are.json diff --git a/src/mod/are/shogunmain.are.json b/src/module/are/shogunmain.are.json similarity index 100% rename from src/mod/are/shogunmain.are.json rename to src/module/are/shogunmain.are.json diff --git a/src/mod/are/shogunnorth.are.json b/src/module/are/shogunnorth.are.json similarity index 100% rename from src/mod/are/shogunnorth.are.json rename to src/module/are/shogunnorth.are.json diff --git a/src/mod/are/shogunprayercham.are.json b/src/module/are/shogunprayercham.are.json similarity index 100% rename from src/mod/are/shogunprayercham.are.json rename to src/module/are/shogunprayercham.are.json diff --git a/src/mod/are/shogunruins.are.json b/src/module/are/shogunruins.are.json similarity index 100% rename from src/mod/are/shogunruins.are.json rename to src/module/are/shogunruins.are.json diff --git a/src/mod/are/shogunsouth.are.json b/src/module/are/shogunsouth.are.json similarity index 100% rename from src/mod/are/shogunsouth.are.json rename to src/module/are/shogunsouth.are.json diff --git a/src/mod/are/shoguntemple.are.json b/src/module/are/shoguntemple.are.json similarity index 100% rename from src/mod/are/shoguntemple.are.json rename to src/module/are/shoguntemple.are.json diff --git a/src/mod/are/shoguntraningroo.are.json b/src/module/are/shoguntraningroo.are.json similarity index 100% rename from src/mod/are/shoguntraningroo.are.json rename to src/module/are/shoguntraningroo.are.json diff --git a/src/mod/are/shogunwest.are.json b/src/module/are/shogunwest.are.json similarity index 100% rename from src/mod/are/shogunwest.are.json rename to src/module/are/shogunwest.are.json diff --git a/src/mod/are/snowcaps.are.json b/src/module/are/snowcaps.are.json similarity index 100% rename from src/mod/are/snowcaps.are.json rename to src/module/are/snowcaps.are.json diff --git a/src/mod/are/solarrift.are.json b/src/module/are/solarrift.are.json similarity index 100% rename from src/mod/are/solarrift.are.json rename to src/module/are/solarrift.are.json diff --git a/src/mod/are/subworldcrossroa.are.json b/src/module/are/subworldcrossroa.are.json similarity index 100% rename from src/mod/are/subworldcrossroa.are.json rename to src/module/are/subworldcrossroa.are.json diff --git a/src/mod/are/temple.are.json b/src/module/are/temple.are.json similarity index 100% rename from src/mod/are/temple.are.json rename to src/module/are/temple.are.json diff --git a/src/mod/are/thecouncil.are.json b/src/module/are/thecouncil.are.json similarity index 100% rename from src/mod/are/thecouncil.are.json rename to src/module/are/thecouncil.are.json diff --git a/src/mod/are/theeasternroad.are.json b/src/module/are/theeasternroad.are.json similarity index 100% rename from src/mod/are/theeasternroad.are.json rename to src/module/are/theeasternroad.are.json diff --git a/src/mod/are/theeasternroad2.are.json b/src/module/are/theeasternroad2.are.json similarity index 100% rename from src/mod/are/theeasternroad2.are.json rename to src/module/are/theeasternroad2.are.json diff --git a/src/mod/are/thefistsguild001.are.json b/src/module/are/thefistsguild001.are.json similarity index 100% rename from src/mod/are/thefistsguild001.are.json rename to src/module/are/thefistsguild001.are.json diff --git a/src/mod/are/themonsterinthec.are.json b/src/module/are/themonsterinthec.are.json similarity index 100% rename from src/mod/are/themonsterinthec.are.json rename to src/module/are/themonsterinthec.are.json diff --git a/src/mod/are/thenightmarebegi.are.json b/src/module/are/thenightmarebegi.are.json similarity index 100% rename from src/mod/are/thenightmarebegi.are.json rename to src/module/are/thenightmarebegi.are.json diff --git a/src/mod/are/theoldworld.are.json b/src/module/are/theoldworld.are.json similarity index 100% rename from src/mod/are/theoldworld.are.json rename to src/module/are/theoldworld.are.json diff --git a/src/mod/are/thequietofthemin.are.json b/src/module/are/thequietofthemin.are.json similarity index 100% rename from src/mod/are/thequietofthemin.are.json rename to src/module/are/thequietofthemin.are.json diff --git a/src/mod/are/thevillageofhill.are.json b/src/module/are/thevillageofhill.are.json similarity index 100% rename from src/mod/are/thevillageofhill.are.json rename to src/module/are/thevillageofhill.are.json diff --git a/src/mod/are/thewilds.are.json b/src/module/are/thewilds.are.json similarity index 100% rename from src/mod/are/thewilds.are.json rename to src/module/are/thewilds.are.json diff --git a/src/mod/are/thunderlordkeep.are.json b/src/module/are/thunderlordkeep.are.json similarity index 100% rename from src/mod/are/thunderlordkeep.are.json rename to src/module/are/thunderlordkeep.are.json diff --git a/src/mod/are/thundermounainja.are.json b/src/module/are/thundermounainja.are.json similarity index 100% rename from src/mod/are/thundermounainja.are.json rename to src/module/are/thundermounainja.are.json diff --git a/src/mod/are/thundermountainb.are.json b/src/module/are/thundermountainb.are.json similarity index 100% rename from src/mod/are/thundermountainb.are.json rename to src/module/are/thundermountainb.are.json diff --git a/src/mod/are/thundermountainc.are.json b/src/module/are/thundermountainc.are.json similarity index 100% rename from src/mod/are/thundermountainc.are.json rename to src/module/are/thundermountainc.are.json diff --git a/src/mod/are/tmprisons.are.json b/src/module/are/tmprisons.are.json similarity index 100% rename from src/mod/are/tmprisons.are.json rename to src/module/are/tmprisons.are.json diff --git a/src/mod/are/tmstronghold.are.json b/src/module/are/tmstronghold.are.json similarity index 100% rename from src/mod/are/tmstronghold.are.json rename to src/module/are/tmstronghold.are.json diff --git a/src/mod/are/totalkoasguildho.are.json b/src/module/are/totalkoasguildho.are.json similarity index 100% rename from src/mod/are/totalkoasguildho.are.json rename to src/module/are/totalkoasguildho.are.json diff --git a/src/mod/are/toveast.are.json b/src/module/are/toveast.are.json similarity index 100% rename from src/mod/are/toveast.are.json rename to src/module/are/toveast.are.json diff --git a/src/mod/are/tovinner.are.json b/src/module/are/tovinner.are.json similarity index 100% rename from src/mod/are/tovinner.are.json rename to src/module/are/tovinner.are.json diff --git a/src/mod/are/tovnorth.are.json b/src/module/are/tovnorth.are.json similarity index 100% rename from src/mod/are/tovnorth.are.json rename to src/module/are/tovnorth.are.json diff --git a/src/mod/are/tovsouth.are.json b/src/module/are/tovsouth.are.json similarity index 100% rename from src/mod/are/tovsouth.are.json rename to src/module/are/tovsouth.are.json diff --git a/src/mod/are/tovwest.are.json b/src/module/are/tovwest.are.json similarity index 100% rename from src/mod/are/tovwest.are.json rename to src/module/are/tovwest.are.json diff --git a/src/mod/are/tridelthouse.are.json b/src/module/are/tridelthouse.are.json similarity index 100% rename from src/mod/are/tridelthouse.are.json rename to src/module/are/tridelthouse.are.json diff --git a/src/mod/are/trinity.are.json b/src/module/are/trinity.are.json similarity index 100% rename from src/mod/are/trinity.are.json rename to src/module/are/trinity.are.json diff --git a/src/mod/are/trinitybank.are.json b/src/module/are/trinitybank.are.json similarity index 100% rename from src/mod/are/trinitybank.are.json rename to src/module/are/trinitybank.are.json diff --git a/src/mod/are/trinitybrewmaste.are.json b/src/module/are/trinitybrewmaste.are.json similarity index 100% rename from src/mod/are/trinitybrewmaste.are.json rename to src/module/are/trinitybrewmaste.are.json diff --git a/src/mod/are/trinitycemetary.are.json b/src/module/are/trinitycemetary.are.json similarity index 100% rename from src/mod/are/trinitycemetary.are.json rename to src/module/are/trinitycemetary.are.json diff --git a/src/mod/are/trinitycrypts.are.json b/src/module/are/trinitycrypts.are.json similarity index 100% rename from src/mod/are/trinitycrypts.are.json rename to src/module/are/trinitycrypts.are.json diff --git a/src/mod/are/trinitydocks.are.json b/src/module/are/trinitydocks.are.json similarity index 100% rename from src/mod/are/trinitydocks.are.json rename to src/module/are/trinitydocks.are.json diff --git a/src/mod/are/trinityelders.are.json b/src/module/are/trinityelders.are.json similarity index 100% rename from src/mod/are/trinityelders.are.json rename to src/module/are/trinityelders.are.json diff --git a/src/mod/are/trinityeventload.are.json b/src/module/are/trinityeventload.are.json similarity index 100% rename from src/mod/are/trinityeventload.are.json rename to src/module/are/trinityeventload.are.json diff --git a/src/mod/are/trinityholychamb.are.json b/src/module/are/trinityholychamb.are.json similarity index 100% rename from src/mod/are/trinityholychamb.are.json rename to src/module/are/trinityholychamb.are.json diff --git a/src/mod/are/trinitylowercryp.are.json b/src/module/are/trinitylowercryp.are.json similarity index 100% rename from src/mod/are/trinitylowercryp.are.json rename to src/module/are/trinitylowercryp.are.json diff --git a/src/mod/are/trinitymagicandc.are.json b/src/module/are/trinitymagicandc.are.json similarity index 100% rename from src/mod/are/trinitymagicandc.are.json rename to src/module/are/trinitymagicandc.are.json diff --git a/src/mod/are/trinityrandomhou.are.json b/src/module/are/trinityrandomhou.are.json similarity index 100% rename from src/mod/are/trinityrandomhou.are.json rename to src/module/are/trinityrandomhou.are.json diff --git a/src/mod/are/trinityreapersgu.are.json b/src/module/are/trinityreapersgu.are.json similarity index 100% rename from src/mod/are/trinityreapersgu.are.json rename to src/module/are/trinityreapersgu.are.json diff --git a/src/mod/are/trinitysenators.are.json b/src/module/are/trinitysenators.are.json similarity index 100% rename from src/mod/are/trinitysenators.are.json rename to src/module/are/trinitysenators.are.json diff --git a/src/mod/are/trinitysewers.are.json b/src/module/are/trinitysewers.are.json similarity index 100% rename from src/mod/are/trinitysewers.are.json rename to src/module/are/trinitysewers.are.json diff --git a/src/mod/are/trinitysewerslev.are.json b/src/module/are/trinitysewerslev.are.json similarity index 100% rename from src/mod/are/trinitysewerslev.are.json rename to src/module/are/trinitysewerslev.are.json diff --git a/src/mod/are/trinitywarriorba.are.json b/src/module/are/trinitywarriorba.are.json similarity index 100% rename from src/mod/are/trinitywarriorba.are.json rename to src/module/are/trinitywarriorba.are.json diff --git a/src/mod/are/trollcaves3.are.json b/src/module/are/trollcaves3.are.json similarity index 100% rename from src/mod/are/trollcaves3.are.json rename to src/module/are/trollcaves3.are.json diff --git a/src/mod/are/tunnelstoholo.are.json b/src/module/are/tunnelstoholo.are.json similarity index 100% rename from src/mod/are/tunnelstoholo.are.json rename to src/module/are/tunnelstoholo.are.json diff --git a/src/mod/are/twingates.are.json b/src/module/are/twingates.are.json similarity index 100% rename from src/mod/are/twingates.are.json rename to src/module/are/twingates.are.json diff --git a/src/mod/are/underdarkportalr.are.json b/src/module/are/underdarkportalr.are.json similarity index 100% rename from src/mod/are/underdarkportalr.are.json rename to src/module/are/underdarkportalr.are.json diff --git a/src/mod/are/unknownpath.are.json b/src/module/are/unknownpath.are.json similarity index 100% rename from src/mod/are/unknownpath.are.json rename to src/module/are/unknownpath.are.json diff --git a/src/mod/are/vampireechos.are.json b/src/module/are/vampireechos.are.json similarity index 100% rename from src/mod/are/vampireechos.are.json rename to src/module/are/vampireechos.are.json diff --git a/src/mod/are/wastelandcaverns.are.json b/src/module/are/wastelandcaverns.are.json similarity index 100% rename from src/mod/are/wastelandcaverns.are.json rename to src/module/are/wastelandcaverns.are.json diff --git a/src/mod/are/westhouse1.are.json b/src/module/are/westhouse1.are.json similarity index 100% rename from src/mod/are/westhouse1.are.json rename to src/module/are/westhouse1.are.json diff --git a/src/mod/are/westhouse2.are.json b/src/module/are/westhouse2.are.json similarity index 100% rename from src/mod/are/westhouse2.are.json rename to src/module/are/westhouse2.are.json diff --git a/src/mod/are/windmillhouse.are.json b/src/module/are/windmillhouse.are.json similarity index 100% rename from src/mod/are/windmillhouse.are.json rename to src/module/are/windmillhouse.are.json diff --git a/src/mod/are/windycaverns.are.json b/src/module/are/windycaverns.are.json similarity index 100% rename from src/mod/are/windycaverns.are.json rename to src/module/are/windycaverns.are.json diff --git a/src/mod/dlg/asg_alchemylab.dlg.json b/src/module/dlg/asg_alchemylab.dlg.json similarity index 100% rename from src/mod/dlg/asg_alchemylab.dlg.json rename to src/module/dlg/asg_alchemylab.dlg.json diff --git a/src/mod/dlg/asg_enanvilaltar.dlg.json b/src/module/dlg/asg_enanvilaltar.dlg.json similarity index 100% rename from src/mod/dlg/asg_enanvilaltar.dlg.json rename to src/module/dlg/asg_enanvilaltar.dlg.json diff --git a/src/mod/dlg/asy_01.dlg.json b/src/module/dlg/asy_01.dlg.json similarity index 100% rename from src/mod/dlg/asy_01.dlg.json rename to src/module/dlg/asy_01.dlg.json diff --git a/src/mod/dlg/asy_02.dlg.json b/src/module/dlg/asy_02.dlg.json similarity index 100% rename from src/mod/dlg/asy_02.dlg.json rename to src/module/dlg/asy_02.dlg.json diff --git a/src/mod/dlg/asy_03.dlg.json b/src/module/dlg/asy_03.dlg.json similarity index 100% rename from src/mod/dlg/asy_03.dlg.json rename to src/module/dlg/asy_03.dlg.json diff --git a/src/mod/dlg/asy_04.dlg.json b/src/module/dlg/asy_04.dlg.json similarity index 100% rename from src/mod/dlg/asy_04.dlg.json rename to src/module/dlg/asy_04.dlg.json diff --git a/src/mod/dlg/asy_05.dlg.json b/src/module/dlg/asy_05.dlg.json similarity index 100% rename from src/mod/dlg/asy_05.dlg.json rename to src/module/dlg/asy_05.dlg.json diff --git a/src/mod/dlg/asy_06.dlg.json b/src/module/dlg/asy_06.dlg.json similarity index 100% rename from src/mod/dlg/asy_06.dlg.json rename to src/module/dlg/asy_06.dlg.json diff --git a/src/mod/dlg/asy_07.dlg.json b/src/module/dlg/asy_07.dlg.json similarity index 100% rename from src/mod/dlg/asy_07.dlg.json rename to src/module/dlg/asy_07.dlg.json diff --git a/src/mod/dlg/asy_08.dlg.json b/src/module/dlg/asy_08.dlg.json similarity index 100% rename from src/mod/dlg/asy_08.dlg.json rename to src/module/dlg/asy_08.dlg.json diff --git a/src/mod/dlg/aw_waitress.dlg.json b/src/module/dlg/aw_waitress.dlg.json similarity index 100% rename from src/mod/dlg/aw_waitress.dlg.json rename to src/module/dlg/aw_waitress.dlg.json diff --git a/src/mod/dlg/awbarmaid.dlg.json b/src/module/dlg/awbarmaid.dlg.json similarity index 100% rename from src/mod/dlg/awbarmaid.dlg.json rename to src/module/dlg/awbarmaid.dlg.json diff --git a/src/mod/dlg/awdel.dlg.json b/src/module/dlg/awdel.dlg.json similarity index 100% rename from src/mod/dlg/awdel.dlg.json rename to src/module/dlg/awdel.dlg.json diff --git a/src/mod/dlg/awdeletethis.dlg.json b/src/module/dlg/awdeletethis.dlg.json similarity index 100% rename from src/mod/dlg/awdeletethis.dlg.json rename to src/module/dlg/awdeletethis.dlg.json diff --git a/src/mod/dlg/awdrowpeenee.dlg.json b/src/module/dlg/awdrowpeenee.dlg.json similarity index 100% rename from src/mod/dlg/awdrowpeenee.dlg.json rename to src/module/dlg/awdrowpeenee.dlg.json diff --git a/src/mod/dlg/awdrowwhore.dlg.json b/src/module/dlg/awdrowwhore.dlg.json similarity index 100% rename from src/mod/dlg/awdrowwhore.dlg.json rename to src/module/dlg/awdrowwhore.dlg.json diff --git a/src/mod/dlg/awdruidbuff.dlg.json b/src/module/dlg/awdruidbuff.dlg.json similarity index 100% rename from src/mod/dlg/awdruidbuff.dlg.json rename to src/module/dlg/awdruidbuff.dlg.json diff --git a/src/mod/dlg/awkat.dlg.json b/src/module/dlg/awkat.dlg.json similarity index 100% rename from src/mod/dlg/awkat.dlg.json rename to src/module/dlg/awkat.dlg.json diff --git a/src/mod/dlg/awportalrune.dlg.json b/src/module/dlg/awportalrune.dlg.json similarity index 100% rename from src/mod/dlg/awportalrune.dlg.json rename to src/module/dlg/awportalrune.dlg.json diff --git a/src/mod/dlg/awsignpost.dlg.json b/src/module/dlg/awsignpost.dlg.json similarity index 100% rename from src/mod/dlg/awsignpost.dlg.json rename to src/module/dlg/awsignpost.dlg.json diff --git a/src/mod/dlg/awverarune.dlg.json b/src/module/dlg/awverarune.dlg.json similarity index 100% rename from src/mod/dlg/awverarune.dlg.json rename to src/module/dlg/awverarune.dlg.json diff --git a/src/mod/dlg/b2_netsball.dlg.json b/src/module/dlg/b2_netsball.dlg.json similarity index 100% rename from src/mod/dlg/b2_netsball.dlg.json rename to src/module/dlg/b2_netsball.dlg.json diff --git a/src/mod/dlg/bankconvo.dlg.json b/src/module/dlg/bankconvo.dlg.json similarity index 100% rename from src/mod/dlg/bankconvo.dlg.json rename to src/module/dlg/bankconvo.dlg.json diff --git a/src/mod/dlg/bill.dlg.json b/src/module/dlg/bill.dlg.json similarity index 100% rename from src/mod/dlg/bill.dlg.json rename to src/module/dlg/bill.dlg.json diff --git a/src/mod/dlg/boim.dlg.json b/src/module/dlg/boim.dlg.json similarity index 100% rename from src/mod/dlg/boim.dlg.json rename to src/module/dlg/boim.dlg.json diff --git a/src/mod/dlg/calis_convo.dlg.json b/src/module/dlg/calis_convo.dlg.json similarity index 100% rename from src/mod/dlg/calis_convo.dlg.json rename to src/module/dlg/calis_convo.dlg.json diff --git a/src/mod/dlg/cb_dm3.dlg.json b/src/module/dlg/cb_dm3.dlg.json similarity index 100% rename from src/mod/dlg/cb_dm3.dlg.json rename to src/module/dlg/cb_dm3.dlg.json diff --git a/src/mod/dlg/confessor_convo.dlg.json b/src/module/dlg/confessor_convo.dlg.json similarity index 100% rename from src/mod/dlg/confessor_convo.dlg.json rename to src/module/dlg/confessor_convo.dlg.json diff --git a/src/mod/dlg/conv_algin.dlg.json b/src/module/dlg/conv_algin.dlg.json similarity index 100% rename from src/mod/dlg/conv_algin.dlg.json rename to src/module/dlg/conv_algin.dlg.json diff --git a/src/mod/dlg/conv_animalmaste.dlg.json b/src/module/dlg/conv_animalmaste.dlg.json similarity index 100% rename from src/mod/dlg/conv_animalmaste.dlg.json rename to src/module/dlg/conv_animalmaste.dlg.json diff --git a/src/mod/dlg/conv_ares2.dlg.json b/src/module/dlg/conv_ares2.dlg.json similarity index 100% rename from src/mod/dlg/conv_ares2.dlg.json rename to src/module/dlg/conv_ares2.dlg.json diff --git a/src/mod/dlg/conv_ass_ship_01.dlg.json b/src/module/dlg/conv_ass_ship_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_ass_ship_01.dlg.json rename to src/module/dlg/conv_ass_ship_01.dlg.json diff --git a/src/mod/dlg/conv_ass_ship_02.dlg.json b/src/module/dlg/conv_ass_ship_02.dlg.json similarity index 100% rename from src/mod/dlg/conv_ass_ship_02.dlg.json rename to src/module/dlg/conv_ass_ship_02.dlg.json diff --git a/src/mod/dlg/conv_asyambass.dlg.json b/src/module/dlg/conv_asyambass.dlg.json similarity index 100% rename from src/mod/dlg/conv_asyambass.dlg.json rename to src/module/dlg/conv_asyambass.dlg.json diff --git a/src/mod/dlg/conv_atl_well.dlg.json b/src/module/dlg/conv_atl_well.dlg.json similarity index 100% rename from src/mod/dlg/conv_atl_well.dlg.json rename to src/module/dlg/conv_atl_well.dlg.json diff --git a/src/mod/dlg/conv_atlantis_01.dlg.json b/src/module/dlg/conv_atlantis_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_atlantis_01.dlg.json rename to src/module/dlg/conv_atlantis_01.dlg.json diff --git a/src/mod/dlg/conv_atlantis_p2.dlg.json b/src/module/dlg/conv_atlantis_p2.dlg.json similarity index 100% rename from src/mod/dlg/conv_atlantis_p2.dlg.json rename to src/module/dlg/conv_atlantis_p2.dlg.json diff --git a/src/mod/dlg/conv_atligloo.dlg.json b/src/module/dlg/conv_atligloo.dlg.json similarity index 100% rename from src/mod/dlg/conv_atligloo.dlg.json rename to src/module/dlg/conv_atligloo.dlg.json diff --git a/src/mod/dlg/conv_bear_01.dlg.json b/src/module/dlg/conv_bear_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_bear_01.dlg.json rename to src/module/dlg/conv_bear_01.dlg.json diff --git a/src/mod/dlg/conv_bearship02.dlg.json b/src/module/dlg/conv_bearship02.dlg.json similarity index 100% rename from src/mod/dlg/conv_bearship02.dlg.json rename to src/module/dlg/conv_bearship02.dlg.json diff --git a/src/mod/dlg/conv_bearship_03.dlg.json b/src/module/dlg/conv_bearship_03.dlg.json similarity index 100% rename from src/mod/dlg/conv_bearship_03.dlg.json rename to src/module/dlg/conv_bearship_03.dlg.json diff --git a/src/mod/dlg/conv_bearship_04.dlg.json b/src/module/dlg/conv_bearship_04.dlg.json similarity index 100% rename from src/mod/dlg/conv_bearship_04.dlg.json rename to src/module/dlg/conv_bearship_04.dlg.json diff --git a/src/mod/dlg/conv_beggar.dlg.json b/src/module/dlg/conv_beggar.dlg.json similarity index 100% rename from src/mod/dlg/conv_beggar.dlg.json rename to src/module/dlg/conv_beggar.dlg.json diff --git a/src/mod/dlg/conv_breth2.dlg.json b/src/module/dlg/conv_breth2.dlg.json similarity index 100% rename from src/mod/dlg/conv_breth2.dlg.json rename to src/module/dlg/conv_breth2.dlg.json diff --git a/src/mod/dlg/conv_brew2.dlg.json b/src/module/dlg/conv_brew2.dlg.json similarity index 100% rename from src/mod/dlg/conv_brew2.dlg.json rename to src/module/dlg/conv_brew2.dlg.json diff --git a/src/mod/dlg/conv_brewmaster.dlg.json b/src/module/dlg/conv_brewmaster.dlg.json similarity index 100% rename from src/mod/dlg/conv_brewmaster.dlg.json rename to src/module/dlg/conv_brewmaster.dlg.json diff --git a/src/mod/dlg/conv_bvcouncil.dlg.json b/src/module/dlg/conv_bvcouncil.dlg.json similarity index 100% rename from src/mod/dlg/conv_bvcouncil.dlg.json rename to src/module/dlg/conv_bvcouncil.dlg.json diff --git a/src/mod/dlg/conv_cainguard.dlg.json b/src/module/dlg/conv_cainguard.dlg.json similarity index 100% rename from src/mod/dlg/conv_cainguard.dlg.json rename to src/module/dlg/conv_cainguard.dlg.json diff --git a/src/mod/dlg/conv_caliman.dlg.json b/src/module/dlg/conv_caliman.dlg.json similarity index 100% rename from src/mod/dlg/conv_caliman.dlg.json rename to src/module/dlg/conv_caliman.dlg.json diff --git a/src/mod/dlg/conv_caretaker.dlg.json b/src/module/dlg/conv_caretaker.dlg.json similarity index 100% rename from src/mod/dlg/conv_caretaker.dlg.json rename to src/module/dlg/conv_caretaker.dlg.json diff --git a/src/mod/dlg/conv_cbdm2.dlg.json b/src/module/dlg/conv_cbdm2.dlg.json similarity index 100% rename from src/mod/dlg/conv_cbdm2.dlg.json rename to src/module/dlg/conv_cbdm2.dlg.json diff --git a/src/mod/dlg/conv_cbrune.dlg.json b/src/module/dlg/conv_cbrune.dlg.json similarity index 100% rename from src/mod/dlg/conv_cbrune.dlg.json rename to src/module/dlg/conv_cbrune.dlg.json diff --git a/src/mod/dlg/conv_cushions.dlg.json b/src/module/dlg/conv_cushions.dlg.json similarity index 100% rename from src/mod/dlg/conv_cushions.dlg.json rename to src/module/dlg/conv_cushions.dlg.json diff --git a/src/mod/dlg/conv_des_merchan.dlg.json b/src/module/dlg/conv_des_merchan.dlg.json similarity index 100% rename from src/mod/dlg/conv_des_merchan.dlg.json rename to src/module/dlg/conv_des_merchan.dlg.json diff --git a/src/mod/dlg/conv_dirth01.dlg.json b/src/module/dlg/conv_dirth01.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth01.dlg.json rename to src/module/dlg/conv_dirth01.dlg.json diff --git a/src/mod/dlg/conv_dirth02.dlg.json b/src/module/dlg/conv_dirth02.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth02.dlg.json rename to src/module/dlg/conv_dirth02.dlg.json diff --git a/src/mod/dlg/conv_dirth03.dlg.json b/src/module/dlg/conv_dirth03.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth03.dlg.json rename to src/module/dlg/conv_dirth03.dlg.json diff --git a/src/mod/dlg/conv_dirth04.dlg.json b/src/module/dlg/conv_dirth04.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth04.dlg.json rename to src/module/dlg/conv_dirth04.dlg.json diff --git a/src/mod/dlg/conv_dirth05.dlg.json b/src/module/dlg/conv_dirth05.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth05.dlg.json rename to src/module/dlg/conv_dirth05.dlg.json diff --git a/src/mod/dlg/conv_dirth06.dlg.json b/src/module/dlg/conv_dirth06.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth06.dlg.json rename to src/module/dlg/conv_dirth06.dlg.json diff --git a/src/mod/dlg/conv_dirth07.dlg.json b/src/module/dlg/conv_dirth07.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth07.dlg.json rename to src/module/dlg/conv_dirth07.dlg.json diff --git a/src/mod/dlg/conv_dirth08.dlg.json b/src/module/dlg/conv_dirth08.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth08.dlg.json rename to src/module/dlg/conv_dirth08.dlg.json diff --git a/src/mod/dlg/conv_dirth09.dlg.json b/src/module/dlg/conv_dirth09.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth09.dlg.json rename to src/module/dlg/conv_dirth09.dlg.json diff --git a/src/mod/dlg/conv_dirth10.dlg.json b/src/module/dlg/conv_dirth10.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth10.dlg.json rename to src/module/dlg/conv_dirth10.dlg.json diff --git a/src/mod/dlg/conv_dirth11.dlg.json b/src/module/dlg/conv_dirth11.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirth11.dlg.json rename to src/module/dlg/conv_dirth11.dlg.json diff --git a/src/mod/dlg/conv_dirthprison.dlg.json b/src/module/dlg/conv_dirthprison.dlg.json similarity index 100% rename from src/mod/dlg/conv_dirthprison.dlg.json rename to src/module/dlg/conv_dirthprison.dlg.json diff --git a/src/mod/dlg/conv_dm1.dlg.json b/src/module/dlg/conv_dm1.dlg.json similarity index 100% rename from src/mod/dlg/conv_dm1.dlg.json rename to src/module/dlg/conv_dm1.dlg.json diff --git a/src/mod/dlg/conv_dm2.dlg.json b/src/module/dlg/conv_dm2.dlg.json similarity index 100% rename from src/mod/dlg/conv_dm2.dlg.json rename to src/module/dlg/conv_dm2.dlg.json diff --git a/src/mod/dlg/conv_dm3.dlg.json b/src/module/dlg/conv_dm3.dlg.json similarity index 100% rename from src/mod/dlg/conv_dm3.dlg.json rename to src/module/dlg/conv_dm3.dlg.json diff --git a/src/mod/dlg/conv_dm44.dlg.json b/src/module/dlg/conv_dm44.dlg.json similarity index 100% rename from src/mod/dlg/conv_dm44.dlg.json rename to src/module/dlg/conv_dm44.dlg.json diff --git a/src/mod/dlg/conv_dm5.dlg.json b/src/module/dlg/conv_dm5.dlg.json similarity index 100% rename from src/mod/dlg/conv_dm5.dlg.json rename to src/module/dlg/conv_dm5.dlg.json diff --git a/src/mod/dlg/conv_doc_04.dlg.json b/src/module/dlg/conv_doc_04.dlg.json similarity index 100% rename from src/mod/dlg/conv_doc_04.dlg.json rename to src/module/dlg/conv_doc_04.dlg.json diff --git a/src/mod/dlg/conv_doc_guild01.dlg.json b/src/module/dlg/conv_doc_guild01.dlg.json similarity index 100% rename from src/mod/dlg/conv_doc_guild01.dlg.json rename to src/module/dlg/conv_doc_guild01.dlg.json diff --git a/src/mod/dlg/conv_door.dlg.json b/src/module/dlg/conv_door.dlg.json similarity index 100% rename from src/mod/dlg/conv_door.dlg.json rename to src/module/dlg/conv_door.dlg.json diff --git a/src/mod/dlg/conv_dragenergy.dlg.json b/src/module/dlg/conv_dragenergy.dlg.json similarity index 100% rename from src/mod/dlg/conv_dragenergy.dlg.json rename to src/module/dlg/conv_dragenergy.dlg.json diff --git a/src/mod/dlg/conv_dragonslaye.dlg.json b/src/module/dlg/conv_dragonslaye.dlg.json similarity index 100% rename from src/mod/dlg/conv_dragonslaye.dlg.json rename to src/module/dlg/conv_dragonslaye.dlg.json diff --git a/src/mod/dlg/conv_dragport.dlg.json b/src/module/dlg/conv_dragport.dlg.json similarity index 100% rename from src/mod/dlg/conv_dragport.dlg.json rename to src/module/dlg/conv_dragport.dlg.json diff --git a/src/mod/dlg/conv_drowwizz.dlg.json b/src/module/dlg/conv_drowwizz.dlg.json similarity index 100% rename from src/mod/dlg/conv_drowwizz.dlg.json rename to src/module/dlg/conv_drowwizz.dlg.json diff --git a/src/mod/dlg/conv_elder_asy.dlg.json b/src/module/dlg/conv_elder_asy.dlg.json similarity index 100% rename from src/mod/dlg/conv_elder_asy.dlg.json rename to src/module/dlg/conv_elder_asy.dlg.json diff --git a/src/mod/dlg/conv_elder_oz.dlg.json b/src/module/dlg/conv_elder_oz.dlg.json similarity index 100% rename from src/mod/dlg/conv_elder_oz.dlg.json rename to src/module/dlg/conv_elder_oz.dlg.json diff --git a/src/mod/dlg/conv_elderrepent.dlg.json b/src/module/dlg/conv_elderrepent.dlg.json similarity index 100% rename from src/mod/dlg/conv_elderrepent.dlg.json rename to src/module/dlg/conv_elderrepent.dlg.json diff --git a/src/mod/dlg/conv_eldershogun.dlg.json b/src/module/dlg/conv_eldershogun.dlg.json similarity index 100% rename from src/mod/dlg/conv_eldershogun.dlg.json rename to src/module/dlg/conv_eldershogun.dlg.json diff --git a/src/mod/dlg/conv_eldertm.dlg.json b/src/module/dlg/conv_eldertm.dlg.json similarity index 100% rename from src/mod/dlg/conv_eldertm.dlg.json rename to src/module/dlg/conv_eldertm.dlg.json diff --git a/src/mod/dlg/conv_elf_well.dlg.json b/src/module/dlg/conv_elf_well.dlg.json similarity index 100% rename from src/mod/dlg/conv_elf_well.dlg.json rename to src/module/dlg/conv_elf_well.dlg.json diff --git a/src/mod/dlg/conv_elfmerch.dlg.json b/src/module/dlg/conv_elfmerch.dlg.json similarity index 100% rename from src/mod/dlg/conv_elfmerch.dlg.json rename to src/module/dlg/conv_elfmerch.dlg.json diff --git a/src/mod/dlg/conv_elfpreist.dlg.json b/src/module/dlg/conv_elfpreist.dlg.json similarity index 100% rename from src/mod/dlg/conv_elfpreist.dlg.json rename to src/module/dlg/conv_elfpreist.dlg.json diff --git a/src/mod/dlg/conv_elvedar_all.dlg.json b/src/module/dlg/conv_elvedar_all.dlg.json similarity index 100% rename from src/mod/dlg/conv_elvedar_all.dlg.json rename to src/module/dlg/conv_elvedar_all.dlg.json diff --git a/src/mod/dlg/conv_emote.dlg.json b/src/module/dlg/conv_emote.dlg.json similarity index 100% rename from src/mod/dlg/conv_emote.dlg.json rename to src/module/dlg/conv_emote.dlg.json diff --git a/src/mod/dlg/conv_enchatedmer.dlg.json b/src/module/dlg/conv_enchatedmer.dlg.json similarity index 100% rename from src/mod/dlg/conv_enchatedmer.dlg.json rename to src/module/dlg/conv_enchatedmer.dlg.json diff --git a/src/mod/dlg/conv_fareast2.dlg.json b/src/module/dlg/conv_fareast2.dlg.json similarity index 100% rename from src/mod/dlg/conv_fareast2.dlg.json rename to src/module/dlg/conv_fareast2.dlg.json diff --git a/src/mod/dlg/conv_farmer_joe.dlg.json b/src/module/dlg/conv_farmer_joe.dlg.json similarity index 100% rename from src/mod/dlg/conv_farmer_joe.dlg.json rename to src/module/dlg/conv_farmer_joe.dlg.json diff --git a/src/mod/dlg/conv_fistsgaurd.dlg.json b/src/module/dlg/conv_fistsgaurd.dlg.json similarity index 100% rename from src/mod/dlg/conv_fistsgaurd.dlg.json rename to src/module/dlg/conv_fistsgaurd.dlg.json diff --git a/src/mod/dlg/conv_fizzle.dlg.json b/src/module/dlg/conv_fizzle.dlg.json similarity index 100% rename from src/mod/dlg/conv_fizzle.dlg.json rename to src/module/dlg/conv_fizzle.dlg.json diff --git a/src/mod/dlg/conv_from_fe.dlg.json b/src/module/dlg/conv_from_fe.dlg.json similarity index 100% rename from src/mod/dlg/conv_from_fe.dlg.json rename to src/module/dlg/conv_from_fe.dlg.json diff --git a/src/mod/dlg/conv_genral.dlg.json b/src/module/dlg/conv_genral.dlg.json similarity index 100% rename from src/mod/dlg/conv_genral.dlg.json rename to src/module/dlg/conv_genral.dlg.json diff --git a/src/mod/dlg/conv_grend.dlg.json b/src/module/dlg/conv_grend.dlg.json similarity index 100% rename from src/mod/dlg/conv_grend.dlg.json rename to src/module/dlg/conv_grend.dlg.json diff --git a/src/mod/dlg/conv_guild_6.dlg.json b/src/module/dlg/conv_guild_6.dlg.json similarity index 100% rename from src/mod/dlg/conv_guild_6.dlg.json rename to src/module/dlg/conv_guild_6.dlg.json diff --git a/src/mod/dlg/conv_healer.dlg.json b/src/module/dlg/conv_healer.dlg.json similarity index 100% rename from src/mod/dlg/conv_healer.dlg.json rename to src/module/dlg/conv_healer.dlg.json diff --git a/src/mod/dlg/conv_healer2.dlg.json b/src/module/dlg/conv_healer2.dlg.json similarity index 100% rename from src/mod/dlg/conv_healer2.dlg.json rename to src/module/dlg/conv_healer2.dlg.json diff --git a/src/mod/dlg/conv_jerkins.dlg.json b/src/module/dlg/conv_jerkins.dlg.json similarity index 100% rename from src/mod/dlg/conv_jerkins.dlg.json rename to src/module/dlg/conv_jerkins.dlg.json diff --git a/src/mod/dlg/conv_jez.dlg.json b/src/module/dlg/conv_jez.dlg.json similarity index 100% rename from src/mod/dlg/conv_jez.dlg.json rename to src/module/dlg/conv_jez.dlg.json diff --git a/src/mod/dlg/conv_jimmys.dlg.json b/src/module/dlg/conv_jimmys.dlg.json similarity index 100% rename from src/mod/dlg/conv_jimmys.dlg.json rename to src/module/dlg/conv_jimmys.dlg.json diff --git a/src/mod/dlg/conv_killer.dlg.json b/src/module/dlg/conv_killer.dlg.json similarity index 100% rename from src/mod/dlg/conv_killer.dlg.json rename to src/module/dlg/conv_killer.dlg.json diff --git a/src/mod/dlg/conv_klaum.dlg.json b/src/module/dlg/conv_klaum.dlg.json similarity index 100% rename from src/mod/dlg/conv_klaum.dlg.json rename to src/module/dlg/conv_klaum.dlg.json diff --git a/src/mod/dlg/conv_legion.dlg.json b/src/module/dlg/conv_legion.dlg.json similarity index 100% rename from src/mod/dlg/conv_legion.dlg.json rename to src/module/dlg/conv_legion.dlg.json diff --git a/src/mod/dlg/conv_legionbar.dlg.json b/src/module/dlg/conv_legionbar.dlg.json similarity index 100% rename from src/mod/dlg/conv_legionbar.dlg.json rename to src/module/dlg/conv_legionbar.dlg.json diff --git a/src/mod/dlg/conv_librarian.dlg.json b/src/module/dlg/conv_librarian.dlg.json similarity index 100% rename from src/mod/dlg/conv_librarian.dlg.json rename to src/module/dlg/conv_librarian.dlg.json diff --git a/src/mod/dlg/conv_librarycloa.dlg.json b/src/module/dlg/conv_librarycloa.dlg.json similarity index 100% rename from src/mod/dlg/conv_librarycloa.dlg.json rename to src/module/dlg/conv_librarycloa.dlg.json diff --git a/src/mod/dlg/conv_lith.dlg.json b/src/module/dlg/conv_lith.dlg.json similarity index 100% rename from src/mod/dlg/conv_lith.dlg.json rename to src/module/dlg/conv_lith.dlg.json diff --git a/src/mod/dlg/conv_lith1.dlg.json b/src/module/dlg/conv_lith1.dlg.json similarity index 100% rename from src/mod/dlg/conv_lith1.dlg.json rename to src/module/dlg/conv_lith1.dlg.json diff --git a/src/mod/dlg/conv_lith2.dlg.json b/src/module/dlg/conv_lith2.dlg.json similarity index 100% rename from src/mod/dlg/conv_lith2.dlg.json rename to src/module/dlg/conv_lith2.dlg.json diff --git a/src/mod/dlg/conv_lith3.dlg.json b/src/module/dlg/conv_lith3.dlg.json similarity index 100% rename from src/mod/dlg/conv_lith3.dlg.json rename to src/module/dlg/conv_lith3.dlg.json diff --git a/src/mod/dlg/conv_malnip.dlg.json b/src/module/dlg/conv_malnip.dlg.json similarity index 100% rename from src/mod/dlg/conv_malnip.dlg.json rename to src/module/dlg/conv_malnip.dlg.json diff --git a/src/mod/dlg/conv_max.dlg.json b/src/module/dlg/conv_max.dlg.json similarity index 100% rename from src/mod/dlg/conv_max.dlg.json rename to src/module/dlg/conv_max.dlg.json diff --git a/src/mod/dlg/conv_mayor.dlg.json b/src/module/dlg/conv_mayor.dlg.json similarity index 100% rename from src/mod/dlg/conv_mayor.dlg.json rename to src/module/dlg/conv_mayor.dlg.json diff --git a/src/mod/dlg/conv_mick_100.dlg.json b/src/module/dlg/conv_mick_100.dlg.json similarity index 100% rename from src/mod/dlg/conv_mick_100.dlg.json rename to src/module/dlg/conv_mick_100.dlg.json diff --git a/src/mod/dlg/conv_mickson.dlg.json b/src/module/dlg/conv_mickson.dlg.json similarity index 100% rename from src/mod/dlg/conv_mickson.dlg.json rename to src/module/dlg/conv_mickson.dlg.json diff --git a/src/mod/dlg/conv_midget.dlg.json b/src/module/dlg/conv_midget.dlg.json similarity index 100% rename from src/mod/dlg/conv_midget.dlg.json rename to src/module/dlg/conv_midget.dlg.json diff --git a/src/mod/dlg/conv_mordkey.dlg.json b/src/module/dlg/conv_mordkey.dlg.json similarity index 100% rename from src/mod/dlg/conv_mordkey.dlg.json rename to src/module/dlg/conv_mordkey.dlg.json diff --git a/src/mod/dlg/conv_mrsjerkin.dlg.json b/src/module/dlg/conv_mrsjerkin.dlg.json similarity index 100% rename from src/mod/dlg/conv_mrsjerkin.dlg.json rename to src/module/dlg/conv_mrsjerkin.dlg.json diff --git a/src/mod/dlg/conv_niki.dlg.json b/src/module/dlg/conv_niki.dlg.json similarity index 100% rename from src/mod/dlg/conv_niki.dlg.json rename to src/module/dlg/conv_niki.dlg.json diff --git a/src/mod/dlg/conv_noble.dlg.json b/src/module/dlg/conv_noble.dlg.json similarity index 100% rename from src/mod/dlg/conv_noble.dlg.json rename to src/module/dlg/conv_noble.dlg.json diff --git a/src/mod/dlg/conv_old_1.dlg.json b/src/module/dlg/conv_old_1.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_1.dlg.json rename to src/module/dlg/conv_old_1.dlg.json diff --git a/src/mod/dlg/conv_old_2.dlg.json b/src/module/dlg/conv_old_2.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_2.dlg.json rename to src/module/dlg/conv_old_2.dlg.json diff --git a/src/mod/dlg/conv_old_3.dlg.json b/src/module/dlg/conv_old_3.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_3.dlg.json rename to src/module/dlg/conv_old_3.dlg.json diff --git a/src/mod/dlg/conv_old_4.dlg.json b/src/module/dlg/conv_old_4.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_4.dlg.json rename to src/module/dlg/conv_old_4.dlg.json diff --git a/src/mod/dlg/conv_old_5.dlg.json b/src/module/dlg/conv_old_5.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_5.dlg.json rename to src/module/dlg/conv_old_5.dlg.json diff --git a/src/mod/dlg/conv_old_6.dlg.json b/src/module/dlg/conv_old_6.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_6.dlg.json rename to src/module/dlg/conv_old_6.dlg.json diff --git a/src/mod/dlg/conv_old_7.dlg.json b/src/module/dlg/conv_old_7.dlg.json similarity index 100% rename from src/mod/dlg/conv_old_7.dlg.json rename to src/module/dlg/conv_old_7.dlg.json diff --git a/src/mod/dlg/conv_orcyield.dlg.json b/src/module/dlg/conv_orcyield.dlg.json similarity index 100% rename from src/mod/dlg/conv_orcyield.dlg.json rename to src/module/dlg/conv_orcyield.dlg.json diff --git a/src/mod/dlg/conv_osdkey.dlg.json b/src/module/dlg/conv_osdkey.dlg.json similarity index 100% rename from src/mod/dlg/conv_osdkey.dlg.json rename to src/module/dlg/conv_osdkey.dlg.json diff --git a/src/mod/dlg/conv_oz_01.dlg.json b/src/module/dlg/conv_oz_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_oz_01.dlg.json rename to src/module/dlg/conv_oz_01.dlg.json diff --git a/src/mod/dlg/conv_ozbook.dlg.json b/src/module/dlg/conv_ozbook.dlg.json similarity index 100% rename from src/mod/dlg/conv_ozbook.dlg.json rename to src/module/dlg/conv_ozbook.dlg.json diff --git a/src/mod/dlg/conv_ozbook2.dlg.json b/src/module/dlg/conv_ozbook2.dlg.json similarity index 100% rename from src/mod/dlg/conv_ozbook2.dlg.json rename to src/module/dlg/conv_ozbook2.dlg.json diff --git a/src/mod/dlg/conv_ozdude_02.dlg.json b/src/module/dlg/conv_ozdude_02.dlg.json similarity index 100% rename from src/mod/dlg/conv_ozdude_02.dlg.json rename to src/module/dlg/conv_ozdude_02.dlg.json diff --git a/src/mod/dlg/conv_oznoble_01.dlg.json b/src/module/dlg/conv_oznoble_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_oznoble_01.dlg.json rename to src/module/dlg/conv_oznoble_01.dlg.json diff --git a/src/mod/dlg/conv_polarbear05.dlg.json b/src/module/dlg/conv_polarbear05.dlg.json similarity index 100% rename from src/mod/dlg/conv_polarbear05.dlg.json rename to src/module/dlg/conv_polarbear05.dlg.json diff --git a/src/mod/dlg/conv_pvp1.dlg.json b/src/module/dlg/conv_pvp1.dlg.json similarity index 100% rename from src/mod/dlg/conv_pvp1.dlg.json rename to src/module/dlg/conv_pvp1.dlg.json diff --git a/src/mod/dlg/conv_pvp2.dlg.json b/src/module/dlg/conv_pvp2.dlg.json similarity index 100% rename from src/mod/dlg/conv_pvp2.dlg.json rename to src/module/dlg/conv_pvp2.dlg.json diff --git a/src/mod/dlg/conv_pvp_evil.dlg.json b/src/module/dlg/conv_pvp_evil.dlg.json similarity index 100% rename from src/mod/dlg/conv_pvp_evil.dlg.json rename to src/module/dlg/conv_pvp_evil.dlg.json diff --git a/src/mod/dlg/conv_pvp_good.dlg.json b/src/module/dlg/conv_pvp_good.dlg.json similarity index 100% rename from src/mod/dlg/conv_pvp_good.dlg.json rename to src/module/dlg/conv_pvp_good.dlg.json diff --git a/src/mod/dlg/conv_pvp_leave.dlg.json b/src/module/dlg/conv_pvp_leave.dlg.json similarity index 100% rename from src/mod/dlg/conv_pvp_leave.dlg.json rename to src/module/dlg/conv_pvp_leave.dlg.json diff --git a/src/mod/dlg/conv_reb.dlg.json b/src/module/dlg/conv_reb.dlg.json similarity index 100% rename from src/mod/dlg/conv_reb.dlg.json rename to src/module/dlg/conv_reb.dlg.json diff --git a/src/mod/dlg/conv_reb2.dlg.json b/src/module/dlg/conv_reb2.dlg.json similarity index 100% rename from src/mod/dlg/conv_reb2.dlg.json rename to src/module/dlg/conv_reb2.dlg.json diff --git a/src/mod/dlg/conv_rebalter.dlg.json b/src/module/dlg/conv_rebalter.dlg.json similarity index 100% rename from src/mod/dlg/conv_rebalter.dlg.json rename to src/module/dlg/conv_rebalter.dlg.json diff --git a/src/mod/dlg/conv_rebgate.dlg.json b/src/module/dlg/conv_rebgate.dlg.json similarity index 100% rename from src/mod/dlg/conv_rebgate.dlg.json rename to src/module/dlg/conv_rebgate.dlg.json diff --git a/src/mod/dlg/conv_repent_cpt.dlg.json b/src/module/dlg/conv_repent_cpt.dlg.json similarity index 100% rename from src/mod/dlg/conv_repent_cpt.dlg.json rename to src/module/dlg/conv_repent_cpt.dlg.json diff --git a/src/mod/dlg/conv_repent_cpt2.dlg.json b/src/module/dlg/conv_repent_cpt2.dlg.json similarity index 100% rename from src/mod/dlg/conv_repent_cpt2.dlg.json rename to src/module/dlg/conv_repent_cpt2.dlg.json diff --git a/src/mod/dlg/conv_research.dlg.json b/src/module/dlg/conv_research.dlg.json similarity index 100% rename from src/mod/dlg/conv_research.dlg.json rename to src/module/dlg/conv_research.dlg.json diff --git a/src/mod/dlg/conv_retire.dlg.json b/src/module/dlg/conv_retire.dlg.json similarity index 100% rename from src/mod/dlg/conv_retire.dlg.json rename to src/module/dlg/conv_retire.dlg.json diff --git a/src/mod/dlg/conv_rope.dlg.json b/src/module/dlg/conv_rope.dlg.json similarity index 100% rename from src/mod/dlg/conv_rope.dlg.json rename to src/module/dlg/conv_rope.dlg.json diff --git a/src/mod/dlg/conv_rope2.dlg.json b/src/module/dlg/conv_rope2.dlg.json similarity index 100% rename from src/mod/dlg/conv_rope2.dlg.json rename to src/module/dlg/conv_rope2.dlg.json diff --git a/src/mod/dlg/conv_sexyfreak.dlg.json b/src/module/dlg/conv_sexyfreak.dlg.json similarity index 100% rename from src/mod/dlg/conv_sexyfreak.dlg.json rename to src/module/dlg/conv_sexyfreak.dlg.json diff --git a/src/mod/dlg/conv_sgtundon.dlg.json b/src/module/dlg/conv_sgtundon.dlg.json similarity index 100% rename from src/mod/dlg/conv_sgtundon.dlg.json rename to src/module/dlg/conv_sgtundon.dlg.json diff --git a/src/mod/dlg/conv_ship_to_fe.dlg.json b/src/module/dlg/conv_ship_to_fe.dlg.json similarity index 100% rename from src/mod/dlg/conv_ship_to_fe.dlg.json rename to src/module/dlg/conv_ship_to_fe.dlg.json diff --git a/src/mod/dlg/conv_sho_priest.dlg.json b/src/module/dlg/conv_sho_priest.dlg.json similarity index 100% rename from src/mod/dlg/conv_sho_priest.dlg.json rename to src/module/dlg/conv_sho_priest.dlg.json diff --git a/src/mod/dlg/conv_sho_priest2.dlg.json b/src/module/dlg/conv_sho_priest2.dlg.json similarity index 100% rename from src/mod/dlg/conv_sho_priest2.dlg.json rename to src/module/dlg/conv_sho_priest2.dlg.json diff --git a/src/mod/dlg/conv_sho_priest3.dlg.json b/src/module/dlg/conv_sho_priest3.dlg.json similarity index 100% rename from src/mod/dlg/conv_sho_priest3.dlg.json rename to src/module/dlg/conv_sho_priest3.dlg.json diff --git a/src/mod/dlg/conv_sho_prison.dlg.json b/src/module/dlg/conv_sho_prison.dlg.json similarity index 100% rename from src/mod/dlg/conv_sho_prison.dlg.json rename to src/module/dlg/conv_sho_prison.dlg.json diff --git a/src/mod/dlg/conv_shrub.dlg.json b/src/module/dlg/conv_shrub.dlg.json similarity index 100% rename from src/mod/dlg/conv_shrub.dlg.json rename to src/module/dlg/conv_shrub.dlg.json diff --git a/src/mod/dlg/conv_sl_capt.dlg.json b/src/module/dlg/conv_sl_capt.dlg.json similarity index 100% rename from src/mod/dlg/conv_sl_capt.dlg.json rename to src/module/dlg/conv_sl_capt.dlg.json diff --git a/src/mod/dlg/conv_sl_capt2.dlg.json b/src/module/dlg/conv_sl_capt2.dlg.json similarity index 100% rename from src/mod/dlg/conv_sl_capt2.dlg.json rename to src/module/dlg/conv_sl_capt2.dlg.json diff --git a/src/mod/dlg/conv_snowdoor.dlg.json b/src/module/dlg/conv_snowdoor.dlg.json similarity index 100% rename from src/mod/dlg/conv_snowdoor.dlg.json rename to src/module/dlg/conv_snowdoor.dlg.json diff --git a/src/mod/dlg/conv_solar_gaurd.dlg.json b/src/module/dlg/conv_solar_gaurd.dlg.json similarity index 100% rename from src/mod/dlg/conv_solar_gaurd.dlg.json rename to src/module/dlg/conv_solar_gaurd.dlg.json diff --git a/src/mod/dlg/conv_spirit.dlg.json b/src/module/dlg/conv_spirit.dlg.json similarity index 100% rename from src/mod/dlg/conv_spirit.dlg.json rename to src/module/dlg/conv_spirit.dlg.json diff --git a/src/mod/dlg/conv_sreaper.dlg.json b/src/module/dlg/conv_sreaper.dlg.json similarity index 100% rename from src/mod/dlg/conv_sreaper.dlg.json rename to src/module/dlg/conv_sreaper.dlg.json diff --git a/src/mod/dlg/conv_tabmind.dlg.json b/src/module/dlg/conv_tabmind.dlg.json similarity index 100% rename from src/mod/dlg/conv_tabmind.dlg.json rename to src/module/dlg/conv_tabmind.dlg.json diff --git a/src/mod/dlg/conv_tabmind1.dlg.json b/src/module/dlg/conv_tabmind1.dlg.json similarity index 100% rename from src/mod/dlg/conv_tabmind1.dlg.json rename to src/module/dlg/conv_tabmind1.dlg.json diff --git a/src/mod/dlg/conv_temp.dlg.json b/src/module/dlg/conv_temp.dlg.json similarity index 100% rename from src/mod/dlg/conv_temp.dlg.json rename to src/module/dlg/conv_temp.dlg.json diff --git a/src/mod/dlg/conv_terrified.dlg.json b/src/module/dlg/conv_terrified.dlg.json similarity index 100% rename from src/mod/dlg/conv_terrified.dlg.json rename to src/module/dlg/conv_terrified.dlg.json diff --git a/src/mod/dlg/conv_testreb.dlg.json b/src/module/dlg/conv_testreb.dlg.json similarity index 100% rename from src/mod/dlg/conv_testreb.dlg.json rename to src/module/dlg/conv_testreb.dlg.json diff --git a/src/mod/dlg/conv_trainer.dlg.json b/src/module/dlg/conv_trainer.dlg.json similarity index 100% rename from src/mod/dlg/conv_trainer.dlg.json rename to src/module/dlg/conv_trainer.dlg.json diff --git a/src/mod/dlg/conv_treas_mas.dlg.json b/src/module/dlg/conv_treas_mas.dlg.json similarity index 100% rename from src/mod/dlg/conv_treas_mas.dlg.json rename to src/module/dlg/conv_treas_mas.dlg.json diff --git a/src/mod/dlg/conv_trinitygrea.dlg.json b/src/module/dlg/conv_trinitygrea.dlg.json similarity index 100% rename from src/mod/dlg/conv_trinitygrea.dlg.json rename to src/module/dlg/conv_trinitygrea.dlg.json diff --git a/src/mod/dlg/conv_tulls_shop.dlg.json b/src/module/dlg/conv_tulls_shop.dlg.json similarity index 100% rename from src/mod/dlg/conv_tulls_shop.dlg.json rename to src/module/dlg/conv_tulls_shop.dlg.json diff --git a/src/mod/dlg/conv_unen_01.dlg.json b/src/module/dlg/conv_unen_01.dlg.json similarity index 100% rename from src/mod/dlg/conv_unen_01.dlg.json rename to src/module/dlg/conv_unen_01.dlg.json diff --git a/src/mod/dlg/conv_vecmor.dlg.json b/src/module/dlg/conv_vecmor.dlg.json similarity index 100% rename from src/mod/dlg/conv_vecmor.dlg.json rename to src/module/dlg/conv_vecmor.dlg.json diff --git a/src/mod/dlg/conv_warn_sign.dlg.json b/src/module/dlg/conv_warn_sign.dlg.json similarity index 100% rename from src/mod/dlg/conv_warn_sign.dlg.json rename to src/module/dlg/conv_warn_sign.dlg.json diff --git a/src/mod/dlg/convelfpriest2.dlg.json b/src/module/dlg/convelfpriest2.dlg.json similarity index 100% rename from src/mod/dlg/convelfpriest2.dlg.json rename to src/module/dlg/convelfpriest2.dlg.json diff --git a/src/mod/dlg/convguild4.dlg.json b/src/module/dlg/convguild4.dlg.json similarity index 100% rename from src/mod/dlg/convguild4.dlg.json rename to src/module/dlg/convguild4.dlg.json diff --git a/src/mod/dlg/convo_bvcaptain.dlg.json b/src/module/dlg/convo_bvcaptain.dlg.json similarity index 100% rename from src/mod/dlg/convo_bvcaptain.dlg.json rename to src/module/dlg/convo_bvcaptain.dlg.json diff --git a/src/mod/dlg/convo_bvcaptain2.dlg.json b/src/module/dlg/convo_bvcaptain2.dlg.json similarity index 100% rename from src/mod/dlg/convo_bvcaptain2.dlg.json rename to src/module/dlg/convo_bvcaptain2.dlg.json diff --git a/src/mod/dlg/convo_farmer.dlg.json b/src/module/dlg/convo_farmer.dlg.json similarity index 100% rename from src/mod/dlg/convo_farmer.dlg.json rename to src/module/dlg/convo_farmer.dlg.json diff --git a/src/mod/dlg/convo_furtherjez.dlg.json b/src/module/dlg/convo_furtherjez.dlg.json similarity index 100% rename from src/mod/dlg/convo_furtherjez.dlg.json rename to src/module/dlg/convo_furtherjez.dlg.json diff --git a/src/mod/dlg/convo_grndkeeper.dlg.json b/src/module/dlg/convo_grndkeeper.dlg.json similarity index 100% rename from src/mod/dlg/convo_grndkeeper.dlg.json rename to src/module/dlg/convo_grndkeeper.dlg.json diff --git a/src/mod/dlg/council.dlg.json b/src/module/dlg/council.dlg.json similarity index 100% rename from src/mod/dlg/council.dlg.json rename to src/module/dlg/council.dlg.json diff --git a/src/mod/dlg/cs_conv_dmspirit.dlg.json b/src/module/dlg/cs_conv_dmspirit.dlg.json similarity index 100% rename from src/mod/dlg/cs_conv_dmspirit.dlg.json rename to src/module/dlg/cs_conv_dmspirit.dlg.json diff --git a/src/mod/dlg/dant.dlg.json b/src/module/dlg/dant.dlg.json similarity index 100% rename from src/mod/dlg/dant.dlg.json rename to src/module/dlg/dant.dlg.json diff --git a/src/mod/dlg/doorcv_dbi_room.dlg.json b/src/module/dlg/doorcv_dbi_room.dlg.json similarity index 100% rename from src/mod/dlg/doorcv_dbi_room.dlg.json rename to src/module/dlg/doorcv_dbi_room.dlg.json diff --git a/src/mod/dlg/doorcv_inn_room.dlg.json b/src/module/dlg/doorcv_inn_room.dlg.json similarity index 100% rename from src/mod/dlg/doorcv_inn_room.dlg.json rename to src/module/dlg/doorcv_inn_room.dlg.json diff --git a/src/mod/dlg/elfdefend.dlg.json b/src/module/dlg/elfdefend.dlg.json similarity index 100% rename from src/mod/dlg/elfdefend.dlg.json rename to src/module/dlg/elfdefend.dlg.json diff --git a/src/mod/dlg/gonv_slgargoyle.dlg.json b/src/module/dlg/gonv_slgargoyle.dlg.json similarity index 100% rename from src/mod/dlg/gonv_slgargoyle.dlg.json rename to src/module/dlg/gonv_slgargoyle.dlg.json diff --git a/src/mod/dlg/gratch_convo.dlg.json b/src/module/dlg/gratch_convo.dlg.json similarity index 100% rename from src/mod/dlg/gratch_convo.dlg.json rename to src/module/dlg/gratch_convo.dlg.json diff --git a/src/mod/dlg/headless.dlg.json b/src/module/dlg/headless.dlg.json similarity index 100% rename from src/mod/dlg/headless.dlg.json rename to src/module/dlg/headless.dlg.json diff --git a/src/mod/dlg/hilllsidesalia.dlg.json b/src/module/dlg/hilllsidesalia.dlg.json similarity index 100% rename from src/mod/dlg/hilllsidesalia.dlg.json rename to src/module/dlg/hilllsidesalia.dlg.json diff --git a/src/mod/dlg/hillsideassistan.dlg.json b/src/module/dlg/hillsideassistan.dlg.json similarity index 100% rename from src/mod/dlg/hillsideassistan.dlg.json rename to src/module/dlg/hillsideassistan.dlg.json diff --git a/src/mod/dlg/hillsidederpi.dlg.json b/src/module/dlg/hillsidederpi.dlg.json similarity index 100% rename from src/mod/dlg/hillsidederpi.dlg.json rename to src/module/dlg/hillsidederpi.dlg.json diff --git a/src/mod/dlg/hillsidedeva.dlg.json b/src/module/dlg/hillsidedeva.dlg.json similarity index 100% rename from src/mod/dlg/hillsidedeva.dlg.json rename to src/module/dlg/hillsidedeva.dlg.json diff --git a/src/mod/dlg/hillsideguard.dlg.json b/src/module/dlg/hillsideguard.dlg.json similarity index 100% rename from src/mod/dlg/hillsideguard.dlg.json rename to src/module/dlg/hillsideguard.dlg.json diff --git a/src/mod/dlg/hillsidetant.dlg.json b/src/module/dlg/hillsidetant.dlg.json similarity index 100% rename from src/mod/dlg/hillsidetant.dlg.json rename to src/module/dlg/hillsidetant.dlg.json diff --git a/src/mod/dlg/isis.dlg.json b/src/module/dlg/isis.dlg.json similarity index 100% rename from src/mod/dlg/isis.dlg.json rename to src/module/dlg/isis.dlg.json diff --git a/src/mod/dlg/jwcheshire.dlg.json b/src/module/dlg/jwcheshire.dlg.json similarity index 100% rename from src/mod/dlg/jwcheshire.dlg.json rename to src/module/dlg/jwcheshire.dlg.json diff --git a/src/mod/dlg/keepsign.dlg.json b/src/module/dlg/keepsign.dlg.json similarity index 100% rename from src/mod/dlg/keepsign.dlg.json rename to src/module/dlg/keepsign.dlg.json diff --git a/src/mod/dlg/lwguildkey.dlg.json b/src/module/dlg/lwguildkey.dlg.json similarity index 100% rename from src/mod/dlg/lwguildkey.dlg.json rename to src/module/dlg/lwguildkey.dlg.json diff --git a/src/mod/dlg/magers1_convo.dlg.json b/src/module/dlg/magers1_convo.dlg.json similarity index 100% rename from src/mod/dlg/magers1_convo.dlg.json rename to src/module/dlg/magers1_convo.dlg.json diff --git a/src/mod/dlg/mags2_convo.dlg.json b/src/module/dlg/mags2_convo.dlg.json similarity index 100% rename from src/mod/dlg/mags2_convo.dlg.json rename to src/module/dlg/mags2_convo.dlg.json diff --git a/src/mod/dlg/nobel_01.dlg.json b/src/module/dlg/nobel_01.dlg.json similarity index 100% rename from src/mod/dlg/nobel_01.dlg.json rename to src/module/dlg/nobel_01.dlg.json diff --git a/src/mod/dlg/oldpeople.dlg.json b/src/module/dlg/oldpeople.dlg.json similarity index 100% rename from src/mod/dlg/oldpeople.dlg.json rename to src/module/dlg/oldpeople.dlg.json diff --git a/src/mod/dlg/oz_01.dlg.json b/src/module/dlg/oz_01.dlg.json similarity index 100% rename from src/mod/dlg/oz_01.dlg.json rename to src/module/dlg/oz_01.dlg.json diff --git a/src/mod/dlg/oz_02.dlg.json b/src/module/dlg/oz_02.dlg.json similarity index 100% rename from src/mod/dlg/oz_02.dlg.json rename to src/module/dlg/oz_02.dlg.json diff --git a/src/mod/dlg/oz_03.dlg.json b/src/module/dlg/oz_03.dlg.json similarity index 100% rename from src/mod/dlg/oz_03.dlg.json rename to src/module/dlg/oz_03.dlg.json diff --git a/src/mod/dlg/oz_04.dlg.json b/src/module/dlg/oz_04.dlg.json similarity index 100% rename from src/mod/dlg/oz_04.dlg.json rename to src/module/dlg/oz_04.dlg.json diff --git a/src/mod/dlg/oz_05.dlg.json b/src/module/dlg/oz_05.dlg.json similarity index 100% rename from src/mod/dlg/oz_05.dlg.json rename to src/module/dlg/oz_05.dlg.json diff --git a/src/mod/dlg/peruppi.dlg.json b/src/module/dlg/peruppi.dlg.json similarity index 100% rename from src/mod/dlg/peruppi.dlg.json rename to src/module/dlg/peruppi.dlg.json diff --git a/src/mod/dlg/raja_shop.dlg.json b/src/module/dlg/raja_shop.dlg.json similarity index 100% rename from src/mod/dlg/raja_shop.dlg.json rename to src/module/dlg/raja_shop.dlg.json diff --git a/src/mod/dlg/reaperkey.dlg.json b/src/module/dlg/reaperkey.dlg.json similarity index 100% rename from src/mod/dlg/reaperkey.dlg.json rename to src/module/dlg/reaperkey.dlg.json diff --git a/src/mod/dlg/ringinfo_convo.dlg.json b/src/module/dlg/ringinfo_convo.dlg.json similarity index 100% rename from src/mod/dlg/ringinfo_convo.dlg.json rename to src/module/dlg/ringinfo_convo.dlg.json diff --git a/src/mod/dlg/senior_monk_conv.dlg.json b/src/module/dlg/senior_monk_conv.dlg.json similarity index 100% rename from src/mod/dlg/senior_monk_conv.dlg.json rename to src/module/dlg/senior_monk_conv.dlg.json diff --git a/src/mod/dlg/shifter.dlg.json b/src/module/dlg/shifter.dlg.json similarity index 100% rename from src/mod/dlg/shifter.dlg.json rename to src/module/dlg/shifter.dlg.json diff --git a/src/mod/dlg/shifterenergy.dlg.json b/src/module/dlg/shifterenergy.dlg.json similarity index 100% rename from src/mod/dlg/shifterenergy.dlg.json rename to src/module/dlg/shifterenergy.dlg.json diff --git a/src/mod/dlg/tkguildkey.dlg.json b/src/module/dlg/tkguildkey.dlg.json similarity index 100% rename from src/mod/dlg/tkguildkey.dlg.json rename to src/module/dlg/tkguildkey.dlg.json diff --git a/src/mod/dlg/zedd2_convo.dlg.json b/src/module/dlg/zedd2_convo.dlg.json similarity index 100% rename from src/mod/dlg/zedd2_convo.dlg.json rename to src/module/dlg/zedd2_convo.dlg.json diff --git a/src/mod/dlg/zedd_convo.dlg.json b/src/module/dlg/zedd_convo.dlg.json similarity index 100% rename from src/mod/dlg/zedd_convo.dlg.json rename to src/module/dlg/zedd_convo.dlg.json diff --git a/src/mod/fac/repute.fac.json b/src/module/fac/repute.fac.json similarity index 100% rename from src/mod/fac/repute.fac.json rename to src/module/fac/repute.fac.json diff --git a/src/mod/gic/a1.gic.json b/src/module/gic/a1.gic.json similarity index 100% rename from src/mod/gic/a1.gic.json rename to src/module/gic/a1.gic.json diff --git a/src/mod/gic/a1hall.gic.json b/src/module/gic/a1hall.gic.json similarity index 100% rename from src/mod/gic/a1hall.gic.json rename to src/module/gic/a1hall.gic.json diff --git a/src/mod/gic/a2.gic.json b/src/module/gic/a2.gic.json similarity index 100% rename from src/mod/gic/a2.gic.json rename to src/module/gic/a2.gic.json diff --git a/src/mod/gic/a2hall.gic.json b/src/module/gic/a2hall.gic.json similarity index 100% rename from src/mod/gic/a2hall.gic.json rename to src/module/gic/a2hall.gic.json diff --git a/src/mod/gic/a3.gic.json b/src/module/gic/a3.gic.json similarity index 100% rename from src/mod/gic/a3.gic.json rename to src/module/gic/a3.gic.json diff --git a/src/mod/gic/ancientmountainc.gic.json b/src/module/gic/ancientmountainc.gic.json similarity index 100% rename from src/mod/gic/ancientmountainc.gic.json rename to src/module/gic/ancientmountainc.gic.json diff --git a/src/mod/gic/ancientmtformian.gic.json b/src/module/gic/ancientmtformian.gic.json similarity index 100% rename from src/mod/gic/ancientmtformian.gic.json rename to src/module/gic/ancientmtformian.gic.json diff --git a/src/mod/gic/ancientmtruins.gic.json b/src/module/gic/ancientmtruins.gic.json similarity index 100% rename from src/mod/gic/ancientmtruins.gic.json rename to src/module/gic/ancientmtruins.gic.json diff --git a/src/mod/gic/ancientmtstinger.gic.json b/src/module/gic/ancientmtstinger.gic.json similarity index 100% rename from src/mod/gic/ancientmtstinger.gic.json rename to src/module/gic/ancientmtstinger.gic.json diff --git a/src/mod/gic/area.gic.json b/src/module/gic/area.gic.json similarity index 100% rename from src/mod/gic/area.gic.json rename to src/module/gic/area.gic.json diff --git a/src/mod/gic/area001.gic.json b/src/module/gic/area001.gic.json similarity index 100% rename from src/mod/gic/area001.gic.json rename to src/module/gic/area001.gic.json diff --git a/src/mod/gic/area002.gic.json b/src/module/gic/area002.gic.json similarity index 100% rename from src/mod/gic/area002.gic.json rename to src/module/gic/area002.gic.json diff --git a/src/mod/gic/area003.gic.json b/src/module/gic/area003.gic.json similarity index 100% rename from src/mod/gic/area003.gic.json rename to src/module/gic/area003.gic.json diff --git a/src/mod/gic/area004.gic.json b/src/module/gic/area004.gic.json similarity index 100% rename from src/mod/gic/area004.gic.json rename to src/module/gic/area004.gic.json diff --git a/src/mod/gic/area005.gic.json b/src/module/gic/area005.gic.json similarity index 100% rename from src/mod/gic/area005.gic.json rename to src/module/gic/area005.gic.json diff --git a/src/mod/gic/area006.gic.json b/src/module/gic/area006.gic.json similarity index 100% rename from src/mod/gic/area006.gic.json rename to src/module/gic/area006.gic.json diff --git a/src/mod/gic/area007.gic.json b/src/module/gic/area007.gic.json similarity index 100% rename from src/mod/gic/area007.gic.json rename to src/module/gic/area007.gic.json diff --git a/src/mod/gic/area008.gic.json b/src/module/gic/area008.gic.json similarity index 100% rename from src/mod/gic/area008.gic.json rename to src/module/gic/area008.gic.json diff --git a/src/mod/gic/area009.gic.json b/src/module/gic/area009.gic.json similarity index 100% rename from src/mod/gic/area009.gic.json rename to src/module/gic/area009.gic.json diff --git a/src/mod/gic/area010.gic.json b/src/module/gic/area010.gic.json similarity index 100% rename from src/mod/gic/area010.gic.json rename to src/module/gic/area010.gic.json diff --git a/src/mod/gic/area011.gic.json b/src/module/gic/area011.gic.json similarity index 100% rename from src/mod/gic/area011.gic.json rename to src/module/gic/area011.gic.json diff --git a/src/mod/gic/area012.gic.json b/src/module/gic/area012.gic.json similarity index 100% rename from src/mod/gic/area012.gic.json rename to src/module/gic/area012.gic.json diff --git a/src/mod/gic/area013.gic.json b/src/module/gic/area013.gic.json similarity index 100% rename from src/mod/gic/area013.gic.json rename to src/module/gic/area013.gic.json diff --git a/src/mod/gic/area014.gic.json b/src/module/gic/area014.gic.json similarity index 100% rename from src/mod/gic/area014.gic.json rename to src/module/gic/area014.gic.json diff --git a/src/mod/gic/area015.gic.json b/src/module/gic/area015.gic.json similarity index 100% rename from src/mod/gic/area015.gic.json rename to src/module/gic/area015.gic.json diff --git a/src/mod/gic/area016.gic.json b/src/module/gic/area016.gic.json similarity index 100% rename from src/mod/gic/area016.gic.json rename to src/module/gic/area016.gic.json diff --git a/src/mod/gic/area017.gic.json b/src/module/gic/area017.gic.json similarity index 100% rename from src/mod/gic/area017.gic.json rename to src/module/gic/area017.gic.json diff --git a/src/mod/gic/area018.gic.json b/src/module/gic/area018.gic.json similarity index 100% rename from src/mod/gic/area018.gic.json rename to src/module/gic/area018.gic.json diff --git a/src/mod/gic/area019.gic.json b/src/module/gic/area019.gic.json similarity index 100% rename from src/mod/gic/area019.gic.json rename to src/module/gic/area019.gic.json diff --git a/src/mod/gic/area022.gic.json b/src/module/gic/area022.gic.json similarity index 100% rename from src/mod/gic/area022.gic.json rename to src/module/gic/area022.gic.json diff --git a/src/mod/gic/area024.gic.json b/src/module/gic/area024.gic.json similarity index 100% rename from src/mod/gic/area024.gic.json rename to src/module/gic/area024.gic.json diff --git a/src/mod/gic/area027.gic.json b/src/module/gic/area027.gic.json similarity index 100% rename from src/mod/gic/area027.gic.json rename to src/module/gic/area027.gic.json diff --git a/src/mod/gic/area028.gic.json b/src/module/gic/area028.gic.json similarity index 100% rename from src/mod/gic/area028.gic.json rename to src/module/gic/area028.gic.json diff --git a/src/mod/gic/area029.gic.json b/src/module/gic/area029.gic.json similarity index 100% rename from src/mod/gic/area029.gic.json rename to src/module/gic/area029.gic.json diff --git a/src/mod/gic/arena.gic.json b/src/module/gic/arena.gic.json similarity index 100% rename from src/mod/gic/arena.gic.json rename to src/module/gic/arena.gic.json diff --git a/src/mod/gic/asyriancastle.gic.json b/src/module/gic/asyriancastle.gic.json similarity index 100% rename from src/mod/gic/asyriancastle.gic.json rename to src/module/gic/asyriancastle.gic.json diff --git a/src/mod/gic/asyriancastle001.gic.json b/src/module/gic/asyriancastle001.gic.json similarity index 100% rename from src/mod/gic/asyriancastle001.gic.json rename to src/module/gic/asyriancastle001.gic.json diff --git a/src/mod/gic/asyrianholyruins.gic.json b/src/module/gic/asyrianholyruins.gic.json similarity index 100% rename from src/mod/gic/asyrianholyruins.gic.json rename to src/module/gic/asyrianholyruins.gic.json diff --git a/src/mod/gic/asyriantreasurer.gic.json b/src/module/gic/asyriantreasurer.gic.json similarity index 100% rename from src/mod/gic/asyriantreasurer.gic.json rename to src/module/gic/asyriantreasurer.gic.json diff --git a/src/mod/gic/asyrianupper.gic.json b/src/module/gic/asyrianupper.gic.json similarity index 100% rename from src/mod/gic/asyrianupper.gic.json rename to src/module/gic/asyrianupper.gic.json diff --git a/src/mod/gic/atlantis.gic.json b/src/module/gic/atlantis.gic.json similarity index 100% rename from src/mod/gic/atlantis.gic.json rename to src/module/gic/atlantis.gic.json diff --git a/src/mod/gic/atlantiseast.gic.json b/src/module/gic/atlantiseast.gic.json similarity index 100% rename from src/mod/gic/atlantiseast.gic.json rename to src/module/gic/atlantiseast.gic.json diff --git a/src/mod/gic/atlantiseastbuil.gic.json b/src/module/gic/atlantiseastbuil.gic.json similarity index 100% rename from src/mod/gic/atlantiseastbuil.gic.json rename to src/module/gic/atlantiseastbuil.gic.json diff --git a/src/mod/gic/atlantisnorth.gic.json b/src/module/gic/atlantisnorth.gic.json similarity index 100% rename from src/mod/gic/atlantisnorth.gic.json rename to src/module/gic/atlantisnorth.gic.json diff --git a/src/mod/gic/atlantisnorthbui.gic.json b/src/module/gic/atlantisnorthbui.gic.json similarity index 100% rename from src/mod/gic/atlantisnorthbui.gic.json rename to src/module/gic/atlantisnorthbui.gic.json diff --git a/src/mod/gic/atlantissouth.gic.json b/src/module/gic/atlantissouth.gic.json similarity index 100% rename from src/mod/gic/atlantissouth.gic.json rename to src/module/gic/atlantissouth.gic.json diff --git a/src/mod/gic/atlantissouthbui.gic.json b/src/module/gic/atlantissouthbui.gic.json similarity index 100% rename from src/mod/gic/atlantissouthbui.gic.json rename to src/module/gic/atlantissouthbui.gic.json diff --git a/src/mod/gic/atlantiswest.gic.json b/src/module/gic/atlantiswest.gic.json similarity index 100% rename from src/mod/gic/atlantiswest.gic.json rename to src/module/gic/atlantiswest.gic.json diff --git a/src/mod/gic/atlantiswestbuil.gic.json b/src/module/gic/atlantiswestbuil.gic.json similarity index 100% rename from src/mod/gic/atlantiswestbuil.gic.json rename to src/module/gic/atlantiswestbuil.gic.json diff --git a/src/mod/gic/awabandonedlodge.gic.json b/src/module/gic/awabandonedlodge.gic.json similarity index 100% rename from src/mod/gic/awabandonedlodge.gic.json rename to src/module/gic/awabandonedlodge.gic.json diff --git a/src/mod/gic/awcavern.gic.json b/src/module/gic/awcavern.gic.json similarity index 100% rename from src/mod/gic/awcavern.gic.json rename to src/module/gic/awcavern.gic.json diff --git a/src/mod/gic/awdesertruins.gic.json b/src/module/gic/awdesertruins.gic.json similarity index 100% rename from src/mod/gic/awdesertruins.gic.json rename to src/module/gic/awdesertruins.gic.json diff --git a/src/mod/gic/awhome.gic.json b/src/module/gic/awhome.gic.json similarity index 100% rename from src/mod/gic/awhome.gic.json rename to src/module/gic/awhome.gic.json diff --git a/src/mod/gic/awillithidinner.gic.json b/src/module/gic/awillithidinner.gic.json similarity index 100% rename from src/mod/gic/awillithidinner.gic.json rename to src/module/gic/awillithidinner.gic.json diff --git a/src/mod/gic/awportaltoverasp.gic.json b/src/module/gic/awportaltoverasp.gic.json similarity index 100% rename from src/mod/gic/awportaltoverasp.gic.json rename to src/module/gic/awportaltoverasp.gic.json diff --git a/src/mod/gic/awtempleofvera.gic.json b/src/module/gic/awtempleofvera.gic.json similarity index 100% rename from src/mod/gic/awtempleofvera.gic.json rename to src/module/gic/awtempleofvera.gic.json diff --git a/src/mod/gic/awtrollcaves.gic.json b/src/module/gic/awtrollcaves.gic.json similarity index 100% rename from src/mod/gic/awtrollcaves.gic.json rename to src/module/gic/awtrollcaves.gic.json diff --git a/src/mod/gic/awtrollcaves2.gic.json b/src/module/gic/awtrollcaves2.gic.json similarity index 100% rename from src/mod/gic/awtrollcaves2.gic.json rename to src/module/gic/awtrollcaves2.gic.json diff --git a/src/mod/gic/b1.gic.json b/src/module/gic/b1.gic.json similarity index 100% rename from src/mod/gic/b1.gic.json rename to src/module/gic/b1.gic.json diff --git a/src/mod/gic/b1hall.gic.json b/src/module/gic/b1hall.gic.json similarity index 100% rename from src/mod/gic/b1hall.gic.json rename to src/module/gic/b1hall.gic.json diff --git a/src/mod/gic/b2.gic.json b/src/module/gic/b2.gic.json similarity index 100% rename from src/mod/gic/b2.gic.json rename to src/module/gic/b2.gic.json diff --git a/src/mod/gic/b3.gic.json b/src/module/gic/b3.gic.json similarity index 100% rename from src/mod/gic/b3.gic.json rename to src/module/gic/b3.gic.json diff --git a/src/mod/gic/bandithold001.gic.json b/src/module/gic/bandithold001.gic.json similarity index 100% rename from src/mod/gic/bandithold001.gic.json rename to src/module/gic/bandithold001.gic.json diff --git a/src/mod/gic/bandithouse.gic.json b/src/module/gic/bandithouse.gic.json similarity index 100% rename from src/mod/gic/bandithouse.gic.json rename to src/module/gic/bandithouse.gic.json diff --git a/src/mod/gic/barn.gic.json b/src/module/gic/barn.gic.json similarity index 100% rename from src/mod/gic/barn.gic.json rename to src/module/gic/barn.gic.json diff --git a/src/mod/gic/barn001.gic.json b/src/module/gic/barn001.gic.json similarity index 100% rename from src/mod/gic/barn001.gic.json rename to src/module/gic/barn001.gic.json diff --git a/src/mod/gic/barrieddesert.gic.json b/src/module/gic/barrieddesert.gic.json similarity index 100% rename from src/mod/gic/barrieddesert.gic.json rename to src/module/gic/barrieddesert.gic.json diff --git a/src/mod/gic/baylibrary.gic.json b/src/module/gic/baylibrary.gic.json similarity index 100% rename from src/mod/gic/baylibrary.gic.json rename to src/module/gic/baylibrary.gic.json diff --git a/src/mod/gic/bayvillage.gic.json b/src/module/gic/bayvillage.gic.json similarity index 100% rename from src/mod/gic/bayvillage.gic.json rename to src/module/gic/bayvillage.gic.json diff --git a/src/mod/gic/bayvillagetownha.gic.json b/src/module/gic/bayvillagetownha.gic.json similarity index 100% rename from src/mod/gic/bayvillagetownha.gic.json rename to src/module/gic/bayvillagetownha.gic.json diff --git a/src/mod/gic/beholdercaves.gic.json b/src/module/gic/beholdercaves.gic.json similarity index 100% rename from src/mod/gic/beholdercaves.gic.json rename to src/module/gic/beholdercaves.gic.json diff --git a/src/mod/gic/beholdercavestyr.gic.json b/src/module/gic/beholdercavestyr.gic.json similarity index 100% rename from src/mod/gic/beholdercavestyr.gic.json rename to src/module/gic/beholdercavestyr.gic.json diff --git a/src/mod/gic/bigginsville.gic.json b/src/module/gic/bigginsville.gic.json similarity index 100% rename from src/mod/gic/bigginsville.gic.json rename to src/module/gic/bigginsville.gic.json diff --git a/src/mod/gic/bluearena.gic.json b/src/module/gic/bluearena.gic.json similarity index 100% rename from src/mod/gic/bluearena.gic.json rename to src/module/gic/bluearena.gic.json diff --git a/src/mod/gic/blueteamcastl001.gic.json b/src/module/gic/blueteamcastl001.gic.json similarity index 100% rename from src/mod/gic/blueteamcastl001.gic.json rename to src/module/gic/blueteamcastl001.gic.json diff --git a/src/mod/gic/boudoirofthepurp.gic.json b/src/module/gic/boudoirofthepurp.gic.json similarity index 100% rename from src/mod/gic/boudoirofthepurp.gic.json rename to src/module/gic/boudoirofthepurp.gic.json diff --git a/src/mod/gic/bretheren1.gic.json b/src/module/gic/bretheren1.gic.json similarity index 100% rename from src/mod/gic/bretheren1.gic.json rename to src/module/gic/bretheren1.gic.json diff --git a/src/mod/gic/bretherenlivingq.gic.json b/src/module/gic/bretherenlivingq.gic.json similarity index 100% rename from src/mod/gic/bretherenlivingq.gic.json rename to src/module/gic/bretherenlivingq.gic.json diff --git a/src/mod/gic/bretherenlounge.gic.json b/src/module/gic/bretherenlounge.gic.json similarity index 100% rename from src/mod/gic/bretherenlounge.gic.json rename to src/module/gic/bretherenlounge.gic.json diff --git a/src/mod/gic/bretherenthroner.gic.json b/src/module/gic/bretherenthroner.gic.json similarity index 100% rename from src/mod/gic/bretherenthroner.gic.json rename to src/module/gic/bretherenthroner.gic.json diff --git a/src/mod/gic/burialchamber.gic.json b/src/module/gic/burialchamber.gic.json similarity index 100% rename from src/mod/gic/burialchamber.gic.json rename to src/module/gic/burialchamber.gic.json diff --git a/src/mod/gic/castleofcain.gic.json b/src/module/gic/castleofcain.gic.json similarity index 100% rename from src/mod/gic/castleofcain.gic.json rename to src/module/gic/castleofcain.gic.json diff --git a/src/mod/gic/castleoftheda001.gic.json b/src/module/gic/castleoftheda001.gic.json similarity index 100% rename from src/mod/gic/castleoftheda001.gic.json rename to src/module/gic/castleoftheda001.gic.json diff --git a/src/mod/gic/castleofthedarkq.gic.json b/src/module/gic/castleofthedarkq.gic.json similarity index 100% rename from src/mod/gic/castleofthedarkq.gic.json rename to src/module/gic/castleofthedarkq.gic.json diff --git a/src/mod/gic/caveoftheclanlea.gic.json b/src/module/gic/caveoftheclanlea.gic.json similarity index 100% rename from src/mod/gic/caveoftheclanlea.gic.json rename to src/module/gic/caveoftheclanlea.gic.json diff --git a/src/mod/gic/chamberofalignme.gic.json b/src/module/gic/chamberofalignme.gic.json similarity index 100% rename from src/mod/gic/chamberofalignme.gic.json rename to src/module/gic/chamberofalignme.gic.json diff --git a/src/mod/gic/cheatcentral.gic.json b/src/module/gic/cheatcentral.gic.json similarity index 100% rename from src/mod/gic/cheatcentral.gic.json rename to src/module/gic/cheatcentral.gic.json diff --git a/src/mod/gic/cityofdirth.gic.json b/src/module/gic/cityofdirth.gic.json similarity index 100% rename from src/mod/gic/cityofdirth.gic.json rename to src/module/gic/cityofdirth.gic.json diff --git a/src/mod/gic/cityofdirthbehol.gic.json b/src/module/gic/cityofdirthbehol.gic.json similarity index 100% rename from src/mod/gic/cityofdirthbehol.gic.json rename to src/module/gic/cityofdirthbehol.gic.json diff --git a/src/mod/gic/cityofdirthcore.gic.json b/src/module/gic/cityofdirthcore.gic.json similarity index 100% rename from src/mod/gic/cityofdirthcore.gic.json rename to src/module/gic/cityofdirthcore.gic.json diff --git a/src/mod/gic/cityofdirthdrowb.gic.json b/src/module/gic/cityofdirthdrowb.gic.json similarity index 100% rename from src/mod/gic/cityofdirthdrowb.gic.json rename to src/module/gic/cityofdirthdrowb.gic.json diff --git a/src/mod/gic/cityofdirthdrows.gic.json b/src/module/gic/cityofdirthdrows.gic.json similarity index 100% rename from src/mod/gic/cityofdirthdrows.gic.json rename to src/module/gic/cityofdirthdrows.gic.json diff --git a/src/mod/gic/cityofdirthoutsk.gic.json b/src/module/gic/cityofdirthoutsk.gic.json similarity index 100% rename from src/mod/gic/cityofdirthoutsk.gic.json rename to src/module/gic/cityofdirthoutsk.gic.json diff --git a/src/mod/gic/cityofdirthpoor.gic.json b/src/module/gic/cityofdirthpoor.gic.json similarity index 100% rename from src/mod/gic/cityofdirthpoor.gic.json rename to src/module/gic/cityofdirthpoor.gic.json diff --git a/src/mod/gic/cityofdirthpoorh.gic.json b/src/module/gic/cityofdirthpoorh.gic.json similarity index 100% rename from src/mod/gic/cityofdirthpoorh.gic.json rename to src/module/gic/cityofdirthpoorh.gic.json diff --git a/src/mod/gic/cityofdirthtempl.gic.json b/src/module/gic/cityofdirthtempl.gic.json similarity index 100% rename from src/mod/gic/cityofdirthtempl.gic.json rename to src/module/gic/cityofdirthtempl.gic.json diff --git a/src/mod/gic/cityofdirthupwiz.gic.json b/src/module/gic/cityofdirthupwiz.gic.json similarity index 100% rename from src/mod/gic/cityofdirthupwiz.gic.json rename to src/module/gic/cityofdirthupwiz.gic.json diff --git a/src/mod/gic/cityofdirthwhore.gic.json b/src/module/gic/cityofdirthwhore.gic.json similarity index 100% rename from src/mod/gic/cityofdirthwhore.gic.json rename to src/module/gic/cityofdirthwhore.gic.json diff --git a/src/mod/gic/cityofdirthwizto.gic.json b/src/module/gic/cityofdirthwizto.gic.json similarity index 100% rename from src/mod/gic/cityofdirthwizto.gic.json rename to src/module/gic/cityofdirthwizto.gic.json diff --git a/src/mod/gic/cityofoz.gic.json b/src/module/gic/cityofoz.gic.json similarity index 100% rename from src/mod/gic/cityofoz.gic.json rename to src/module/gic/cityofoz.gic.json diff --git a/src/mod/gic/cloaktowerheadli.gic.json b/src/module/gic/cloaktowerheadli.gic.json similarity index 100% rename from src/mod/gic/cloaktowerheadli.gic.json rename to src/module/gic/cloaktowerheadli.gic.json diff --git a/src/mod/gic/cloaktowerlevel1.gic.json b/src/module/gic/cloaktowerlevel1.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel1.gic.json rename to src/module/gic/cloaktowerlevel1.gic.json diff --git a/src/mod/gic/cloaktowerlevel2.gic.json b/src/module/gic/cloaktowerlevel2.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel2.gic.json rename to src/module/gic/cloaktowerlevel2.gic.json diff --git a/src/mod/gic/cloaktowerlevel3.gic.json b/src/module/gic/cloaktowerlevel3.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel3.gic.json rename to src/module/gic/cloaktowerlevel3.gic.json diff --git a/src/mod/gic/cloaktowerlevel4.gic.json b/src/module/gic/cloaktowerlevel4.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel4.gic.json rename to src/module/gic/cloaktowerlevel4.gic.json diff --git a/src/mod/gic/cloaktowerlevel5.gic.json b/src/module/gic/cloaktowerlevel5.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel5.gic.json rename to src/module/gic/cloaktowerlevel5.gic.json diff --git a/src/mod/gic/cloaktowerlevel6.gic.json b/src/module/gic/cloaktowerlevel6.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel6.gic.json rename to src/module/gic/cloaktowerlevel6.gic.json diff --git a/src/mod/gic/cloaktowerlevel7.gic.json b/src/module/gic/cloaktowerlevel7.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel7.gic.json rename to src/module/gic/cloaktowerlevel7.gic.json diff --git a/src/mod/gic/cloaktowerlevel8.gic.json b/src/module/gic/cloaktowerlevel8.gic.json similarity index 100% rename from src/mod/gic/cloaktowerlevel8.gic.json rename to src/module/gic/cloaktowerlevel8.gic.json diff --git a/src/mod/gic/coalmines.gic.json b/src/module/gic/coalmines.gic.json similarity index 100% rename from src/mod/gic/coalmines.gic.json rename to src/module/gic/coalmines.gic.json diff --git a/src/mod/gic/coastalcity.gic.json b/src/module/gic/coastalcity.gic.json similarity index 100% rename from src/mod/gic/coastalcity.gic.json rename to src/module/gic/coastalcity.gic.json diff --git a/src/mod/gic/coastalroad.gic.json b/src/module/gic/coastalroad.gic.json similarity index 100% rename from src/mod/gic/coastalroad.gic.json rename to src/module/gic/coastalroad.gic.json diff --git a/src/mod/gic/conciousroom.gic.json b/src/module/gic/conciousroom.gic.json similarity index 100% rename from src/mod/gic/conciousroom.gic.json rename to src/module/gic/conciousroom.gic.json diff --git a/src/mod/gic/cuyahogawilderne.gic.json b/src/module/gic/cuyahogawilderne.gic.json similarity index 100% rename from src/mod/gic/cuyahogawilderne.gic.json rename to src/module/gic/cuyahogawilderne.gic.json diff --git a/src/mod/gic/darkqueenchamb.gic.json b/src/module/gic/darkqueenchamb.gic.json similarity index 100% rename from src/mod/gic/darkqueenchamb.gic.json rename to src/module/gic/darkqueenchamb.gic.json diff --git a/src/mod/gic/dbi_pc_rooms.gic.json b/src/module/gic/dbi_pc_rooms.gic.json similarity index 100% rename from src/mod/gic/dbi_pc_rooms.gic.json rename to src/module/gic/dbi_pc_rooms.gic.json diff --git a/src/mod/gic/desertcavern.gic.json b/src/module/gic/desertcavern.gic.json similarity index 100% rename from src/mod/gic/desertcavern.gic.json rename to src/module/gic/desertcavern.gic.json diff --git a/src/mod/gic/desertdwarfruins.gic.json b/src/module/gic/desertdwarfruins.gic.json similarity index 100% rename from src/mod/gic/desertdwarfruins.gic.json rename to src/module/gic/desertdwarfruins.gic.json diff --git a/src/mod/gic/desertruins.gic.json b/src/module/gic/desertruins.gic.json similarity index 100% rename from src/mod/gic/desertruins.gic.json rename to src/module/gic/desertruins.gic.json diff --git a/src/mod/gic/desolateanddespa.gic.json b/src/module/gic/desolateanddespa.gic.json similarity index 100% rename from src/mod/gic/desolateanddespa.gic.json rename to src/module/gic/desolateanddespa.gic.json diff --git a/src/mod/gic/dirthtower1.gic.json b/src/module/gic/dirthtower1.gic.json similarity index 100% rename from src/mod/gic/dirthtower1.gic.json rename to src/module/gic/dirthtower1.gic.json diff --git a/src/mod/gic/dirthtransporter.gic.json b/src/module/gic/dirthtransporter.gic.json similarity index 100% rename from src/mod/gic/dirthtransporter.gic.json rename to src/module/gic/dirthtransporter.gic.json diff --git a/src/mod/gic/doctorsguild.gic.json b/src/module/gic/doctorsguild.gic.json similarity index 100% rename from src/mod/gic/doctorsguild.gic.json rename to src/module/gic/doctorsguild.gic.json diff --git a/src/mod/gic/doctorsmain.gic.json b/src/module/gic/doctorsmain.gic.json similarity index 100% rename from src/mod/gic/doctorsmain.gic.json rename to src/module/gic/doctorsmain.gic.json diff --git a/src/mod/gic/doctorsmain001.gic.json b/src/module/gic/doctorsmain001.gic.json similarity index 100% rename from src/mod/gic/doctorsmain001.gic.json rename to src/module/gic/doctorsmain001.gic.json diff --git a/src/mod/gic/downtherabbithol.gic.json b/src/module/gic/downtherabbithol.gic.json similarity index 100% rename from src/mod/gic/downtherabbithol.gic.json rename to src/module/gic/downtherabbithol.gic.json diff --git a/src/mod/gic/draculascrypt.gic.json b/src/module/gic/draculascrypt.gic.json similarity index 100% rename from src/mod/gic/draculascrypt.gic.json rename to src/module/gic/draculascrypt.gic.json diff --git a/src/mod/gic/dragonbackinn.gic.json b/src/module/gic/dragonbackinn.gic.json similarity index 100% rename from src/mod/gic/dragonbackinn.gic.json rename to src/module/gic/dragonbackinn.gic.json diff --git a/src/mod/gic/dragoncaverns.gic.json b/src/module/gic/dragoncaverns.gic.json similarity index 100% rename from src/mod/gic/dragoncaverns.gic.json rename to src/module/gic/dragoncaverns.gic.json diff --git a/src/mod/gic/dragoncaverntunn.gic.json b/src/module/gic/dragoncaverntunn.gic.json similarity index 100% rename from src/mod/gic/dragoncaverntunn.gic.json rename to src/module/gic/dragoncaverntunn.gic.json diff --git a/src/mod/gic/dragoncaves001.gic.json b/src/module/gic/dragoncaves001.gic.json similarity index 100% rename from src/mod/gic/dragoncaves001.gic.json rename to src/module/gic/dragoncaves001.gic.json diff --git a/src/mod/gic/dragoncultbarrak.gic.json b/src/module/gic/dragoncultbarrak.gic.json similarity index 100% rename from src/mod/gic/dragoncultbarrak.gic.json rename to src/module/gic/dragoncultbarrak.gic.json diff --git a/src/mod/gic/dragoncultcastle.gic.json b/src/module/gic/dragoncultcastle.gic.json similarity index 100% rename from src/mod/gic/dragoncultcastle.gic.json rename to src/module/gic/dragoncultcastle.gic.json diff --git a/src/mod/gic/dragoncultenergy.gic.json b/src/module/gic/dragoncultenergy.gic.json similarity index 100% rename from src/mod/gic/dragoncultenergy.gic.json rename to src/module/gic/dragoncultenergy.gic.json diff --git a/src/mod/gic/dreamweaver001.gic.json b/src/module/gic/dreamweaver001.gic.json similarity index 100% rename from src/mod/gic/dreamweaver001.gic.json rename to src/module/gic/dreamweaver001.gic.json diff --git a/src/mod/gic/drowbarraks.gic.json b/src/module/gic/drowbarraks.gic.json similarity index 100% rename from src/mod/gic/drowbarraks.gic.json rename to src/module/gic/drowbarraks.gic.json diff --git a/src/mod/gic/drowtemple.gic.json b/src/module/gic/drowtemple.gic.json similarity index 100% rename from src/mod/gic/drowtemple.gic.json rename to src/module/gic/drowtemple.gic.json diff --git a/src/mod/gic/durbonshire.gic.json b/src/module/gic/durbonshire.gic.json similarity index 100% rename from src/mod/gic/durbonshire.gic.json rename to src/module/gic/durbonshire.gic.json diff --git a/src/mod/gic/dwarvencaverns.gic.json b/src/module/gic/dwarvencaverns.gic.json similarity index 100% rename from src/mod/gic/dwarvencaverns.gic.json rename to src/module/gic/dwarvencaverns.gic.json diff --git a/src/mod/gic/dwarvencavernslv.gic.json b/src/module/gic/dwarvencavernslv.gic.json similarity index 100% rename from src/mod/gic/dwarvencavernslv.gic.json rename to src/module/gic/dwarvencavernslv.gic.json diff --git a/src/mod/gic/dwarvendungeons.gic.json b/src/module/gic/dwarvendungeons.gic.json similarity index 100% rename from src/mod/gic/dwarvendungeons.gic.json rename to src/module/gic/dwarvendungeons.gic.json diff --git a/src/mod/gic/dwarvendungeonsl.gic.json b/src/module/gic/dwarvendungeonsl.gic.json similarity index 100% rename from src/mod/gic/dwarvendungeonsl.gic.json rename to src/module/gic/dwarvendungeonsl.gic.json diff --git a/src/mod/gic/eleventoeddwarfs.gic.json b/src/module/gic/eleventoeddwarfs.gic.json similarity index 100% rename from src/mod/gic/eleventoeddwarfs.gic.json rename to src/module/gic/eleventoeddwarfs.gic.json diff --git a/src/mod/gic/elvendar.gic.json b/src/module/gic/elvendar.gic.json similarity index 100% rename from src/mod/gic/elvendar.gic.json rename to src/module/gic/elvendar.gic.json diff --git a/src/mod/gic/elvendargener001.gic.json b/src/module/gic/elvendargener001.gic.json similarity index 100% rename from src/mod/gic/elvendargener001.gic.json rename to src/module/gic/elvendargener001.gic.json diff --git a/src/mod/gic/elvendarnorth001.gic.json b/src/module/gic/elvendarnorth001.gic.json similarity index 100% rename from src/mod/gic/elvendarnorth001.gic.json rename to src/module/gic/elvendarnorth001.gic.json diff --git a/src/mod/gic/elvendarnorthern.gic.json b/src/module/gic/elvendarnorthern.gic.json similarity index 100% rename from src/mod/gic/elvendarnorthern.gic.json rename to src/module/gic/elvendarnorthern.gic.json diff --git a/src/mod/gic/elvendarouterfor.gic.json b/src/module/gic/elvendarouterfor.gic.json similarity index 100% rename from src/mod/gic/elvendarouterfor.gic.json rename to src/module/gic/elvendarouterfor.gic.json diff --git a/src/mod/gic/elvendarunder001.gic.json b/src/module/gic/elvendarunder001.gic.json similarity index 100% rename from src/mod/gic/elvendarunder001.gic.json rename to src/module/gic/elvendarunder001.gic.json diff --git a/src/mod/gic/elvendarunder002.gic.json b/src/module/gic/elvendarunder002.gic.json similarity index 100% rename from src/mod/gic/elvendarunder002.gic.json rename to src/module/gic/elvendarunder002.gic.json diff --git a/src/mod/gic/elvendarundergro.gic.json b/src/module/gic/elvendarundergro.gic.json similarity index 100% rename from src/mod/gic/elvendarundergro.gic.json rename to src/module/gic/elvendarundergro.gic.json diff --git a/src/mod/gic/elvendarweste001.gic.json b/src/module/gic/elvendarweste001.gic.json similarity index 100% rename from src/mod/gic/elvendarweste001.gic.json rename to src/module/gic/elvendarweste001.gic.json diff --git a/src/mod/gic/elvendarwesternb.gic.json b/src/module/gic/elvendarwesternb.gic.json similarity index 100% rename from src/mod/gic/elvendarwesternb.gic.json rename to src/module/gic/elvendarwesternb.gic.json diff --git a/src/mod/gic/evilclericceremo.gic.json b/src/module/gic/evilclericceremo.gic.json similarity index 100% rename from src/mod/gic/evilclericceremo.gic.json rename to src/module/gic/evilclericceremo.gic.json diff --git a/src/mod/gic/evilclericruins.gic.json b/src/module/gic/evilclericruins.gic.json similarity index 100% rename from src/mod/gic/evilclericruins.gic.json rename to src/module/gic/evilclericruins.gic.json diff --git a/src/mod/gic/ey_dpcon_erewood.gic.json b/src/module/gic/ey_dpcon_erewood.gic.json similarity index 100% rename from src/mod/gic/ey_dpcon_erewood.gic.json rename to src/module/gic/ey_dpcon_erewood.gic.json diff --git a/src/mod/gic/fareast001.gic.json b/src/module/gic/fareast001.gic.json similarity index 100% rename from src/mod/gic/fareast001.gic.json rename to src/module/gic/fareast001.gic.json diff --git a/src/mod/gic/fareastdesert.gic.json b/src/module/gic/fareastdesert.gic.json similarity index 100% rename from src/mod/gic/fareastdesert.gic.json rename to src/module/gic/fareastdesert.gic.json diff --git a/src/mod/gic/fareastdesertrui.gic.json b/src/module/gic/fareastdesertrui.gic.json similarity index 100% rename from src/mod/gic/fareastdesertrui.gic.json rename to src/module/gic/fareastdesertrui.gic.json diff --git a/src/mod/gic/followersofmorda.gic.json b/src/module/gic/followersofmorda.gic.json similarity index 100% rename from src/mod/gic/followersofmorda.gic.json rename to src/module/gic/followersofmorda.gic.json diff --git a/src/mod/gic/foresttemple001.gic.json b/src/module/gic/foresttemple001.gic.json similarity index 100% rename from src/mod/gic/foresttemple001.gic.json rename to src/module/gic/foresttemple001.gic.json diff --git a/src/mod/gic/frostedpits.gic.json b/src/module/gic/frostedpits.gic.json similarity index 100% rename from src/mod/gic/frostedpits.gic.json rename to src/module/gic/frostedpits.gic.json diff --git a/src/mod/gic/frozantundraeast.gic.json b/src/module/gic/frozantundraeast.gic.json similarity index 100% rename from src/mod/gic/frozantundraeast.gic.json rename to src/module/gic/frozantundraeast.gic.json diff --git a/src/mod/gic/frozedtundra.gic.json b/src/module/gic/frozedtundra.gic.json similarity index 100% rename from src/mod/gic/frozedtundra.gic.json rename to src/module/gic/frozedtundra.gic.json diff --git a/src/mod/gic/frozentimes.gic.json b/src/module/gic/frozentimes.gic.json similarity index 100% rename from src/mod/gic/frozentimes.gic.json rename to src/module/gic/frozentimes.gic.json diff --git a/src/mod/gic/frozentundranort.gic.json b/src/module/gic/frozentundranort.gic.json similarity index 100% rename from src/mod/gic/frozentundranort.gic.json rename to src/module/gic/frozentundranort.gic.json diff --git a/src/mod/gic/frozentundrawest.gic.json b/src/module/gic/frozentundrawest.gic.json similarity index 100% rename from src/mod/gic/frozentundrawest.gic.json rename to src/module/gic/frozentundrawest.gic.json diff --git a/src/mod/gic/granolalodge.gic.json b/src/module/gic/granolalodge.gic.json similarity index 100% rename from src/mod/gic/granolalodge.gic.json rename to src/module/gic/granolalodge.gic.json diff --git a/src/mod/gic/groundskeeper.gic.json b/src/module/gic/groundskeeper.gic.json similarity index 100% rename from src/mod/gic/groundskeeper.gic.json rename to src/module/gic/groundskeeper.gic.json diff --git a/src/mod/gic/halloftheancient.gic.json b/src/module/gic/halloftheancient.gic.json similarity index 100% rename from src/mod/gic/halloftheancient.gic.json rename to src/module/gic/halloftheancient.gic.json diff --git a/src/mod/gic/hallowedground1.gic.json b/src/module/gic/hallowedground1.gic.json similarity index 100% rename from src/mod/gic/hallowedground1.gic.json rename to src/module/gic/hallowedground1.gic.json diff --git a/src/mod/gic/healerhouse.gic.json b/src/module/gic/healerhouse.gic.json similarity index 100% rename from src/mod/gic/healerhouse.gic.json rename to src/module/gic/healerhouse.gic.json diff --git a/src/mod/gic/hillsidehome001.gic.json b/src/module/gic/hillsidehome001.gic.json similarity index 100% rename from src/mod/gic/hillsidehome001.gic.json rename to src/module/gic/hillsidehome001.gic.json diff --git a/src/mod/gic/hillsideinn.gic.json b/src/module/gic/hillsideinn.gic.json similarity index 100% rename from src/mod/gic/hillsideinn.gic.json rename to src/module/gic/hillsideinn.gic.json diff --git a/src/mod/gic/hillsidemysticto.gic.json b/src/module/gic/hillsidemysticto.gic.json similarity index 100% rename from src/mod/gic/hillsidemysticto.gic.json rename to src/module/gic/hillsidemysticto.gic.json diff --git a/src/mod/gic/hillsidetempl001.gic.json b/src/module/gic/hillsidetempl001.gic.json similarity index 100% rename from src/mod/gic/hillsidetempl001.gic.json rename to src/module/gic/hillsidetempl001.gic.json diff --git a/src/mod/gic/historywing.gic.json b/src/module/gic/historywing.gic.json similarity index 100% rename from src/mod/gic/historywing.gic.json rename to src/module/gic/historywing.gic.json diff --git a/src/mod/gic/holyground.gic.json b/src/module/gic/holyground.gic.json similarity index 100% rename from src/mod/gic/holyground.gic.json rename to src/module/gic/holyground.gic.json diff --git a/src/mod/gic/horrorwing.gic.json b/src/module/gic/horrorwing.gic.json similarity index 100% rename from src/mod/gic/horrorwing.gic.json rename to src/module/gic/horrorwing.gic.json diff --git a/src/mod/gic/ifm_pc_rooms.gic.json b/src/module/gic/ifm_pc_rooms.gic.json similarity index 100% rename from src/mod/gic/ifm_pc_rooms.gic.json rename to src/module/gic/ifm_pc_rooms.gic.json diff --git a/src/mod/gic/igloo.gic.json b/src/module/gic/igloo.gic.json similarity index 100% rename from src/mod/gic/igloo.gic.json rename to src/module/gic/igloo.gic.json diff --git a/src/mod/gic/illithidbridges.gic.json b/src/module/gic/illithidbridges.gic.json similarity index 100% rename from src/mod/gic/illithidbridges.gic.json rename to src/module/gic/illithidbridges.gic.json diff --git a/src/mod/gic/illithidresingch.gic.json b/src/module/gic/illithidresingch.gic.json similarity index 100% rename from src/mod/gic/illithidresingch.gic.json rename to src/module/gic/illithidresingch.gic.json diff --git a/src/mod/gic/ironclawbattlegr.gic.json b/src/module/gic/ironclawbattlegr.gic.json similarity index 100% rename from src/mod/gic/ironclawbattlegr.gic.json rename to src/module/gic/ironclawbattlegr.gic.json diff --git a/src/mod/gic/ironclawcastle.gic.json b/src/module/gic/ironclawcastle.gic.json similarity index 100% rename from src/mod/gic/ironclawcastle.gic.json rename to src/module/gic/ironclawcastle.gic.json diff --git a/src/mod/gic/ironclawcastleup.gic.json b/src/module/gic/ironclawcastleup.gic.json similarity index 100% rename from src/mod/gic/ironclawcastleup.gic.json rename to src/module/gic/ironclawcastleup.gic.json diff --git a/src/mod/gic/ironclawdungeons.gic.json b/src/module/gic/ironclawdungeons.gic.json similarity index 100% rename from src/mod/gic/ironclawdungeons.gic.json rename to src/module/gic/ironclawdungeons.gic.json diff --git a/src/mod/gic/ironclawhalltoto.gic.json b/src/module/gic/ironclawhalltoto.gic.json similarity index 100% rename from src/mod/gic/ironclawhalltoto.gic.json rename to src/module/gic/ironclawhalltoto.gic.json diff --git a/src/mod/gic/ironclawinnercas.gic.json b/src/module/gic/ironclawinnercas.gic.json similarity index 100% rename from src/mod/gic/ironclawinnercas.gic.json rename to src/module/gic/ironclawinnercas.gic.json diff --git a/src/mod/gic/ironclawtower.gic.json b/src/module/gic/ironclawtower.gic.json similarity index 100% rename from src/mod/gic/ironclawtower.gic.json rename to src/module/gic/ironclawtower.gic.json diff --git a/src/mod/gic/irongoblinleader.gic.json b/src/module/gic/irongoblinleader.gic.json similarity index 100% rename from src/mod/gic/irongoblinleader.gic.json rename to src/module/gic/irongoblinleader.gic.json diff --git a/src/mod/gic/ironmineslevel2.gic.json b/src/module/gic/ironmineslevel2.gic.json similarity index 100% rename from src/mod/gic/ironmineslevel2.gic.json rename to src/module/gic/ironmineslevel2.gic.json diff --git a/src/mod/gic/ironminesupper.gic.json b/src/module/gic/ironminesupper.gic.json similarity index 100% rename from src/mod/gic/ironminesupper.gic.json rename to src/module/gic/ironminesupper.gic.json diff --git a/src/mod/gic/isleofrepent.gic.json b/src/module/gic/isleofrepent.gic.json similarity index 100% rename from src/mod/gic/isleofrepent.gic.json rename to src/module/gic/isleofrepent.gic.json diff --git a/src/mod/gic/jerkinsbarn.gic.json b/src/module/gic/jerkinsbarn.gic.json similarity index 100% rename from src/mod/gic/jerkinsbarn.gic.json rename to src/module/gic/jerkinsbarn.gic.json diff --git a/src/mod/gic/keepofthefallinp.gic.json b/src/module/gic/keepofthefallinp.gic.json similarity index 100% rename from src/mod/gic/keepofthefallinp.gic.json rename to src/module/gic/keepofthefallinp.gic.json diff --git a/src/mod/gic/koboldcaves.gic.json b/src/module/gic/koboldcaves.gic.json similarity index 100% rename from src/mod/gic/koboldcaves.gic.json rename to src/module/gic/koboldcaves.gic.json diff --git a/src/mod/gic/lairofkluam.gic.json b/src/module/gic/lairofkluam.gic.json similarity index 100% rename from src/mod/gic/lairofkluam.gic.json rename to src/module/gic/lairofkluam.gic.json diff --git a/src/mod/gic/lethalweaponsgui.gic.json b/src/module/gic/lethalweaponsgui.gic.json similarity index 100% rename from src/mod/gic/lethalweaponsgui.gic.json rename to src/module/gic/lethalweaponsgui.gic.json diff --git a/src/mod/gic/limbo001.gic.json b/src/module/gic/limbo001.gic.json similarity index 100% rename from src/mod/gic/limbo001.gic.json rename to src/module/gic/limbo001.gic.json diff --git a/src/mod/gic/lithiuminfusionc.gic.json b/src/module/gic/lithiuminfusionc.gic.json similarity index 100% rename from src/mod/gic/lithiuminfusionc.gic.json rename to src/module/gic/lithiuminfusionc.gic.json diff --git a/src/mod/gic/livingforest.gic.json b/src/module/gic/livingforest.gic.json similarity index 100% rename from src/mod/gic/livingforest.gic.json rename to src/module/gic/livingforest.gic.json diff --git a/src/mod/gic/livingforesteast.gic.json b/src/module/gic/livingforesteast.gic.json similarity index 100% rename from src/mod/gic/livingforesteast.gic.json rename to src/module/gic/livingforesteast.gic.json diff --git a/src/mod/gic/livingforestnort.gic.json b/src/module/gic/livingforestnort.gic.json similarity index 100% rename from src/mod/gic/livingforestnort.gic.json rename to src/module/gic/livingforestnort.gic.json diff --git a/src/mod/gic/livingforestwest.gic.json b/src/module/gic/livingforestwest.gic.json similarity index 100% rename from src/mod/gic/livingforestwest.gic.json rename to src/module/gic/livingforestwest.gic.json diff --git a/src/mod/gic/manypaths.gic.json b/src/module/gic/manypaths.gic.json similarity index 100% rename from src/mod/gic/manypaths.gic.json rename to src/module/gic/manypaths.gic.json diff --git a/src/mod/gic/minihouse.gic.json b/src/module/gic/minihouse.gic.json similarity index 100% rename from src/mod/gic/minihouse.gic.json rename to src/module/gic/minihouse.gic.json diff --git a/src/mod/gic/minihouseupper.gic.json b/src/module/gic/minihouseupper.gic.json similarity index 100% rename from src/mod/gic/minihouseupper.gic.json rename to src/module/gic/minihouseupper.gic.json diff --git a/src/mod/gic/mithralmines.gic.json b/src/module/gic/mithralmines.gic.json similarity index 100% rename from src/mod/gic/mithralmines.gic.json rename to src/module/gic/mithralmines.gic.json diff --git a/src/mod/gic/mordmagman01.gic.json b/src/module/gic/mordmagman01.gic.json similarity index 100% rename from src/mod/gic/mordmagman01.gic.json rename to src/module/gic/mordmagman01.gic.json diff --git a/src/mod/gic/mordmagman02.gic.json b/src/module/gic/mordmagman02.gic.json similarity index 100% rename from src/mod/gic/mordmagman02.gic.json rename to src/module/gic/mordmagman02.gic.json diff --git a/src/mod/gic/mordmagman03.gic.json b/src/module/gic/mordmagman03.gic.json similarity index 100% rename from src/mod/gic/mordmagman03.gic.json rename to src/module/gic/mordmagman03.gic.json diff --git a/src/mod/gic/mordmagman04.gic.json b/src/module/gic/mordmagman04.gic.json similarity index 100% rename from src/mod/gic/mordmagman04.gic.json rename to src/module/gic/mordmagman04.gic.json diff --git a/src/mod/gic/mordmagman05.gic.json b/src/module/gic/mordmagman05.gic.json similarity index 100% rename from src/mod/gic/mordmagman05.gic.json rename to src/module/gic/mordmagman05.gic.json diff --git a/src/mod/gic/mordmagman06.gic.json b/src/module/gic/mordmagman06.gic.json similarity index 100% rename from src/mod/gic/mordmagman06.gic.json rename to src/module/gic/mordmagman06.gic.json diff --git a/src/mod/gic/mountianside.gic.json b/src/module/gic/mountianside.gic.json similarity index 100% rename from src/mod/gic/mountianside.gic.json rename to src/module/gic/mountianside.gic.json diff --git a/src/mod/gic/mountiansidenort.gic.json b/src/module/gic/mountiansidenort.gic.json similarity index 100% rename from src/mod/gic/mountiansidenort.gic.json rename to src/module/gic/mountiansidenort.gic.json diff --git a/src/mod/gic/nightofthunder.gic.json b/src/module/gic/nightofthunder.gic.json similarity index 100% rename from src/mod/gic/nightofthunder.gic.json rename to src/module/gic/nightofthunder.gic.json diff --git a/src/mod/gic/nodropitemsarea.gic.json b/src/module/gic/nodropitemsarea.gic.json similarity index 100% rename from src/mod/gic/nodropitemsarea.gic.json rename to src/module/gic/nodropitemsarea.gic.json diff --git a/src/mod/gic/nordicpolarpass.gic.json b/src/module/gic/nordicpolarpass.gic.json similarity index 100% rename from src/mod/gic/nordicpolarpass.gic.json rename to src/module/gic/nordicpolarpass.gic.json diff --git a/src/mod/gic/northernport.gic.json b/src/module/gic/northernport.gic.json similarity index 100% rename from src/mod/gic/northernport.gic.json rename to src/module/gic/northernport.gic.json diff --git a/src/mod/gic/northernroad001.gic.json b/src/module/gic/northernroad001.gic.json similarity index 100% rename from src/mod/gic/northernroad001.gic.json rename to src/module/gic/northernroad001.gic.json diff --git a/src/mod/gic/northernwoods.gic.json b/src/module/gic/northernwoods.gic.json similarity index 100% rename from src/mod/gic/northernwoods.gic.json rename to src/module/gic/northernwoods.gic.json diff --git a/src/mod/gic/oddbuilding.gic.json b/src/module/gic/oddbuilding.gic.json similarity index 100% rename from src/mod/gic/oddbuilding.gic.json rename to src/module/gic/oddbuilding.gic.json diff --git a/src/mod/gic/ogrecaves.gic.json b/src/module/gic/ogrecaves.gic.json similarity index 100% rename from src/mod/gic/ogrecaves.gic.json rename to src/module/gic/ogrecaves.gic.json diff --git a/src/mod/gic/ogrecaveslevel2.gic.json b/src/module/gic/ogrecaveslevel2.gic.json similarity index 100% rename from src/mod/gic/ogrecaveslevel2.gic.json rename to src/module/gic/ogrecaveslevel2.gic.json diff --git a/src/mod/gic/ogrecaveslevel3.gic.json b/src/module/gic/ogrecaveslevel3.gic.json similarity index 100% rename from src/mod/gic/ogrecaveslevel3.gic.json rename to src/module/gic/ogrecaveslevel3.gic.json diff --git a/src/mod/gic/oldhouse1.gic.json b/src/module/gic/oldhouse1.gic.json similarity index 100% rename from src/mod/gic/oldhouse1.gic.json rename to src/module/gic/oldhouse1.gic.json diff --git a/src/mod/gic/oldhouse2.gic.json b/src/module/gic/oldhouse2.gic.json similarity index 100% rename from src/mod/gic/oldhouse2.gic.json rename to src/module/gic/oldhouse2.gic.json diff --git a/src/mod/gic/oldhouse3.gic.json b/src/module/gic/oldhouse3.gic.json similarity index 100% rename from src/mod/gic/oldhouse3.gic.json rename to src/module/gic/oldhouse3.gic.json diff --git a/src/mod/gic/oldhouse4.gic.json b/src/module/gic/oldhouse4.gic.json similarity index 100% rename from src/mod/gic/oldhouse4.gic.json rename to src/module/gic/oldhouse4.gic.json diff --git a/src/mod/gic/oldhouse5.gic.json b/src/module/gic/oldhouse5.gic.json similarity index 100% rename from src/mod/gic/oldhouse5.gic.json rename to src/module/gic/oldhouse5.gic.json diff --git a/src/mod/gic/oldhouse6.gic.json b/src/module/gic/oldhouse6.gic.json similarity index 100% rename from src/mod/gic/oldhouse6.gic.json rename to src/module/gic/oldhouse6.gic.json diff --git a/src/mod/gic/oldhouse7.gic.json b/src/module/gic/oldhouse7.gic.json similarity index 100% rename from src/mod/gic/oldhouse7.gic.json rename to src/module/gic/oldhouse7.gic.json diff --git a/src/mod/gic/oldmanjerkinshou.gic.json b/src/module/gic/oldmanjerkinshou.gic.json similarity index 100% rename from src/mod/gic/oldmanjerkinshou.gic.json rename to src/module/gic/oldmanjerkinshou.gic.json diff --git a/src/mod/gic/oldmines.gic.json b/src/module/gic/oldmines.gic.json similarity index 100% rename from src/mod/gic/oldmines.gic.json rename to src/module/gic/oldmines.gic.json diff --git a/src/mod/gic/orcbarracks.gic.json b/src/module/gic/orcbarracks.gic.json similarity index 100% rename from src/mod/gic/orcbarracks.gic.json rename to src/module/gic/orcbarracks.gic.json diff --git a/src/mod/gic/orcbarrackslevel.gic.json b/src/module/gic/orcbarrackslevel.gic.json similarity index 100% rename from src/mod/gic/orcbarrackslevel.gic.json rename to src/module/gic/orcbarrackslevel.gic.json diff --git a/src/mod/gic/orcmasterbarrack.gic.json b/src/module/gic/orcmasterbarrack.gic.json similarity index 100% rename from src/mod/gic/orcmasterbarrack.gic.json rename to src/module/gic/orcmasterbarrack.gic.json diff --git a/src/mod/gic/orcsublevel.gic.json b/src/module/gic/orcsublevel.gic.json similarity index 100% rename from src/mod/gic/orcsublevel.gic.json rename to src/module/gic/orcsublevel.gic.json diff --git a/src/mod/gic/osu.gic.json b/src/module/gic/osu.gic.json similarity index 100% rename from src/mod/gic/osu.gic.json rename to src/module/gic/osu.gic.json diff --git a/src/mod/gic/outfitterspos001.gic.json b/src/module/gic/outfitterspos001.gic.json similarity index 100% rename from src/mod/gic/outfitterspos001.gic.json rename to src/module/gic/outfitterspos001.gic.json diff --git a/src/mod/gic/ozcastle.gic.json b/src/module/gic/ozcastle.gic.json similarity index 100% rename from src/mod/gic/ozcastle.gic.json rename to src/module/gic/ozcastle.gic.json diff --git a/src/mod/gic/ozcastleupper.gic.json b/src/module/gic/ozcastleupper.gic.json similarity index 100% rename from src/mod/gic/ozcastleupper.gic.json rename to src/module/gic/ozcastleupper.gic.json diff --git a/src/mod/gic/ozchamberofmysti.gic.json b/src/module/gic/ozchamberofmysti.gic.json similarity index 100% rename from src/mod/gic/ozchamberofmysti.gic.json rename to src/module/gic/ozchamberofmysti.gic.json diff --git a/src/mod/gic/ozeastwing.gic.json b/src/module/gic/ozeastwing.gic.json similarity index 100% rename from src/mod/gic/ozeastwing.gic.json rename to src/module/gic/ozeastwing.gic.json diff --git a/src/mod/gic/ozjail.gic.json b/src/module/gic/ozjail.gic.json similarity index 100% rename from src/mod/gic/ozjail.gic.json rename to src/module/gic/ozjail.gic.json diff --git a/src/mod/gic/ozmaincastle.gic.json b/src/module/gic/ozmaincastle.gic.json similarity index 100% rename from src/mod/gic/ozmaincastle.gic.json rename to src/module/gic/ozmaincastle.gic.json diff --git a/src/mod/gic/ozmainlibrary.gic.json b/src/module/gic/ozmainlibrary.gic.json similarity index 100% rename from src/mod/gic/ozmainlibrary.gic.json rename to src/module/gic/ozmainlibrary.gic.json diff --git a/src/mod/gic/ozwestwing.gic.json b/src/module/gic/ozwestwing.gic.json similarity index 100% rename from src/mod/gic/ozwestwing.gic.json rename to src/module/gic/ozwestwing.gic.json diff --git a/src/mod/gic/pathtoozcastle.gic.json b/src/module/gic/pathtoozcastle.gic.json similarity index 100% rename from src/mod/gic/pathtoozcastle.gic.json rename to src/module/gic/pathtoozcastle.gic.json diff --git a/src/mod/gic/pathtotheancient.gic.json b/src/module/gic/pathtotheancient.gic.json similarity index 100% rename from src/mod/gic/pathtotheancient.gic.json rename to src/module/gic/pathtotheancient.gic.json diff --git a/src/mod/gic/pleasantville.gic.json b/src/module/gic/pleasantville.gic.json similarity index 100% rename from src/mod/gic/pleasantville.gic.json rename to src/module/gic/pleasantville.gic.json diff --git a/src/mod/gic/prc_maze_01.gic.json b/src/module/gic/prc_maze_01.gic.json similarity index 100% rename from src/mod/gic/prc_maze_01.gic.json rename to src/module/gic/prc_maze_01.gic.json diff --git a/src/mod/gic/pvpexitingroom.gic.json b/src/module/gic/pvpexitingroom.gic.json similarity index 100% rename from src/mod/gic/pvpexitingroom.gic.json rename to src/module/gic/pvpexitingroom.gic.json diff --git a/src/mod/gic/pvppreparationro.gic.json b/src/module/gic/pvppreparationro.gic.json similarity index 100% rename from src/mod/gic/pvppreparationro.gic.json rename to src/module/gic/pvppreparationro.gic.json diff --git a/src/mod/gic/pvprespawn.gic.json b/src/module/gic/pvprespawn.gic.json similarity index 100% rename from src/mod/gic/pvprespawn.gic.json rename to src/module/gic/pvprespawn.gic.json diff --git a/src/mod/gic/rajashouse.gic.json b/src/module/gic/rajashouse.gic.json similarity index 100% rename from src/mod/gic/rajashouse.gic.json rename to src/module/gic/rajashouse.gic.json diff --git a/src/mod/gic/realmofcain.gic.json b/src/module/gic/realmofcain.gic.json similarity index 100% rename from src/mod/gic/realmofcain.gic.json rename to src/module/gic/realmofcain.gic.json diff --git a/src/mod/gic/realmofcain2.gic.json b/src/module/gic/realmofcain2.gic.json similarity index 100% rename from src/mod/gic/realmofcain2.gic.json rename to src/module/gic/realmofcain2.gic.json diff --git a/src/mod/gic/realmofcaincastl.gic.json b/src/module/gic/realmofcaincastl.gic.json similarity index 100% rename from src/mod/gic/realmofcaincastl.gic.json rename to src/module/gic/realmofcaincastl.gic.json diff --git a/src/mod/gic/realmofsubzeroes.gic.json b/src/module/gic/realmofsubzeroes.gic.json similarity index 100% rename from src/mod/gic/realmofsubzeroes.gic.json rename to src/module/gic/realmofsubzeroes.gic.json diff --git a/src/mod/gic/realmofthedarksi.gic.json b/src/module/gic/realmofthedarksi.gic.json similarity index 100% rename from src/mod/gic/realmofthedarksi.gic.json rename to src/module/gic/realmofthedarksi.gic.json diff --git a/src/mod/gic/reb.gic.json b/src/module/gic/reb.gic.json similarity index 100% rename from src/mod/gic/reb.gic.json rename to src/module/gic/reb.gic.json diff --git a/src/mod/gic/redarena.gic.json b/src/module/gic/redarena.gic.json similarity index 100% rename from src/mod/gic/redarena.gic.json rename to src/module/gic/redarena.gic.json diff --git a/src/mod/gic/redteamcastle002.gic.json b/src/module/gic/redteamcastle002.gic.json similarity index 100% rename from src/mod/gic/redteamcastle002.gic.json rename to src/module/gic/redteamcastle002.gic.json diff --git a/src/mod/gic/resident002.gic.json b/src/module/gic/resident002.gic.json similarity index 100% rename from src/mod/gic/resident002.gic.json rename to src/module/gic/resident002.gic.json diff --git a/src/mod/gic/resident003.gic.json b/src/module/gic/resident003.gic.json similarity index 100% rename from src/mod/gic/resident003.gic.json rename to src/module/gic/resident003.gic.json diff --git a/src/mod/gic/resident004.gic.json b/src/module/gic/resident004.gic.json similarity index 100% rename from src/mod/gic/resident004.gic.json rename to src/module/gic/resident004.gic.json diff --git a/src/mod/gic/riversidetrail.gic.json b/src/module/gic/riversidetrail.gic.json similarity index 100% rename from src/mod/gic/riversidetrail.gic.json rename to src/module/gic/riversidetrail.gic.json diff --git a/src/mod/gic/rollinghills001.gic.json b/src/module/gic/rollinghills001.gic.json similarity index 100% rename from src/mod/gic/rollinghills001.gic.json rename to src/module/gic/rollinghills001.gic.json diff --git a/src/mod/gic/rollingmeadows.gic.json b/src/module/gic/rollingmeadows.gic.json similarity index 100% rename from src/mod/gic/rollingmeadows.gic.json rename to src/module/gic/rollingmeadows.gic.json diff --git a/src/mod/gic/romancewing.gic.json b/src/module/gic/romancewing.gic.json similarity index 100% rename from src/mod/gic/romancewing.gic.json rename to src/module/gic/romancewing.gic.json diff --git a/src/mod/gic/ruinedminds001.gic.json b/src/module/gic/ruinedminds001.gic.json similarity index 100% rename from src/mod/gic/ruinedminds001.gic.json rename to src/module/gic/ruinedminds001.gic.json diff --git a/src/mod/gic/ruralfarms.gic.json b/src/module/gic/ruralfarms.gic.json similarity index 100% rename from src/mod/gic/ruralfarms.gic.json rename to src/module/gic/ruralfarms.gic.json diff --git a/src/mod/gic/scifiwing.gic.json b/src/module/gic/scifiwing.gic.json similarity index 100% rename from src/mod/gic/scifiwing.gic.json rename to src/module/gic/scifiwing.gic.json diff --git a/src/mod/gic/sector1.gic.json b/src/module/gic/sector1.gic.json similarity index 100% rename from src/mod/gic/sector1.gic.json rename to src/module/gic/sector1.gic.json diff --git a/src/mod/gic/sector2.gic.json b/src/module/gic/sector2.gic.json similarity index 100% rename from src/mod/gic/sector2.gic.json rename to src/module/gic/sector2.gic.json diff --git a/src/mod/gic/sector3.gic.json b/src/module/gic/sector3.gic.json similarity index 100% rename from src/mod/gic/sector3.gic.json rename to src/module/gic/sector3.gic.json diff --git a/src/mod/gic/sexyfreakguildho.gic.json b/src/module/gic/sexyfreakguildho.gic.json similarity index 100% rename from src/mod/gic/sexyfreakguildho.gic.json rename to src/module/gic/sexyfreakguildho.gic.json diff --git a/src/mod/gic/shadowlegionmain.gic.json b/src/module/gic/shadowlegionmain.gic.json similarity index 100% rename from src/mod/gic/shadowlegionmain.gic.json rename to src/module/gic/shadowlegionmain.gic.json diff --git a/src/mod/gic/shadowlegionreal.gic.json b/src/module/gic/shadowlegionreal.gic.json similarity index 100% rename from src/mod/gic/shadowlegionreal.gic.json rename to src/module/gic/shadowlegionreal.gic.json diff --git a/src/mod/gic/shadyladypub.gic.json b/src/module/gic/shadyladypub.gic.json similarity index 100% rename from src/mod/gic/shadyladypub.gic.json rename to src/module/gic/shadyladypub.gic.json diff --git a/src/mod/gic/shogunforesteast.gic.json b/src/module/gic/shogunforesteast.gic.json similarity index 100% rename from src/mod/gic/shogunforesteast.gic.json rename to src/module/gic/shogunforesteast.gic.json diff --git a/src/mod/gic/shogunmain.gic.json b/src/module/gic/shogunmain.gic.json similarity index 100% rename from src/mod/gic/shogunmain.gic.json rename to src/module/gic/shogunmain.gic.json diff --git a/src/mod/gic/shogunnorth.gic.json b/src/module/gic/shogunnorth.gic.json similarity index 100% rename from src/mod/gic/shogunnorth.gic.json rename to src/module/gic/shogunnorth.gic.json diff --git a/src/mod/gic/shogunprayercham.gic.json b/src/module/gic/shogunprayercham.gic.json similarity index 100% rename from src/mod/gic/shogunprayercham.gic.json rename to src/module/gic/shogunprayercham.gic.json diff --git a/src/mod/gic/shogunruins.gic.json b/src/module/gic/shogunruins.gic.json similarity index 100% rename from src/mod/gic/shogunruins.gic.json rename to src/module/gic/shogunruins.gic.json diff --git a/src/mod/gic/shogunsouth.gic.json b/src/module/gic/shogunsouth.gic.json similarity index 100% rename from src/mod/gic/shogunsouth.gic.json rename to src/module/gic/shogunsouth.gic.json diff --git a/src/mod/gic/shoguntemple.gic.json b/src/module/gic/shoguntemple.gic.json similarity index 100% rename from src/mod/gic/shoguntemple.gic.json rename to src/module/gic/shoguntemple.gic.json diff --git a/src/mod/gic/shoguntraningroo.gic.json b/src/module/gic/shoguntraningroo.gic.json similarity index 100% rename from src/mod/gic/shoguntraningroo.gic.json rename to src/module/gic/shoguntraningroo.gic.json diff --git a/src/mod/gic/shogunwest.gic.json b/src/module/gic/shogunwest.gic.json similarity index 100% rename from src/mod/gic/shogunwest.gic.json rename to src/module/gic/shogunwest.gic.json diff --git a/src/mod/gic/snowcaps.gic.json b/src/module/gic/snowcaps.gic.json similarity index 100% rename from src/mod/gic/snowcaps.gic.json rename to src/module/gic/snowcaps.gic.json diff --git a/src/mod/gic/solarrift.gic.json b/src/module/gic/solarrift.gic.json similarity index 100% rename from src/mod/gic/solarrift.gic.json rename to src/module/gic/solarrift.gic.json diff --git a/src/mod/gic/subworldcrossroa.gic.json b/src/module/gic/subworldcrossroa.gic.json similarity index 100% rename from src/mod/gic/subworldcrossroa.gic.json rename to src/module/gic/subworldcrossroa.gic.json diff --git a/src/mod/gic/temple.gic.json b/src/module/gic/temple.gic.json similarity index 100% rename from src/mod/gic/temple.gic.json rename to src/module/gic/temple.gic.json diff --git a/src/mod/gic/thecouncil.gic.json b/src/module/gic/thecouncil.gic.json similarity index 100% rename from src/mod/gic/thecouncil.gic.json rename to src/module/gic/thecouncil.gic.json diff --git a/src/mod/gic/theeasternroad.gic.json b/src/module/gic/theeasternroad.gic.json similarity index 100% rename from src/mod/gic/theeasternroad.gic.json rename to src/module/gic/theeasternroad.gic.json diff --git a/src/mod/gic/theeasternroad2.gic.json b/src/module/gic/theeasternroad2.gic.json similarity index 100% rename from src/mod/gic/theeasternroad2.gic.json rename to src/module/gic/theeasternroad2.gic.json diff --git a/src/mod/gic/thefistsguild001.gic.json b/src/module/gic/thefistsguild001.gic.json similarity index 100% rename from src/mod/gic/thefistsguild001.gic.json rename to src/module/gic/thefistsguild001.gic.json diff --git a/src/mod/gic/themonsterinthec.gic.json b/src/module/gic/themonsterinthec.gic.json similarity index 100% rename from src/mod/gic/themonsterinthec.gic.json rename to src/module/gic/themonsterinthec.gic.json diff --git a/src/mod/gic/thenightmarebegi.gic.json b/src/module/gic/thenightmarebegi.gic.json similarity index 100% rename from src/mod/gic/thenightmarebegi.gic.json rename to src/module/gic/thenightmarebegi.gic.json diff --git a/src/mod/gic/theoldworld.gic.json b/src/module/gic/theoldworld.gic.json similarity index 100% rename from src/mod/gic/theoldworld.gic.json rename to src/module/gic/theoldworld.gic.json diff --git a/src/mod/gic/thequietofthemin.gic.json b/src/module/gic/thequietofthemin.gic.json similarity index 100% rename from src/mod/gic/thequietofthemin.gic.json rename to src/module/gic/thequietofthemin.gic.json diff --git a/src/mod/gic/thevillageofhill.gic.json b/src/module/gic/thevillageofhill.gic.json similarity index 100% rename from src/mod/gic/thevillageofhill.gic.json rename to src/module/gic/thevillageofhill.gic.json diff --git a/src/mod/gic/thewilds.gic.json b/src/module/gic/thewilds.gic.json similarity index 100% rename from src/mod/gic/thewilds.gic.json rename to src/module/gic/thewilds.gic.json diff --git a/src/mod/gic/thunderlordkeep.gic.json b/src/module/gic/thunderlordkeep.gic.json similarity index 100% rename from src/mod/gic/thunderlordkeep.gic.json rename to src/module/gic/thunderlordkeep.gic.json diff --git a/src/mod/gic/thundermounainja.gic.json b/src/module/gic/thundermounainja.gic.json similarity index 100% rename from src/mod/gic/thundermounainja.gic.json rename to src/module/gic/thundermounainja.gic.json diff --git a/src/mod/gic/thundermountainb.gic.json b/src/module/gic/thundermountainb.gic.json similarity index 100% rename from src/mod/gic/thundermountainb.gic.json rename to src/module/gic/thundermountainb.gic.json diff --git a/src/mod/gic/thundermountainc.gic.json b/src/module/gic/thundermountainc.gic.json similarity index 100% rename from src/mod/gic/thundermountainc.gic.json rename to src/module/gic/thundermountainc.gic.json diff --git a/src/mod/gic/tmprisons.gic.json b/src/module/gic/tmprisons.gic.json similarity index 100% rename from src/mod/gic/tmprisons.gic.json rename to src/module/gic/tmprisons.gic.json diff --git a/src/mod/gic/tmstronghold.gic.json b/src/module/gic/tmstronghold.gic.json similarity index 100% rename from src/mod/gic/tmstronghold.gic.json rename to src/module/gic/tmstronghold.gic.json diff --git a/src/mod/gic/totalkoasguildho.gic.json b/src/module/gic/totalkoasguildho.gic.json similarity index 100% rename from src/mod/gic/totalkoasguildho.gic.json rename to src/module/gic/totalkoasguildho.gic.json diff --git a/src/mod/gic/toveast.gic.json b/src/module/gic/toveast.gic.json similarity index 100% rename from src/mod/gic/toveast.gic.json rename to src/module/gic/toveast.gic.json diff --git a/src/mod/gic/tovinner.gic.json b/src/module/gic/tovinner.gic.json similarity index 100% rename from src/mod/gic/tovinner.gic.json rename to src/module/gic/tovinner.gic.json diff --git a/src/mod/gic/tovnorth.gic.json b/src/module/gic/tovnorth.gic.json similarity index 100% rename from src/mod/gic/tovnorth.gic.json rename to src/module/gic/tovnorth.gic.json diff --git a/src/mod/gic/tovsouth.gic.json b/src/module/gic/tovsouth.gic.json similarity index 100% rename from src/mod/gic/tovsouth.gic.json rename to src/module/gic/tovsouth.gic.json diff --git a/src/mod/gic/tovwest.gic.json b/src/module/gic/tovwest.gic.json similarity index 100% rename from src/mod/gic/tovwest.gic.json rename to src/module/gic/tovwest.gic.json diff --git a/src/mod/gic/tridelthouse.gic.json b/src/module/gic/tridelthouse.gic.json similarity index 100% rename from src/mod/gic/tridelthouse.gic.json rename to src/module/gic/tridelthouse.gic.json diff --git a/src/mod/gic/trinity.gic.json b/src/module/gic/trinity.gic.json similarity index 100% rename from src/mod/gic/trinity.gic.json rename to src/module/gic/trinity.gic.json diff --git a/src/mod/gic/trinitybank.gic.json b/src/module/gic/trinitybank.gic.json similarity index 100% rename from src/mod/gic/trinitybank.gic.json rename to src/module/gic/trinitybank.gic.json diff --git a/src/mod/gic/trinitybrewmaste.gic.json b/src/module/gic/trinitybrewmaste.gic.json similarity index 100% rename from src/mod/gic/trinitybrewmaste.gic.json rename to src/module/gic/trinitybrewmaste.gic.json diff --git a/src/mod/gic/trinitycemetary.gic.json b/src/module/gic/trinitycemetary.gic.json similarity index 100% rename from src/mod/gic/trinitycemetary.gic.json rename to src/module/gic/trinitycemetary.gic.json diff --git a/src/mod/gic/trinitycrypts.gic.json b/src/module/gic/trinitycrypts.gic.json similarity index 100% rename from src/mod/gic/trinitycrypts.gic.json rename to src/module/gic/trinitycrypts.gic.json diff --git a/src/mod/gic/trinitydocks.gic.json b/src/module/gic/trinitydocks.gic.json similarity index 100% rename from src/mod/gic/trinitydocks.gic.json rename to src/module/gic/trinitydocks.gic.json diff --git a/src/mod/gic/trinityelders.gic.json b/src/module/gic/trinityelders.gic.json similarity index 100% rename from src/mod/gic/trinityelders.gic.json rename to src/module/gic/trinityelders.gic.json diff --git a/src/mod/gic/trinityeventload.gic.json b/src/module/gic/trinityeventload.gic.json similarity index 100% rename from src/mod/gic/trinityeventload.gic.json rename to src/module/gic/trinityeventload.gic.json diff --git a/src/mod/gic/trinityholychamb.gic.json b/src/module/gic/trinityholychamb.gic.json similarity index 100% rename from src/mod/gic/trinityholychamb.gic.json rename to src/module/gic/trinityholychamb.gic.json diff --git a/src/mod/gic/trinitylowercryp.gic.json b/src/module/gic/trinitylowercryp.gic.json similarity index 100% rename from src/mod/gic/trinitylowercryp.gic.json rename to src/module/gic/trinitylowercryp.gic.json diff --git a/src/mod/gic/trinitymagicandc.gic.json b/src/module/gic/trinitymagicandc.gic.json similarity index 100% rename from src/mod/gic/trinitymagicandc.gic.json rename to src/module/gic/trinitymagicandc.gic.json diff --git a/src/mod/gic/trinityrandomhou.gic.json b/src/module/gic/trinityrandomhou.gic.json similarity index 100% rename from src/mod/gic/trinityrandomhou.gic.json rename to src/module/gic/trinityrandomhou.gic.json diff --git a/src/mod/gic/trinityreapersgu.gic.json b/src/module/gic/trinityreapersgu.gic.json similarity index 100% rename from src/mod/gic/trinityreapersgu.gic.json rename to src/module/gic/trinityreapersgu.gic.json diff --git a/src/mod/gic/trinitysenators.gic.json b/src/module/gic/trinitysenators.gic.json similarity index 100% rename from src/mod/gic/trinitysenators.gic.json rename to src/module/gic/trinitysenators.gic.json diff --git a/src/mod/gic/trinitysewers.gic.json b/src/module/gic/trinitysewers.gic.json similarity index 100% rename from src/mod/gic/trinitysewers.gic.json rename to src/module/gic/trinitysewers.gic.json diff --git a/src/mod/gic/trinitysewerslev.gic.json b/src/module/gic/trinitysewerslev.gic.json similarity index 100% rename from src/mod/gic/trinitysewerslev.gic.json rename to src/module/gic/trinitysewerslev.gic.json diff --git a/src/mod/gic/trinitywarriorba.gic.json b/src/module/gic/trinitywarriorba.gic.json similarity index 100% rename from src/mod/gic/trinitywarriorba.gic.json rename to src/module/gic/trinitywarriorba.gic.json diff --git a/src/mod/gic/trollcaves3.gic.json b/src/module/gic/trollcaves3.gic.json similarity index 100% rename from src/mod/gic/trollcaves3.gic.json rename to src/module/gic/trollcaves3.gic.json diff --git a/src/mod/gic/tunnelstoholo.gic.json b/src/module/gic/tunnelstoholo.gic.json similarity index 100% rename from src/mod/gic/tunnelstoholo.gic.json rename to src/module/gic/tunnelstoholo.gic.json diff --git a/src/mod/gic/twingates.gic.json b/src/module/gic/twingates.gic.json similarity index 100% rename from src/mod/gic/twingates.gic.json rename to src/module/gic/twingates.gic.json diff --git a/src/mod/gic/underdarkportalr.gic.json b/src/module/gic/underdarkportalr.gic.json similarity index 100% rename from src/mod/gic/underdarkportalr.gic.json rename to src/module/gic/underdarkportalr.gic.json diff --git a/src/mod/gic/unknownpath.gic.json b/src/module/gic/unknownpath.gic.json similarity index 100% rename from src/mod/gic/unknownpath.gic.json rename to src/module/gic/unknownpath.gic.json diff --git a/src/mod/gic/vampireechos.gic.json b/src/module/gic/vampireechos.gic.json similarity index 100% rename from src/mod/gic/vampireechos.gic.json rename to src/module/gic/vampireechos.gic.json diff --git a/src/mod/gic/wastelandcaverns.gic.json b/src/module/gic/wastelandcaverns.gic.json similarity index 100% rename from src/mod/gic/wastelandcaverns.gic.json rename to src/module/gic/wastelandcaverns.gic.json diff --git a/src/mod/gic/westhouse1.gic.json b/src/module/gic/westhouse1.gic.json similarity index 100% rename from src/mod/gic/westhouse1.gic.json rename to src/module/gic/westhouse1.gic.json diff --git a/src/mod/gic/westhouse2.gic.json b/src/module/gic/westhouse2.gic.json similarity index 100% rename from src/mod/gic/westhouse2.gic.json rename to src/module/gic/westhouse2.gic.json diff --git a/src/mod/gic/windmillhouse.gic.json b/src/module/gic/windmillhouse.gic.json similarity index 100% rename from src/mod/gic/windmillhouse.gic.json rename to src/module/gic/windmillhouse.gic.json diff --git a/src/mod/gic/windycaverns.gic.json b/src/module/gic/windycaverns.gic.json similarity index 100% rename from src/mod/gic/windycaverns.gic.json rename to src/module/gic/windycaverns.gic.json diff --git a/src/mod/git/a1.git.json b/src/module/git/a1.git.json similarity index 100% rename from src/mod/git/a1.git.json rename to src/module/git/a1.git.json diff --git a/src/mod/git/a1hall.git.json b/src/module/git/a1hall.git.json similarity index 100% rename from src/mod/git/a1hall.git.json rename to src/module/git/a1hall.git.json diff --git a/src/mod/git/a2.git.json b/src/module/git/a2.git.json similarity index 100% rename from src/mod/git/a2.git.json rename to src/module/git/a2.git.json diff --git a/src/mod/git/a2hall.git.json b/src/module/git/a2hall.git.json similarity index 100% rename from src/mod/git/a2hall.git.json rename to src/module/git/a2hall.git.json diff --git a/src/mod/git/a3.git.json b/src/module/git/a3.git.json similarity index 100% rename from src/mod/git/a3.git.json rename to src/module/git/a3.git.json diff --git a/src/mod/git/ancientmountainc.git.json b/src/module/git/ancientmountainc.git.json similarity index 100% rename from src/mod/git/ancientmountainc.git.json rename to src/module/git/ancientmountainc.git.json diff --git a/src/mod/git/ancientmtformian.git.json b/src/module/git/ancientmtformian.git.json similarity index 100% rename from src/mod/git/ancientmtformian.git.json rename to src/module/git/ancientmtformian.git.json diff --git a/src/mod/git/ancientmtruins.git.json b/src/module/git/ancientmtruins.git.json similarity index 100% rename from src/mod/git/ancientmtruins.git.json rename to src/module/git/ancientmtruins.git.json diff --git a/src/mod/git/ancientmtstinger.git.json b/src/module/git/ancientmtstinger.git.json similarity index 100% rename from src/mod/git/ancientmtstinger.git.json rename to src/module/git/ancientmtstinger.git.json diff --git a/src/mod/git/area.git.json b/src/module/git/area.git.json similarity index 100% rename from src/mod/git/area.git.json rename to src/module/git/area.git.json diff --git a/src/mod/git/area001.git.json b/src/module/git/area001.git.json similarity index 100% rename from src/mod/git/area001.git.json rename to src/module/git/area001.git.json diff --git a/src/mod/git/area002.git.json b/src/module/git/area002.git.json similarity index 100% rename from src/mod/git/area002.git.json rename to src/module/git/area002.git.json diff --git a/src/mod/git/area003.git.json b/src/module/git/area003.git.json similarity index 100% rename from src/mod/git/area003.git.json rename to src/module/git/area003.git.json diff --git a/src/mod/git/area004.git.json b/src/module/git/area004.git.json similarity index 100% rename from src/mod/git/area004.git.json rename to src/module/git/area004.git.json diff --git a/src/mod/git/area005.git.json b/src/module/git/area005.git.json similarity index 100% rename from src/mod/git/area005.git.json rename to src/module/git/area005.git.json diff --git a/src/mod/git/area006.git.json b/src/module/git/area006.git.json similarity index 100% rename from src/mod/git/area006.git.json rename to src/module/git/area006.git.json diff --git a/src/mod/git/area007.git.json b/src/module/git/area007.git.json similarity index 100% rename from src/mod/git/area007.git.json rename to src/module/git/area007.git.json diff --git a/src/mod/git/area008.git.json b/src/module/git/area008.git.json similarity index 100% rename from src/mod/git/area008.git.json rename to src/module/git/area008.git.json diff --git a/src/mod/git/area009.git.json b/src/module/git/area009.git.json similarity index 100% rename from src/mod/git/area009.git.json rename to src/module/git/area009.git.json diff --git a/src/mod/git/area010.git.json b/src/module/git/area010.git.json similarity index 100% rename from src/mod/git/area010.git.json rename to src/module/git/area010.git.json diff --git a/src/mod/git/area011.git.json b/src/module/git/area011.git.json similarity index 100% rename from src/mod/git/area011.git.json rename to src/module/git/area011.git.json diff --git a/src/mod/git/area012.git.json b/src/module/git/area012.git.json similarity index 100% rename from src/mod/git/area012.git.json rename to src/module/git/area012.git.json diff --git a/src/mod/git/area013.git.json b/src/module/git/area013.git.json similarity index 100% rename from src/mod/git/area013.git.json rename to src/module/git/area013.git.json diff --git a/src/mod/git/area014.git.json b/src/module/git/area014.git.json similarity index 100% rename from src/mod/git/area014.git.json rename to src/module/git/area014.git.json diff --git a/src/mod/git/area015.git.json b/src/module/git/area015.git.json similarity index 100% rename from src/mod/git/area015.git.json rename to src/module/git/area015.git.json diff --git a/src/mod/git/area016.git.json b/src/module/git/area016.git.json similarity index 100% rename from src/mod/git/area016.git.json rename to src/module/git/area016.git.json diff --git a/src/mod/git/area017.git.json b/src/module/git/area017.git.json similarity index 100% rename from src/mod/git/area017.git.json rename to src/module/git/area017.git.json diff --git a/src/mod/git/area018.git.json b/src/module/git/area018.git.json similarity index 100% rename from src/mod/git/area018.git.json rename to src/module/git/area018.git.json diff --git a/src/mod/git/area019.git.json b/src/module/git/area019.git.json similarity index 100% rename from src/mod/git/area019.git.json rename to src/module/git/area019.git.json diff --git a/src/mod/git/area022.git.json b/src/module/git/area022.git.json similarity index 100% rename from src/mod/git/area022.git.json rename to src/module/git/area022.git.json diff --git a/src/mod/git/area024.git.json b/src/module/git/area024.git.json similarity index 100% rename from src/mod/git/area024.git.json rename to src/module/git/area024.git.json diff --git a/src/mod/git/area027.git.json b/src/module/git/area027.git.json similarity index 100% rename from src/mod/git/area027.git.json rename to src/module/git/area027.git.json diff --git a/src/mod/git/area028.git.json b/src/module/git/area028.git.json similarity index 100% rename from src/mod/git/area028.git.json rename to src/module/git/area028.git.json diff --git a/src/mod/git/area029.git.json b/src/module/git/area029.git.json similarity index 100% rename from src/mod/git/area029.git.json rename to src/module/git/area029.git.json diff --git a/src/mod/git/arena.git.json b/src/module/git/arena.git.json similarity index 100% rename from src/mod/git/arena.git.json rename to src/module/git/arena.git.json diff --git a/src/mod/git/asyriancastle.git.json b/src/module/git/asyriancastle.git.json similarity index 100% rename from src/mod/git/asyriancastle.git.json rename to src/module/git/asyriancastle.git.json diff --git a/src/mod/git/asyriancastle001.git.json b/src/module/git/asyriancastle001.git.json similarity index 100% rename from src/mod/git/asyriancastle001.git.json rename to src/module/git/asyriancastle001.git.json diff --git a/src/mod/git/asyrianholyruins.git.json b/src/module/git/asyrianholyruins.git.json similarity index 100% rename from src/mod/git/asyrianholyruins.git.json rename to src/module/git/asyrianholyruins.git.json diff --git a/src/mod/git/asyriantreasurer.git.json b/src/module/git/asyriantreasurer.git.json similarity index 100% rename from src/mod/git/asyriantreasurer.git.json rename to src/module/git/asyriantreasurer.git.json diff --git a/src/mod/git/asyrianupper.git.json b/src/module/git/asyrianupper.git.json similarity index 100% rename from src/mod/git/asyrianupper.git.json rename to src/module/git/asyrianupper.git.json diff --git a/src/mod/git/atlantis.git.json b/src/module/git/atlantis.git.json similarity index 100% rename from src/mod/git/atlantis.git.json rename to src/module/git/atlantis.git.json diff --git a/src/mod/git/atlantiseast.git.json b/src/module/git/atlantiseast.git.json similarity index 100% rename from src/mod/git/atlantiseast.git.json rename to src/module/git/atlantiseast.git.json diff --git a/src/mod/git/atlantiseastbuil.git.json b/src/module/git/atlantiseastbuil.git.json similarity index 100% rename from src/mod/git/atlantiseastbuil.git.json rename to src/module/git/atlantiseastbuil.git.json diff --git a/src/mod/git/atlantisnorth.git.json b/src/module/git/atlantisnorth.git.json similarity index 100% rename from src/mod/git/atlantisnorth.git.json rename to src/module/git/atlantisnorth.git.json diff --git a/src/mod/git/atlantisnorthbui.git.json b/src/module/git/atlantisnorthbui.git.json similarity index 100% rename from src/mod/git/atlantisnorthbui.git.json rename to src/module/git/atlantisnorthbui.git.json diff --git a/src/mod/git/atlantissouth.git.json b/src/module/git/atlantissouth.git.json similarity index 100% rename from src/mod/git/atlantissouth.git.json rename to src/module/git/atlantissouth.git.json diff --git a/src/mod/git/atlantissouthbui.git.json b/src/module/git/atlantissouthbui.git.json similarity index 100% rename from src/mod/git/atlantissouthbui.git.json rename to src/module/git/atlantissouthbui.git.json diff --git a/src/mod/git/atlantiswest.git.json b/src/module/git/atlantiswest.git.json similarity index 100% rename from src/mod/git/atlantiswest.git.json rename to src/module/git/atlantiswest.git.json diff --git a/src/mod/git/atlantiswestbuil.git.json b/src/module/git/atlantiswestbuil.git.json similarity index 100% rename from src/mod/git/atlantiswestbuil.git.json rename to src/module/git/atlantiswestbuil.git.json diff --git a/src/mod/git/awabandonedlodge.git.json b/src/module/git/awabandonedlodge.git.json similarity index 100% rename from src/mod/git/awabandonedlodge.git.json rename to src/module/git/awabandonedlodge.git.json diff --git a/src/mod/git/awcavern.git.json b/src/module/git/awcavern.git.json similarity index 100% rename from src/mod/git/awcavern.git.json rename to src/module/git/awcavern.git.json diff --git a/src/mod/git/awdesertruins.git.json b/src/module/git/awdesertruins.git.json similarity index 100% rename from src/mod/git/awdesertruins.git.json rename to src/module/git/awdesertruins.git.json diff --git a/src/mod/git/awhome.git.json b/src/module/git/awhome.git.json similarity index 100% rename from src/mod/git/awhome.git.json rename to src/module/git/awhome.git.json diff --git a/src/mod/git/awillithidinner.git.json b/src/module/git/awillithidinner.git.json similarity index 100% rename from src/mod/git/awillithidinner.git.json rename to src/module/git/awillithidinner.git.json diff --git a/src/mod/git/awportaltoverasp.git.json b/src/module/git/awportaltoverasp.git.json similarity index 100% rename from src/mod/git/awportaltoverasp.git.json rename to src/module/git/awportaltoverasp.git.json diff --git a/src/mod/git/awtempleofvera.git.json b/src/module/git/awtempleofvera.git.json similarity index 100% rename from src/mod/git/awtempleofvera.git.json rename to src/module/git/awtempleofvera.git.json diff --git a/src/mod/git/awtrollcaves.git.json b/src/module/git/awtrollcaves.git.json similarity index 100% rename from src/mod/git/awtrollcaves.git.json rename to src/module/git/awtrollcaves.git.json diff --git a/src/mod/git/awtrollcaves2.git.json b/src/module/git/awtrollcaves2.git.json similarity index 100% rename from src/mod/git/awtrollcaves2.git.json rename to src/module/git/awtrollcaves2.git.json diff --git a/src/mod/git/b1.git.json b/src/module/git/b1.git.json similarity index 100% rename from src/mod/git/b1.git.json rename to src/module/git/b1.git.json diff --git a/src/mod/git/b1hall.git.json b/src/module/git/b1hall.git.json similarity index 100% rename from src/mod/git/b1hall.git.json rename to src/module/git/b1hall.git.json diff --git a/src/mod/git/b2.git.json b/src/module/git/b2.git.json similarity index 100% rename from src/mod/git/b2.git.json rename to src/module/git/b2.git.json diff --git a/src/mod/git/b3.git.json b/src/module/git/b3.git.json similarity index 100% rename from src/mod/git/b3.git.json rename to src/module/git/b3.git.json diff --git a/src/mod/git/bandithold001.git.json b/src/module/git/bandithold001.git.json similarity index 100% rename from src/mod/git/bandithold001.git.json rename to src/module/git/bandithold001.git.json diff --git a/src/mod/git/bandithouse.git.json b/src/module/git/bandithouse.git.json similarity index 100% rename from src/mod/git/bandithouse.git.json rename to src/module/git/bandithouse.git.json diff --git a/src/mod/git/barn.git.json b/src/module/git/barn.git.json similarity index 100% rename from src/mod/git/barn.git.json rename to src/module/git/barn.git.json diff --git a/src/mod/git/barn001.git.json b/src/module/git/barn001.git.json similarity index 100% rename from src/mod/git/barn001.git.json rename to src/module/git/barn001.git.json diff --git a/src/mod/git/barrieddesert.git.json b/src/module/git/barrieddesert.git.json similarity index 100% rename from src/mod/git/barrieddesert.git.json rename to src/module/git/barrieddesert.git.json diff --git a/src/mod/git/baylibrary.git.json b/src/module/git/baylibrary.git.json similarity index 100% rename from src/mod/git/baylibrary.git.json rename to src/module/git/baylibrary.git.json diff --git a/src/mod/git/bayvillage.git.json b/src/module/git/bayvillage.git.json similarity index 100% rename from src/mod/git/bayvillage.git.json rename to src/module/git/bayvillage.git.json diff --git a/src/mod/git/bayvillagetownha.git.json b/src/module/git/bayvillagetownha.git.json similarity index 100% rename from src/mod/git/bayvillagetownha.git.json rename to src/module/git/bayvillagetownha.git.json diff --git a/src/mod/git/beholdercaves.git.json b/src/module/git/beholdercaves.git.json similarity index 100% rename from src/mod/git/beholdercaves.git.json rename to src/module/git/beholdercaves.git.json diff --git a/src/mod/git/beholdercavestyr.git.json b/src/module/git/beholdercavestyr.git.json similarity index 100% rename from src/mod/git/beholdercavestyr.git.json rename to src/module/git/beholdercavestyr.git.json diff --git a/src/mod/git/bigginsville.git.json b/src/module/git/bigginsville.git.json similarity index 100% rename from src/mod/git/bigginsville.git.json rename to src/module/git/bigginsville.git.json diff --git a/src/mod/git/bluearena.git.json b/src/module/git/bluearena.git.json similarity index 100% rename from src/mod/git/bluearena.git.json rename to src/module/git/bluearena.git.json diff --git a/src/mod/git/blueteamcastl001.git.json b/src/module/git/blueteamcastl001.git.json similarity index 100% rename from src/mod/git/blueteamcastl001.git.json rename to src/module/git/blueteamcastl001.git.json diff --git a/src/mod/git/boudoirofthepurp.git.json b/src/module/git/boudoirofthepurp.git.json similarity index 100% rename from src/mod/git/boudoirofthepurp.git.json rename to src/module/git/boudoirofthepurp.git.json diff --git a/src/mod/git/bretheren1.git.json b/src/module/git/bretheren1.git.json similarity index 100% rename from src/mod/git/bretheren1.git.json rename to src/module/git/bretheren1.git.json diff --git a/src/mod/git/bretherenlivingq.git.json b/src/module/git/bretherenlivingq.git.json similarity index 100% rename from src/mod/git/bretherenlivingq.git.json rename to src/module/git/bretherenlivingq.git.json diff --git a/src/mod/git/bretherenlounge.git.json b/src/module/git/bretherenlounge.git.json similarity index 100% rename from src/mod/git/bretherenlounge.git.json rename to src/module/git/bretherenlounge.git.json diff --git a/src/mod/git/bretherenthroner.git.json b/src/module/git/bretherenthroner.git.json similarity index 100% rename from src/mod/git/bretherenthroner.git.json rename to src/module/git/bretherenthroner.git.json diff --git a/src/mod/git/burialchamber.git.json b/src/module/git/burialchamber.git.json similarity index 100% rename from src/mod/git/burialchamber.git.json rename to src/module/git/burialchamber.git.json diff --git a/src/mod/git/castleofcain.git.json b/src/module/git/castleofcain.git.json similarity index 100% rename from src/mod/git/castleofcain.git.json rename to src/module/git/castleofcain.git.json diff --git a/src/mod/git/castleoftheda001.git.json b/src/module/git/castleoftheda001.git.json similarity index 100% rename from src/mod/git/castleoftheda001.git.json rename to src/module/git/castleoftheda001.git.json diff --git a/src/mod/git/castleofthedarkq.git.json b/src/module/git/castleofthedarkq.git.json similarity index 100% rename from src/mod/git/castleofthedarkq.git.json rename to src/module/git/castleofthedarkq.git.json diff --git a/src/mod/git/caveoftheclanlea.git.json b/src/module/git/caveoftheclanlea.git.json similarity index 100% rename from src/mod/git/caveoftheclanlea.git.json rename to src/module/git/caveoftheclanlea.git.json diff --git a/src/mod/git/chamberofalignme.git.json b/src/module/git/chamberofalignme.git.json similarity index 100% rename from src/mod/git/chamberofalignme.git.json rename to src/module/git/chamberofalignme.git.json diff --git a/src/mod/git/cheatcentral.git.json b/src/module/git/cheatcentral.git.json similarity index 100% rename from src/mod/git/cheatcentral.git.json rename to src/module/git/cheatcentral.git.json diff --git a/src/mod/git/cityofdirth.git.json b/src/module/git/cityofdirth.git.json similarity index 100% rename from src/mod/git/cityofdirth.git.json rename to src/module/git/cityofdirth.git.json diff --git a/src/mod/git/cityofdirthbehol.git.json b/src/module/git/cityofdirthbehol.git.json similarity index 100% rename from src/mod/git/cityofdirthbehol.git.json rename to src/module/git/cityofdirthbehol.git.json diff --git a/src/mod/git/cityofdirthcore.git.json b/src/module/git/cityofdirthcore.git.json similarity index 100% rename from src/mod/git/cityofdirthcore.git.json rename to src/module/git/cityofdirthcore.git.json diff --git a/src/mod/git/cityofdirthdrowb.git.json b/src/module/git/cityofdirthdrowb.git.json similarity index 100% rename from src/mod/git/cityofdirthdrowb.git.json rename to src/module/git/cityofdirthdrowb.git.json diff --git a/src/mod/git/cityofdirthdrows.git.json b/src/module/git/cityofdirthdrows.git.json similarity index 99% rename from src/mod/git/cityofdirthdrows.git.json rename to src/module/git/cityofdirthdrows.git.json index 3b4ae10..4c4dcfb 100644 --- a/src/mod/git/cityofdirthdrows.git.json +++ b/src/module/git/cityofdirthdrows.git.json @@ -9534,7 +9534,7 @@ "__struct_id": 2, "Orientation": { "type": "float", - "value": -3.1416 + "value": 3.1416 }, "X": { "type": "float", diff --git a/src/mod/git/cityofdirthoutsk.git.json b/src/module/git/cityofdirthoutsk.git.json similarity index 100% rename from src/mod/git/cityofdirthoutsk.git.json rename to src/module/git/cityofdirthoutsk.git.json diff --git a/src/mod/git/cityofdirthpoor.git.json b/src/module/git/cityofdirthpoor.git.json similarity index 100% rename from src/mod/git/cityofdirthpoor.git.json rename to src/module/git/cityofdirthpoor.git.json diff --git a/src/mod/git/cityofdirthpoorh.git.json b/src/module/git/cityofdirthpoorh.git.json similarity index 100% rename from src/mod/git/cityofdirthpoorh.git.json rename to src/module/git/cityofdirthpoorh.git.json diff --git a/src/mod/git/cityofdirthtempl.git.json b/src/module/git/cityofdirthtempl.git.json similarity index 100% rename from src/mod/git/cityofdirthtempl.git.json rename to src/module/git/cityofdirthtempl.git.json diff --git a/src/mod/git/cityofdirthupwiz.git.json b/src/module/git/cityofdirthupwiz.git.json similarity index 100% rename from src/mod/git/cityofdirthupwiz.git.json rename to src/module/git/cityofdirthupwiz.git.json diff --git a/src/mod/git/cityofdirthwhore.git.json b/src/module/git/cityofdirthwhore.git.json similarity index 100% rename from src/mod/git/cityofdirthwhore.git.json rename to src/module/git/cityofdirthwhore.git.json diff --git a/src/mod/git/cityofdirthwizto.git.json b/src/module/git/cityofdirthwizto.git.json similarity index 100% rename from src/mod/git/cityofdirthwizto.git.json rename to src/module/git/cityofdirthwizto.git.json diff --git a/src/mod/git/cityofoz.git.json b/src/module/git/cityofoz.git.json similarity index 100% rename from src/mod/git/cityofoz.git.json rename to src/module/git/cityofoz.git.json diff --git a/src/mod/git/cloaktowerheadli.git.json b/src/module/git/cloaktowerheadli.git.json similarity index 100% rename from src/mod/git/cloaktowerheadli.git.json rename to src/module/git/cloaktowerheadli.git.json diff --git a/src/mod/git/cloaktowerlevel1.git.json b/src/module/git/cloaktowerlevel1.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel1.git.json rename to src/module/git/cloaktowerlevel1.git.json diff --git a/src/mod/git/cloaktowerlevel2.git.json b/src/module/git/cloaktowerlevel2.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel2.git.json rename to src/module/git/cloaktowerlevel2.git.json diff --git a/src/mod/git/cloaktowerlevel3.git.json b/src/module/git/cloaktowerlevel3.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel3.git.json rename to src/module/git/cloaktowerlevel3.git.json diff --git a/src/mod/git/cloaktowerlevel4.git.json b/src/module/git/cloaktowerlevel4.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel4.git.json rename to src/module/git/cloaktowerlevel4.git.json diff --git a/src/mod/git/cloaktowerlevel5.git.json b/src/module/git/cloaktowerlevel5.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel5.git.json rename to src/module/git/cloaktowerlevel5.git.json diff --git a/src/mod/git/cloaktowerlevel6.git.json b/src/module/git/cloaktowerlevel6.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel6.git.json rename to src/module/git/cloaktowerlevel6.git.json diff --git a/src/mod/git/cloaktowerlevel7.git.json b/src/module/git/cloaktowerlevel7.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel7.git.json rename to src/module/git/cloaktowerlevel7.git.json diff --git a/src/mod/git/cloaktowerlevel8.git.json b/src/module/git/cloaktowerlevel8.git.json similarity index 100% rename from src/mod/git/cloaktowerlevel8.git.json rename to src/module/git/cloaktowerlevel8.git.json diff --git a/src/mod/git/coalmines.git.json b/src/module/git/coalmines.git.json similarity index 100% rename from src/mod/git/coalmines.git.json rename to src/module/git/coalmines.git.json diff --git a/src/mod/git/coastalcity.git.json b/src/module/git/coastalcity.git.json similarity index 100% rename from src/mod/git/coastalcity.git.json rename to src/module/git/coastalcity.git.json diff --git a/src/mod/git/coastalroad.git.json b/src/module/git/coastalroad.git.json similarity index 100% rename from src/mod/git/coastalroad.git.json rename to src/module/git/coastalroad.git.json diff --git a/src/mod/git/conciousroom.git.json b/src/module/git/conciousroom.git.json similarity index 100% rename from src/mod/git/conciousroom.git.json rename to src/module/git/conciousroom.git.json diff --git a/src/mod/git/cuyahogawilderne.git.json b/src/module/git/cuyahogawilderne.git.json similarity index 100% rename from src/mod/git/cuyahogawilderne.git.json rename to src/module/git/cuyahogawilderne.git.json diff --git a/src/mod/git/darkqueenchamb.git.json b/src/module/git/darkqueenchamb.git.json similarity index 100% rename from src/mod/git/darkqueenchamb.git.json rename to src/module/git/darkqueenchamb.git.json diff --git a/src/mod/git/dbi_pc_rooms.git.json b/src/module/git/dbi_pc_rooms.git.json similarity index 100% rename from src/mod/git/dbi_pc_rooms.git.json rename to src/module/git/dbi_pc_rooms.git.json diff --git a/src/mod/git/desertcavern.git.json b/src/module/git/desertcavern.git.json similarity index 100% rename from src/mod/git/desertcavern.git.json rename to src/module/git/desertcavern.git.json diff --git a/src/mod/git/desertdwarfruins.git.json b/src/module/git/desertdwarfruins.git.json similarity index 100% rename from src/mod/git/desertdwarfruins.git.json rename to src/module/git/desertdwarfruins.git.json diff --git a/src/mod/git/desertruins.git.json b/src/module/git/desertruins.git.json similarity index 100% rename from src/mod/git/desertruins.git.json rename to src/module/git/desertruins.git.json diff --git a/src/mod/git/desolateanddespa.git.json b/src/module/git/desolateanddespa.git.json similarity index 100% rename from src/mod/git/desolateanddespa.git.json rename to src/module/git/desolateanddespa.git.json diff --git a/src/mod/git/dirthtower1.git.json b/src/module/git/dirthtower1.git.json similarity index 100% rename from src/mod/git/dirthtower1.git.json rename to src/module/git/dirthtower1.git.json diff --git a/src/mod/git/dirthtransporter.git.json b/src/module/git/dirthtransporter.git.json similarity index 100% rename from src/mod/git/dirthtransporter.git.json rename to src/module/git/dirthtransporter.git.json diff --git a/src/mod/git/doctorsguild.git.json b/src/module/git/doctorsguild.git.json similarity index 100% rename from src/mod/git/doctorsguild.git.json rename to src/module/git/doctorsguild.git.json diff --git a/src/mod/git/doctorsmain.git.json b/src/module/git/doctorsmain.git.json similarity index 100% rename from src/mod/git/doctorsmain.git.json rename to src/module/git/doctorsmain.git.json diff --git a/src/mod/git/doctorsmain001.git.json b/src/module/git/doctorsmain001.git.json similarity index 100% rename from src/mod/git/doctorsmain001.git.json rename to src/module/git/doctorsmain001.git.json diff --git a/src/mod/git/downtherabbithol.git.json b/src/module/git/downtherabbithol.git.json similarity index 100% rename from src/mod/git/downtherabbithol.git.json rename to src/module/git/downtherabbithol.git.json diff --git a/src/mod/git/draculascrypt.git.json b/src/module/git/draculascrypt.git.json similarity index 100% rename from src/mod/git/draculascrypt.git.json rename to src/module/git/draculascrypt.git.json diff --git a/src/mod/git/dragonbackinn.git.json b/src/module/git/dragonbackinn.git.json similarity index 100% rename from src/mod/git/dragonbackinn.git.json rename to src/module/git/dragonbackinn.git.json diff --git a/src/mod/git/dragoncaverns.git.json b/src/module/git/dragoncaverns.git.json similarity index 100% rename from src/mod/git/dragoncaverns.git.json rename to src/module/git/dragoncaverns.git.json diff --git a/src/mod/git/dragoncaverntunn.git.json b/src/module/git/dragoncaverntunn.git.json similarity index 100% rename from src/mod/git/dragoncaverntunn.git.json rename to src/module/git/dragoncaverntunn.git.json diff --git a/src/mod/git/dragoncaves001.git.json b/src/module/git/dragoncaves001.git.json similarity index 100% rename from src/mod/git/dragoncaves001.git.json rename to src/module/git/dragoncaves001.git.json diff --git a/src/mod/git/dragoncultbarrak.git.json b/src/module/git/dragoncultbarrak.git.json similarity index 100% rename from src/mod/git/dragoncultbarrak.git.json rename to src/module/git/dragoncultbarrak.git.json diff --git a/src/mod/git/dragoncultcastle.git.json b/src/module/git/dragoncultcastle.git.json similarity index 100% rename from src/mod/git/dragoncultcastle.git.json rename to src/module/git/dragoncultcastle.git.json diff --git a/src/mod/git/dragoncultenergy.git.json b/src/module/git/dragoncultenergy.git.json similarity index 100% rename from src/mod/git/dragoncultenergy.git.json rename to src/module/git/dragoncultenergy.git.json diff --git a/src/mod/git/dreamweaver001.git.json b/src/module/git/dreamweaver001.git.json similarity index 100% rename from src/mod/git/dreamweaver001.git.json rename to src/module/git/dreamweaver001.git.json diff --git a/src/mod/git/drowbarraks.git.json b/src/module/git/drowbarraks.git.json similarity index 100% rename from src/mod/git/drowbarraks.git.json rename to src/module/git/drowbarraks.git.json diff --git a/src/mod/git/drowtemple.git.json b/src/module/git/drowtemple.git.json similarity index 100% rename from src/mod/git/drowtemple.git.json rename to src/module/git/drowtemple.git.json diff --git a/src/mod/git/durbonshire.git.json b/src/module/git/durbonshire.git.json similarity index 100% rename from src/mod/git/durbonshire.git.json rename to src/module/git/durbonshire.git.json diff --git a/src/mod/git/dwarvencaverns.git.json b/src/module/git/dwarvencaverns.git.json similarity index 100% rename from src/mod/git/dwarvencaverns.git.json rename to src/module/git/dwarvencaverns.git.json diff --git a/src/mod/git/dwarvencavernslv.git.json b/src/module/git/dwarvencavernslv.git.json similarity index 100% rename from src/mod/git/dwarvencavernslv.git.json rename to src/module/git/dwarvencavernslv.git.json diff --git a/src/mod/git/dwarvendungeons.git.json b/src/module/git/dwarvendungeons.git.json similarity index 100% rename from src/mod/git/dwarvendungeons.git.json rename to src/module/git/dwarvendungeons.git.json diff --git a/src/mod/git/dwarvendungeonsl.git.json b/src/module/git/dwarvendungeonsl.git.json similarity index 100% rename from src/mod/git/dwarvendungeonsl.git.json rename to src/module/git/dwarvendungeonsl.git.json diff --git a/src/mod/git/eleventoeddwarfs.git.json b/src/module/git/eleventoeddwarfs.git.json similarity index 100% rename from src/mod/git/eleventoeddwarfs.git.json rename to src/module/git/eleventoeddwarfs.git.json diff --git a/src/mod/git/elvendar.git.json b/src/module/git/elvendar.git.json similarity index 100% rename from src/mod/git/elvendar.git.json rename to src/module/git/elvendar.git.json diff --git a/src/mod/git/elvendargener001.git.json b/src/module/git/elvendargener001.git.json similarity index 100% rename from src/mod/git/elvendargener001.git.json rename to src/module/git/elvendargener001.git.json diff --git a/src/mod/git/elvendarnorth001.git.json b/src/module/git/elvendarnorth001.git.json similarity index 100% rename from src/mod/git/elvendarnorth001.git.json rename to src/module/git/elvendarnorth001.git.json diff --git a/src/mod/git/elvendarnorthern.git.json b/src/module/git/elvendarnorthern.git.json similarity index 100% rename from src/mod/git/elvendarnorthern.git.json rename to src/module/git/elvendarnorthern.git.json diff --git a/src/mod/git/elvendarouterfor.git.json b/src/module/git/elvendarouterfor.git.json similarity index 100% rename from src/mod/git/elvendarouterfor.git.json rename to src/module/git/elvendarouterfor.git.json diff --git a/src/mod/git/elvendarunder001.git.json b/src/module/git/elvendarunder001.git.json similarity index 100% rename from src/mod/git/elvendarunder001.git.json rename to src/module/git/elvendarunder001.git.json diff --git a/src/mod/git/elvendarunder002.git.json b/src/module/git/elvendarunder002.git.json similarity index 100% rename from src/mod/git/elvendarunder002.git.json rename to src/module/git/elvendarunder002.git.json diff --git a/src/mod/git/elvendarundergro.git.json b/src/module/git/elvendarundergro.git.json similarity index 100% rename from src/mod/git/elvendarundergro.git.json rename to src/module/git/elvendarundergro.git.json diff --git a/src/mod/git/elvendarweste001.git.json b/src/module/git/elvendarweste001.git.json similarity index 100% rename from src/mod/git/elvendarweste001.git.json rename to src/module/git/elvendarweste001.git.json diff --git a/src/mod/git/elvendarwesternb.git.json b/src/module/git/elvendarwesternb.git.json similarity index 100% rename from src/mod/git/elvendarwesternb.git.json rename to src/module/git/elvendarwesternb.git.json diff --git a/src/mod/git/evilclericceremo.git.json b/src/module/git/evilclericceremo.git.json similarity index 100% rename from src/mod/git/evilclericceremo.git.json rename to src/module/git/evilclericceremo.git.json diff --git a/src/mod/git/evilclericruins.git.json b/src/module/git/evilclericruins.git.json similarity index 100% rename from src/mod/git/evilclericruins.git.json rename to src/module/git/evilclericruins.git.json diff --git a/src/mod/git/ey_dpcon_erewood.git.json b/src/module/git/ey_dpcon_erewood.git.json similarity index 100% rename from src/mod/git/ey_dpcon_erewood.git.json rename to src/module/git/ey_dpcon_erewood.git.json diff --git a/src/mod/git/fareast001.git.json b/src/module/git/fareast001.git.json similarity index 100% rename from src/mod/git/fareast001.git.json rename to src/module/git/fareast001.git.json diff --git a/src/mod/git/fareastdesert.git.json b/src/module/git/fareastdesert.git.json similarity index 100% rename from src/mod/git/fareastdesert.git.json rename to src/module/git/fareastdesert.git.json diff --git a/src/mod/git/fareastdesertrui.git.json b/src/module/git/fareastdesertrui.git.json similarity index 100% rename from src/mod/git/fareastdesertrui.git.json rename to src/module/git/fareastdesertrui.git.json diff --git a/src/mod/git/followersofmorda.git.json b/src/module/git/followersofmorda.git.json similarity index 100% rename from src/mod/git/followersofmorda.git.json rename to src/module/git/followersofmorda.git.json diff --git a/src/mod/git/foresttemple001.git.json b/src/module/git/foresttemple001.git.json similarity index 100% rename from src/mod/git/foresttemple001.git.json rename to src/module/git/foresttemple001.git.json diff --git a/src/mod/git/frostedpits.git.json b/src/module/git/frostedpits.git.json similarity index 100% rename from src/mod/git/frostedpits.git.json rename to src/module/git/frostedpits.git.json diff --git a/src/mod/git/frozantundraeast.git.json b/src/module/git/frozantundraeast.git.json similarity index 100% rename from src/mod/git/frozantundraeast.git.json rename to src/module/git/frozantundraeast.git.json diff --git a/src/mod/git/frozedtundra.git.json b/src/module/git/frozedtundra.git.json similarity index 100% rename from src/mod/git/frozedtundra.git.json rename to src/module/git/frozedtundra.git.json diff --git a/src/mod/git/frozentimes.git.json b/src/module/git/frozentimes.git.json similarity index 100% rename from src/mod/git/frozentimes.git.json rename to src/module/git/frozentimes.git.json diff --git a/src/mod/git/frozentundranort.git.json b/src/module/git/frozentundranort.git.json similarity index 100% rename from src/mod/git/frozentundranort.git.json rename to src/module/git/frozentundranort.git.json diff --git a/src/mod/git/frozentundrawest.git.json b/src/module/git/frozentundrawest.git.json similarity index 100% rename from src/mod/git/frozentundrawest.git.json rename to src/module/git/frozentundrawest.git.json diff --git a/src/mod/git/granolalodge.git.json b/src/module/git/granolalodge.git.json similarity index 100% rename from src/mod/git/granolalodge.git.json rename to src/module/git/granolalodge.git.json diff --git a/src/mod/git/groundskeeper.git.json b/src/module/git/groundskeeper.git.json similarity index 100% rename from src/mod/git/groundskeeper.git.json rename to src/module/git/groundskeeper.git.json diff --git a/src/mod/git/halloftheancient.git.json b/src/module/git/halloftheancient.git.json similarity index 100% rename from src/mod/git/halloftheancient.git.json rename to src/module/git/halloftheancient.git.json diff --git a/src/mod/git/hallowedground1.git.json b/src/module/git/hallowedground1.git.json similarity index 100% rename from src/mod/git/hallowedground1.git.json rename to src/module/git/hallowedground1.git.json diff --git a/src/mod/git/healerhouse.git.json b/src/module/git/healerhouse.git.json similarity index 100% rename from src/mod/git/healerhouse.git.json rename to src/module/git/healerhouse.git.json diff --git a/src/mod/git/hillsidehome001.git.json b/src/module/git/hillsidehome001.git.json similarity index 100% rename from src/mod/git/hillsidehome001.git.json rename to src/module/git/hillsidehome001.git.json diff --git a/src/mod/git/hillsideinn.git.json b/src/module/git/hillsideinn.git.json similarity index 100% rename from src/mod/git/hillsideinn.git.json rename to src/module/git/hillsideinn.git.json diff --git a/src/mod/git/hillsidemysticto.git.json b/src/module/git/hillsidemysticto.git.json similarity index 100% rename from src/mod/git/hillsidemysticto.git.json rename to src/module/git/hillsidemysticto.git.json diff --git a/src/mod/git/hillsidetempl001.git.json b/src/module/git/hillsidetempl001.git.json similarity index 100% rename from src/mod/git/hillsidetempl001.git.json rename to src/module/git/hillsidetempl001.git.json diff --git a/src/mod/git/historywing.git.json b/src/module/git/historywing.git.json similarity index 100% rename from src/mod/git/historywing.git.json rename to src/module/git/historywing.git.json diff --git a/src/mod/git/holyground.git.json b/src/module/git/holyground.git.json similarity index 100% rename from src/mod/git/holyground.git.json rename to src/module/git/holyground.git.json diff --git a/src/mod/git/horrorwing.git.json b/src/module/git/horrorwing.git.json similarity index 100% rename from src/mod/git/horrorwing.git.json rename to src/module/git/horrorwing.git.json diff --git a/src/mod/git/ifm_pc_rooms.git.json b/src/module/git/ifm_pc_rooms.git.json similarity index 100% rename from src/mod/git/ifm_pc_rooms.git.json rename to src/module/git/ifm_pc_rooms.git.json diff --git a/src/mod/git/igloo.git.json b/src/module/git/igloo.git.json similarity index 100% rename from src/mod/git/igloo.git.json rename to src/module/git/igloo.git.json diff --git a/src/mod/git/illithidbridges.git.json b/src/module/git/illithidbridges.git.json similarity index 100% rename from src/mod/git/illithidbridges.git.json rename to src/module/git/illithidbridges.git.json diff --git a/src/mod/git/illithidresingch.git.json b/src/module/git/illithidresingch.git.json similarity index 100% rename from src/mod/git/illithidresingch.git.json rename to src/module/git/illithidresingch.git.json diff --git a/src/mod/git/ironclawbattlegr.git.json b/src/module/git/ironclawbattlegr.git.json similarity index 100% rename from src/mod/git/ironclawbattlegr.git.json rename to src/module/git/ironclawbattlegr.git.json diff --git a/src/mod/git/ironclawcastle.git.json b/src/module/git/ironclawcastle.git.json similarity index 100% rename from src/mod/git/ironclawcastle.git.json rename to src/module/git/ironclawcastle.git.json diff --git a/src/mod/git/ironclawcastleup.git.json b/src/module/git/ironclawcastleup.git.json similarity index 100% rename from src/mod/git/ironclawcastleup.git.json rename to src/module/git/ironclawcastleup.git.json diff --git a/src/mod/git/ironclawdungeons.git.json b/src/module/git/ironclawdungeons.git.json similarity index 100% rename from src/mod/git/ironclawdungeons.git.json rename to src/module/git/ironclawdungeons.git.json diff --git a/src/mod/git/ironclawhalltoto.git.json b/src/module/git/ironclawhalltoto.git.json similarity index 100% rename from src/mod/git/ironclawhalltoto.git.json rename to src/module/git/ironclawhalltoto.git.json diff --git a/src/mod/git/ironclawinnercas.git.json b/src/module/git/ironclawinnercas.git.json similarity index 100% rename from src/mod/git/ironclawinnercas.git.json rename to src/module/git/ironclawinnercas.git.json diff --git a/src/mod/git/ironclawtower.git.json b/src/module/git/ironclawtower.git.json similarity index 100% rename from src/mod/git/ironclawtower.git.json rename to src/module/git/ironclawtower.git.json diff --git a/src/mod/git/irongoblinleader.git.json b/src/module/git/irongoblinleader.git.json similarity index 100% rename from src/mod/git/irongoblinleader.git.json rename to src/module/git/irongoblinleader.git.json diff --git a/src/mod/git/ironmineslevel2.git.json b/src/module/git/ironmineslevel2.git.json similarity index 100% rename from src/mod/git/ironmineslevel2.git.json rename to src/module/git/ironmineslevel2.git.json diff --git a/src/mod/git/ironminesupper.git.json b/src/module/git/ironminesupper.git.json similarity index 100% rename from src/mod/git/ironminesupper.git.json rename to src/module/git/ironminesupper.git.json diff --git a/src/mod/git/isleofrepent.git.json b/src/module/git/isleofrepent.git.json similarity index 100% rename from src/mod/git/isleofrepent.git.json rename to src/module/git/isleofrepent.git.json diff --git a/src/mod/git/jerkinsbarn.git.json b/src/module/git/jerkinsbarn.git.json similarity index 100% rename from src/mod/git/jerkinsbarn.git.json rename to src/module/git/jerkinsbarn.git.json diff --git a/src/mod/git/keepofthefallinp.git.json b/src/module/git/keepofthefallinp.git.json similarity index 100% rename from src/mod/git/keepofthefallinp.git.json rename to src/module/git/keepofthefallinp.git.json diff --git a/src/mod/git/koboldcaves.git.json b/src/module/git/koboldcaves.git.json similarity index 100% rename from src/mod/git/koboldcaves.git.json rename to src/module/git/koboldcaves.git.json diff --git a/src/mod/git/lairofkluam.git.json b/src/module/git/lairofkluam.git.json similarity index 100% rename from src/mod/git/lairofkluam.git.json rename to src/module/git/lairofkluam.git.json diff --git a/src/mod/git/lethalweaponsgui.git.json b/src/module/git/lethalweaponsgui.git.json similarity index 100% rename from src/mod/git/lethalweaponsgui.git.json rename to src/module/git/lethalweaponsgui.git.json diff --git a/src/mod/git/limbo001.git.json b/src/module/git/limbo001.git.json similarity index 100% rename from src/mod/git/limbo001.git.json rename to src/module/git/limbo001.git.json diff --git a/src/mod/git/lithiuminfusionc.git.json b/src/module/git/lithiuminfusionc.git.json similarity index 100% rename from src/mod/git/lithiuminfusionc.git.json rename to src/module/git/lithiuminfusionc.git.json diff --git a/src/mod/git/livingforest.git.json b/src/module/git/livingforest.git.json similarity index 100% rename from src/mod/git/livingforest.git.json rename to src/module/git/livingforest.git.json diff --git a/src/mod/git/livingforesteast.git.json b/src/module/git/livingforesteast.git.json similarity index 100% rename from src/mod/git/livingforesteast.git.json rename to src/module/git/livingforesteast.git.json diff --git a/src/mod/git/livingforestnort.git.json b/src/module/git/livingforestnort.git.json similarity index 100% rename from src/mod/git/livingforestnort.git.json rename to src/module/git/livingforestnort.git.json diff --git a/src/mod/git/livingforestwest.git.json b/src/module/git/livingforestwest.git.json similarity index 100% rename from src/mod/git/livingforestwest.git.json rename to src/module/git/livingforestwest.git.json diff --git a/src/mod/git/manypaths.git.json b/src/module/git/manypaths.git.json similarity index 100% rename from src/mod/git/manypaths.git.json rename to src/module/git/manypaths.git.json diff --git a/src/mod/git/minihouse.git.json b/src/module/git/minihouse.git.json similarity index 100% rename from src/mod/git/minihouse.git.json rename to src/module/git/minihouse.git.json diff --git a/src/mod/git/minihouseupper.git.json b/src/module/git/minihouseupper.git.json similarity index 100% rename from src/mod/git/minihouseupper.git.json rename to src/module/git/minihouseupper.git.json diff --git a/src/mod/git/mithralmines.git.json b/src/module/git/mithralmines.git.json similarity index 100% rename from src/mod/git/mithralmines.git.json rename to src/module/git/mithralmines.git.json diff --git a/src/mod/git/mordmagman01.git.json b/src/module/git/mordmagman01.git.json similarity index 100% rename from src/mod/git/mordmagman01.git.json rename to src/module/git/mordmagman01.git.json diff --git a/src/mod/git/mordmagman02.git.json b/src/module/git/mordmagman02.git.json similarity index 100% rename from src/mod/git/mordmagman02.git.json rename to src/module/git/mordmagman02.git.json diff --git a/src/mod/git/mordmagman03.git.json b/src/module/git/mordmagman03.git.json similarity index 100% rename from src/mod/git/mordmagman03.git.json rename to src/module/git/mordmagman03.git.json diff --git a/src/mod/git/mordmagman04.git.json b/src/module/git/mordmagman04.git.json similarity index 100% rename from src/mod/git/mordmagman04.git.json rename to src/module/git/mordmagman04.git.json diff --git a/src/mod/git/mordmagman05.git.json b/src/module/git/mordmagman05.git.json similarity index 100% rename from src/mod/git/mordmagman05.git.json rename to src/module/git/mordmagman05.git.json diff --git a/src/mod/git/mordmagman06.git.json b/src/module/git/mordmagman06.git.json similarity index 100% rename from src/mod/git/mordmagman06.git.json rename to src/module/git/mordmagman06.git.json diff --git a/src/mod/git/mountianside.git.json b/src/module/git/mountianside.git.json similarity index 100% rename from src/mod/git/mountianside.git.json rename to src/module/git/mountianside.git.json diff --git a/src/mod/git/mountiansidenort.git.json b/src/module/git/mountiansidenort.git.json similarity index 100% rename from src/mod/git/mountiansidenort.git.json rename to src/module/git/mountiansidenort.git.json diff --git a/src/mod/git/nightofthunder.git.json b/src/module/git/nightofthunder.git.json similarity index 100% rename from src/mod/git/nightofthunder.git.json rename to src/module/git/nightofthunder.git.json diff --git a/src/mod/git/nodropitemsarea.git.json b/src/module/git/nodropitemsarea.git.json similarity index 100% rename from src/mod/git/nodropitemsarea.git.json rename to src/module/git/nodropitemsarea.git.json diff --git a/src/mod/git/nordicpolarpass.git.json b/src/module/git/nordicpolarpass.git.json similarity index 100% rename from src/mod/git/nordicpolarpass.git.json rename to src/module/git/nordicpolarpass.git.json diff --git a/src/mod/git/northernport.git.json b/src/module/git/northernport.git.json similarity index 100% rename from src/mod/git/northernport.git.json rename to src/module/git/northernport.git.json diff --git a/src/mod/git/northernroad001.git.json b/src/module/git/northernroad001.git.json similarity index 100% rename from src/mod/git/northernroad001.git.json rename to src/module/git/northernroad001.git.json diff --git a/src/mod/git/northernwoods.git.json b/src/module/git/northernwoods.git.json similarity index 100% rename from src/mod/git/northernwoods.git.json rename to src/module/git/northernwoods.git.json diff --git a/src/mod/git/oddbuilding.git.json b/src/module/git/oddbuilding.git.json similarity index 100% rename from src/mod/git/oddbuilding.git.json rename to src/module/git/oddbuilding.git.json diff --git a/src/mod/git/ogrecaves.git.json b/src/module/git/ogrecaves.git.json similarity index 100% rename from src/mod/git/ogrecaves.git.json rename to src/module/git/ogrecaves.git.json diff --git a/src/mod/git/ogrecaveslevel2.git.json b/src/module/git/ogrecaveslevel2.git.json similarity index 100% rename from src/mod/git/ogrecaveslevel2.git.json rename to src/module/git/ogrecaveslevel2.git.json diff --git a/src/mod/git/ogrecaveslevel3.git.json b/src/module/git/ogrecaveslevel3.git.json similarity index 100% rename from src/mod/git/ogrecaveslevel3.git.json rename to src/module/git/ogrecaveslevel3.git.json diff --git a/src/mod/git/oldhouse1.git.json b/src/module/git/oldhouse1.git.json similarity index 100% rename from src/mod/git/oldhouse1.git.json rename to src/module/git/oldhouse1.git.json diff --git a/src/mod/git/oldhouse2.git.json b/src/module/git/oldhouse2.git.json similarity index 100% rename from src/mod/git/oldhouse2.git.json rename to src/module/git/oldhouse2.git.json diff --git a/src/mod/git/oldhouse3.git.json b/src/module/git/oldhouse3.git.json similarity index 100% rename from src/mod/git/oldhouse3.git.json rename to src/module/git/oldhouse3.git.json diff --git a/src/mod/git/oldhouse4.git.json b/src/module/git/oldhouse4.git.json similarity index 100% rename from src/mod/git/oldhouse4.git.json rename to src/module/git/oldhouse4.git.json diff --git a/src/mod/git/oldhouse5.git.json b/src/module/git/oldhouse5.git.json similarity index 100% rename from src/mod/git/oldhouse5.git.json rename to src/module/git/oldhouse5.git.json diff --git a/src/mod/git/oldhouse6.git.json b/src/module/git/oldhouse6.git.json similarity index 100% rename from src/mod/git/oldhouse6.git.json rename to src/module/git/oldhouse6.git.json diff --git a/src/mod/git/oldhouse7.git.json b/src/module/git/oldhouse7.git.json similarity index 100% rename from src/mod/git/oldhouse7.git.json rename to src/module/git/oldhouse7.git.json diff --git a/src/mod/git/oldmanjerkinshou.git.json b/src/module/git/oldmanjerkinshou.git.json similarity index 100% rename from src/mod/git/oldmanjerkinshou.git.json rename to src/module/git/oldmanjerkinshou.git.json diff --git a/src/mod/git/oldmines.git.json b/src/module/git/oldmines.git.json similarity index 100% rename from src/mod/git/oldmines.git.json rename to src/module/git/oldmines.git.json diff --git a/src/mod/git/orcbarracks.git.json b/src/module/git/orcbarracks.git.json similarity index 100% rename from src/mod/git/orcbarracks.git.json rename to src/module/git/orcbarracks.git.json diff --git a/src/mod/git/orcbarrackslevel.git.json b/src/module/git/orcbarrackslevel.git.json similarity index 100% rename from src/mod/git/orcbarrackslevel.git.json rename to src/module/git/orcbarrackslevel.git.json diff --git a/src/mod/git/orcmasterbarrack.git.json b/src/module/git/orcmasterbarrack.git.json similarity index 100% rename from src/mod/git/orcmasterbarrack.git.json rename to src/module/git/orcmasterbarrack.git.json diff --git a/src/mod/git/orcsublevel.git.json b/src/module/git/orcsublevel.git.json similarity index 100% rename from src/mod/git/orcsublevel.git.json rename to src/module/git/orcsublevel.git.json diff --git a/src/mod/git/osu.git.json b/src/module/git/osu.git.json similarity index 100% rename from src/mod/git/osu.git.json rename to src/module/git/osu.git.json diff --git a/src/mod/git/outfitterspos001.git.json b/src/module/git/outfitterspos001.git.json similarity index 100% rename from src/mod/git/outfitterspos001.git.json rename to src/module/git/outfitterspos001.git.json diff --git a/src/mod/git/ozcastle.git.json b/src/module/git/ozcastle.git.json similarity index 100% rename from src/mod/git/ozcastle.git.json rename to src/module/git/ozcastle.git.json diff --git a/src/mod/git/ozcastleupper.git.json b/src/module/git/ozcastleupper.git.json similarity index 100% rename from src/mod/git/ozcastleupper.git.json rename to src/module/git/ozcastleupper.git.json diff --git a/src/mod/git/ozchamberofmysti.git.json b/src/module/git/ozchamberofmysti.git.json similarity index 100% rename from src/mod/git/ozchamberofmysti.git.json rename to src/module/git/ozchamberofmysti.git.json diff --git a/src/mod/git/ozeastwing.git.json b/src/module/git/ozeastwing.git.json similarity index 100% rename from src/mod/git/ozeastwing.git.json rename to src/module/git/ozeastwing.git.json diff --git a/src/mod/git/ozjail.git.json b/src/module/git/ozjail.git.json similarity index 100% rename from src/mod/git/ozjail.git.json rename to src/module/git/ozjail.git.json diff --git a/src/mod/git/ozmaincastle.git.json b/src/module/git/ozmaincastle.git.json similarity index 100% rename from src/mod/git/ozmaincastle.git.json rename to src/module/git/ozmaincastle.git.json diff --git a/src/mod/git/ozmainlibrary.git.json b/src/module/git/ozmainlibrary.git.json similarity index 100% rename from src/mod/git/ozmainlibrary.git.json rename to src/module/git/ozmainlibrary.git.json diff --git a/src/mod/git/ozwestwing.git.json b/src/module/git/ozwestwing.git.json similarity index 100% rename from src/mod/git/ozwestwing.git.json rename to src/module/git/ozwestwing.git.json diff --git a/src/mod/git/pathtoozcastle.git.json b/src/module/git/pathtoozcastle.git.json similarity index 100% rename from src/mod/git/pathtoozcastle.git.json rename to src/module/git/pathtoozcastle.git.json diff --git a/src/mod/git/pathtotheancient.git.json b/src/module/git/pathtotheancient.git.json similarity index 100% rename from src/mod/git/pathtotheancient.git.json rename to src/module/git/pathtotheancient.git.json diff --git a/src/mod/git/pleasantville.git.json b/src/module/git/pleasantville.git.json similarity index 100% rename from src/mod/git/pleasantville.git.json rename to src/module/git/pleasantville.git.json diff --git a/src/mod/git/prc_maze_01.git.json b/src/module/git/prc_maze_01.git.json similarity index 100% rename from src/mod/git/prc_maze_01.git.json rename to src/module/git/prc_maze_01.git.json diff --git a/src/mod/git/pvpexitingroom.git.json b/src/module/git/pvpexitingroom.git.json similarity index 100% rename from src/mod/git/pvpexitingroom.git.json rename to src/module/git/pvpexitingroom.git.json diff --git a/src/mod/git/pvppreparationro.git.json b/src/module/git/pvppreparationro.git.json similarity index 100% rename from src/mod/git/pvppreparationro.git.json rename to src/module/git/pvppreparationro.git.json diff --git a/src/mod/git/pvprespawn.git.json b/src/module/git/pvprespawn.git.json similarity index 100% rename from src/mod/git/pvprespawn.git.json rename to src/module/git/pvprespawn.git.json diff --git a/src/mod/git/rajashouse.git.json b/src/module/git/rajashouse.git.json similarity index 100% rename from src/mod/git/rajashouse.git.json rename to src/module/git/rajashouse.git.json diff --git a/src/mod/git/realmofcain.git.json b/src/module/git/realmofcain.git.json similarity index 100% rename from src/mod/git/realmofcain.git.json rename to src/module/git/realmofcain.git.json diff --git a/src/mod/git/realmofcain2.git.json b/src/module/git/realmofcain2.git.json similarity index 100% rename from src/mod/git/realmofcain2.git.json rename to src/module/git/realmofcain2.git.json diff --git a/src/mod/git/realmofcaincastl.git.json b/src/module/git/realmofcaincastl.git.json similarity index 100% rename from src/mod/git/realmofcaincastl.git.json rename to src/module/git/realmofcaincastl.git.json diff --git a/src/mod/git/realmofsubzeroes.git.json b/src/module/git/realmofsubzeroes.git.json similarity index 100% rename from src/mod/git/realmofsubzeroes.git.json rename to src/module/git/realmofsubzeroes.git.json diff --git a/src/mod/git/realmofthedarksi.git.json b/src/module/git/realmofthedarksi.git.json similarity index 100% rename from src/mod/git/realmofthedarksi.git.json rename to src/module/git/realmofthedarksi.git.json diff --git a/src/mod/git/reb.git.json b/src/module/git/reb.git.json similarity index 100% rename from src/mod/git/reb.git.json rename to src/module/git/reb.git.json diff --git a/src/mod/git/redarena.git.json b/src/module/git/redarena.git.json similarity index 100% rename from src/mod/git/redarena.git.json rename to src/module/git/redarena.git.json diff --git a/src/mod/git/redteamcastle002.git.json b/src/module/git/redteamcastle002.git.json similarity index 100% rename from src/mod/git/redteamcastle002.git.json rename to src/module/git/redteamcastle002.git.json diff --git a/src/mod/git/resident002.git.json b/src/module/git/resident002.git.json similarity index 100% rename from src/mod/git/resident002.git.json rename to src/module/git/resident002.git.json diff --git a/src/mod/git/resident003.git.json b/src/module/git/resident003.git.json similarity index 100% rename from src/mod/git/resident003.git.json rename to src/module/git/resident003.git.json diff --git a/src/mod/git/resident004.git.json b/src/module/git/resident004.git.json similarity index 100% rename from src/mod/git/resident004.git.json rename to src/module/git/resident004.git.json diff --git a/src/mod/git/riversidetrail.git.json b/src/module/git/riversidetrail.git.json similarity index 100% rename from src/mod/git/riversidetrail.git.json rename to src/module/git/riversidetrail.git.json diff --git a/src/mod/git/rollinghills001.git.json b/src/module/git/rollinghills001.git.json similarity index 100% rename from src/mod/git/rollinghills001.git.json rename to src/module/git/rollinghills001.git.json diff --git a/src/mod/git/rollingmeadows.git.json b/src/module/git/rollingmeadows.git.json similarity index 100% rename from src/mod/git/rollingmeadows.git.json rename to src/module/git/rollingmeadows.git.json diff --git a/src/mod/git/romancewing.git.json b/src/module/git/romancewing.git.json similarity index 100% rename from src/mod/git/romancewing.git.json rename to src/module/git/romancewing.git.json diff --git a/src/mod/git/ruinedminds001.git.json b/src/module/git/ruinedminds001.git.json similarity index 100% rename from src/mod/git/ruinedminds001.git.json rename to src/module/git/ruinedminds001.git.json diff --git a/src/mod/git/ruralfarms.git.json b/src/module/git/ruralfarms.git.json similarity index 100% rename from src/mod/git/ruralfarms.git.json rename to src/module/git/ruralfarms.git.json diff --git a/src/mod/git/scifiwing.git.json b/src/module/git/scifiwing.git.json similarity index 100% rename from src/mod/git/scifiwing.git.json rename to src/module/git/scifiwing.git.json diff --git a/src/mod/git/sector1.git.json b/src/module/git/sector1.git.json similarity index 100% rename from src/mod/git/sector1.git.json rename to src/module/git/sector1.git.json diff --git a/src/mod/git/sector2.git.json b/src/module/git/sector2.git.json similarity index 100% rename from src/mod/git/sector2.git.json rename to src/module/git/sector2.git.json diff --git a/src/mod/git/sector3.git.json b/src/module/git/sector3.git.json similarity index 100% rename from src/mod/git/sector3.git.json rename to src/module/git/sector3.git.json diff --git a/src/mod/git/sexyfreakguildho.git.json b/src/module/git/sexyfreakguildho.git.json similarity index 100% rename from src/mod/git/sexyfreakguildho.git.json rename to src/module/git/sexyfreakguildho.git.json diff --git a/src/mod/git/shadowlegionmain.git.json b/src/module/git/shadowlegionmain.git.json similarity index 100% rename from src/mod/git/shadowlegionmain.git.json rename to src/module/git/shadowlegionmain.git.json diff --git a/src/mod/git/shadowlegionreal.git.json b/src/module/git/shadowlegionreal.git.json similarity index 100% rename from src/mod/git/shadowlegionreal.git.json rename to src/module/git/shadowlegionreal.git.json diff --git a/src/mod/git/shadyladypub.git.json b/src/module/git/shadyladypub.git.json similarity index 100% rename from src/mod/git/shadyladypub.git.json rename to src/module/git/shadyladypub.git.json diff --git a/src/mod/git/shogunforesteast.git.json b/src/module/git/shogunforesteast.git.json similarity index 100% rename from src/mod/git/shogunforesteast.git.json rename to src/module/git/shogunforesteast.git.json diff --git a/src/mod/git/shogunmain.git.json b/src/module/git/shogunmain.git.json similarity index 100% rename from src/mod/git/shogunmain.git.json rename to src/module/git/shogunmain.git.json diff --git a/src/mod/git/shogunnorth.git.json b/src/module/git/shogunnorth.git.json similarity index 100% rename from src/mod/git/shogunnorth.git.json rename to src/module/git/shogunnorth.git.json diff --git a/src/mod/git/shogunprayercham.git.json b/src/module/git/shogunprayercham.git.json similarity index 100% rename from src/mod/git/shogunprayercham.git.json rename to src/module/git/shogunprayercham.git.json diff --git a/src/mod/git/shogunruins.git.json b/src/module/git/shogunruins.git.json similarity index 100% rename from src/mod/git/shogunruins.git.json rename to src/module/git/shogunruins.git.json diff --git a/src/mod/git/shogunsouth.git.json b/src/module/git/shogunsouth.git.json similarity index 100% rename from src/mod/git/shogunsouth.git.json rename to src/module/git/shogunsouth.git.json diff --git a/src/mod/git/shoguntemple.git.json b/src/module/git/shoguntemple.git.json similarity index 100% rename from src/mod/git/shoguntemple.git.json rename to src/module/git/shoguntemple.git.json diff --git a/src/mod/git/shoguntraningroo.git.json b/src/module/git/shoguntraningroo.git.json similarity index 100% rename from src/mod/git/shoguntraningroo.git.json rename to src/module/git/shoguntraningroo.git.json diff --git a/src/mod/git/shogunwest.git.json b/src/module/git/shogunwest.git.json similarity index 100% rename from src/mod/git/shogunwest.git.json rename to src/module/git/shogunwest.git.json diff --git a/src/mod/git/snowcaps.git.json b/src/module/git/snowcaps.git.json similarity index 100% rename from src/mod/git/snowcaps.git.json rename to src/module/git/snowcaps.git.json diff --git a/src/mod/git/solarrift.git.json b/src/module/git/solarrift.git.json similarity index 100% rename from src/mod/git/solarrift.git.json rename to src/module/git/solarrift.git.json diff --git a/src/mod/git/subworldcrossroa.git.json b/src/module/git/subworldcrossroa.git.json similarity index 100% rename from src/mod/git/subworldcrossroa.git.json rename to src/module/git/subworldcrossroa.git.json diff --git a/src/mod/git/temple.git.json b/src/module/git/temple.git.json similarity index 100% rename from src/mod/git/temple.git.json rename to src/module/git/temple.git.json diff --git a/src/mod/git/thecouncil.git.json b/src/module/git/thecouncil.git.json similarity index 100% rename from src/mod/git/thecouncil.git.json rename to src/module/git/thecouncil.git.json diff --git a/src/mod/git/theeasternroad.git.json b/src/module/git/theeasternroad.git.json similarity index 100% rename from src/mod/git/theeasternroad.git.json rename to src/module/git/theeasternroad.git.json diff --git a/src/mod/git/theeasternroad2.git.json b/src/module/git/theeasternroad2.git.json similarity index 100% rename from src/mod/git/theeasternroad2.git.json rename to src/module/git/theeasternroad2.git.json diff --git a/src/mod/git/thefistsguild001.git.json b/src/module/git/thefistsguild001.git.json similarity index 100% rename from src/mod/git/thefistsguild001.git.json rename to src/module/git/thefistsguild001.git.json diff --git a/src/mod/git/themonsterinthec.git.json b/src/module/git/themonsterinthec.git.json similarity index 100% rename from src/mod/git/themonsterinthec.git.json rename to src/module/git/themonsterinthec.git.json diff --git a/src/mod/git/thenightmarebegi.git.json b/src/module/git/thenightmarebegi.git.json similarity index 100% rename from src/mod/git/thenightmarebegi.git.json rename to src/module/git/thenightmarebegi.git.json diff --git a/src/mod/git/theoldworld.git.json b/src/module/git/theoldworld.git.json similarity index 100% rename from src/mod/git/theoldworld.git.json rename to src/module/git/theoldworld.git.json diff --git a/src/mod/git/thequietofthemin.git.json b/src/module/git/thequietofthemin.git.json similarity index 100% rename from src/mod/git/thequietofthemin.git.json rename to src/module/git/thequietofthemin.git.json diff --git a/src/mod/git/thevillageofhill.git.json b/src/module/git/thevillageofhill.git.json similarity index 100% rename from src/mod/git/thevillageofhill.git.json rename to src/module/git/thevillageofhill.git.json diff --git a/src/mod/git/thewilds.git.json b/src/module/git/thewilds.git.json similarity index 100% rename from src/mod/git/thewilds.git.json rename to src/module/git/thewilds.git.json diff --git a/src/mod/git/thunderlordkeep.git.json b/src/module/git/thunderlordkeep.git.json similarity index 100% rename from src/mod/git/thunderlordkeep.git.json rename to src/module/git/thunderlordkeep.git.json diff --git a/src/mod/git/thundermounainja.git.json b/src/module/git/thundermounainja.git.json similarity index 100% rename from src/mod/git/thundermounainja.git.json rename to src/module/git/thundermounainja.git.json diff --git a/src/mod/git/thundermountainb.git.json b/src/module/git/thundermountainb.git.json similarity index 100% rename from src/mod/git/thundermountainb.git.json rename to src/module/git/thundermountainb.git.json diff --git a/src/mod/git/thundermountainc.git.json b/src/module/git/thundermountainc.git.json similarity index 100% rename from src/mod/git/thundermountainc.git.json rename to src/module/git/thundermountainc.git.json diff --git a/src/mod/git/tmprisons.git.json b/src/module/git/tmprisons.git.json similarity index 100% rename from src/mod/git/tmprisons.git.json rename to src/module/git/tmprisons.git.json diff --git a/src/mod/git/tmstronghold.git.json b/src/module/git/tmstronghold.git.json similarity index 100% rename from src/mod/git/tmstronghold.git.json rename to src/module/git/tmstronghold.git.json diff --git a/src/mod/git/totalkoasguildho.git.json b/src/module/git/totalkoasguildho.git.json similarity index 100% rename from src/mod/git/totalkoasguildho.git.json rename to src/module/git/totalkoasguildho.git.json diff --git a/src/mod/git/toveast.git.json b/src/module/git/toveast.git.json similarity index 100% rename from src/mod/git/toveast.git.json rename to src/module/git/toveast.git.json diff --git a/src/mod/git/tovinner.git.json b/src/module/git/tovinner.git.json similarity index 100% rename from src/mod/git/tovinner.git.json rename to src/module/git/tovinner.git.json diff --git a/src/mod/git/tovnorth.git.json b/src/module/git/tovnorth.git.json similarity index 99% rename from src/mod/git/tovnorth.git.json rename to src/module/git/tovnorth.git.json index d9a3c1f..2c46c4c 100644 --- a/src/mod/git/tovnorth.git.json +++ b/src/module/git/tovnorth.git.json @@ -933,7 +933,7 @@ "__struct_id": 2, "Orientation": { "type": "float", - "value": -3.1416 + "value": 3.1416 }, "X": { "type": "float", diff --git a/src/mod/git/tovsouth.git.json b/src/module/git/tovsouth.git.json similarity index 100% rename from src/mod/git/tovsouth.git.json rename to src/module/git/tovsouth.git.json diff --git a/src/mod/git/tovwest.git.json b/src/module/git/tovwest.git.json similarity index 100% rename from src/mod/git/tovwest.git.json rename to src/module/git/tovwest.git.json diff --git a/src/mod/git/tridelthouse.git.json b/src/module/git/tridelthouse.git.json similarity index 100% rename from src/mod/git/tridelthouse.git.json rename to src/module/git/tridelthouse.git.json diff --git a/src/mod/git/trinity.git.json b/src/module/git/trinity.git.json similarity index 100% rename from src/mod/git/trinity.git.json rename to src/module/git/trinity.git.json diff --git a/src/mod/git/trinitybank.git.json b/src/module/git/trinitybank.git.json similarity index 100% rename from src/mod/git/trinitybank.git.json rename to src/module/git/trinitybank.git.json diff --git a/src/mod/git/trinitybrewmaste.git.json b/src/module/git/trinitybrewmaste.git.json similarity index 100% rename from src/mod/git/trinitybrewmaste.git.json rename to src/module/git/trinitybrewmaste.git.json diff --git a/src/mod/git/trinitycemetary.git.json b/src/module/git/trinitycemetary.git.json similarity index 100% rename from src/mod/git/trinitycemetary.git.json rename to src/module/git/trinitycemetary.git.json diff --git a/src/mod/git/trinitycrypts.git.json b/src/module/git/trinitycrypts.git.json similarity index 100% rename from src/mod/git/trinitycrypts.git.json rename to src/module/git/trinitycrypts.git.json diff --git a/src/mod/git/trinitydocks.git.json b/src/module/git/trinitydocks.git.json similarity index 100% rename from src/mod/git/trinitydocks.git.json rename to src/module/git/trinitydocks.git.json diff --git a/src/mod/git/trinityelders.git.json b/src/module/git/trinityelders.git.json similarity index 100% rename from src/mod/git/trinityelders.git.json rename to src/module/git/trinityelders.git.json diff --git a/src/mod/git/trinityeventload.git.json b/src/module/git/trinityeventload.git.json similarity index 100% rename from src/mod/git/trinityeventload.git.json rename to src/module/git/trinityeventload.git.json diff --git a/src/mod/git/trinityholychamb.git.json b/src/module/git/trinityholychamb.git.json similarity index 100% rename from src/mod/git/trinityholychamb.git.json rename to src/module/git/trinityholychamb.git.json diff --git a/src/mod/git/trinitylowercryp.git.json b/src/module/git/trinitylowercryp.git.json similarity index 100% rename from src/mod/git/trinitylowercryp.git.json rename to src/module/git/trinitylowercryp.git.json diff --git a/src/mod/git/trinitymagicandc.git.json b/src/module/git/trinitymagicandc.git.json similarity index 100% rename from src/mod/git/trinitymagicandc.git.json rename to src/module/git/trinitymagicandc.git.json diff --git a/src/mod/git/trinityrandomhou.git.json b/src/module/git/trinityrandomhou.git.json similarity index 100% rename from src/mod/git/trinityrandomhou.git.json rename to src/module/git/trinityrandomhou.git.json diff --git a/src/mod/git/trinityreapersgu.git.json b/src/module/git/trinityreapersgu.git.json similarity index 100% rename from src/mod/git/trinityreapersgu.git.json rename to src/module/git/trinityreapersgu.git.json diff --git a/src/mod/git/trinitysenators.git.json b/src/module/git/trinitysenators.git.json similarity index 100% rename from src/mod/git/trinitysenators.git.json rename to src/module/git/trinitysenators.git.json diff --git a/src/mod/git/trinitysewers.git.json b/src/module/git/trinitysewers.git.json similarity index 100% rename from src/mod/git/trinitysewers.git.json rename to src/module/git/trinitysewers.git.json diff --git a/src/mod/git/trinitysewerslev.git.json b/src/module/git/trinitysewerslev.git.json similarity index 100% rename from src/mod/git/trinitysewerslev.git.json rename to src/module/git/trinitysewerslev.git.json diff --git a/src/mod/git/trinitywarriorba.git.json b/src/module/git/trinitywarriorba.git.json similarity index 100% rename from src/mod/git/trinitywarriorba.git.json rename to src/module/git/trinitywarriorba.git.json diff --git a/src/mod/git/trollcaves3.git.json b/src/module/git/trollcaves3.git.json similarity index 100% rename from src/mod/git/trollcaves3.git.json rename to src/module/git/trollcaves3.git.json diff --git a/src/mod/git/tunnelstoholo.git.json b/src/module/git/tunnelstoholo.git.json similarity index 100% rename from src/mod/git/tunnelstoholo.git.json rename to src/module/git/tunnelstoholo.git.json diff --git a/src/mod/git/twingates.git.json b/src/module/git/twingates.git.json similarity index 100% rename from src/mod/git/twingates.git.json rename to src/module/git/twingates.git.json diff --git a/src/mod/git/underdarkportalr.git.json b/src/module/git/underdarkportalr.git.json similarity index 100% rename from src/mod/git/underdarkportalr.git.json rename to src/module/git/underdarkportalr.git.json diff --git a/src/mod/git/unknownpath.git.json b/src/module/git/unknownpath.git.json similarity index 100% rename from src/mod/git/unknownpath.git.json rename to src/module/git/unknownpath.git.json diff --git a/src/mod/git/vampireechos.git.json b/src/module/git/vampireechos.git.json similarity index 100% rename from src/mod/git/vampireechos.git.json rename to src/module/git/vampireechos.git.json diff --git a/src/mod/git/wastelandcaverns.git.json b/src/module/git/wastelandcaverns.git.json similarity index 100% rename from src/mod/git/wastelandcaverns.git.json rename to src/module/git/wastelandcaverns.git.json diff --git a/src/mod/git/westhouse1.git.json b/src/module/git/westhouse1.git.json similarity index 100% rename from src/mod/git/westhouse1.git.json rename to src/module/git/westhouse1.git.json diff --git a/src/mod/git/westhouse2.git.json b/src/module/git/westhouse2.git.json similarity index 100% rename from src/mod/git/westhouse2.git.json rename to src/module/git/westhouse2.git.json diff --git a/src/mod/git/windmillhouse.git.json b/src/module/git/windmillhouse.git.json similarity index 100% rename from src/mod/git/windmillhouse.git.json rename to src/module/git/windmillhouse.git.json diff --git a/src/mod/git/windycaverns.git.json b/src/module/git/windycaverns.git.json similarity index 100% rename from src/mod/git/windycaverns.git.json rename to src/module/git/windycaverns.git.json diff --git a/src/mod/ifo/module.ifo.json b/src/module/ifo/module.ifo.json similarity index 99% rename from src/mod/ifo/module.ifo.json rename to src/module/ifo/module.ifo.json index e53d08d..85a0a9e 100644 --- a/src/mod/ifo/module.ifo.json +++ b/src/module/ifo/module.ifo.json @@ -2538,6 +2538,13 @@ "Mod_HakList": { "type": "list", "value": [ + { + "__struct_id": 8, + "Mod_Hak": { + "type": "cexostring", + "value": "peps_prc8" + } + }, { "__struct_id": 8, "Mod_Hak": { diff --git a/src/mod/itp/creaturepalcus.itp.json b/src/module/itp/creaturepalcus.itp.json similarity index 99% rename from src/mod/itp/creaturepalcus.itp.json rename to src/module/itp/creaturepalcus.itp.json index 6aeed60..3a47624 100644 --- a/src/mod/itp/creaturepalcus.itp.json +++ b/src/module/itp/creaturepalcus.itp.json @@ -10,10 +10,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 48 - }, "LIST": { "type": "list", "value": [ @@ -601,10 +597,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ @@ -788,10 +780,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -937,10 +925,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "LIST": { "type": "list", "value": [ @@ -1029,10 +1013,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "LIST": { "type": "list", "value": [ @@ -1121,10 +1101,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 9 - }, "LIST": { "type": "list", "value": [ @@ -1391,10 +1367,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 20 - }, "LIST": { "type": "list", "value": [ @@ -1920,10 +1892,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 21 - }, "LIST": { "type": "list", "value": [ @@ -2487,10 +2455,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 22 - }, "LIST": { "type": "list", "value": [ @@ -3762,10 +3726,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 34 - }, "STRREF": { "type": "dword", "value": 6727 @@ -3773,10 +3733,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 35 - }, "STRREF": { "type": "dword", "value": 6728 @@ -3784,10 +3740,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 36 - }, "LIST": { "type": "list", "value": [ @@ -3857,10 +3809,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 37 - }, "LIST": { "type": "list", "value": [ @@ -3961,10 +3909,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 14 - }, "STRREF": { "type": "dword", "value": 6706 @@ -3972,10 +3916,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 15 - }, "LIST": { "type": "list", "value": [ @@ -4045,10 +3985,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 16 - }, "LIST": { "type": "list", "value": [ @@ -4175,10 +4111,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 17 - }, "LIST": { "type": "list", "value": [ @@ -4248,10 +4180,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 18 - }, "LIST": { "type": "list", "value": [ @@ -4302,10 +4230,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 19 - }, "LIST": { "type": "list", "value": [ @@ -4622,10 +4546,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 50 - }, "LIST": { "type": "list", "value": [ @@ -4878,10 +4798,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 10 - }, "STRREF": { "type": "dword", "value": 6701 @@ -4889,10 +4805,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 11 - }, "LIST": { "type": "list", "value": [ @@ -4988,10 +4900,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 49 - }, "LIST": { "type": "list", "value": [ @@ -5232,10 +5140,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 13 - }, "LIST": { "type": "list", "value": [ @@ -5462,10 +5366,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 23 - }, "LIST": { "type": "list", "value": [ @@ -5687,10 +5587,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 24 - }, "LIST": { "type": "list", "value": [ @@ -6178,10 +6074,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 25 - }, "LIST": { "type": "list", "value": [ @@ -6251,10 +6143,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 47 - }, "LIST": { "type": "list", "value": [ @@ -6381,10 +6269,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 26 - }, "STRREF": { "type": "dword", "value": 6719 @@ -6399,10 +6283,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 12 - }, "LIST": { "type": "list", "value": [ @@ -6439,10 +6319,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 27 - }, "LIST": { "type": "list", "value": [ @@ -6474,10 +6350,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 28 - }, "LIST": { "type": "list", "value": [ @@ -6528,10 +6400,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 29 - }, "LIST": { "type": "list", "value": [ @@ -7057,10 +6925,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 30 - }, "LIST": { "type": "list", "value": [ @@ -7282,10 +7146,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 31 - }, "LIST": { "type": "list", "value": [ @@ -7431,10 +7291,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 32 - }, "LIST": { "type": "list", "value": [ @@ -7637,10 +7493,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 33 - }, "LIST": { "type": "list", "value": [ @@ -7862,10 +7714,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 38 - }, "LIST": { "type": "list", "value": [ @@ -8619,10 +8467,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 39 - }, "LIST": { "type": "list", "value": [ @@ -9224,10 +9068,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 40 - }, "LIST": { "type": "list", "value": [ @@ -9582,10 +9422,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 42 - }, "LIST": { "type": "list", "value": [ @@ -9617,10 +9453,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 41 - }, "LIST": { "type": "list", "value": [ @@ -9975,10 +9807,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 43 - }, "LIST": { "type": "list", "value": [ @@ -10143,10 +9971,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 44 - }, "LIST": { "type": "list", "value": [ @@ -11793,10 +11617,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 45 - }, "LIST": { "type": "list", "value": [ @@ -12068,10 +11888,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -14820,10 +14636,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "LIST": { "type": "list", "value": [ @@ -15064,10 +14876,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "LIST": { "type": "list", "value": [ @@ -15555,10 +15363,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "LIST": { "type": "list", "value": [ @@ -18269,10 +18073,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "LIST": { "type": "list", "value": [ @@ -36247,10 +36047,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 46 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/doorpalcus.itp.json b/src/module/itp/doorpalcus.itp.json similarity index 86% rename from src/mod/itp/doorpalcus.itp.json rename to src/module/itp/doorpalcus.itp.json index ac084e3..032fabd 100644 --- a/src/mod/itp/doorpalcus.itp.json +++ b/src/module/itp/doorpalcus.itp.json @@ -10,10 +10,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -48,10 +44,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "STRREF": { "type": "dword", "value": 6689 @@ -59,10 +51,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -70,10 +58,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "STRREF": { "type": "dword", "value": 6691 @@ -81,10 +65,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "STRREF": { "type": "dword", "value": 6692 @@ -99,10 +79,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "STRREF": { "type": "dword", "value": 6734 @@ -115,10 +91,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -153,10 +125,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 9 - }, "STRREF": { "type": "dword", "value": 201 @@ -164,10 +132,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "LIST": { "type": "list", "value": [ @@ -202,10 +166,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/encounterpalcus.itp.json b/src/module/itp/encounterpalcus.itp.json similarity index 98% rename from src/mod/itp/encounterpalcus.itp.json rename to src/module/itp/encounterpalcus.itp.json index f07e78b..cd7d125 100644 --- a/src/mod/itp/encounterpalcus.itp.json +++ b/src/module/itp/encounterpalcus.itp.json @@ -5,10 +5,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "LIST": { "type": "list", "value": [ @@ -109,10 +105,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 9 - }, "LIST": { "type": "list", "value": [ @@ -246,10 +238,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -339,10 +327,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "LIST": { "type": "list", "value": [ @@ -492,10 +476,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -981,10 +961,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "LIST": { "type": "list", "value": [ @@ -1217,10 +1193,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "LIST": { "type": "list", "value": [ @@ -1475,10 +1447,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "LIST": { "type": "list", "value": [ @@ -1821,10 +1789,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "LIST": { "type": "list", "value": [ @@ -2152,10 +2116,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/itempalcus.itp.json b/src/module/itp/itempalcus.itp.json similarity index 99% rename from src/mod/itp/itempalcus.itp.json rename to src/module/itp/itempalcus.itp.json index 9ae8050..c37d23e 100644 --- a/src/mod/itp/itempalcus.itp.json +++ b/src/module/itp/itempalcus.itp.json @@ -10,10 +10,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ @@ -609,10 +605,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "LIST": { "type": "list", "value": [ @@ -1043,10 +1035,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 9 - }, "LIST": { "type": "list", "value": [ @@ -1466,10 +1454,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -1790,10 +1774,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "LIST": { "type": "list", "value": [ @@ -1949,10 +1929,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 58 - }, "LIST": { "type": "list", "value": [ @@ -3092,10 +3068,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 11 - }, "LIST": { "type": "list", "value": [ @@ -3185,10 +3157,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 10 - }, "LIST": { "type": "list", "value": [ @@ -3223,10 +3191,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 12 - }, "LIST": { "type": "list", "value": [ @@ -3368,10 +3332,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 55 - }, "LIST": { "type": "list", "value": [ @@ -5639,10 +5599,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 13 - }, "LIST": { "type": "list", "value": [ @@ -7756,10 +7712,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 63 - }, "LIST": { "type": "list", "value": [ @@ -8091,10 +8043,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 59 - }, "LIST": { "type": "list", "value": [ @@ -8118,10 +8066,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 14 - }, "LIST": { "type": "list", "value": [ @@ -10048,10 +9992,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 56 - }, "LIST": { "type": "list", "value": [ @@ -11341,10 +11281,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 60 - }, "LIST": { "type": "list", "value": [ @@ -12539,10 +12475,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 16 - }, "LIST": { "type": "list", "value": [ @@ -12654,10 +12586,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 15 - }, "LIST": { "type": "list", "value": [ @@ -12857,10 +12785,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 17 - }, "LIST": { "type": "list", "value": [ @@ -12972,10 +12896,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 18 - }, "LIST": { "type": "list", "value": [ @@ -13142,10 +13062,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 19 - }, "LIST": { "type": "list", "value": [ @@ -13341,10 +13257,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 64 - }, "LIST": { "type": "list", "value": [ @@ -13368,10 +13280,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 57 - }, "LIST": { "type": "list", "value": [ @@ -13422,10 +13330,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 21 - }, "LIST": { "type": "list", "value": [ @@ -13614,10 +13518,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 22 - }, "LIST": { "type": "list", "value": [ @@ -13879,10 +13779,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 20 - }, "LIST": { "type": "list", "value": [ @@ -13950,10 +13846,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 23 - }, "LIST": { "type": "list", "value": [ @@ -14714,10 +14606,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 24 - }, "LIST": { "type": "list", "value": [ @@ -15225,10 +15113,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 26 - }, "LIST": { "type": "list", "value": [ @@ -26721,10 +26605,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 54 - }, "LIST": { "type": "list", "value": [ @@ -27325,10 +27205,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -29849,10 +29725,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "LIST": { "type": "list", "value": [ @@ -29997,10 +29869,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "LIST": { "type": "list", "value": [ @@ -30277,10 +30145,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "LIST": { "type": "list", "value": [ @@ -30799,10 +30663,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "LIST": { "type": "list", "value": [ @@ -31350,10 +31210,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 53 - }, "LIST": { "type": "list", "value": [ @@ -31464,10 +31320,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 27 - }, "LIST": { "type": "list", "value": [ @@ -31656,10 +31508,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 28 - }, "LIST": { "type": "list", "value": [ @@ -31749,10 +31597,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 29 - }, "LIST": { "type": "list", "value": [ @@ -31810,10 +31654,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 32 - }, "LIST": { "type": "list", "value": [ @@ -31936,10 +31776,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 30 - }, "LIST": { "type": "list", "value": [ @@ -32040,10 +31876,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 31 - }, "LIST": { "type": "list", "value": [ @@ -32112,10 +31944,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 33 - }, "LIST": { "type": "list", "value": [ @@ -32260,10 +32088,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 34 - }, "LIST": { "type": "list", "value": [ @@ -32386,10 +32210,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 35 - }, "LIST": { "type": "list", "value": [ @@ -32600,10 +32420,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 36 - }, "LIST": { "type": "list", "value": [ @@ -32891,10 +32707,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 37 - }, "LIST": { "type": "list", "value": [ @@ -33204,10 +33016,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 38 - }, "LIST": { "type": "list", "value": [ @@ -33408,10 +33216,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 39 - }, "LIST": { "type": "list", "value": [ @@ -33479,10 +33283,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 40 - }, "LIST": { "type": "list", "value": [ @@ -33550,10 +33350,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 41 - }, "LIST": { "type": "list", "value": [ @@ -33698,10 +33494,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 42 - }, "LIST": { "type": "list", "value": [ @@ -33813,10 +33605,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 61 - }, "LIST": { "type": "list", "value": [ @@ -33913,10 +33701,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 46 - }, "LIST": { "type": "list", "value": [ @@ -34094,10 +33878,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 47 - }, "LIST": { "type": "list", "value": [ @@ -34555,10 +34335,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 48 - }, "LIST": { "type": "list", "value": [ @@ -34582,10 +34358,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 49 - }, "LIST": { "type": "list", "value": [ @@ -35126,10 +34898,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 50 - }, "LIST": { "type": "list", "value": [ @@ -35204,10 +34972,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 51 - }, "LIST": { "type": "list", "value": [ @@ -35434,10 +35198,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 43 - }, "LIST": { "type": "list", "value": [ @@ -35527,10 +35287,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 44 - }, "LIST": { "type": "list", "value": [ @@ -35730,10 +35486,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 45 - }, "LIST": { "type": "list", "value": [ @@ -35790,10 +35542,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 62 - }, "LIST": { "type": "list", "value": [ @@ -35835,10 +35583,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 52 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/placeablepalcus.itp.json b/src/module/itp/placeablepalcus.itp.json similarity index 96% rename from src/mod/itp/placeablepalcus.itp.json rename to src/module/itp/placeablepalcus.itp.json index 4f0cef3..e00325c 100644 --- a/src/mod/itp/placeablepalcus.itp.json +++ b/src/module/itp/placeablepalcus.itp.json @@ -5,10 +5,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "LIST": { "type": "list", "value": [ @@ -98,10 +94,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 22 - }, "STRREF": { "type": "dword", "value": 111663 @@ -109,10 +101,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -224,10 +212,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "LIST": { "type": "list", "value": [ @@ -284,10 +268,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 9 - }, "LIST": { "type": "list", "value": [ @@ -553,10 +533,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 10 - }, "LIST": { "type": "list", "value": [ @@ -800,10 +776,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 11 - }, "LIST": { "type": "list", "value": [ @@ -871,10 +843,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 12 - }, "LIST": { "type": "list", "value": [ @@ -898,10 +866,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 14 - }, "STRREF": { "type": "dword", "value": 9122 @@ -909,10 +873,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 15 - }, "LIST": { "type": "list", "value": [ @@ -1117,10 +1077,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -1177,10 +1133,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "LIST": { "type": "list", "value": [ @@ -1314,10 +1266,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -1325,10 +1273,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "LIST": { "type": "list", "value": [ @@ -1352,10 +1296,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "LIST": { "type": "list", "value": [ @@ -1397,10 +1337,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 13 - }, "LIST": { "type": "list", "value": [ @@ -1501,19 +1437,11 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 16 - }, "LIST": { "type": "list", "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 17 - }, "STRREF": { "type": "dword", "value": 62485 @@ -1521,10 +1449,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 19 - }, "STRREF": { "type": "dword", "value": 5836 @@ -1532,10 +1456,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 21 - }, "STRREF": { "type": "dword", "value": 67585 @@ -1543,10 +1463,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 20 - }, "STRREF": { "type": "dword", "value": 53151 @@ -1554,10 +1470,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 18 - }, "STRREF": { "type": "dword", "value": 67132 @@ -1572,10 +1484,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/soundpalcus.itp.json b/src/module/itp/soundpalcus.itp.json similarity index 70% rename from src/mod/itp/soundpalcus.itp.json rename to src/module/itp/soundpalcus.itp.json index faaa4de..244e77e 100644 --- a/src/mod/itp/soundpalcus.itp.json +++ b/src/module/itp/soundpalcus.itp.json @@ -5,10 +5,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "STRREF": { "type": "dword", "value": 6694 @@ -16,10 +12,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 13 - }, "STRREF": { "type": "dword", "value": 63289 @@ -27,10 +19,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 12 - }, "LIST": { "type": "list", "value": [ @@ -54,10 +42,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 7 - }, "STRREF": { "type": "dword", "value": 62483 @@ -65,10 +49,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "STRREF": { "type": "dword", "value": 62482 @@ -81,10 +61,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "STRREF": { "type": "dword", "value": 6688 @@ -92,10 +68,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "STRREF": { "type": "dword", "value": 6689 @@ -103,10 +75,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -114,10 +82,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "STRREF": { "type": "dword", "value": 6691 @@ -125,10 +89,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "STRREF": { "type": "dword", "value": 6692 @@ -143,10 +103,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 8 - }, "STRREF": { "type": "dword", "value": 62484 diff --git a/src/mod/itp/storepalcus.itp.json b/src/module/itp/storepalcus.itp.json similarity index 90% rename from src/mod/itp/storepalcus.itp.json rename to src/module/itp/storepalcus.itp.json index 7798863..61a2525 100644 --- a/src/mod/itp/storepalcus.itp.json +++ b/src/module/itp/storepalcus.itp.json @@ -5,10 +5,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ @@ -147,10 +143,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -185,10 +177,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "STRREF": { "type": "dword", "value": 6689 @@ -196,10 +184,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -207,10 +191,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "STRREF": { "type": "dword", "value": 6691 @@ -218,10 +198,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "STRREF": { "type": "dword", "value": 6692 diff --git a/src/mod/itp/triggerpalcus.itp.json b/src/module/itp/triggerpalcus.itp.json similarity index 93% rename from src/mod/itp/triggerpalcus.itp.json rename to src/module/itp/triggerpalcus.itp.json index f31a4ee..349049c 100644 --- a/src/mod/itp/triggerpalcus.itp.json +++ b/src/module/itp/triggerpalcus.itp.json @@ -5,10 +5,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ @@ -153,10 +149,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 6 - }, "LIST": { "type": "list", "value": [ @@ -554,10 +546,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 16 - }, "STRREF": { "type": "dword", "value": 9129 @@ -570,10 +558,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -597,10 +581,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "STRREF": { "type": "dword", "value": 6689 @@ -608,10 +588,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -619,10 +595,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "STRREF": { "type": "dword", "value": 6691 @@ -630,10 +602,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "STRREF": { "type": "dword", "value": 6692 @@ -653,10 +621,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 11 - }, "STRREF": { "type": "dword", "value": 53181 @@ -664,10 +628,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 12 - }, "STRREF": { "type": "dword", "value": 2255 @@ -675,10 +635,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 13 - }, "STRREF": { "type": "dword", "value": 2256 @@ -686,10 +642,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 14 - }, "STRREF": { "type": "dword", "value": 2257 @@ -697,10 +649,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 15 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/itp/waypointpalcus.itp.json b/src/module/itp/waypointpalcus.itp.json similarity index 99% rename from src/mod/itp/waypointpalcus.itp.json rename to src/module/itp/waypointpalcus.itp.json index f1c9648..673e3a2 100644 --- a/src/mod/itp/waypointpalcus.itp.json +++ b/src/module/itp/waypointpalcus.itp.json @@ -10,10 +10,6 @@ "value": [ { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 0 - }, "LIST": { "type": "list", "value": [ @@ -37,10 +33,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 1 - }, "STRREF": { "type": "dword", "value": 6689 @@ -48,10 +40,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 2 - }, "STRREF": { "type": "dword", "value": 6690 @@ -59,10 +47,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 3 - }, "STRREF": { "type": "dword", "value": 6691 @@ -70,10 +54,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 4 - }, "LIST": { "type": "list", "value": [ @@ -104,10 +84,6 @@ }, { "__struct_id": 0, - "ID": { - "type": "byte", - "value": 5 - }, "LIST": { "type": "list", "value": [ diff --git a/src/mod/jrl/module.jrl.json b/src/module/jrl/module.jrl.json similarity index 100% rename from src/mod/jrl/module.jrl.json rename to src/module/jrl/module.jrl.json diff --git a/src/mod/nss/0_chair_sit.nss b/src/module/nss/0_chair_sit.nss similarity index 100% rename from src/mod/nss/0_chair_sit.nss rename to src/module/nss/0_chair_sit.nss diff --git a/src/mod/nss/0_conv_placable.nss b/src/module/nss/0_conv_placable.nss similarity index 100% rename from src/mod/nss/0_conv_placable.nss rename to src/module/nss/0_conv_placable.nss diff --git a/src/mod/nss/0_council_sit.nss b/src/module/nss/0_council_sit.nss similarity index 100% rename from src/mod/nss/0_council_sit.nss rename to src/module/nss/0_council_sit.nss diff --git a/src/mod/nss/0_disarmsuccess.nss b/src/module/nss/0_disarmsuccess.nss similarity index 100% rename from src/mod/nss/0_disarmsuccess.nss rename to src/module/nss/0_disarmsuccess.nss diff --git a/src/mod/nss/0_door_close.nss b/src/module/nss/0_door_close.nss similarity index 100% rename from src/mod/nss/0_door_close.nss rename to src/module/nss/0_door_close.nss diff --git a/src/mod/nss/0_door_limit.nss b/src/module/nss/0_door_limit.nss similarity index 100% rename from src/mod/nss/0_door_limit.nss rename to src/module/nss/0_door_limit.nss diff --git a/src/mod/nss/0_door_limit30.nss b/src/module/nss/0_door_limit30.nss similarity index 100% rename from src/mod/nss/0_door_limit30.nss rename to src/module/nss/0_door_limit30.nss diff --git a/src/mod/nss/0_gen_10.nss b/src/module/nss/0_gen_10.nss similarity index 100% rename from src/mod/nss/0_gen_10.nss rename to src/module/nss/0_gen_10.nss diff --git a/src/mod/nss/0_gen_20.nss b/src/module/nss/0_gen_20.nss similarity index 100% rename from src/mod/nss/0_gen_20.nss rename to src/module/nss/0_gen_20.nss diff --git a/src/mod/nss/0_gen_30.nss b/src/module/nss/0_gen_30.nss similarity index 100% rename from src/mod/nss/0_gen_30.nss rename to src/module/nss/0_gen_30.nss diff --git a/src/mod/nss/0_gen_40.nss b/src/module/nss/0_gen_40.nss similarity index 100% rename from src/mod/nss/0_gen_40.nss rename to src/module/nss/0_gen_40.nss diff --git a/src/mod/nss/0_gen_5.nss b/src/module/nss/0_gen_5.nss similarity index 100% rename from src/mod/nss/0_gen_5.nss rename to src/module/nss/0_gen_5.nss diff --git a/src/mod/nss/0_gen_50.nss b/src/module/nss/0_gen_50.nss similarity index 100% rename from src/mod/nss/0_gen_50.nss rename to src/module/nss/0_gen_50.nss diff --git a/src/mod/nss/0_gen_60.nss b/src/module/nss/0_gen_60.nss similarity index 100% rename from src/mod/nss/0_gen_60.nss rename to src/module/nss/0_gen_60.nss diff --git a/src/mod/nss/0_gen_70.nss b/src/module/nss/0_gen_70.nss similarity index 100% rename from src/mod/nss/0_gen_70.nss rename to src/module/nss/0_gen_70.nss diff --git a/src/mod/nss/0_gen_loot.nss b/src/module/nss/0_gen_loot.nss similarity index 100% rename from src/mod/nss/0_gen_loot.nss rename to src/module/nss/0_gen_loot.nss diff --git a/src/mod/nss/0_party_port.nss b/src/module/nss/0_party_port.nss similarity index 100% rename from src/mod/nss/0_party_port.nss rename to src/module/nss/0_party_port.nss diff --git a/src/mod/nss/0_tab_ondeath1.nss b/src/module/nss/0_tab_ondeath1.nss similarity index 100% rename from src/mod/nss/0_tab_ondeath1.nss rename to src/module/nss/0_tab_ondeath1.nss diff --git a/src/mod/nss/0_tab_ondeath2.nss b/src/module/nss/0_tab_ondeath2.nss similarity index 100% rename from src/mod/nss/0_tab_ondeath2.nss rename to src/module/nss/0_tab_ondeath2.nss diff --git a/src/mod/nss/0_tab_ondeath3.nss b/src/module/nss/0_tab_ondeath3.nss similarity index 100% rename from src/mod/nss/0_tab_ondeath3.nss rename to src/module/nss/0_tab_ondeath3.nss diff --git a/src/mod/nss/0_trinity_home.nss b/src/module/nss/0_trinity_home.nss similarity index 100% rename from src/mod/nss/0_trinity_home.nss rename to src/module/nss/0_trinity_home.nss 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..7d9570e --- /dev/null +++ b/src/module/nss/0e_c2_7_ondeath.nss @@ -0,0 +1,34 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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(AI_DEBUG) ai_Debug("0e_c2_7_ondeath", "14", "AI_RULE_PERM_ASSOC: " + IntToString(GetLocalInt(oModule, AI_RULE_PERM_ASSOC))); + if(GetLocalInt(oModule, AI_RULE_PERM_ASSOC)) + { + object oAssociate; + int nIndex; + for(nIndex = 2; nIndex < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oCreature); + if(oAssociate != OBJECT_INVALID) + { + SetIsDestroyable(FALSE, FALSE, FALSE, oAssociate); + DelayCommand(0.1, ChangeToStandardFaction(oAssociate, STANDARD_FACTION_HOSTILE)); + DelayCommand(3.0, SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate)); + } + } + } + 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..bb36552 --- /dev/null +++ b/src/module/nss/0e_ch_7_ondeath.nss @@ -0,0 +1,42 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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 < 6; nIndex++) + { + oAssociate = GetAssociate(nIndex, oCreature); + if(oAssociate != OBJECT_INVALID) + { + SetIsDestroyable(FALSE, FALSE, FALSE, oAssociate); + DelayCommand(0.1, ChangeToStandardFaction(oAssociate, STANDARD_FACTION_HOSTILE)); + DelayCommand(3.0, SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate)); + } + } + } + // 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_id_events.nss b/src/module/nss/0e_id_events.nss new file mode 100644 index 0000000..c68e74c --- /dev/null +++ b/src/module/nss/0e_id_events.nss @@ -0,0 +1,277 @@ +/*////////////////////////////////////////////////////////////////////////////// +// Script Name: 0e_id_events +//////////////////////////////////////////////////////////////////////////////// + Infinite Dungeons monster event handler. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_actions" +#include "x0_i0_assoc" +// Followers special heartbeat script. +void ai_hen_id1_heart(object oCreature); +// Followers special conversation script. +void ai_hen_id1_convo(object oCreature, int nMatch); +// Followers special perception script. +void ai_hen_id1_percept(object oCreature); +// Followers special end of round script. +void ai_hen_id1_endcombat(object oCreature, int bFollower); +// Followers special castat script. +void ai_hen_id1_castat(object oCreature); + +void main() +{ + object oCreature = OBJECT_SELF; + int nEvent = GetCurrentlyRunningEvent(); + int bFollower = GetLocalInt(oCreature, "bFollower"); + //WriteTimestampedLogEntry("0e_id_events [24] " + GetName(oCreature) + " nEvent: " + IntToString(nEvent) + + // " bFollower: " + IntToString(bFollower)); + switch (nEvent) + { + case EVENT_SCRIPT_CREATURE_ON_HEARTBEAT: + { + if(bFollower) ai_hen_id1_heart(oCreature); + else ExecuteScript("nw_c2_default1", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_NOTICE: + { + if(bFollower) ai_hen_id1_percept(oCreature); + else ExecuteScript("nw_c2_default2", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DIALOGUE: + { + int nMatch = GetListenPatternNumber(); + if(nMatch == -1) + { + if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature) || + GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return; + ai_ClearCreatureActions(); + string sConversation = GetLocalString(oCreature, "sConversation"); + if(sConversation != "") BeginConversation(sConversation); + else BeginConversation(); + } + if(bFollower) ai_hen_id1_convo(oCreature, nMatch); + else ExecuteScript("nw_c2_default4", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED: + { + if(bFollower) ExecuteScript("nw_ch_ac5", oCreature); + else ExecuteScript("nw_c2_default5", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DAMAGED: + { + if(bFollower) ExecuteScript("nw_ch_ac6", oCreature); + else ExecuteScript("nw_c2_default6", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT: + { + if(bFollower) ai_hen_id1_castat(oCreature); + else ExecuteScript("nw_c2_defaultb", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND: + { + ai_hen_id1_endcombat(oCreature, bFollower); + break; + } + case EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR: + { + if(bFollower) ExecuteScript("nw_ch_ace", oCreature); + else ExecuteScript("nw_c2_defaulte", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_RESTED: + { + if(bFollower) ExecuteScript("nw_ch_aca", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DISTURBED: + { + if(bFollower) ExecuteScript("nw_ch_ac8", oCreature); + else ExecuteScript("nw_c2_default8", oCreature); + break; + } + case EVENT_SCRIPT_CREATURE_ON_DEATH: + { + if(bFollower) ExecuteScript("nw_ch_ac7", oCreature); + else + { + ExecuteScript("nw_c2_default7", oCreature); + } + break; + } + } +} + +void ai_hen_id1_heart(object oCreature) +{ + // Sometimes they slip out of this mode! + if(GetAssociateState(NW_ASC_MODE_DYING, oCreature) && + GetCommandable()) + { + ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT, 1.0, 65.0); + SetCommandable(FALSE); + } + ExecuteScript("nw_ch_ac1", oCreature); +} +void ai_hen_id1_convo(object oCreature, int nMatch) +{ + if(nMatch == ASSOCIATE_COMMAND_INVENTORY) + { + // * cannot modify disabled equipment + if(!GetLocalInt(OBJECT_SELF, "X2_JUST_A_DISABLEEQUIP")) + { + OpenInventory(oCreature, GetLastSpeaker()); + } + // * feedback as to why + else SendMessageToPCByStrRef(GetMaster(), 100895); + return; + } + else if(nMatch == ASSOCIATE_COMMAND_LEAVEPARTY) + { + object oMaster = GetMaster(); + string sTag = GetTag(GetArea(oMaster)); + // * henchman cannot be kicked out in the reaper realm + // * Followers can never be kicked out + if (sTag == "GatesofCania" || GetIsFollower(oCreature)) return; + if(GetIsObjectValid(oMaster)) + { + ai_ClearCreatureActions(); + if(GetAssociateType(oCreature) == ASSOCIATE_TYPE_HENCHMAN) + { + string sConversation = GetLocalString(oCreature, "sConversation"); + if (sConversation == "id1_plotgiver") + { + string sVariable = GetLocalString(oCreature, "sVariable"); + object oDungeon = GetLocalObject(GetModule(), "oCurrentDungeon"); + SetLocalInt(oDungeon, "b" + sVariable + "Gone", FALSE); + } + RemoveHenchman(oMaster); + DestroyObject(oCreature); + } + } + return; + } + ExecuteScript("nw_ch_ac4", oCreature); +} +void ai_hen_id1_percept(object oCreature) +{ + // If henchman is dying and Player disappears then force a respawn of the henchman + if (GetIsHenchmanDying(oCreature)) + { + // The henchman must be removed otherwise their corpse will follow the player + object oOldMaster = GetMaster(); + object oPC = GetLastPerceived(); + int bVanish = GetLastPerceptionVanished(); + if(GetIsObjectValid(oPC) && bVanish) + { + if (oPC == oOldMaster) + { + RemoveHenchman(oPC, oCreature); + // Only in chapter 1 + if(GetTag(GetModule()) == "x0_module1") + { + SetCommandable(TRUE); + DoRespawn(oPC, oCreature); // Should teleport henchman back + } + } + } + } + ExecuteScript("nw_ch_ac2", oCreature); +} +void ai_hen_id1_endcombat(object oCreature, int bFollower) +{ + if (ai_GetIsInCombat(oCreature)) + { + int nNum; + int nLine; + string sString; + int nCreature; + int bIntelligent; + int nRandom = d100(); + // chance of a oneliner + int nOnelinerPercentage = GetLocalInt(GetModule(), "nFlagCombatOneLinerFrequencyValue"); + if(nRandom <= nOnelinerPercentage) + { + string sCreature = GetLocalString(oCreature, "sVariable"); + // if the current creature is hostile towards PCs + if(sCreature != "") + { + object oDungeon = GetLocalObject(GetModule(), "oCurrentDungeon"); + if(GetIsReactionTypeHostile(GetFirstPC())) + { + nCreature = GetLocalInt(oDungeon, "n" + sCreature); + bIntelligent = GetLocalInt(oDungeon, "bListCreature" + IntToString(nCreature) + "Intelligent"); + if(bIntelligent) + { + nNum = GetLocalInt(GetModule(), "nLinesHostileNum"); + nLine = Random(nNum) + 1; + if(nLine > 0) + { + sString = GetLocalString(GetModule(), "sLinesHostile" + IntToString(nLine)); + SpeakString(sString, TALKVOLUME_SHOUT); + } + } + } + else + { + nCreature = GetLocalInt(oDungeon, "n" + sCreature); + bIntelligent = GetLocalInt(oDungeon, "bListCreature" + IntToString(nCreature) + "Intelligent"); + if(bIntelligent) + { + nNum = GetLocalInt(GetModule(), "nLinesAlliesNum"); + nLine = Random(nNum) + 1; + if (nLine > 0) + { + sString = GetLocalString(GetModule(), "sLinesAllies" + IntToString(nLine)); + SpeakString(sString, TALKVOLUME_SHOUT); + } + } + } + } + } + } + if(bFollower) ExecuteScript("nw_ch_ac3", oCreature); + else ExecuteScript("nw_c2_default3", oCreature); +} +void ai_hen_id1_castat(object oCreature) +{ + if(!GetLastSpellHarmful()) + { + int nSpell = GetLastSpell(); + if(nSpell == SPELL_RAISE_DEAD || nSpell == SPELL_RESURRECTION) + { + object oCaster = GetLastSpellCaster(); + // Restore faction to neutral + SetStandardFactionReputation(STANDARD_FACTION_MERCHANT, 100, oCaster); + SetStandardFactionReputation(STANDARD_FACTION_COMMONER, 100, oCaster); + SetStandardFactionReputation(STANDARD_FACTION_DEFENDER, 100, oCaster); + ClearPersonalReputation(oCaster, oCreature); + AssignCommand(oCreature, SurrenderToEnemies()); + AssignCommand(oCreature, ai_ClearCreatureActions(TRUE)); + // Reset henchmen attack state - Oct 28 (BK) + ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE); + ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE); + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE); + ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE); + // Oct 30 - If player previously hired this hench + // then just have them rejoin automatically + if(GetPlayerHasHired(oCaster, oCreature)) + { + // Feb 11, 2004 - Jon: Don't fire the HireHenchman function if the + // henchman is already oCaster's associate. Fixes a silly little problem + // that occured when you try to raise a henchman who wasn't actually dead. + if(GetMaster(oCreature)!= oCaster) HireHenchman(oCaster, oCreature, TRUE); + } + else + { + string sFile = GetDialogFileToUse(oCaster); + AssignCommand(oCaster, ActionStartConversation(oCreature, sFile)); + } + } + } + ExecuteScript("nw_ch_acb", oCreature); +} diff --git a/src/module/nss/0e_nui.nss b/src/module/nss/0e_nui.nss new file mode 100644 index 0000000..aa5dd96 --- /dev/null +++ b/src/module/nss/0e_nui.nss @@ -0,0 +1,1972 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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()); + } + int nWidgetLength = JsonGetLength(jWidget); + if(nWidgetLength < 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); + ai_PopulateWidgetList(oPC, oAssociate, nToken, jWidget); + } + 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_") // Removes ability from quick use 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); + ai_PopulateWidgetList(oPC, oAssociate, nToken, jWidget); + } + } + 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 nSpell = JsonGetInt(JsonArrayGet(jSpellArray, nIndex)); + string sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + string sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + int nSlot; + int nMaxMemorizationSlot = GetMemorizedSpellCountByLevel(oAssociate, nClass, nLevel); + string sSlot; + while(nSlot < nMaxMemorizationSlot) + { + if(GetMemorizedSpellId(oAssociate, nClass, nLevel, nSlot) == -1) + { + SetMemorizedSpell(oAssociate, nClass, nLevel, nSlot, nSpell, FALSE); + sSlot = IntToString(nSlot); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_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_") // Remove memorized 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 sSlot = GetStringRight(sElem, 1); + ClearMemorizedSpell(oAssociate, nClass, nLevel, StringToInt(sSlot)); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_image", JsonString("ctl_cg_btn_splvl")); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_tooltip", JsonString("")); + NuiSetBind(oPC, nToken, "btn_memorized_" + sSlot + "_event", JsonBool(FALSE)); + } + } + 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 sClass, sName, sSpellIcon, sSlot; + 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); + sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + sSpellIcon = Get2DAString("spells", "IconResRef", nSpell); + sSlot = IntToString(nSlot); + NuiSetBind(oPC, nToken, "btn_known_" + sSlot + "_event", JsonBool(TRUE)); + NuiSetBind(oPC, nToken, "btn_known_" + sSlot + "_image", JsonString(sSpellIcon)); + NuiSetBind(oPC, nToken, "btn_known_" + sSlot + "_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..bb7dbe8 --- /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.20.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..e32aa71 --- /dev/null +++ b/src/module/nss/0i_main.nss @@ -0,0 +1,1347 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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) + { + // Variable name set to a creatures full name to set debugging on. + jRules = JsonObjectSet(JsonObject(), 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"; + int nIndex = 1; + string sAITag = GetLocalString(oAssociate, AI_TAG); + object oCreature; + if(sAITag == "") + { + int nAssociateType = GetAssociateType(oAssociate); + if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) + { + sAITag = GetTag(oAssociate); + oCreature = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPlayer, nIndex); + // Check for duplicate tags and change. + while(nIndex <= AI_MAX_HENCHMAN && oCreature != OBJECT_INVALID) + { + if(oAssociate != oCreature && sAITag == GetTag(oCreature)) + { + sAITag += IntToString(Random(1000)); + break; + } + oCreature = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPlayer, ++nIndex); + } + } + else if(nAssociateType == ASSOCIATE_TYPE_SUMMONED) + { + int nCounter; + sAITag = GetTag(oAssociate); + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPlayer, nIndex); + while(nIndex <= 10 && oCreature != OBJECT_INVALID) + { + if(oAssociate != oCreature && sAITag == GetTag(oCreature)) + { + nCounter++; + sAITag += IntToString(nCounter); + nIndex = 0; + } + oCreature = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPlayer, ++nIndex); + } + } + else + { + if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) sAITag = "companion"; + else if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) sAITag = "familiar"; + else if(nAssociateType == ASSOCIATE_TYPE_DOMINATED) sAITag = "dominated"; + } + 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, 777, 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, 787, 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, sAssociateType + 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..756797c --- /dev/null +++ b/src/module/nss/0i_menus.nss @@ -0,0 +1,4935 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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); +// Populates the Quick widget list menu. +void ai_PopulateWidgetList(object oPC, object oAssociate, int nToken, json jWidget); +// 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_PopulateWidgetList(object oPC, object oAssociate, int nToken, json jWidget) +{ + int nSAIndex, nSpell, nClass, nFeat, nBaseItemType, nIprpSubType, nUses; + int nLevel, nMetaMagic, nDomain, nIndex; + string sIndex, sBaseName, sName, sSpellIcon, sText, sClass, sMetaMagicText; + object oItem; + json jSpell; + 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. + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + nBaseItemType = JsonGetInt(JsonArrayGet(jSpell, 3)); + 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))); + 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)); + if(nClass == 255) + { + nSAIndex = JsonGetInt(JsonArrayGet(jSpell, 6)); + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")")); + } + else + { + 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)); + if(nClass == 255) + { + nSAIndex = JsonGetInt(JsonArrayGet(jSpell, 6)); + if(GetSpellAbilityReady(oAssociate, nSAIndex)) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")")); + } + } + else + { + 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_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; + int nAssociateType = GetAssociateType(oAssociate); + 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(nAssociateType != ASSOCIATE_TYPE_SUMMONED && nAssociateType != ASSOCIATE_TYPE_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(nAssociateType != ASSOCIATE_TYPE_SUMMONED && nAssociateType != ASSOCIATE_TYPE_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, nSAIndex; + 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)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + 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)); + nSAIndex = JsonGetInt(JsonArrayGet(jSpell, 6)); + if(nClass == 255 && GetSpellAbilityReady(oAssociate, nSAIndex)) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")")); + } + else 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)); + nMetaMagic = JsonGetInt(JsonArrayGet(jSpell, 3)); + nDomain = JsonGetInt(JsonArrayGet(jSpell, 4)); + 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(nClass == 255) + { + nSAIndex = JsonGetInt(JsonArrayGet(jSpell, 6)); + if(GetSpellAbilityReady(oAssociate, nSAIndex)) + { + sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))); + NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")")); + } + } + else 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; + } + } + } +} +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"); + 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")); + //SendMessageToPC(oPC, "0i_menu, 2901, sAssociateType: " + sAssociateType + AI_WIDGET_NUI + " jLocations: " + JsonDump(jLocations, 1)); + // Keeps the widgets from bunching up in the top corner. + if(fY == 0.0 && fX == 0.0) + { + int nAssociateType = GetAssociateType(oAssociate); + if(sAssociateType == "pc") fY = 1.0; + else if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) fY = 96.0 * fScale; + else if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) fY = 192.0 * fScale; + else if(nAssociateType == ASSOCIATE_TYPE_SUMMONED) fY = 288.0 * fScale; + else if(nAssociateType == ASSOCIATE_TYPE_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 / 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 / 185 + float fHeight = 213.0; + int nIndex; + string sAssocName; + object oAssoc; + for(nIndex = 1; nIndex < AI_MAX_HENCHMAN; nIndex++) + { + oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, 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_summons" + IntToString(nIndex), 220.0, 20.0); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + fHeight += 28.0; + } + else break; + } + // Row 5+ ****************************************************************** 244 / 241 + 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 = ai_GetCasterTotalLevel(oAssociate, nClass); + 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(-1)); // Level + jSpell = JsonArrayInsert(jSpell, JsonInt(255)); // MetaMagic + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // Domain + 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)); // Level + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // MetaMagic + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // Domain + jSpell = JsonArrayInsert(jSpell, JsonInt(nFeat)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + } + } + } + nCounter++; + } + } + } + // Checks for monsters special abilities. + int nCounter = 0, nPreviousSpell = -1, nMaxSpellAbility = GetSpellAbilityCount(oAssociate); + while(nCounter < nMaxSpellAbility) + { + nSpell = GetSpellAbilitySpell(oAssociate, nCounter); + if(nPreviousSpell != nSpell) + { + nPreviousSpell = nSpell; + // Check for subfeats. + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell1", nSpell)); + if(nSubSpell) + { + for(nSubSpellIndex = 1; nSubSpellIndex <= 5; nSubSpellIndex++) + { + sSubSpellIndex = IntToString(nSubSpellIndex); + nSubSpell = StringToInt(Get2DAString("spells", "SubRadSpell" + sSubSpellIndex, nSpell)); + 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)); // Level + jSpell = JsonArrayInsert(jSpell, JsonInt(255)); // MetaMagic + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // Domain + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // Feat + 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(255)); // Class - Special abilities is always 255. + jSpell = JsonArrayInsert(jSpell, JsonInt(GetSpellAbilityCasterLevel(oAssociate, nCounter))); + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // metamagic + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // domain + jSpell = JsonArrayInsert(jSpell, JsonInt(0)); // feat + // Index of Special ability on monster. + jSpell = JsonArrayInsert(jSpell, JsonInt(nCounter)); + jQuickListArray = JsonArrayInsert(jQuickListArray, jSpell); + //SendMessageToPC(oPC, "nSpell: " + IntToString(nSpell) + + // " sSpellIcon: " + sSpellIcon + + // " sSpellName: " + sSpellName+ + // " nMaxSlot: " + IntToString(nMaxSpellAbility) + + // " nSpellAbilityIndex: " + IntToString(nCounter)); + } + } + 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 + ai_PopulateWidgetList(oPC, oAssociate, nToken, JsonArrayGet(jSpells, 2)); +} +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 = ai_GetCasterTotalLevel(oAssociate, nClass); + 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 = ai_GetCasterTotalLevel(oAssociate, nClass); + 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..3c064c9 --- /dev/null +++ b/src/module/nss/0i_spells.nss @@ -0,0 +1,2180 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// + 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; +}; +// Gets the total caster levels for nClass for oCreature. +int ai_GetCasterTotalLevel(object oCreature, int nClass); +// 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_GetCasterTotalLevel(object oCreature, int nClass) +{ + int nIndex, nCheckClass; + int nLevel = GetLevelByClass(nClass, oCreature); + if(nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_WIZARD) + { + for(nIndex = 1; nIndex <= AI_MAX_CLASSES_PER_CHARACTER; nIndex ++) + { + nCheckClass = GetClassByPosition(nIndex, oCreature); + if(nCheckClass == CLASS_TYPE_PALE_MASTER) + { + nLevel += (GetLevelByClass(CLASS_TYPE_PALE_MASTER, oCreature) + 1) / 2; + } + } + } + return nLevel; +} +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)); + int nLevel = JsonGetInt(JsonArrayGet(jFeat, 2)); + // We use nLevel at -1 to denote this is a feat with a subradial spell. + int nSubSpell; + if(nLevel == -1) nSubSpell = JsonGetInt(JsonArrayGet(jFeat, 0)); + 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, nSubSpell, lLocation)); + } + else AssignCommand(oAssociate, ActionUseFeat(nFeat, oTarget, nSubSpell)); +} +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..6728abb --- /dev/null +++ b/src/module/nss/0i_talents.nss @@ -0,0 +1,3100 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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) +{ + // Lets check to see if we should actually Polymorph? + + 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/mod/nss/1_clean_store.nss b/src/module/nss/1_clean_store.nss similarity index 100% rename from src/mod/nss/1_clean_store.nss rename to src/module/nss/1_clean_store.nss diff --git a/src/mod/nss/1_loot_inc_data.nss b/src/module/nss/1_loot_inc_data.nss similarity index 100% rename from src/mod/nss/1_loot_inc_data.nss rename to src/module/nss/1_loot_inc_data.nss diff --git a/src/mod/nss/1_loot_inc_gen.nss b/src/module/nss/1_loot_inc_gen.nss similarity index 100% rename from src/mod/nss/1_loot_inc_gen.nss rename to src/module/nss/1_loot_inc_gen.nss diff --git a/src/mod/nss/1_loot_inc_main.nss b/src/module/nss/1_loot_inc_main.nss similarity index 100% rename from src/mod/nss/1_loot_inc_main.nss rename to src/module/nss/1_loot_inc_main.nss diff --git a/src/mod/nss/1_loot_unique.nss b/src/module/nss/1_loot_unique.nss similarity index 100% rename from src/mod/nss/1_loot_unique.nss rename to src/module/nss/1_loot_unique.nss diff --git a/src/mod/nss/2_close_lock.nss b/src/module/nss/2_close_lock.nss similarity index 100% rename from src/mod/nss/2_close_lock.nss rename to src/module/nss/2_close_lock.nss diff --git a/src/mod/nss/2_despawn_loot.nss b/src/module/nss/2_despawn_loot.nss similarity index 100% rename from src/mod/nss/2_despawn_loot.nss rename to src/module/nss/2_despawn_loot.nss diff --git a/src/mod/nss/2_die_portals_ho.nss b/src/module/nss/2_die_portals_ho.nss similarity index 100% rename from src/mod/nss/2_die_portals_ho.nss rename to src/module/nss/2_die_portals_ho.nss diff --git a/src/mod/nss/2_door_close_10.nss b/src/module/nss/2_door_close_10.nss similarity index 100% rename from src/mod/nss/2_door_close_10.nss rename to src/module/nss/2_door_close_10.nss diff --git a/src/mod/nss/2_door_close_5.nss b/src/module/nss/2_door_close_5.nss similarity index 100% rename from src/mod/nss/2_door_close_5.nss rename to src/module/nss/2_door_close_5.nss diff --git a/src/mod/nss/2_explode_death.nss b/src/module/nss/2_explode_death.nss similarity index 100% rename from src/mod/nss/2_explode_death.nss rename to src/module/nss/2_explode_death.nss diff --git a/src/mod/nss/2_gong_port.nss b/src/module/nss/2_gong_port.nss similarity index 100% rename from src/mod/nss/2_gong_port.nss rename to src/module/nss/2_gong_port.nss diff --git a/src/mod/nss/2_polar_party1.nss b/src/module/nss/2_polar_party1.nss similarity index 100% rename from src/mod/nss/2_polar_party1.nss rename to src/module/nss/2_polar_party1.nss diff --git a/src/mod/nss/2_polar_party2.nss b/src/module/nss/2_polar_party2.nss similarity index 100% rename from src/mod/nss/2_polar_party2.nss rename to src/module/nss/2_polar_party2.nss diff --git a/src/mod/nss/2_ship_2k.nss b/src/module/nss/2_ship_2k.nss similarity index 100% rename from src/mod/nss/2_ship_2k.nss rename to src/module/nss/2_ship_2k.nss diff --git a/src/mod/nss/2_ship_gold.nss b/src/module/nss/2_ship_gold.nss similarity index 100% rename from src/mod/nss/2_ship_gold.nss rename to src/module/nss/2_ship_gold.nss diff --git a/src/mod/nss/2_sit_down.nss b/src/module/nss/2_sit_down.nss similarity index 100% rename from src/mod/nss/2_sit_down.nss rename to src/module/nss/2_sit_down.nss diff --git a/src/mod/nss/2_trin_home_01.nss b/src/module/nss/2_trin_home_01.nss similarity index 100% rename from src/mod/nss/2_trin_home_01.nss rename to src/module/nss/2_trin_home_01.nss diff --git a/src/mod/nss/2_trinarena.nss b/src/module/nss/2_trinarena.nss similarity index 100% rename from src/mod/nss/2_trinarena.nss rename to src/module/nss/2_trinarena.nss diff --git a/src/mod/nss/9_goblinl_loot.nss b/src/module/nss/9_goblinl_loot.nss similarity index 100% rename from src/mod/nss/9_goblinl_loot.nss rename to src/module/nss/9_goblinl_loot.nss diff --git a/src/mod/nss/_1_lock_3secs.nss b/src/module/nss/_1_lock_3secs.nss similarity index 100% rename from src/mod/nss/_1_lock_3secs.nss rename to src/module/nss/_1_lock_3secs.nss diff --git a/src/mod/nss/_1_lock_door.nss b/src/module/nss/_1_lock_door.nss similarity index 100% rename from src/mod/nss/_1_lock_door.nss rename to src/module/nss/_1_lock_door.nss diff --git a/src/mod/nss/_key.nss b/src/module/nss/_key.nss similarity index 100% rename from src/mod/nss/_key.nss rename to src/module/nss/_key.nss diff --git a/src/mod/nss/_mac_closedoor.nss b/src/module/nss/_mac_closedoor.nss similarity index 100% rename from src/mod/nss/_mac_closedoor.nss rename to src/module/nss/_mac_closedoor.nss diff --git a/src/mod/nss/aa_removequest.nss b/src/module/nss/aa_removequest.nss similarity index 100% rename from src/mod/nss/aa_removequest.nss rename to src/module/nss/aa_removequest.nss 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..6491fdf --- /dev/null +++ b/src/module/nss/ai_a_default.nss @@ -0,0 +1,84 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// 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; + } + } + // 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; + } + } + if(nDifficulty >= AI_COMBAT_MODERATE) + { + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) return; + // ************************** CLASS FEATURES *************************** + if(ai_TryPolymorphSelfFeat(oCreature)) return; + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TrySummonAnimalCompanionTalent(oCreature)) return; + if(ai_TrySummonFamiliarTalent(oCreature)) 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..53b9303 --- /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; + // 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; + // *************************** 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; + } + } + if(nDifficulty >= AI_COMBAT_MODERATE && ai_TryPolymorphSelfFeat(oCreature)) return; + //************************** SKILL FEATURES ************************** + if(ai_TryAnimalEmpathy(oCreature)) 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..f84f6f7 --- /dev/null +++ b/src/module/nss/ai_default.nss @@ -0,0 +1,50 @@ +/*//////////////////////////////////////////////////////////////////////////////////////////////////// +// 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(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; + 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; + //**************************** CLASS FEATURES **************************** + if(ai_TryPolymorphSelfFeat(oCreature)) return; + if(ai_TryBarbarianRageFeat(oCreature)) return; + if(ai_TryBardSongFeat(oCreature)) return; + if(ai_TryTurningTalent(oCreature)) 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..7ec19fa --- /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; + //**************************** 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; + //**************************** SKILL FEATURES **************************** + if(ai_TryAnimalEmpathy(oCreature)) 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/mod/nss/asg_alcdesk_01t.nss b/src/module/nss/asg_alcdesk_01t.nss similarity index 100% rename from src/mod/nss/asg_alcdesk_01t.nss rename to src/module/nss/asg_alcdesk_01t.nss diff --git a/src/mod/nss/asg_alcdsk_mat01.nss b/src/module/nss/asg_alcdsk_mat01.nss similarity index 100% rename from src/mod/nss/asg_alcdsk_mat01.nss rename to src/module/nss/asg_alcdsk_mat01.nss diff --git a/src/mod/nss/asg_enchan_01t.nss b/src/module/nss/asg_enchan_01t.nss similarity index 100% rename from src/mod/nss/asg_enchan_01t.nss rename to src/module/nss/asg_enchan_01t.nss diff --git a/src/mod/nss/asg_i_dbcustom.nss b/src/module/nss/asg_i_dbcustom.nss similarity index 100% rename from src/mod/nss/asg_i_dbcustom.nss rename to src/module/nss/asg_i_dbcustom.nss diff --git a/src/mod/nss/asg_i_dbplayer.nss b/src/module/nss/asg_i_dbplayer.nss similarity index 100% rename from src/mod/nss/asg_i_dbplayer.nss rename to src/module/nss/asg_i_dbplayer.nss diff --git a/src/mod/nss/asg_include_mics.nss b/src/module/nss/asg_include_mics.nss similarity index 100% rename from src/mod/nss/asg_include_mics.nss rename to src/module/nss/asg_include_mics.nss diff --git a/src/mod/nss/asg_resdesk_06t.nss b/src/module/nss/asg_resdesk_06t.nss similarity index 100% rename from src/mod/nss/asg_resdesk_06t.nss rename to src/module/nss/asg_resdesk_06t.nss diff --git a/src/mod/nss/asg_rul_buldmagi.nss b/src/module/nss/asg_rul_buldmagi.nss similarity index 100% rename from src/mod/nss/asg_rul_buldmagi.nss rename to src/module/nss/asg_rul_buldmagi.nss diff --git a/src/mod/nss/asg_rul_micscfx.nss b/src/module/nss/asg_rul_micscfx.nss similarity index 100% rename from src/mod/nss/asg_rul_micscfx.nss rename to src/module/nss/asg_rul_micscfx.nss diff --git a/src/mod/nss/asg_rul_testmcop.nss b/src/module/nss/asg_rul_testmcop.nss similarity index 100% rename from src/mod/nss/asg_rul_testmcop.nss rename to src/module/nss/asg_rul_testmcop.nss diff --git a/src/mod/nss/asg_tes_alanvtim.nss b/src/module/nss/asg_tes_alanvtim.nss similarity index 100% rename from src/mod/nss/asg_tes_alanvtim.nss rename to src/module/nss/asg_tes_alanvtim.nss diff --git a/src/mod/nss/asg_tes_alteranv.nss b/src/module/nss/asg_tes_alteranv.nss similarity index 100% rename from src/mod/nss/asg_tes_alteranv.nss rename to src/module/nss/asg_tes_alteranv.nss diff --git a/src/mod/nss/asg_tes_anvaltrc.nss b/src/module/nss/asg_tes_anvaltrc.nss similarity index 100% rename from src/mod/nss/asg_tes_anvaltrc.nss rename to src/module/nss/asg_tes_anvaltrc.nss diff --git a/src/mod/nss/at__jerkinsammy.nss b/src/module/nss/at__jerkinsammy.nss similarity index 100% rename from src/mod/nss/at__jerkinsammy.nss rename to src/module/nss/at__jerkinsammy.nss diff --git a/src/mod/nss/at_ambas_die.nss b/src/module/nss/at_ambas_die.nss similarity index 100% rename from src/mod/nss/at_ambas_die.nss rename to src/module/nss/at_ambas_die.nss diff --git a/src/mod/nss/at_ambasattack.nss b/src/module/nss/at_ambasattack.nss similarity index 100% rename from src/mod/nss/at_ambasattack.nss rename to src/module/nss/at_ambasattack.nss diff --git a/src/mod/nss/at_ass_ship_01.nss b/src/module/nss/at_ass_ship_01.nss similarity index 100% rename from src/mod/nss/at_ass_ship_01.nss rename to src/module/nss/at_ass_ship_01.nss diff --git a/src/mod/nss/at_ass_ship_02.nss b/src/module/nss/at_ass_ship_02.nss similarity index 100% rename from src/mod/nss/at_ass_ship_02.nss rename to src/module/nss/at_ass_ship_02.nss diff --git a/src/mod/nss/at_assbook_02.nss b/src/module/nss/at_assbook_02.nss similarity index 100% rename from src/mod/nss/at_assbook_02.nss rename to src/module/nss/at_assbook_02.nss diff --git a/src/mod/nss/at_assbook_03.nss b/src/module/nss/at_assbook_03.nss similarity index 100% rename from src/mod/nss/at_assbook_03.nss rename to src/module/nss/at_assbook_03.nss diff --git a/src/mod/nss/at_assbook_04.nss b/src/module/nss/at_assbook_04.nss similarity index 100% rename from src/mod/nss/at_assbook_04.nss rename to src/module/nss/at_assbook_04.nss diff --git a/src/mod/nss/at_assbook_05.nss b/src/module/nss/at_assbook_05.nss similarity index 100% rename from src/mod/nss/at_assbook_05.nss rename to src/module/nss/at_assbook_05.nss diff --git a/src/mod/nss/at_assbook_06.nss b/src/module/nss/at_assbook_06.nss similarity index 100% rename from src/mod/nss/at_assbook_06.nss rename to src/module/nss/at_assbook_06.nss diff --git a/src/mod/nss/at_assbook_07.nss b/src/module/nss/at_assbook_07.nss similarity index 100% rename from src/mod/nss/at_assbook_07.nss rename to src/module/nss/at_assbook_07.nss diff --git a/src/mod/nss/at_assbook_08.nss b/src/module/nss/at_assbook_08.nss similarity index 100% rename from src/mod/nss/at_assbook_08.nss rename to src/module/nss/at_assbook_08.nss diff --git a/src/mod/nss/at_assbook_09.nss b/src/module/nss/at_assbook_09.nss similarity index 100% rename from src/mod/nss/at_assbook_09.nss rename to src/module/nss/at_assbook_09.nss diff --git a/src/mod/nss/at_assbook_1.nss b/src/module/nss/at_assbook_1.nss similarity index 100% rename from src/mod/nss/at_assbook_1.nss rename to src/module/nss/at_assbook_1.nss diff --git a/src/mod/nss/at_assbook_10.nss b/src/module/nss/at_assbook_10.nss similarity index 100% rename from src/mod/nss/at_assbook_10.nss rename to src/module/nss/at_assbook_10.nss diff --git a/src/mod/nss/at_assbook_11.nss b/src/module/nss/at_assbook_11.nss similarity index 100% rename from src/mod/nss/at_assbook_11.nss rename to src/module/nss/at_assbook_11.nss diff --git a/src/mod/nss/at_assbook_12.nss b/src/module/nss/at_assbook_12.nss similarity index 100% rename from src/mod/nss/at_assbook_12.nss rename to src/module/nss/at_assbook_12.nss diff --git a/src/mod/nss/at_assbook_13.nss b/src/module/nss/at_assbook_13.nss similarity index 100% rename from src/mod/nss/at_assbook_13.nss rename to src/module/nss/at_assbook_13.nss diff --git a/src/mod/nss/at_assbook_14.nss b/src/module/nss/at_assbook_14.nss similarity index 100% rename from src/mod/nss/at_assbook_14.nss rename to src/module/nss/at_assbook_14.nss diff --git a/src/mod/nss/at_asscpt_die.nss b/src/module/nss/at_asscpt_die.nss similarity index 100% rename from src/mod/nss/at_asscpt_die.nss rename to src/module/nss/at_asscpt_die.nss diff --git a/src/mod/nss/at_asy_noble_die.nss b/src/module/nss/at_asy_noble_die.nss similarity index 100% rename from src/mod/nss/at_asy_noble_die.nss rename to src/module/nss/at_asy_noble_die.nss diff --git a/src/mod/nss/at_asy_treas_die.nss b/src/module/nss/at_asy_treas_die.nss similarity index 100% rename from src/mod/nss/at_asy_treas_die.nss rename to src/module/nss/at_asy_treas_die.nss diff --git a/src/mod/nss/at_asy_treas_por.nss b/src/module/nss/at_asy_treas_por.nss similarity index 100% rename from src/mod/nss/at_asy_treas_por.nss rename to src/module/nss/at_asy_treas_por.nss diff --git a/src/mod/nss/at_asyfinal.nss b/src/module/nss/at_asyfinal.nss similarity index 100% rename from src/mod/nss/at_asyfinal.nss rename to src/module/nss/at_asyfinal.nss diff --git a/src/mod/nss/at_atlantis_home.nss b/src/module/nss/at_atlantis_home.nss similarity index 100% rename from src/mod/nss/at_atlantis_home.nss rename to src/module/nss/at_atlantis_home.nss diff --git a/src/mod/nss/at_attackpc.nss b/src/module/nss/at_attackpc.nss similarity index 100% rename from src/mod/nss/at_attackpc.nss rename to src/module/nss/at_attackpc.nss diff --git a/src/mod/nss/at_balorjail.nss b/src/module/nss/at_balorjail.nss similarity index 100% rename from src/mod/nss/at_balorjail.nss rename to src/module/nss/at_balorjail.nss diff --git a/src/mod/nss/at_bear_01.nss b/src/module/nss/at_bear_01.nss similarity index 100% rename from src/mod/nss/at_bear_01.nss rename to src/module/nss/at_bear_01.nss diff --git a/src/mod/nss/at_bear_04.nss b/src/module/nss/at_bear_04.nss similarity index 100% rename from src/mod/nss/at_bear_04.nss rename to src/module/nss/at_bear_04.nss diff --git a/src/mod/nss/at_bearship_02.nss b/src/module/nss/at_bearship_02.nss similarity index 100% rename from src/mod/nss/at_bearship_02.nss rename to src/module/nss/at_bearship_02.nss diff --git a/src/mod/nss/at_ch_flaw.nss b/src/module/nss/at_ch_flaw.nss similarity index 100% rename from src/mod/nss/at_ch_flaw.nss rename to src/module/nss/at_ch_flaw.nss diff --git a/src/mod/nss/at_check_100k.nss b/src/module/nss/at_check_100k.nss similarity index 100% rename from src/mod/nss/at_check_100k.nss rename to src/module/nss/at_check_100k.nss diff --git a/src/mod/nss/at_check_meat.nss b/src/module/nss/at_check_meat.nss similarity index 100% rename from src/mod/nss/at_check_meat.nss rename to src/module/nss/at_check_meat.nss diff --git a/src/mod/nss/at_check_sewer.nss b/src/module/nss/at_check_sewer.nss similarity index 100% rename from src/mod/nss/at_check_sewer.nss rename to src/module/nss/at_check_sewer.nss diff --git a/src/mod/nss/at_checkpelt.nss b/src/module/nss/at_checkpelt.nss similarity index 100% rename from src/mod/nss/at_checkpelt.nss rename to src/module/nss/at_checkpelt.nss diff --git a/src/mod/nss/at_chk_25k.nss b/src/module/nss/at_chk_25k.nss similarity index 100% rename from src/mod/nss/at_chk_25k.nss rename to src/module/nss/at_chk_25k.nss diff --git a/src/mod/nss/at_chk_50k.nss b/src/module/nss/at_chk_50k.nss similarity index 100% rename from src/mod/nss/at_chk_50k.nss rename to src/module/nss/at_chk_50k.nss diff --git a/src/mod/nss/at_chk_5k.nss b/src/module/nss/at_chk_5k.nss similarity index 100% rename from src/mod/nss/at_chk_5k.nss rename to src/module/nss/at_chk_5k.nss diff --git a/src/mod/nss/at_chk_broom.nss b/src/module/nss/at_chk_broom.nss similarity index 100% rename from src/mod/nss/at_chk_broom.nss rename to src/module/nss/at_chk_broom.nss diff --git a/src/mod/nss/at_chk_dragem.nss b/src/module/nss/at_chk_dragem.nss similarity index 100% rename from src/mod/nss/at_chk_dragem.nss rename to src/module/nss/at_chk_dragem.nss diff --git a/src/mod/nss/at_chk_elvis.nss b/src/module/nss/at_chk_elvis.nss similarity index 100% rename from src/mod/nss/at_chk_elvis.nss rename to src/module/nss/at_chk_elvis.nss diff --git a/src/mod/nss/at_chk_engtools.nss b/src/module/nss/at_chk_engtools.nss similarity index 100% rename from src/mod/nss/at_chk_engtools.nss rename to src/module/nss/at_chk_engtools.nss diff --git a/src/mod/nss/at_chk_ironore.nss b/src/module/nss/at_chk_ironore.nss similarity index 100% rename from src/mod/nss/at_chk_ironore.nss rename to src/module/nss/at_chk_ironore.nss diff --git a/src/mod/nss/at_chk_jerkquest.nss b/src/module/nss/at_chk_jerkquest.nss similarity index 100% rename from src/mod/nss/at_chk_jerkquest.nss rename to src/module/nss/at_chk_jerkquest.nss diff --git a/src/mod/nss/at_chk_lvl2.nss b/src/module/nss/at_chk_lvl2.nss similarity index 100% rename from src/mod/nss/at_chk_lvl2.nss rename to src/module/nss/at_chk_lvl2.nss diff --git a/src/mod/nss/at_chk_massarmor.nss b/src/module/nss/at_chk_massarmor.nss similarity index 100% rename from src/mod/nss/at_chk_massarmor.nss rename to src/module/nss/at_chk_massarmor.nss diff --git a/src/mod/nss/at_chk_masshelm.nss b/src/module/nss/at_chk_masshelm.nss similarity index 100% rename from src/mod/nss/at_chk_masshelm.nss rename to src/module/nss/at_chk_masshelm.nss diff --git a/src/mod/nss/at_chk_necklace.nss b/src/module/nss/at_chk_necklace.nss similarity index 100% rename from src/mod/nss/at_chk_necklace.nss rename to src/module/nss/at_chk_necklace.nss diff --git a/src/mod/nss/at_chk_oldneck.nss b/src/module/nss/at_chk_oldneck.nss similarity index 100% rename from src/mod/nss/at_chk_oldneck.nss rename to src/module/nss/at_chk_oldneck.nss diff --git a/src/mod/nss/at_chk_painting.nss b/src/module/nss/at_chk_painting.nss similarity index 100% rename from src/mod/nss/at_chk_painting.nss rename to src/module/nss/at_chk_painting.nss diff --git a/src/mod/nss/at_chk_pickaxe.nss b/src/module/nss/at_chk_pickaxe.nss similarity index 100% rename from src/mod/nss/at_chk_pickaxe.nss rename to src/module/nss/at_chk_pickaxe.nss diff --git a/src/mod/nss/at_chk_puzz.nss b/src/module/nss/at_chk_puzz.nss similarity index 100% rename from src/mod/nss/at_chk_puzz.nss rename to src/module/nss/at_chk_puzz.nss diff --git a/src/mod/nss/at_chk_shieldleg.nss b/src/module/nss/at_chk_shieldleg.nss similarity index 100% rename from src/mod/nss/at_chk_shieldleg.nss rename to src/module/nss/at_chk_shieldleg.nss diff --git a/src/mod/nss/at_chk_shovel.nss b/src/module/nss/at_chk_shovel.nss similarity index 100% rename from src/mod/nss/at_chk_shovel.nss rename to src/module/nss/at_chk_shovel.nss diff --git a/src/mod/nss/at_chk_shsword.nss b/src/module/nss/at_chk_shsword.nss similarity index 100% rename from src/mod/nss/at_chk_shsword.nss rename to src/module/nss/at_chk_shsword.nss diff --git a/src/mod/nss/at_chk_weavfeath.nss b/src/module/nss/at_chk_weavfeath.nss similarity index 100% rename from src/mod/nss/at_chk_weavfeath.nss rename to src/module/nss/at_chk_weavfeath.nss diff --git a/src/mod/nss/at_chk_wp.nss b/src/module/nss/at_chk_wp.nss similarity index 100% rename from src/mod/nss/at_chk_wp.nss rename to src/module/nss/at_chk_wp.nss diff --git a/src/mod/nss/at_chk_wphelm.nss b/src/module/nss/at_chk_wphelm.nss similarity index 100% rename from src/mod/nss/at_chk_wphelm.nss rename to src/module/nss/at_chk_wphelm.nss diff --git a/src/mod/nss/at_chk_yoga.nss b/src/module/nss/at_chk_yoga.nss similarity index 100% rename from src/mod/nss/at_chk_yoga.nss rename to src/module/nss/at_chk_yoga.nss diff --git a/src/mod/nss/at_chkjimq1.nss b/src/module/nss/at_chkjimq1.nss similarity index 100% rename from src/mod/nss/at_chkjimq1.nss rename to src/module/nss/at_chkjimq1.nss diff --git a/src/mod/nss/at_chkunenq2.nss b/src/module/nss/at_chkunenq2.nss similarity index 100% rename from src/mod/nss/at_chkunenq2.nss rename to src/module/nss/at_chkunenq2.nss diff --git a/src/mod/nss/at_ck_arcanemas.nss b/src/module/nss/at_ck_arcanemas.nss similarity index 100% rename from src/mod/nss/at_ck_arcanemas.nss rename to src/module/nss/at_ck_arcanemas.nss diff --git a/src/mod/nss/at_ck_ass_armor.nss b/src/module/nss/at_ck_ass_armor.nss similarity index 100% rename from src/mod/nss/at_ck_ass_armor.nss rename to src/module/nss/at_ck_ass_armor.nss diff --git a/src/mod/nss/at_ck_robelegend.nss b/src/module/nss/at_ck_robelegend.nss similarity index 100% rename from src/mod/nss/at_ck_robelegend.nss rename to src/module/nss/at_ck_robelegend.nss diff --git a/src/mod/nss/at_cke_reapboth.nss b/src/module/nss/at_cke_reapboth.nss similarity index 100% rename from src/mod/nss/at_cke_reapboth.nss rename to src/module/nss/at_cke_reapboth.nss diff --git a/src/mod/nss/at_ckeglovesle.nss b/src/module/nss/at_ckeglovesle.nss similarity index 100% rename from src/mod/nss/at_ckeglovesle.nss rename to src/module/nss/at_ckeglovesle.nss diff --git a/src/mod/nss/at_ckemonkhelm.nss b/src/module/nss/at_ckemonkhelm.nss similarity index 100% rename from src/mod/nss/at_ckemonkhelm.nss rename to src/module/nss/at_ckemonkhelm.nss diff --git a/src/mod/nss/at_cloaksecret.nss b/src/module/nss/at_cloaksecret.nss similarity index 100% rename from src/mod/nss/at_cloaksecret.nss rename to src/module/nss/at_cloaksecret.nss diff --git a/src/mod/nss/at_desert_store.nss b/src/module/nss/at_desert_store.nss similarity index 100% rename from src/mod/nss/at_desert_store.nss rename to src/module/nss/at_desert_store.nss diff --git a/src/mod/nss/at_dickshield.nss b/src/module/nss/at_dickshield.nss similarity index 100% rename from src/mod/nss/at_dickshield.nss rename to src/module/nss/at_dickshield.nss diff --git a/src/mod/nss/at_dm_4caves.nss b/src/module/nss/at_dm_4caves.nss similarity index 100% rename from src/mod/nss/at_dm_4caves.nss rename to src/module/nss/at_dm_4caves.nss diff --git a/src/mod/nss/at_dm_dragon.nss b/src/module/nss/at_dm_dragon.nss similarity index 100% rename from src/mod/nss/at_dm_dragon.nss rename to src/module/nss/at_dm_dragon.nss diff --git a/src/mod/nss/at_dm_dwarf.nss b/src/module/nss/at_dm_dwarf.nss similarity index 100% rename from src/mod/nss/at_dm_dwarf.nss rename to src/module/nss/at_dm_dwarf.nss diff --git a/src/mod/nss/at_dm_fareast.nss b/src/module/nss/at_dm_fareast.nss similarity index 100% rename from src/mod/nss/at_dm_fareast.nss rename to src/module/nss/at_dm_fareast.nss diff --git a/src/mod/nss/at_dm_shogun.nss b/src/module/nss/at_dm_shogun.nss similarity index 100% rename from src/mod/nss/at_dm_shogun.nss rename to src/module/nss/at_dm_shogun.nss diff --git a/src/mod/nss/at_dmbadge.nss b/src/module/nss/at_dmbadge.nss similarity index 100% rename from src/mod/nss/at_dmbadge.nss rename to src/module/nss/at_dmbadge.nss diff --git a/src/mod/nss/at_dmmerch.nss b/src/module/nss/at_dmmerch.nss similarity index 100% rename from src/mod/nss/at_dmmerch.nss rename to src/module/nss/at_dmmerch.nss diff --git a/src/mod/nss/at_dmport32.nss b/src/module/nss/at_dmport32.nss similarity index 100% rename from src/mod/nss/at_dmport32.nss rename to src/module/nss/at_dmport32.nss diff --git a/src/mod/nss/at_doc_01.nss b/src/module/nss/at_doc_01.nss similarity index 100% rename from src/mod/nss/at_doc_01.nss rename to src/module/nss/at_doc_01.nss diff --git a/src/mod/nss/at_doc_02.nss b/src/module/nss/at_doc_02.nss similarity index 100% rename from src/mod/nss/at_doc_02.nss rename to src/module/nss/at_doc_02.nss diff --git a/src/mod/nss/at_doc_key.nss b/src/module/nss/at_doc_key.nss similarity index 100% rename from src/mod/nss/at_doc_key.nss rename to src/module/nss/at_doc_key.nss diff --git a/src/mod/nss/at_docport02.nss b/src/module/nss/at_docport02.nss similarity index 100% rename from src/mod/nss/at_docport02.nss rename to src/module/nss/at_docport02.nss diff --git a/src/mod/nss/at_docport03.nss b/src/module/nss/at_docport03.nss similarity index 100% rename from src/mod/nss/at_docport03.nss rename to src/module/nss/at_docport03.nss diff --git a/src/mod/nss/at_docport4.nss b/src/module/nss/at_docport4.nss similarity index 100% rename from src/mod/nss/at_docport4.nss rename to src/module/nss/at_docport4.nss diff --git a/src/mod/nss/at_dragport_01.nss b/src/module/nss/at_dragport_01.nss similarity index 100% rename from src/mod/nss/at_dragport_01.nss rename to src/module/nss/at_dragport_01.nss diff --git a/src/mod/nss/at_dragport_02.nss b/src/module/nss/at_dragport_02.nss similarity index 100% rename from src/mod/nss/at_dragport_02.nss rename to src/module/nss/at_dragport_02.nss diff --git a/src/mod/nss/at_dreamport.nss b/src/module/nss/at_dreamport.nss similarity index 100% rename from src/mod/nss/at_dreamport.nss rename to src/module/nss/at_dreamport.nss diff --git a/src/mod/nss/at_ent_dbi_room.nss b/src/module/nss/at_ent_dbi_room.nss similarity index 100% rename from src/mod/nss/at_ent_dbi_room.nss rename to src/module/nss/at_ent_dbi_room.nss diff --git a/src/mod/nss/at_enter_fists.nss b/src/module/nss/at_enter_fists.nss similarity index 100% rename from src/mod/nss/at_enter_fists.nss rename to src/module/nss/at_enter_fists.nss diff --git a/src/mod/nss/at_enter_issac.nss b/src/module/nss/at_enter_issac.nss similarity index 100% rename from src/mod/nss/at_enter_issac.nss rename to src/module/nss/at_enter_issac.nss diff --git a/src/mod/nss/at_enter_pc_room.nss b/src/module/nss/at_enter_pc_room.nss similarity index 100% rename from src/mod/nss/at_enter_pc_room.nss rename to src/module/nss/at_enter_pc_room.nss diff --git a/src/mod/nss/at_farm_joe_01.nss b/src/module/nss/at_farm_joe_01.nss similarity index 100% rename from src/mod/nss/at_farm_joe_01.nss rename to src/module/nss/at_farm_joe_01.nss diff --git a/src/mod/nss/at_fists_key.nss b/src/module/nss/at_fists_key.nss similarity index 100% rename from src/mod/nss/at_fists_key.nss rename to src/module/nss/at_fists_key.nss diff --git a/src/mod/nss/at_forge_staff.nss b/src/module/nss/at_forge_staff.nss similarity index 100% rename from src/mod/nss/at_forge_staff.nss rename to src/module/nss/at_forge_staff.nss diff --git a/src/mod/nss/at_from_fe.nss b/src/module/nss/at_from_fe.nss similarity index 100% rename from src/mod/nss/at_from_fe.nss rename to src/module/nss/at_from_fe.nss diff --git a/src/mod/nss/at_give1mill.nss b/src/module/nss/at_give1mill.nss similarity index 100% rename from src/mod/nss/at_give1mill.nss rename to src/module/nss/at_give1mill.nss diff --git a/src/mod/nss/at_give2k.nss b/src/module/nss/at_give2k.nss similarity index 100% rename from src/mod/nss/at_give2k.nss rename to src/module/nss/at_give2k.nss diff --git a/src/mod/nss/at_give_300k.nss b/src/module/nss/at_give_300k.nss similarity index 100% rename from src/mod/nss/at_give_300k.nss rename to src/module/nss/at_give_300k.nss diff --git a/src/mod/nss/at_give_50kxp.nss b/src/module/nss/at_give_50kxp.nss similarity index 100% rename from src/mod/nss/at_give_50kxp.nss rename to src/module/nss/at_give_50kxp.nss diff --git a/src/mod/nss/at_give_demin_ke.nss b/src/module/nss/at_give_demin_ke.nss similarity index 100% rename from src/mod/nss/at_give_demin_ke.nss rename to src/module/nss/at_give_demin_ke.nss diff --git a/src/mod/nss/at_give_dream.nss b/src/module/nss/at_give_dream.nss similarity index 100% rename from src/mod/nss/at_give_dream.nss rename to src/module/nss/at_give_dream.nss diff --git a/src/mod/nss/at_give_engtools.nss b/src/module/nss/at_give_engtools.nss similarity index 100% rename from src/mod/nss/at_give_engtools.nss rename to src/module/nss/at_give_engtools.nss diff --git a/src/mod/nss/at_give_oh_stuff.nss b/src/module/nss/at_give_oh_stuff.nss similarity index 100% rename from src/mod/nss/at_give_oh_stuff.nss rename to src/module/nss/at_give_oh_stuff.nss diff --git a/src/mod/nss/at_give_oldbroom.nss b/src/module/nss/at_give_oldbroom.nss similarity index 100% rename from src/mod/nss/at_give_oldbroom.nss rename to src/module/nss/at_give_oldbroom.nss diff --git a/src/mod/nss/at_give_oldshove.nss b/src/module/nss/at_give_oldshove.nss similarity index 100% rename from src/mod/nss/at_give_oldshove.nss rename to src/module/nss/at_give_oldshove.nss diff --git a/src/mod/nss/at_give_painting.nss b/src/module/nss/at_give_painting.nss similarity index 100% rename from src/mod/nss/at_give_painting.nss rename to src/module/nss/at_give_painting.nss diff --git a/src/mod/nss/at_give_pickaxe.nss b/src/module/nss/at_give_pickaxe.nss similarity index 100% rename from src/mod/nss/at_give_pickaxe.nss rename to src/module/nss/at_give_pickaxe.nss diff --git a/src/mod/nss/at_give_r_key.nss b/src/module/nss/at_give_r_key.nss similarity index 100% rename from src/mod/nss/at_give_r_key.nss rename to src/module/nss/at_give_r_key.nss diff --git a/src/mod/nss/at_give_redpowde.nss b/src/module/nss/at_give_redpowde.nss similarity index 100% rename from src/mod/nss/at_give_redpowde.nss rename to src/module/nss/at_give_redpowde.nss diff --git a/src/mod/nss/at_give_retrunst.nss b/src/module/nss/at_give_retrunst.nss similarity index 100% rename from src/mod/nss/at_give_retrunst.nss rename to src/module/nss/at_give_retrunst.nss diff --git a/src/mod/nss/at_give_shsword.nss b/src/module/nss/at_give_shsword.nss similarity index 100% rename from src/mod/nss/at_give_shsword.nss rename to src/module/nss/at_give_shsword.nss diff --git a/src/mod/nss/at_givebrethkey.nss b/src/module/nss/at_givebrethkey.nss similarity index 100% rename from src/mod/nss/at_givebrethkey.nss rename to src/module/nss/at_givebrethkey.nss diff --git a/src/mod/nss/at_giveelvis.nss b/src/module/nss/at_giveelvis.nss similarity index 100% rename from src/mod/nss/at_giveelvis.nss rename to src/module/nss/at_giveelvis.nss diff --git a/src/mod/nss/at_giveemote.nss b/src/module/nss/at_giveemote.nss similarity index 100% rename from src/mod/nss/at_giveemote.nss rename to src/module/nss/at_giveemote.nss diff --git a/src/mod/nss/at_giveffofmord.nss b/src/module/nss/at_giveffofmord.nss similarity index 100% rename from src/mod/nss/at_giveffofmord.nss rename to src/module/nss/at_giveffofmord.nss diff --git a/src/mod/nss/at_givefistskey.nss b/src/module/nss/at_givefistskey.nss similarity index 100% rename from src/mod/nss/at_givefistskey.nss rename to src/module/nss/at_givefistskey.nss diff --git a/src/mod/nss/at_givegloves.nss b/src/module/nss/at_givegloves.nss similarity index 100% rename from src/mod/nss/at_givegloves.nss rename to src/module/nss/at_givegloves.nss diff --git a/src/mod/nss/at_giveunensword.nss b/src/module/nss/at_giveunensword.nss similarity index 100% rename from src/mod/nss/at_giveunensword.nss rename to src/module/nss/at_giveunensword.nss diff --git a/src/mod/nss/at_gnome_death.nss b/src/module/nss/at_gnome_death.nss similarity index 100% rename from src/mod/nss/at_gnome_death.nss rename to src/module/nss/at_gnome_death.nss diff --git a/src/mod/nss/at_gv_dragem.nss b/src/module/nss/at_gv_dragem.nss similarity index 100% rename from src/mod/nss/at_gv_dragem.nss rename to src/module/nss/at_gv_dragem.nss diff --git a/src/mod/nss/at_hall1.nss b/src/module/nss/at_hall1.nss similarity index 100% rename from src/mod/nss/at_hall1.nss rename to src/module/nss/at_hall1.nss diff --git a/src/mod/nss/at_hall2.nss b/src/module/nss/at_hall2.nss similarity index 100% rename from src/mod/nss/at_hall2.nss rename to src/module/nss/at_hall2.nss diff --git a/src/mod/nss/at_hall3.nss b/src/module/nss/at_hall3.nss similarity index 100% rename from src/mod/nss/at_hall3.nss rename to src/module/nss/at_hall3.nss diff --git a/src/mod/nss/at_hall4.nss b/src/module/nss/at_hall4.nss similarity index 100% rename from src/mod/nss/at_hall4.nss rename to src/module/nss/at_hall4.nss diff --git a/src/mod/nss/at_hall5.nss b/src/module/nss/at_hall5.nss similarity index 100% rename from src/mod/nss/at_hall5.nss rename to src/module/nss/at_hall5.nss diff --git a/src/mod/nss/at_hall6.nss b/src/module/nss/at_hall6.nss similarity index 100% rename from src/mod/nss/at_hall6.nss rename to src/module/nss/at_hall6.nss diff --git a/src/mod/nss/at_hall7.nss b/src/module/nss/at_hall7.nss similarity index 100% rename from src/mod/nss/at_hall7.nss rename to src/module/nss/at_hall7.nss diff --git a/src/mod/nss/at_hall8.nss b/src/module/nss/at_hall8.nss similarity index 100% rename from src/mod/nss/at_hall8.nss rename to src/module/nss/at_hall8.nss diff --git a/src/mod/nss/at_hall9.nss b/src/module/nss/at_hall9.nss similarity index 100% rename from src/mod/nss/at_hall9.nss rename to src/module/nss/at_hall9.nss diff --git a/src/mod/nss/at_headless01.nss b/src/module/nss/at_headless01.nss similarity index 100% rename from src/mod/nss/at_headless01.nss rename to src/module/nss/at_headless01.nss diff --git a/src/mod/nss/at_headless02.nss b/src/module/nss/at_headless02.nss similarity index 100% rename from src/mod/nss/at_headless02.nss rename to src/module/nss/at_headless02.nss diff --git a/src/mod/nss/at_healermerch.nss b/src/module/nss/at_healermerch.nss similarity index 100% rename from src/mod/nss/at_healermerch.nss rename to src/module/nss/at_healermerch.nss diff --git a/src/mod/nss/at_inferno_01.nss b/src/module/nss/at_inferno_01.nss similarity index 100% rename from src/mod/nss/at_inferno_01.nss rename to src/module/nss/at_inferno_01.nss diff --git a/src/mod/nss/at_inferno_02.nss b/src/module/nss/at_inferno_02.nss similarity index 100% rename from src/mod/nss/at_inferno_02.nss rename to src/module/nss/at_inferno_02.nss diff --git a/src/mod/nss/at_inferno_03.nss b/src/module/nss/at_inferno_03.nss similarity index 100% rename from src/mod/nss/at_inferno_03.nss rename to src/module/nss/at_inferno_03.nss diff --git a/src/mod/nss/at_inferno_04.nss b/src/module/nss/at_inferno_04.nss similarity index 100% rename from src/mod/nss/at_inferno_04.nss rename to src/module/nss/at_inferno_04.nss diff --git a/src/mod/nss/at_inferno_enter.nss b/src/module/nss/at_inferno_enter.nss similarity index 100% rename from src/mod/nss/at_inferno_enter.nss rename to src/module/nss/at_inferno_enter.nss diff --git a/src/mod/nss/at_iron_01.nss b/src/module/nss/at_iron_01.nss similarity index 100% rename from src/mod/nss/at_iron_01.nss rename to src/module/nss/at_iron_01.nss diff --git a/src/mod/nss/at_iron_02.nss b/src/module/nss/at_iron_02.nss similarity index 100% rename from src/mod/nss/at_iron_02.nss rename to src/module/nss/at_iron_02.nss diff --git a/src/mod/nss/at_iron_03.nss b/src/module/nss/at_iron_03.nss similarity index 100% rename from src/mod/nss/at_iron_03.nss rename to src/module/nss/at_iron_03.nss diff --git a/src/mod/nss/at_iron_04.nss b/src/module/nss/at_iron_04.nss similarity index 100% rename from src/mod/nss/at_iron_04.nss rename to src/module/nss/at_iron_04.nss diff --git a/src/mod/nss/at_iron_05.nss b/src/module/nss/at_iron_05.nss similarity index 100% rename from src/mod/nss/at_iron_05.nss rename to src/module/nss/at_iron_05.nss diff --git a/src/mod/nss/at_iron_06.nss b/src/module/nss/at_iron_06.nss similarity index 100% rename from src/mod/nss/at_iron_06.nss rename to src/module/nss/at_iron_06.nss diff --git a/src/mod/nss/at_iron_07.nss b/src/module/nss/at_iron_07.nss similarity index 100% rename from src/mod/nss/at_iron_07.nss rename to src/module/nss/at_iron_07.nss diff --git a/src/mod/nss/at_iron_08.nss b/src/module/nss/at_iron_08.nss similarity index 100% rename from src/mod/nss/at_iron_08.nss rename to src/module/nss/at_iron_08.nss diff --git a/src/mod/nss/at_iron_port_09.nss b/src/module/nss/at_iron_port_09.nss similarity index 100% rename from src/mod/nss/at_iron_port_09.nss rename to src/module/nss/at_iron_port_09.nss diff --git a/src/mod/nss/at_issac_01.nss b/src/module/nss/at_issac_01.nss similarity index 100% rename from src/mod/nss/at_issac_01.nss rename to src/module/nss/at_issac_01.nss diff --git a/src/mod/nss/at_issac_02.nss b/src/module/nss/at_issac_02.nss similarity index 100% rename from src/mod/nss/at_issac_02.nss rename to src/module/nss/at_issac_02.nss diff --git a/src/mod/nss/at_issac_03.nss b/src/module/nss/at_issac_03.nss similarity index 100% rename from src/mod/nss/at_issac_03.nss rename to src/module/nss/at_issac_03.nss diff --git a/src/mod/nss/at_issac_04.nss b/src/module/nss/at_issac_04.nss similarity index 100% rename from src/mod/nss/at_issac_04.nss rename to src/module/nss/at_issac_04.nss diff --git a/src/mod/nss/at_jimlast.nss b/src/module/nss/at_jimlast.nss similarity index 100% rename from src/mod/nss/at_jimlast.nss rename to src/module/nss/at_jimlast.nss diff --git a/src/mod/nss/at_jimmybook.nss b/src/module/nss/at_jimmybook.nss similarity index 100% rename from src/mod/nss/at_jimmybook.nss rename to src/module/nss/at_jimmybook.nss diff --git a/src/mod/nss/at_jimsword.nss b/src/module/nss/at_jimsword.nss similarity index 100% rename from src/mod/nss/at_jimsword.nss rename to src/module/nss/at_jimsword.nss diff --git a/src/mod/nss/at_keg.nss b/src/module/nss/at_keg.nss similarity index 100% rename from src/mod/nss/at_keg.nss rename to src/module/nss/at_keg.nss diff --git a/src/mod/nss/at_kill_legion2.nss b/src/module/nss/at_kill_legion2.nss similarity index 100% rename from src/mod/nss/at_kill_legion2.nss rename to src/module/nss/at_kill_legion2.nss diff --git a/src/mod/nss/at_kill_mage_01.nss b/src/module/nss/at_kill_mage_01.nss similarity index 100% rename from src/mod/nss/at_kill_mage_01.nss rename to src/module/nss/at_kill_mage_01.nss diff --git a/src/mod/nss/at_legionport7.nss b/src/module/nss/at_legionport7.nss similarity index 100% rename from src/mod/nss/at_legionport7.nss rename to src/module/nss/at_legionport7.nss diff --git a/src/mod/nss/at_lil_fight_die.nss b/src/module/nss/at_lil_fight_die.nss similarity index 100% rename from src/mod/nss/at_lil_fight_die.nss rename to src/module/nss/at_lil_fight_die.nss diff --git a/src/mod/nss/at_lucephdie.nss b/src/module/nss/at_lucephdie.nss similarity index 100% rename from src/mod/nss/at_lucephdie.nss rename to src/module/nss/at_lucephdie.nss diff --git a/src/mod/nss/at_make_mnystone.nss b/src/module/nss/at_make_mnystone.nss similarity index 100% rename from src/mod/nss/at_make_mnystone.nss rename to src/module/nss/at_make_mnystone.nss diff --git a/src/mod/nss/at_make_ozkey.nss b/src/module/nss/at_make_ozkey.nss similarity index 100% rename from src/mod/nss/at_make_ozkey.nss rename to src/module/nss/at_make_ozkey.nss diff --git a/src/mod/nss/at_mared03.nss b/src/module/nss/at_mared03.nss similarity index 100% rename from src/mod/nss/at_mared03.nss rename to src/module/nss/at_mared03.nss diff --git a/src/mod/nss/at_mick_000.nss b/src/module/nss/at_mick_000.nss similarity index 100% rename from src/mod/nss/at_mick_000.nss rename to src/module/nss/at_mick_000.nss diff --git a/src/mod/nss/at_mick_100.nss b/src/module/nss/at_mick_100.nss similarity index 100% rename from src/mod/nss/at_mick_100.nss rename to src/module/nss/at_mick_100.nss diff --git a/src/mod/nss/at_mindport.nss b/src/module/nss/at_mindport.nss similarity index 100% rename from src/mod/nss/at_mindport.nss rename to src/module/nss/at_mindport.nss diff --git a/src/mod/nss/at_mosquito_spaw.nss b/src/module/nss/at_mosquito_spaw.nss similarity index 100% rename from src/mod/nss/at_mosquito_spaw.nss rename to src/module/nss/at_mosquito_spaw.nss diff --git a/src/mod/nss/at_move_asscpt.nss b/src/module/nss/at_move_asscpt.nss similarity index 100% rename from src/mod/nss/at_move_asscpt.nss rename to src/module/nss/at_move_asscpt.nss diff --git a/src/mod/nss/at_mystic_party.nss b/src/module/nss/at_mystic_party.nss similarity index 100% rename from src/mod/nss/at_mystic_party.nss rename to src/module/nss/at_mystic_party.nss diff --git a/src/mod/nss/at_nikiperceive.nss b/src/module/nss/at_nikiperceive.nss similarity index 100% rename from src/mod/nss/at_nikiperceive.nss rename to src/module/nss/at_nikiperceive.nss diff --git a/src/mod/nss/at_northernport.nss b/src/module/nss/at_northernport.nss similarity index 100% rename from src/mod/nss/at_northernport.nss rename to src/module/nss/at_northernport.nss diff --git a/src/mod/nss/at_nude_die.nss b/src/module/nss/at_nude_die.nss similarity index 100% rename from src/mod/nss/at_nude_die.nss rename to src/module/nss/at_nude_die.nss diff --git a/src/mod/nss/at_nude_perc.nss b/src/module/nss/at_nude_perc.nss similarity index 100% rename from src/mod/nss/at_nude_perc.nss rename to src/module/nss/at_nude_perc.nss diff --git a/src/mod/nss/at_osdkey.nss b/src/module/nss/at_osdkey.nss similarity index 100% rename from src/mod/nss/at_osdkey.nss rename to src/module/nss/at_osdkey.nss diff --git a/src/mod/nss/at_oz10k.nss b/src/module/nss/at_oz10k.nss similarity index 100% rename from src/mod/nss/at_oz10k.nss rename to src/module/nss/at_oz10k.nss diff --git a/src/mod/nss/at_oz50k.nss b/src/module/nss/at_oz50k.nss similarity index 100% rename from src/mod/nss/at_oz50k.nss rename to src/module/nss/at_oz50k.nss diff --git a/src/mod/nss/at_oz_lowerbook.nss b/src/module/nss/at_oz_lowerbook.nss similarity index 100% rename from src/mod/nss/at_oz_lowerbook.nss rename to src/module/nss/at_oz_lowerbook.nss diff --git a/src/mod/nss/at_oz_port_02.nss b/src/module/nss/at_oz_port_02.nss similarity index 100% rename from src/mod/nss/at_oz_port_02.nss rename to src/module/nss/at_oz_port_02.nss diff --git a/src/mod/nss/at_oz_port_trin.nss b/src/module/nss/at_oz_port_trin.nss similarity index 100% rename from src/mod/nss/at_oz_port_trin.nss rename to src/module/nss/at_oz_port_trin.nss diff --git a/src/mod/nss/at_oz_return.nss b/src/module/nss/at_oz_return.nss similarity index 100% rename from src/mod/nss/at_oz_return.nss rename to src/module/nss/at_oz_return.nss diff --git a/src/mod/nss/at_oz_ruinbook.nss b/src/module/nss/at_oz_ruinbook.nss similarity index 100% rename from src/mod/nss/at_oz_ruinbook.nss rename to src/module/nss/at_oz_ruinbook.nss diff --git a/src/mod/nss/at_ozcase.nss b/src/module/nss/at_ozcase.nss similarity index 100% rename from src/mod/nss/at_ozcase.nss rename to src/module/nss/at_ozcase.nss diff --git a/src/mod/nss/at_ozgrail.nss b/src/module/nss/at_ozgrail.nss similarity index 100% rename from src/mod/nss/at_ozgrail.nss rename to src/module/nss/at_ozgrail.nss diff --git a/src/mod/nss/at_ozking_die.nss b/src/module/nss/at_ozking_die.nss similarity index 100% rename from src/mod/nss/at_ozking_die.nss rename to src/module/nss/at_ozking_die.nss diff --git a/src/mod/nss/at_ozknight_spaw.nss b/src/module/nss/at_ozknight_spaw.nss similarity index 100% rename from src/mod/nss/at_ozknight_spaw.nss rename to src/module/nss/at_ozknight_spaw.nss diff --git a/src/mod/nss/at_oznoblekey.nss b/src/module/nss/at_oznoblekey.nss similarity index 100% rename from src/mod/nss/at_oznoblekey.nss rename to src/module/nss/at_oznoblekey.nss diff --git a/src/mod/nss/at_ozwine.nss b/src/module/nss/at_ozwine.nss similarity index 100% rename from src/mod/nss/at_ozwine.nss rename to src/module/nss/at_ozwine.nss diff --git a/src/mod/nss/at_port_recruit.nss b/src/module/nss/at_port_recruit.nss similarity index 100% rename from src/mod/nss/at_port_recruit.nss rename to src/module/nss/at_port_recruit.nss diff --git a/src/mod/nss/at_portbreth_01.nss b/src/module/nss/at_portbreth_01.nss similarity index 100% rename from src/mod/nss/at_portbreth_01.nss rename to src/module/nss/at_portbreth_01.nss diff --git a/src/mod/nss/at_quito_die2.nss b/src/module/nss/at_quito_die2.nss similarity index 100% rename from src/mod/nss/at_quito_die2.nss rename to src/module/nss/at_quito_die2.nss diff --git a/src/mod/nss/at_reaperkey.nss b/src/module/nss/at_reaperkey.nss similarity index 100% rename from src/mod/nss/at_reaperkey.nss rename to src/module/nss/at_reaperkey.nss diff --git a/src/mod/nss/at_reb_trialspor.nss b/src/module/nss/at_reb_trialspor.nss similarity index 100% rename from src/mod/nss/at_reb_trialspor.nss rename to src/module/nss/at_reb_trialspor.nss diff --git a/src/mod/nss/at_recruit_boot.nss b/src/module/nss/at_recruit_boot.nss similarity index 100% rename from src/mod/nss/at_recruit_boot.nss rename to src/module/nss/at_recruit_boot.nss diff --git a/src/mod/nss/at_recruit_chk.nss b/src/module/nss/at_recruit_chk.nss similarity index 100% rename from src/mod/nss/at_recruit_chk.nss rename to src/module/nss/at_recruit_chk.nss diff --git a/src/mod/nss/at_reddragon.nss b/src/module/nss/at_reddragon.nss similarity index 100% rename from src/mod/nss/at_reddragon.nss rename to src/module/nss/at_reddragon.nss diff --git a/src/mod/nss/at_retire_attack.nss b/src/module/nss/at_retire_attack.nss similarity index 100% rename from src/mod/nss/at_retire_attack.nss rename to src/module/nss/at_retire_attack.nss diff --git a/src/mod/nss/at_returncoast.nss b/src/module/nss/at_returncoast.nss similarity index 100% rename from src/mod/nss/at_returncoast.nss rename to src/module/nss/at_returncoast.nss diff --git a/src/mod/nss/at_rp_assarmor2.nss b/src/module/nss/at_rp_assarmor2.nss similarity index 100% rename from src/mod/nss/at_rp_assarmor2.nss rename to src/module/nss/at_rp_assarmor2.nss diff --git a/src/mod/nss/at_rp_giveboth.nss b/src/module/nss/at_rp_giveboth.nss similarity index 100% rename from src/mod/nss/at_rp_giveboth.nss rename to src/module/nss/at_rp_giveboth.nss diff --git a/src/mod/nss/at_rp_robeleg.nss b/src/module/nss/at_rp_robeleg.nss similarity index 100% rename from src/mod/nss/at_rp_robeleg.nss rename to src/module/nss/at_rp_robeleg.nss diff --git a/src/mod/nss/at_rparcanehe.nss b/src/module/nss/at_rparcanehe.nss similarity index 100% rename from src/mod/nss/at_rparcanehe.nss rename to src/module/nss/at_rparcanehe.nss diff --git a/src/mod/nss/at_rpelvis.nss b/src/module/nss/at_rpelvis.nss similarity index 100% rename from src/mod/nss/at_rpelvis.nss rename to src/module/nss/at_rpelvis.nss diff --git a/src/mod/nss/at_rpflawhelm.nss b/src/module/nss/at_rpflawhelm.nss similarity index 100% rename from src/mod/nss/at_rpflawhelm.nss rename to src/module/nss/at_rpflawhelm.nss diff --git a/src/mod/nss/at_rpmcarmor.nss b/src/module/nss/at_rpmcarmor.nss similarity index 100% rename from src/mod/nss/at_rpmcarmor.nss rename to src/module/nss/at_rpmcarmor.nss diff --git a/src/mod/nss/at_rpmchelm.nss b/src/module/nss/at_rpmchelm.nss similarity index 100% rename from src/mod/nss/at_rpmchelm.nss rename to src/module/nss/at_rpmchelm.nss diff --git a/src/mod/nss/at_rpshield.nss b/src/module/nss/at_rpshield.nss similarity index 100% rename from src/mod/nss/at_rpshield.nss rename to src/module/nss/at_rpshield.nss diff --git a/src/mod/nss/at_rpwp.nss b/src/module/nss/at_rpwp.nss similarity index 100% rename from src/mod/nss/at_rpwp.nss rename to src/module/nss/at_rpwp.nss diff --git a/src/mod/nss/at_rpwphelm.nss b/src/module/nss/at_rpwphelm.nss similarity index 100% rename from src/mod/nss/at_rpwphelm.nss rename to src/module/nss/at_rpwphelm.nss diff --git a/src/mod/nss/at_secret_king.nss b/src/module/nss/at_secret_king.nss similarity index 100% rename from src/mod/nss/at_secret_king.nss rename to src/module/nss/at_secret_king.nss diff --git a/src/mod/nss/at_secret_king2.nss b/src/module/nss/at_secret_king2.nss similarity index 100% rename from src/mod/nss/at_secret_king2.nss rename to src/module/nss/at_secret_king2.nss diff --git a/src/mod/nss/at_secret_sexy1.nss b/src/module/nss/at_secret_sexy1.nss similarity index 100% rename from src/mod/nss/at_secret_sexy1.nss rename to src/module/nss/at_secret_sexy1.nss diff --git a/src/mod/nss/at_secret_sexy2.nss b/src/module/nss/at_secret_sexy2.nss similarity index 100% rename from src/mod/nss/at_secret_sexy2.nss rename to src/module/nss/at_secret_sexy2.nss diff --git a/src/mod/nss/at_secret_tk.nss b/src/module/nss/at_secret_tk.nss similarity index 100% rename from src/mod/nss/at_secret_tk.nss rename to src/module/nss/at_secret_tk.nss diff --git a/src/mod/nss/at_secret_tk2.nss b/src/module/nss/at_secret_tk2.nss similarity index 100% rename from src/mod/nss/at_secret_tk2.nss rename to src/module/nss/at_secret_tk2.nss diff --git a/src/mod/nss/at_sen_weap_key.nss b/src/module/nss/at_sen_weap_key.nss similarity index 100% rename from src/mod/nss/at_sen_weap_key.nss rename to src/module/nss/at_sen_weap_key.nss diff --git a/src/mod/nss/at_sewers_1.nss b/src/module/nss/at_sewers_1.nss similarity index 100% rename from src/mod/nss/at_sewers_1.nss rename to src/module/nss/at_sewers_1.nss diff --git a/src/mod/nss/at_sewers_2.nss b/src/module/nss/at_sewers_2.nss similarity index 100% rename from src/mod/nss/at_sewers_2.nss rename to src/module/nss/at_sewers_2.nss diff --git a/src/mod/nss/at_sexykey.nss b/src/module/nss/at_sexykey.nss similarity index 100% rename from src/mod/nss/at_sexykey.nss rename to src/module/nss/at_sexykey.nss diff --git a/src/mod/nss/at_ship_to_fe.nss b/src/module/nss/at_ship_to_fe.nss similarity index 100% rename from src/mod/nss/at_ship_to_fe.nss rename to src/module/nss/at_ship_to_fe.nss diff --git a/src/mod/nss/at_sl_chk_grail.nss b/src/module/nss/at_sl_chk_grail.nss similarity index 100% rename from src/mod/nss/at_sl_chk_grail.nss rename to src/module/nss/at_sl_chk_grail.nss diff --git a/src/mod/nss/at_spawn_ironbos.nss b/src/module/nss/at_spawn_ironbos.nss similarity index 100% rename from src/mod/nss/at_spawn_ironbos.nss rename to src/module/nss/at_spawn_ironbos.nss diff --git a/src/mod/nss/at_take50kxp.nss b/src/module/nss/at_take50kxp.nss similarity index 100% rename from src/mod/nss/at_take50kxp.nss rename to src/module/nss/at_take50kxp.nss diff --git a/src/mod/nss/at_take_100k.nss b/src/module/nss/at_take_100k.nss similarity index 100% rename from src/mod/nss/at_take_100k.nss rename to src/module/nss/at_take_100k.nss diff --git a/src/mod/nss/at_take_10k.nss b/src/module/nss/at_take_10k.nss similarity index 100% rename from src/mod/nss/at_take_10k.nss rename to src/module/nss/at_take_10k.nss diff --git a/src/mod/nss/at_take_1k.nss b/src/module/nss/at_take_1k.nss similarity index 100% rename from src/mod/nss/at_take_1k.nss rename to src/module/nss/at_take_1k.nss diff --git a/src/mod/nss/at_take_2k.nss b/src/module/nss/at_take_2k.nss similarity index 100% rename from src/mod/nss/at_take_2k.nss rename to src/module/nss/at_take_2k.nss diff --git a/src/mod/nss/at_take_ass_head.nss b/src/module/nss/at_take_ass_head.nss similarity index 100% rename from src/mod/nss/at_take_ass_head.nss rename to src/module/nss/at_take_ass_head.nss diff --git a/src/mod/nss/at_take_broom.nss b/src/module/nss/at_take_broom.nss similarity index 100% rename from src/mod/nss/at_take_broom.nss rename to src/module/nss/at_take_broom.nss diff --git a/src/mod/nss/at_take_engtools.nss b/src/module/nss/at_take_engtools.nss similarity index 100% rename from src/mod/nss/at_take_engtools.nss rename to src/module/nss/at_take_engtools.nss diff --git a/src/mod/nss/at_take_grails.nss b/src/module/nss/at_take_grails.nss similarity index 100% rename from src/mod/nss/at_take_grails.nss rename to src/module/nss/at_take_grails.nss diff --git a/src/mod/nss/at_take_meat.nss b/src/module/nss/at_take_meat.nss similarity index 100% rename from src/mod/nss/at_take_meat.nss rename to src/module/nss/at_take_meat.nss diff --git a/src/mod/nss/at_take_painting.nss b/src/module/nss/at_take_painting.nss similarity index 100% rename from src/mod/nss/at_take_painting.nss rename to src/module/nss/at_take_painting.nss diff --git a/src/mod/nss/at_take_pelt.nss b/src/module/nss/at_take_pelt.nss similarity index 100% rename from src/mod/nss/at_take_pelt.nss rename to src/module/nss/at_take_pelt.nss diff --git a/src/mod/nss/at_take_pickaxe.nss b/src/module/nss/at_take_pickaxe.nss similarity index 100% rename from src/mod/nss/at_take_pickaxe.nss rename to src/module/nss/at_take_pickaxe.nss diff --git a/src/mod/nss/at_take_shieldle.nss b/src/module/nss/at_take_shieldle.nss similarity index 100% rename from src/mod/nss/at_take_shieldle.nss rename to src/module/nss/at_take_shieldle.nss diff --git a/src/mod/nss/at_take_shovel.nss b/src/module/nss/at_take_shovel.nss similarity index 100% rename from src/mod/nss/at_take_shovel.nss rename to src/module/nss/at_take_shovel.nss diff --git a/src/mod/nss/at_take_shsword.nss b/src/module/nss/at_take_shsword.nss similarity index 100% rename from src/mod/nss/at_take_shsword.nss rename to src/module/nss/at_take_shsword.nss diff --git a/src/mod/nss/at_takexp.nss b/src/module/nss/at_takexp.nss similarity index 100% rename from src/mod/nss/at_takexp.nss rename to src/module/nss/at_takexp.nss diff --git a/src/mod/nss/at_temple.nss b/src/module/nss/at_temple.nss similarity index 100% rename from src/mod/nss/at_temple.nss rename to src/module/nss/at_temple.nss diff --git a/src/mod/nss/at_testreb.nss b/src/module/nss/at_testreb.nss similarity index 100% rename from src/mod/nss/at_testreb.nss rename to src/module/nss/at_testreb.nss diff --git a/src/mod/nss/at_tk_arcanemas.nss b/src/module/nss/at_tk_arcanemas.nss similarity index 100% rename from src/mod/nss/at_tk_arcanemas.nss rename to src/module/nss/at_tk_arcanemas.nss diff --git a/src/mod/nss/at_tk_flaw.nss b/src/module/nss/at_tk_flaw.nss similarity index 100% rename from src/mod/nss/at_tk_flaw.nss rename to src/module/nss/at_tk_flaw.nss diff --git a/src/mod/nss/at_tk_massarmor.nss b/src/module/nss/at_tk_massarmor.nss similarity index 100% rename from src/mod/nss/at_tk_massarmor.nss rename to src/module/nss/at_tk_massarmor.nss diff --git a/src/mod/nss/at_tk_masshelm.nss b/src/module/nss/at_tk_masshelm.nss similarity index 100% rename from src/mod/nss/at_tk_masshelm.nss rename to src/module/nss/at_tk_masshelm.nss diff --git a/src/mod/nss/at_tk_wp.nss b/src/module/nss/at_tk_wp.nss similarity index 100% rename from src/mod/nss/at_tk_wp.nss rename to src/module/nss/at_tk_wp.nss diff --git a/src/mod/nss/at_tk_wphelm.nss b/src/module/nss/at_tk_wphelm.nss similarity index 100% rename from src/mod/nss/at_tk_wphelm.nss rename to src/module/nss/at_tk_wphelm.nss diff --git a/src/mod/nss/at_tke_25k.nss b/src/module/nss/at_tke_25k.nss similarity index 100% rename from src/mod/nss/at_tke_25k.nss rename to src/module/nss/at_tke_25k.nss diff --git a/src/mod/nss/at_tke_dreamcatc.nss b/src/module/nss/at_tke_dreamcatc.nss similarity index 100% rename from src/mod/nss/at_tke_dreamcatc.nss rename to src/module/nss/at_tke_dreamcatc.nss diff --git a/src/mod/nss/at_tke_glovesle.nss b/src/module/nss/at_tke_glovesle.nss similarity index 100% rename from src/mod/nss/at_tke_glovesle.nss rename to src/module/nss/at_tke_glovesle.nss diff --git a/src/mod/nss/at_tke_monkhelm.nss b/src/module/nss/at_tke_monkhelm.nss similarity index 100% rename from src/mod/nss/at_tke_monkhelm.nss rename to src/module/nss/at_tke_monkhelm.nss diff --git a/src/mod/nss/at_tke_robelegen.nss b/src/module/nss/at_tke_robelegen.nss similarity index 100% rename from src/mod/nss/at_tke_robelegen.nss rename to src/module/nss/at_tke_robelegen.nss diff --git a/src/mod/nss/at_tke_rpboth.nss b/src/module/nss/at_tke_rpboth.nss similarity index 100% rename from src/mod/nss/at_tke_rpboth.nss rename to src/module/nss/at_tke_rpboth.nss diff --git a/src/mod/nss/at_tke_scrolls.nss b/src/module/nss/at_tke_scrolls.nss similarity index 100% rename from src/mod/nss/at_tke_scrolls.nss rename to src/module/nss/at_tke_scrolls.nss diff --git a/src/mod/nss/at_tkeass_armor.nss b/src/module/nss/at_tkeass_armor.nss similarity index 100% rename from src/mod/nss/at_tkeass_armor.nss rename to src/module/nss/at_tkeass_armor.nss diff --git a/src/mod/nss/at_tmlord_dead.nss b/src/module/nss/at_tmlord_dead.nss similarity index 100% rename from src/mod/nss/at_tmlord_dead.nss rename to src/module/nss/at_tmlord_dead.nss diff --git a/src/mod/nss/at_to_fareast.nss b/src/module/nss/at_to_fareast.nss similarity index 100% rename from src/mod/nss/at_to_fareast.nss rename to src/module/nss/at_to_fareast.nss diff --git a/src/mod/nss/at_to_repent.nss b/src/module/nss/at_to_repent.nss similarity index 100% rename from src/mod/nss/at_to_repent.nss rename to src/module/nss/at_to_repent.nss diff --git a/src/mod/nss/at_to_repent2.nss b/src/module/nss/at_to_repent2.nss similarity index 100% rename from src/mod/nss/at_to_repent2.nss rename to src/module/nss/at_to_repent2.nss diff --git a/src/mod/nss/at_treamas_attac.nss b/src/module/nss/at_treamas_attac.nss similarity index 100% rename from src/mod/nss/at_treamas_attac.nss rename to src/module/nss/at_treamas_attac.nss diff --git a/src/mod/nss/at_treas_mas_die.nss b/src/module/nss/at_treas_mas_die.nss similarity index 100% rename from src/mod/nss/at_treas_mas_die.nss rename to src/module/nss/at_treas_mas_die.nss diff --git a/src/mod/nss/at_tree_port01.nss b/src/module/nss/at_tree_port01.nss similarity index 100% rename from src/mod/nss/at_tree_port01.nss rename to src/module/nss/at_tree_port01.nss diff --git a/src/mod/nss/at_treeport_03.nss b/src/module/nss/at_treeport_03.nss similarity index 100% rename from src/mod/nss/at_treeport_03.nss rename to src/module/nss/at_treeport_03.nss diff --git a/src/mod/nss/at_treeport_04.nss b/src/module/nss/at_treeport_04.nss similarity index 100% rename from src/mod/nss/at_treeport_04.nss rename to src/module/nss/at_treeport_04.nss diff --git a/src/mod/nss/at_treeport_05.nss b/src/module/nss/at_treeport_05.nss similarity index 100% rename from src/mod/nss/at_treeport_05.nss rename to src/module/nss/at_treeport_05.nss diff --git a/src/mod/nss/at_treeport_06.nss b/src/module/nss/at_treeport_06.nss similarity index 100% rename from src/mod/nss/at_treeport_06.nss rename to src/module/nss/at_treeport_06.nss diff --git a/src/mod/nss/at_treeport_07.nss b/src/module/nss/at_treeport_07.nss similarity index 100% rename from src/mod/nss/at_treeport_07.nss rename to src/module/nss/at_treeport_07.nss diff --git a/src/mod/nss/at_tulls.nss b/src/module/nss/at_tulls.nss similarity index 100% rename from src/mod/nss/at_tulls.nss rename to src/module/nss/at_tulls.nss diff --git a/src/mod/nss/at_tulls_chk_lvl.nss b/src/module/nss/at_tulls_chk_lvl.nss similarity index 100% rename from src/mod/nss/at_tulls_chk_lvl.nss rename to src/module/nss/at_tulls_chk_lvl.nss diff --git a/src/mod/nss/at_urfucked.nss b/src/module/nss/at_urfucked.nss similarity index 100% rename from src/mod/nss/at_urfucked.nss rename to src/module/nss/at_urfucked.nss diff --git a/src/mod/nss/at_yoga3.nss b/src/module/nss/at_yoga3.nss similarity index 100% rename from src/mod/nss/at_yoga3.nss rename to src/module/nss/at_yoga3.nss diff --git a/src/mod/nss/atgivemonklehiel.nss b/src/module/nss/atgivemonklehiel.nss similarity index 100% rename from src/mod/nss/atgivemonklehiel.nss rename to src/module/nss/atgivemonklehiel.nss diff --git a/src/mod/nss/atport_to_ma.nss b/src/module/nss/atport_to_ma.nss similarity index 100% rename from src/mod/nss/atport_to_ma.nss rename to src/module/nss/atport_to_ma.nss diff --git a/src/mod/nss/aw_anitcheat2.nss b/src/module/nss/aw_anitcheat2.nss similarity index 100% rename from src/mod/nss/aw_anitcheat2.nss rename to src/module/nss/aw_anitcheat2.nss diff --git a/src/mod/nss/aw_archerdig.nss b/src/module/nss/aw_archerdig.nss similarity index 100% rename from src/mod/nss/aw_archerdig.nss rename to src/module/nss/aw_archerdig.nss diff --git a/src/mod/nss/aw_archermoredig.nss b/src/module/nss/aw_archermoredig.nss similarity index 100% rename from src/mod/nss/aw_archermoredig.nss rename to src/module/nss/aw_archermoredig.nss diff --git a/src/mod/nss/aw_bluespawnin.nss b/src/module/nss/aw_bluespawnin.nss similarity index 100% rename from src/mod/nss/aw_bluespawnin.nss rename to src/module/nss/aw_bluespawnin.nss diff --git a/src/mod/nss/aw_boogiedeath.nss b/src/module/nss/aw_boogiedeath.nss similarity index 100% rename from src/mod/nss/aw_boogiedeath.nss rename to src/module/nss/aw_boogiedeath.nss diff --git a/src/mod/nss/aw_boogieportal.nss b/src/module/nss/aw_boogieportal.nss similarity index 100% rename from src/mod/nss/aw_boogieportal.nss rename to src/module/nss/aw_boogieportal.nss diff --git a/src/mod/nss/aw_c_shifter_beh.nss b/src/module/nss/aw_c_shifter_beh.nss similarity index 100% rename from src/mod/nss/aw_c_shifter_beh.nss rename to src/module/nss/aw_c_shifter_beh.nss diff --git a/src/mod/nss/aw_c_shifter_dri.nss b/src/module/nss/aw_c_shifter_dri.nss similarity index 100% rename from src/mod/nss/aw_c_shifter_dri.nss rename to src/module/nss/aw_c_shifter_dri.nss diff --git a/src/mod/nss/aw_c_shifter_min.nss b/src/module/nss/aw_c_shifter_min.nss similarity index 100% rename from src/mod/nss/aw_c_shifter_min.nss rename to src/module/nss/aw_c_shifter_min.nss diff --git a/src/mod/nss/aw_checkdivine.nss b/src/module/nss/aw_checkdivine.nss similarity index 100% rename from src/mod/nss/aw_checkdivine.nss rename to src/module/nss/aw_checkdivine.nss diff --git a/src/mod/nss/aw_checkmagical.nss b/src/module/nss/aw_checkmagical.nss similarity index 100% rename from src/mod/nss/aw_checkmagical.nss rename to src/module/nss/aw_checkmagical.nss diff --git a/src/mod/nss/aw_checknegaitve.nss b/src/module/nss/aw_checknegaitve.nss similarity index 100% rename from src/mod/nss/aw_checknegaitve.nss rename to src/module/nss/aw_checknegaitve.nss diff --git a/src/mod/nss/aw_checkpossitiv.nss b/src/module/nss/aw_checkpossitiv.nss similarity index 100% rename from src/mod/nss/aw_checkpossitiv.nss rename to src/module/nss/aw_checkpossitiv.nss diff --git a/src/mod/nss/aw_closetdeath.nss b/src/module/nss/aw_closetdeath.nss similarity index 100% rename from src/mod/nss/aw_closetdeath.nss rename to src/module/nss/aw_closetdeath.nss diff --git a/src/mod/nss/aw_closetportal.nss b/src/module/nss/aw_closetportal.nss similarity index 100% rename from src/mod/nss/aw_closetportal.nss rename to src/module/nss/aw_closetportal.nss diff --git a/src/mod/nss/aw_craft_beholde.nss b/src/module/nss/aw_craft_beholde.nss similarity index 100% rename from src/mod/nss/aw_craft_beholde.nss rename to src/module/nss/aw_craft_beholde.nss diff --git a/src/mod/nss/aw_craft_db.nss b/src/module/nss/aw_craft_db.nss similarity index 100% rename from src/mod/nss/aw_craft_db.nss rename to src/module/nss/aw_craft_db.nss diff --git a/src/mod/nss/aw_craft_drider.nss b/src/module/nss/aw_craft_drider.nss similarity index 100% rename from src/mod/nss/aw_craft_drider.nss rename to src/module/nss/aw_craft_drider.nss diff --git a/src/mod/nss/aw_craft_dv.nss b/src/module/nss/aw_craft_dv.nss similarity index 100% rename from src/mod/nss/aw_craft_dv.nss rename to src/module/nss/aw_craft_dv.nss diff --git a/src/mod/nss/aw_dimdoor.nss b/src/module/nss/aw_dimdoor.nss similarity index 100% rename from src/mod/nss/aw_dimdoor.nss rename to src/module/nss/aw_dimdoor.nss diff --git a/src/mod/nss/aw_dimdoors.nss b/src/module/nss/aw_dimdoors.nss similarity index 100% rename from src/mod/nss/aw_dimdoors.nss rename to src/module/nss/aw_dimdoors.nss diff --git a/src/mod/nss/aw_dire_badger.nss b/src/module/nss/aw_dire_badger.nss similarity index 100% rename from src/mod/nss/aw_dire_badger.nss rename to src/module/nss/aw_dire_badger.nss diff --git a/src/mod/nss/aw_dire_bear.nss b/src/module/nss/aw_dire_bear.nss similarity index 100% rename from src/mod/nss/aw_dire_bear.nss rename to src/module/nss/aw_dire_bear.nss diff --git a/src/mod/nss/aw_dire_boar.nss b/src/module/nss/aw_dire_boar.nss similarity index 100% rename from src/mod/nss/aw_dire_boar.nss rename to src/module/nss/aw_dire_boar.nss diff --git a/src/mod/nss/aw_dire_panther.nss b/src/module/nss/aw_dire_panther.nss similarity index 100% rename from src/mod/nss/aw_dire_panther.nss rename to src/module/nss/aw_dire_panther.nss diff --git a/src/mod/nss/aw_dire_wolf.nss b/src/module/nss/aw_dire_wolf.nss similarity index 100% rename from src/mod/nss/aw_dire_wolf.nss rename to src/module/nss/aw_dire_wolf.nss diff --git a/src/mod/nss/aw_distroydiv.nss b/src/module/nss/aw_distroydiv.nss similarity index 100% rename from src/mod/nss/aw_distroydiv.nss rename to src/module/nss/aw_distroydiv.nss diff --git a/src/mod/nss/aw_distroymag.nss b/src/module/nss/aw_distroymag.nss similarity index 100% rename from src/mod/nss/aw_distroymag.nss rename to src/module/nss/aw_distroymag.nss diff --git a/src/mod/nss/aw_distroyneg.nss b/src/module/nss/aw_distroyneg.nss similarity index 100% rename from src/mod/nss/aw_distroyneg.nss rename to src/module/nss/aw_distroyneg.nss diff --git a/src/mod/nss/aw_distroypos.nss b/src/module/nss/aw_distroypos.nss similarity index 100% rename from src/mod/nss/aw_distroypos.nss rename to src/module/nss/aw_distroypos.nss diff --git a/src/mod/nss/aw_domedoors.nss b/src/module/nss/aw_domedoors.nss similarity index 100% rename from src/mod/nss/aw_domedoors.nss rename to src/module/nss/aw_domedoors.nss diff --git a/src/mod/nss/aw_doorcloselock.nss b/src/module/nss/aw_doorcloselock.nss similarity index 100% rename from src/mod/nss/aw_doorcloselock.nss rename to src/module/nss/aw_doorcloselock.nss diff --git a/src/mod/nss/aw_drops.nss b/src/module/nss/aw_drops.nss similarity index 100% rename from src/mod/nss/aw_drops.nss rename to src/module/nss/aw_drops.nss diff --git a/src/mod/nss/aw_druid_air.nss b/src/module/nss/aw_druid_air.nss similarity index 100% rename from src/mod/nss/aw_druid_air.nss rename to src/module/nss/aw_druid_air.nss diff --git a/src/mod/nss/aw_druid_badger.nss b/src/module/nss/aw_druid_badger.nss similarity index 100% rename from src/mod/nss/aw_druid_badger.nss rename to src/module/nss/aw_druid_badger.nss diff --git a/src/mod/nss/aw_druid_bear.nss b/src/module/nss/aw_druid_bear.nss similarity index 100% rename from src/mod/nss/aw_druid_bear.nss rename to src/module/nss/aw_druid_bear.nss diff --git a/src/mod/nss/aw_druid_boar.nss b/src/module/nss/aw_druid_boar.nss similarity index 100% rename from src/mod/nss/aw_druid_boar.nss rename to src/module/nss/aw_druid_boar.nss diff --git a/src/mod/nss/aw_druid_dragon.nss b/src/module/nss/aw_druid_dragon.nss similarity index 100% rename from src/mod/nss/aw_druid_dragon.nss rename to src/module/nss/aw_druid_dragon.nss diff --git a/src/mod/nss/aw_druid_earth.nss b/src/module/nss/aw_druid_earth.nss similarity index 100% rename from src/mod/nss/aw_druid_earth.nss rename to src/module/nss/aw_druid_earth.nss diff --git a/src/mod/nss/aw_druid_fire.nss b/src/module/nss/aw_druid_fire.nss similarity index 100% rename from src/mod/nss/aw_druid_fire.nss rename to src/module/nss/aw_druid_fire.nss diff --git a/src/mod/nss/aw_druid_lvl12.nss b/src/module/nss/aw_druid_lvl12.nss similarity index 100% rename from src/mod/nss/aw_druid_lvl12.nss rename to src/module/nss/aw_druid_lvl12.nss diff --git a/src/mod/nss/aw_druid_lvl16.nss b/src/module/nss/aw_druid_lvl16.nss similarity index 100% rename from src/mod/nss/aw_druid_lvl16.nss rename to src/module/nss/aw_druid_lvl16.nss diff --git a/src/mod/nss/aw_druid_lvl20.nss b/src/module/nss/aw_druid_lvl20.nss similarity index 100% rename from src/mod/nss/aw_druid_lvl20.nss rename to src/module/nss/aw_druid_lvl20.nss diff --git a/src/mod/nss/aw_druid_lvl5.nss b/src/module/nss/aw_druid_lvl5.nss similarity index 100% rename from src/mod/nss/aw_druid_lvl5.nss rename to src/module/nss/aw_druid_lvl5.nss diff --git a/src/mod/nss/aw_druid_panther.nss b/src/module/nss/aw_druid_panther.nss similarity index 100% rename from src/mod/nss/aw_druid_panther.nss rename to src/module/nss/aw_druid_panther.nss diff --git a/src/mod/nss/aw_druid_water.nss b/src/module/nss/aw_druid_water.nss similarity index 100% rename from src/mod/nss/aw_druid_water.nss rename to src/module/nss/aw_druid_water.nss diff --git a/src/mod/nss/aw_druid_werewol.nss b/src/module/nss/aw_druid_werewol.nss similarity index 100% rename from src/mod/nss/aw_druid_werewol.nss rename to src/module/nss/aw_druid_werewol.nss diff --git a/src/mod/nss/aw_druid_wolf.nss b/src/module/nss/aw_druid_wolf.nss similarity index 100% rename from src/mod/nss/aw_druid_wolf.nss rename to src/module/nss/aw_druid_wolf.nss diff --git a/src/mod/nss/aw_egg.nss b/src/module/nss/aw_egg.nss similarity index 100% rename from src/mod/nss/aw_egg.nss rename to src/module/nss/aw_egg.nss diff --git a/src/mod/nss/aw_essencecheck.nss b/src/module/nss/aw_essencecheck.nss similarity index 100% rename from src/mod/nss/aw_essencecheck.nss rename to src/module/nss/aw_essencecheck.nss diff --git a/src/mod/nss/aw_finalessence.nss b/src/module/nss/aw_finalessence.nss similarity index 100% rename from src/mod/nss/aw_finalessence.nss rename to src/module/nss/aw_finalessence.nss diff --git a/src/mod/nss/aw_forcedoor1.nss b/src/module/nss/aw_forcedoor1.nss similarity index 100% rename from src/mod/nss/aw_forcedoor1.nss rename to src/module/nss/aw_forcedoor1.nss diff --git a/src/mod/nss/aw_forcedoor2.nss b/src/module/nss/aw_forcedoor2.nss similarity index 100% rename from src/mod/nss/aw_forcedoor2.nss rename to src/module/nss/aw_forcedoor2.nss diff --git a/src/mod/nss/aw_getdivine.nss b/src/module/nss/aw_getdivine.nss similarity index 100% rename from src/mod/nss/aw_getdivine.nss rename to src/module/nss/aw_getdivine.nss diff --git a/src/mod/nss/aw_getshifter.nss b/src/module/nss/aw_getshifter.nss similarity index 100% rename from src/mod/nss/aw_getshifter.nss rename to src/module/nss/aw_getshifter.nss diff --git a/src/mod/nss/aw_getshifterbro.nss b/src/module/nss/aw_getshifterbro.nss similarity index 100% rename from src/mod/nss/aw_getshifterbro.nss rename to src/module/nss/aw_getshifterbro.nss diff --git a/src/mod/nss/aw_getwhorekey.nss b/src/module/nss/aw_getwhorekey.nss similarity index 100% rename from src/mod/nss/aw_getwhorekey.nss rename to src/module/nss/aw_getwhorekey.nss diff --git a/src/mod/nss/aw_givetooth.nss b/src/module/nss/aw_givetooth.nss similarity index 100% rename from src/mod/nss/aw_givetooth.nss rename to src/module/nss/aw_givetooth.nss diff --git a/src/mod/nss/aw_glowing.nss b/src/module/nss/aw_glowing.nss similarity index 100% rename from src/mod/nss/aw_glowing.nss rename to src/module/nss/aw_glowing.nss diff --git a/src/mod/nss/aw_gold1millchec.nss b/src/module/nss/aw_gold1millchec.nss similarity index 100% rename from src/mod/nss/aw_gold1millchec.nss rename to src/module/nss/aw_gold1millchec.nss diff --git a/src/mod/nss/aw_hasbracelet.nss b/src/module/nss/aw_hasbracelet.nss similarity index 100% rename from src/mod/nss/aw_hasbracelet.nss rename to src/module/nss/aw_hasbracelet.nss diff --git a/src/mod/nss/aw_hastooth.nss b/src/module/nss/aw_hastooth.nss similarity index 100% rename from src/mod/nss/aw_hastooth.nss rename to src/module/nss/aw_hastooth.nss diff --git a/src/mod/nss/aw_hillsideboim.nss b/src/module/nss/aw_hillsideboim.nss similarity index 100% rename from src/mod/nss/aw_hillsideboim.nss rename to src/module/nss/aw_hillsideboim.nss diff --git a/src/mod/nss/aw_hillsidedant.nss b/src/module/nss/aw_hillsidedant.nss similarity index 100% rename from src/mod/nss/aw_hillsidedant.nss rename to src/module/nss/aw_hillsidedant.nss diff --git a/src/mod/nss/aw_hillsidedeva.nss b/src/module/nss/aw_hillsidedeva.nss similarity index 100% rename from src/mod/nss/aw_hillsidedeva.nss rename to src/module/nss/aw_hillsidedeva.nss diff --git a/src/mod/nss/aw_hillsideisis.nss b/src/module/nss/aw_hillsideisis.nss similarity index 100% rename from src/mod/nss/aw_hillsideisis.nss rename to src/module/nss/aw_hillsideisis.nss diff --git a/src/mod/nss/aw_hillsideport.nss b/src/module/nss/aw_hillsideport.nss similarity index 100% rename from src/mod/nss/aw_hillsideport.nss rename to src/module/nss/aw_hillsideport.nss diff --git a/src/mod/nss/aw_isisbroken.nss b/src/module/nss/aw_isisbroken.nss similarity index 100% rename from src/mod/nss/aw_isisbroken.nss rename to src/module/nss/aw_isisbroken.nss diff --git a/src/mod/nss/aw_isisditzy.nss b/src/module/nss/aw_isisditzy.nss similarity index 100% rename from src/mod/nss/aw_isisditzy.nss rename to src/module/nss/aw_isisditzy.nss diff --git a/src/mod/nss/aw_isisquestion.nss b/src/module/nss/aw_isisquestion.nss similarity index 100% rename from src/mod/nss/aw_isisquestion.nss rename to src/module/nss/aw_isisquestion.nss diff --git a/src/mod/nss/aw_isistakeessen.nss b/src/module/nss/aw_isistakeessen.nss similarity index 100% rename from src/mod/nss/aw_isistakeessen.nss rename to src/module/nss/aw_isistakeessen.nss diff --git a/src/mod/nss/aw_levelcheck_18.nss b/src/module/nss/aw_levelcheck_18.nss similarity index 100% rename from src/mod/nss/aw_levelcheck_18.nss rename to src/module/nss/aw_levelcheck_18.nss diff --git a/src/mod/nss/aw_longdoorlock.nss b/src/module/nss/aw_longdoorlock.nss similarity index 100% rename from src/mod/nss/aw_longdoorlock.nss rename to src/module/nss/aw_longdoorlock.nss diff --git a/src/mod/nss/aw_moreisis.nss b/src/module/nss/aw_moreisis.nss similarity index 100% rename from src/mod/nss/aw_moreisis.nss rename to src/module/nss/aw_moreisis.nss diff --git a/src/mod/nss/aw_nightmareente.nss b/src/module/nss/aw_nightmareente.nss similarity index 100% rename from src/mod/nss/aw_nightmareente.nss rename to src/module/nss/aw_nightmareente.nss diff --git a/src/mod/nss/aw_passout.nss b/src/module/nss/aw_passout.nss similarity index 100% rename from src/mod/nss/aw_passout.nss rename to src/module/nss/aw_passout.nss diff --git a/src/mod/nss/aw_placeablecon.nss b/src/module/nss/aw_placeablecon.nss similarity index 100% rename from src/mod/nss/aw_placeablecon.nss rename to src/module/nss/aw_placeablecon.nss diff --git a/src/mod/nss/aw_portalfromver.nss b/src/module/nss/aw_portalfromver.nss similarity index 100% rename from src/mod/nss/aw_portalfromver.nss rename to src/module/nss/aw_portalfromver.nss diff --git a/src/mod/nss/aw_portaltovera.nss b/src/module/nss/aw_portaltovera.nss similarity index 100% rename from src/mod/nss/aw_portaltovera.nss rename to src/module/nss/aw_portaltovera.nss diff --git a/src/mod/nss/aw_portaltoveram.nss b/src/module/nss/aw_portaltoveram.nss similarity index 100% rename from src/mod/nss/aw_portaltoveram.nss rename to src/module/nss/aw_portaltoveram.nss diff --git a/src/mod/nss/aw_ptthdestro.nss b/src/module/nss/aw_ptthdestro.nss similarity index 100% rename from src/mod/nss/aw_ptthdestro.nss rename to src/module/nss/aw_ptthdestro.nss diff --git a/src/mod/nss/aw_reaperdeath.nss b/src/module/nss/aw_reaperdeath.nss similarity index 100% rename from src/mod/nss/aw_reaperdeath.nss rename to src/module/nss/aw_reaperdeath.nss diff --git a/src/mod/nss/aw_reaperportal.nss b/src/module/nss/aw_reaperportal.nss similarity index 100% rename from src/mod/nss/aw_reaperportal.nss rename to src/module/nss/aw_reaperportal.nss diff --git a/src/mod/nss/aw_ruinsdoorjump.nss b/src/module/nss/aw_ruinsdoorjump.nss similarity index 100% rename from src/mod/nss/aw_ruinsdoorjump.nss rename to src/module/nss/aw_ruinsdoorjump.nss diff --git a/src/mod/nss/aw_runecheck.nss b/src/module/nss/aw_runecheck.nss similarity index 100% rename from src/mod/nss/aw_runecheck.nss rename to src/module/nss/aw_runecheck.nss diff --git a/src/mod/nss/aw_saliacheck.nss b/src/module/nss/aw_saliacheck.nss similarity index 100% rename from src/mod/nss/aw_saliacheck.nss rename to src/module/nss/aw_saliacheck.nss diff --git a/src/mod/nss/aw_saliacheck2.nss b/src/module/nss/aw_saliacheck2.nss similarity index 100% rename from src/mod/nss/aw_saliacheck2.nss rename to src/module/nss/aw_saliacheck2.nss diff --git a/src/mod/nss/aw_shifter_basta.nss b/src/module/nss/aw_shifter_basta.nss similarity index 100% rename from src/mod/nss/aw_shifter_basta.nss rename to src/module/nss/aw_shifter_basta.nss diff --git a/src/mod/nss/aw_shifter_con6.nss b/src/module/nss/aw_shifter_con6.nss similarity index 100% rename from src/mod/nss/aw_shifter_con6.nss rename to src/module/nss/aw_shifter_con6.nss diff --git a/src/mod/nss/aw_shifter_cross.nss b/src/module/nss/aw_shifter_cross.nss similarity index 100% rename from src/mod/nss/aw_shifter_cross.nss rename to src/module/nss/aw_shifter_cross.nss diff --git a/src/mod/nss/aw_shifter_great.nss b/src/module/nss/aw_shifter_great.nss similarity index 100% rename from src/mod/nss/aw_shifter_great.nss rename to src/module/nss/aw_shifter_great.nss diff --git a/src/mod/nss/aw_shifter_lb.nss b/src/module/nss/aw_shifter_lb.nss similarity index 100% rename from src/mod/nss/aw_shifter_lb.nss rename to src/module/nss/aw_shifter_lb.nss diff --git a/src/mod/nss/aw_shifter_long.nss b/src/module/nss/aw_shifter_long.nss similarity index 100% rename from src/mod/nss/aw_shifter_long.nss rename to src/module/nss/aw_shifter_long.nss diff --git a/src/mod/nss/aw_shifter_quart.nss b/src/module/nss/aw_shifter_quart.nss similarity index 100% rename from src/mod/nss/aw_shifter_quart.nss rename to src/module/nss/aw_shifter_quart.nss diff --git a/src/mod/nss/aw_shifter_sb.nss b/src/module/nss/aw_shifter_sb.nss similarity index 100% rename from src/mod/nss/aw_shifter_sb.nss rename to src/module/nss/aw_shifter_sb.nss diff --git a/src/mod/nss/aw_shifter_scyth.nss b/src/module/nss/aw_shifter_scyth.nss similarity index 100% rename from src/mod/nss/aw_shifter_scyth.nss rename to src/module/nss/aw_shifter_scyth.nss diff --git a/src/mod/nss/aw_shifter_short.nss b/src/module/nss/aw_shifter_short.nss similarity index 100% rename from src/mod/nss/aw_shifter_short.nss rename to src/module/nss/aw_shifter_short.nss diff --git a/src/mod/nss/aw_shifter_star.nss b/src/module/nss/aw_shifter_star.nss similarity index 100% rename from src/mod/nss/aw_shifter_star.nss rename to src/module/nss/aw_shifter_star.nss diff --git a/src/mod/nss/aw_shifter_twin.nss b/src/module/nss/aw_shifter_twin.nss similarity index 100% rename from src/mod/nss/aw_shifter_twin.nss rename to src/module/nss/aw_shifter_twin.nss diff --git a/src/mod/nss/aw_sparkdeath.nss b/src/module/nss/aw_sparkdeath.nss similarity index 100% rename from src/mod/nss/aw_sparkdeath.nss rename to src/module/nss/aw_sparkdeath.nss diff --git a/src/mod/nss/aw_spawnvera.nss b/src/module/nss/aw_spawnvera.nss similarity index 100% rename from src/mod/nss/aw_spawnvera.nss rename to src/module/nss/aw_spawnvera.nss diff --git a/src/mod/nss/aw_spell_capture.nss b/src/module/nss/aw_spell_capture.nss similarity index 100% rename from src/mod/nss/aw_spell_capture.nss rename to src/module/nss/aw_spell_capture.nss diff --git a/src/mod/nss/aw_spell_control.nss b/src/module/nss/aw_spell_control.nss similarity index 100% rename from src/mod/nss/aw_spell_control.nss rename to src/module/nss/aw_spell_control.nss diff --git a/src/mod/nss/aw_spell_darkven.nss b/src/module/nss/aw_spell_darkven.nss similarity index 100% rename from src/mod/nss/aw_spell_darkven.nss rename to src/module/nss/aw_spell_darkven.nss diff --git a/src/mod/nss/aw_spell_db.nss b/src/module/nss/aw_spell_db.nss similarity index 100% rename from src/mod/nss/aw_spell_db.nss rename to src/module/nss/aw_spell_db.nss diff --git a/src/mod/nss/aw_staffofvera.nss b/src/module/nss/aw_staffofvera.nss similarity index 100% rename from src/mod/nss/aw_staffofvera.nss rename to src/module/nss/aw_staffofvera.nss diff --git a/src/mod/nss/aw_startglow.nss b/src/module/nss/aw_startglow.nss similarity index 100% rename from src/mod/nss/aw_startglow.nss rename to src/module/nss/aw_startglow.nss diff --git a/src/mod/nss/aw_stopcheater1.nss b/src/module/nss/aw_stopcheater1.nss similarity index 100% rename from src/mod/nss/aw_stopcheater1.nss rename to src/module/nss/aw_stopcheater1.nss diff --git a/src/mod/nss/aw_stopcheater2.nss b/src/module/nss/aw_stopcheater2.nss similarity index 100% rename from src/mod/nss/aw_stopcheater2.nss rename to src/module/nss/aw_stopcheater2.nss diff --git a/src/mod/nss/aw_take2k.nss b/src/module/nss/aw_take2k.nss similarity index 100% rename from src/mod/nss/aw_take2k.nss rename to src/module/nss/aw_take2k.nss diff --git a/src/mod/nss/aw_takebracelet.nss b/src/module/nss/aw_takebracelet.nss similarity index 100% rename from src/mod/nss/aw_takebracelet.nss rename to src/module/nss/aw_takebracelet.nss diff --git a/src/mod/nss/aw_takerunesforp.nss b/src/module/nss/aw_takerunesforp.nss similarity index 100% rename from src/mod/nss/aw_takerunesforp.nss rename to src/module/nss/aw_takerunesforp.nss diff --git a/src/mod/nss/aw_tantgold.nss b/src/module/nss/aw_tantgold.nss similarity index 100% rename from src/mod/nss/aw_tantgold.nss rename to src/module/nss/aw_tantgold.nss diff --git a/src/mod/nss/aw_totrinity.nss b/src/module/nss/aw_totrinity.nss similarity index 100% rename from src/mod/nss/aw_totrinity.nss rename to src/module/nss/aw_totrinity.nss diff --git a/src/mod/nss/aw_veradeath.nss b/src/module/nss/aw_veradeath.nss similarity index 100% rename from src/mod/nss/aw_veradeath.nss rename to src/module/nss/aw_veradeath.nss diff --git a/src/mod/nss/aw_whorekeycheck.nss b/src/module/nss/aw_whorekeycheck.nss similarity index 100% rename from src/mod/nss/aw_whorekeycheck.nss rename to src/module/nss/aw_whorekeycheck.nss diff --git a/src/mod/nss/bank_getgold.nss b/src/module/nss/bank_getgold.nss similarity index 100% rename from src/mod/nss/bank_getgold.nss rename to src/module/nss/bank_getgold.nss diff --git a/src/mod/nss/bank_tellerconvo.nss b/src/module/nss/bank_tellerconvo.nss similarity index 100% rename from src/mod/nss/bank_tellerconvo.nss rename to src/module/nss/bank_tellerconvo.nss diff --git a/src/mod/nss/bank_tellerspawn.nss b/src/module/nss/bank_tellerspawn.nss similarity index 100% rename from src/mod/nss/bank_tellerspawn.nss rename to src/module/nss/bank_tellerspawn.nss diff --git a/src/mod/nss/bill_gndr_check.nss b/src/module/nss/bill_gndr_check.nss similarity index 100% rename from src/mod/nss/bill_gndr_check.nss rename to src/module/nss/bill_gndr_check.nss diff --git a/src/mod/nss/bill_key_check.nss b/src/module/nss/bill_key_check.nss similarity index 100% rename from src/mod/nss/bill_key_check.nss rename to src/module/nss/bill_key_check.nss diff --git a/src/mod/nss/bill_key_take.nss b/src/module/nss/bill_key_take.nss similarity index 100% rename from src/mod/nss/bill_key_take.nss rename to src/module/nss/bill_key_take.nss diff --git a/src/mod/nss/bill_open_door.nss b/src/module/nss/bill_open_door.nss similarity index 100% rename from src/mod/nss/bill_open_door.nss rename to src/module/nss/bill_open_door.nss diff --git a/src/mod/nss/bill_var_check.nss b/src/module/nss/bill_var_check.nss similarity index 100% rename from src/mod/nss/bill_var_check.nss rename to src/module/nss/bill_var_check.nss diff --git a/src/mod/nss/bill_var_set.nss b/src/module/nss/bill_var_set.nss similarity index 100% rename from src/mod/nss/bill_var_set.nss rename to src/module/nss/bill_var_set.nss diff --git a/src/mod/nss/btr_chest_reset.nss b/src/module/nss/btr_chest_reset.nss similarity index 100% rename from src/mod/nss/btr_chest_reset.nss rename to src/module/nss/btr_chest_reset.nss diff --git a/src/mod/nss/bush_conv_start.nss b/src/module/nss/bush_conv_start.nss similarity index 100% rename from src/mod/nss/bush_conv_start.nss rename to src/module/nss/bush_conv_start.nss diff --git a/src/mod/nss/bvcapt_to_trin.nss b/src/module/nss/bvcapt_to_trin.nss similarity index 100% rename from src/mod/nss/bvcapt_to_trin.nss rename to src/module/nss/bvcapt_to_trin.nss diff --git a/src/mod/nss/bvcaptain_charge.nss b/src/module/nss/bvcaptain_charge.nss similarity index 100% rename from src/mod/nss/bvcaptain_charge.nss rename to src/module/nss/bvcaptain_charge.nss diff --git a/src/mod/nss/bvcaptain_got20k.nss b/src/module/nss/bvcaptain_got20k.nss similarity index 100% rename from src/mod/nss/bvcaptain_got20k.nss rename to src/module/nss/bvcaptain_got20k.nss diff --git a/src/mod/nss/bvcaptain_levchk.nss b/src/module/nss/bvcaptain_levchk.nss similarity index 100% rename from src/mod/nss/bvcaptain_levchk.nss rename to src/module/nss/bvcaptain_levchk.nss diff --git a/src/mod/nss/bvcaptain_port.nss b/src/module/nss/bvcaptain_port.nss similarity index 100% rename from src/mod/nss/bvcaptain_port.nss rename to src/module/nss/bvcaptain_port.nss diff --git a/src/mod/nss/cb_11port_01.nss b/src/module/nss/cb_11port_01.nss similarity index 100% rename from src/mod/nss/cb_11port_01.nss rename to src/module/nss/cb_11port_01.nss diff --git a/src/mod/nss/cb_2ndmonkjump.nss b/src/module/nss/cb_2ndmonkjump.nss similarity index 100% rename from src/mod/nss/cb_2ndmonkjump.nss rename to src/module/nss/cb_2ndmonkjump.nss diff --git a/src/mod/nss/cb_areacold.nss b/src/module/nss/cb_areacold.nss similarity index 100% rename from src/mod/nss/cb_areacold.nss rename to src/module/nss/cb_areacold.nss diff --git a/src/mod/nss/cb_asyglobe.nss b/src/module/nss/cb_asyglobe.nss similarity index 100% rename from src/mod/nss/cb_asyglobe.nss rename to src/module/nss/cb_asyglobe.nss diff --git a/src/mod/nss/cb_asyglobe2.nss b/src/module/nss/cb_asyglobe2.nss similarity index 100% rename from src/mod/nss/cb_asyglobe2.nss rename to src/module/nss/cb_asyglobe2.nss diff --git a/src/mod/nss/cb_asyglobe4.nss b/src/module/nss/cb_asyglobe4.nss similarity index 100% rename from src/mod/nss/cb_asyglobe4.nss rename to src/module/nss/cb_asyglobe4.nss diff --git a/src/mod/nss/cb_asyglobe5.nss b/src/module/nss/cb_asyglobe5.nss similarity index 100% rename from src/mod/nss/cb_asyglobe5.nss rename to src/module/nss/cb_asyglobe5.nss diff --git a/src/mod/nss/cb_asyglobe6.nss b/src/module/nss/cb_asyglobe6.nss similarity index 100% rename from src/mod/nss/cb_asyglobe6.nss rename to src/module/nss/cb_asyglobe6.nss diff --git a/src/mod/nss/cb_atl_port.nss b/src/module/nss/cb_atl_port.nss similarity index 100% rename from src/mod/nss/cb_atl_port.nss rename to src/module/nss/cb_atl_port.nss diff --git a/src/mod/nss/cb_atl_take.nss b/src/module/nss/cb_atl_take.nss similarity index 100% rename from src/mod/nss/cb_atl_take.nss rename to src/module/nss/cb_atl_take.nss diff --git a/src/mod/nss/cb_attack_all.nss b/src/module/nss/cb_attack_all.nss similarity index 100% rename from src/mod/nss/cb_attack_all.nss rename to src/module/nss/cb_attack_all.nss diff --git a/src/mod/nss/cb_attack_pc.nss b/src/module/nss/cb_attack_pc.nss similarity index 100% rename from src/mod/nss/cb_attack_pc.nss rename to src/module/nss/cb_attack_pc.nss diff --git a/src/mod/nss/cb_battlefield.nss b/src/module/nss/cb_battlefield.nss similarity index 100% rename from src/mod/nss/cb_battlefield.nss rename to src/module/nss/cb_battlefield.nss diff --git a/src/mod/nss/cb_boneydie.nss b/src/module/nss/cb_boneydie.nss similarity index 100% rename from src/mod/nss/cb_boneydie.nss rename to src/module/nss/cb_boneydie.nss diff --git a/src/mod/nss/cb_brewmastersto.nss b/src/module/nss/cb_brewmastersto.nss similarity index 100% rename from src/mod/nss/cb_brewmastersto.nss rename to src/module/nss/cb_brewmastersto.nss diff --git a/src/mod/nss/cb_brewreward.nss b/src/module/nss/cb_brewreward.nss similarity index 100% rename from src/mod/nss/cb_brewreward.nss rename to src/module/nss/cb_brewreward.nss diff --git a/src/mod/nss/cb_caliman.nss b/src/module/nss/cb_caliman.nss similarity index 100% rename from src/mod/nss/cb_caliman.nss rename to src/module/nss/cb_caliman.nss diff --git a/src/mod/nss/cb_caliman2.nss b/src/module/nss/cb_caliman2.nss similarity index 100% rename from src/mod/nss/cb_caliman2.nss rename to src/module/nss/cb_caliman2.nss diff --git a/src/mod/nss/cb_caretaker.nss b/src/module/nss/cb_caretaker.nss similarity index 100% rename from src/mod/nss/cb_caretaker.nss rename to src/module/nss/cb_caretaker.nss diff --git a/src/mod/nss/cb_chk_100k.nss b/src/module/nss/cb_chk_100k.nss similarity index 100% rename from src/mod/nss/cb_chk_100k.nss rename to src/module/nss/cb_chk_100k.nss diff --git a/src/mod/nss/cb_chk_25k.nss b/src/module/nss/cb_chk_25k.nss similarity index 100% rename from src/mod/nss/cb_chk_25k.nss rename to src/module/nss/cb_chk_25k.nss diff --git a/src/mod/nss/cb_chk_2k.nss b/src/module/nss/cb_chk_2k.nss similarity index 100% rename from src/mod/nss/cb_chk_2k.nss rename to src/module/nss/cb_chk_2k.nss diff --git a/src/mod/nss/cb_chk_30.nss b/src/module/nss/cb_chk_30.nss similarity index 100% rename from src/mod/nss/cb_chk_30.nss rename to src/module/nss/cb_chk_30.nss diff --git a/src/mod/nss/cb_chk_5k.nss b/src/module/nss/cb_chk_5k.nss similarity index 100% rename from src/mod/nss/cb_chk_5k.nss rename to src/module/nss/cb_chk_5k.nss diff --git a/src/mod/nss/cb_chk_acidstick.nss b/src/module/nss/cb_chk_acidstick.nss similarity index 100% rename from src/mod/nss/cb_chk_acidstick.nss rename to src/module/nss/cb_chk_acidstick.nss diff --git a/src/mod/nss/cb_chk_atlstone.nss b/src/module/nss/cb_chk_atlstone.nss similarity index 100% rename from src/mod/nss/cb_chk_atlstone.nss rename to src/module/nss/cb_chk_atlstone.nss diff --git a/src/mod/nss/cb_chk_blueplan.nss b/src/module/nss/cb_chk_blueplan.nss similarity index 100% rename from src/mod/nss/cb_chk_blueplan.nss rename to src/module/nss/cb_chk_blueplan.nss diff --git a/src/mod/nss/cb_chk_booknoble.nss b/src/module/nss/cb_chk_booknoble.nss similarity index 100% rename from src/mod/nss/cb_chk_booknoble.nss rename to src/module/nss/cb_chk_booknoble.nss diff --git a/src/mod/nss/cb_chk_dragammy.nss b/src/module/nss/cb_chk_dragammy.nss similarity index 100% rename from src/mod/nss/cb_chk_dragammy.nss rename to src/module/nss/cb_chk_dragammy.nss diff --git a/src/mod/nss/cb_chk_drageverg.nss b/src/module/nss/cb_chk_drageverg.nss similarity index 100% rename from src/mod/nss/cb_chk_drageverg.nss rename to src/module/nss/cb_chk_drageverg.nss diff --git a/src/mod/nss/cb_chk_drownoble.nss b/src/module/nss/cb_chk_drownoble.nss similarity index 100% rename from src/mod/nss/cb_chk_drownoble.nss rename to src/module/nss/cb_chk_drownoble.nss diff --git a/src/mod/nss/cb_chk_evilorb.nss b/src/module/nss/cb_chk_evilorb.nss similarity index 100% rename from src/mod/nss/cb_chk_evilorb.nss rename to src/module/nss/cb_chk_evilorb.nss diff --git a/src/mod/nss/cb_chk_globe.nss b/src/module/nss/cb_chk_globe.nss similarity index 100% rename from src/mod/nss/cb_chk_globe.nss rename to src/module/nss/cb_chk_globe.nss diff --git a/src/mod/nss/cb_chk_goodorb.nss b/src/module/nss/cb_chk_goodorb.nss similarity index 100% rename from src/mod/nss/cb_chk_goodorb.nss rename to src/module/nss/cb_chk_goodorb.nss diff --git a/src/mod/nss/cb_chk_grail.nss b/src/module/nss/cb_chk_grail.nss similarity index 100% rename from src/mod/nss/cb_chk_grail.nss rename to src/module/nss/cb_chk_grail.nss diff --git a/src/mod/nss/cb_chk_greenplan.nss b/src/module/nss/cb_chk_greenplan.nss similarity index 100% rename from src/mod/nss/cb_chk_greenplan.nss rename to src/module/nss/cb_chk_greenplan.nss diff --git a/src/mod/nss/cb_chk_grial.nss b/src/module/nss/cb_chk_grial.nss similarity index 100% rename from src/mod/nss/cb_chk_grial.nss rename to src/module/nss/cb_chk_grial.nss diff --git a/src/mod/nss/cb_chk_horn.nss b/src/module/nss/cb_chk_horn.nss similarity index 100% rename from src/mod/nss/cb_chk_horn.nss rename to src/module/nss/cb_chk_horn.nss diff --git a/src/mod/nss/cb_chk_lith.nss b/src/module/nss/cb_chk_lith.nss similarity index 100% rename from src/mod/nss/cb_chk_lith.nss rename to src/module/nss/cb_chk_lith.nss diff --git a/src/mod/nss/cb_chk_lstaff.nss b/src/module/nss/cb_chk_lstaff.nss similarity index 100% rename from src/mod/nss/cb_chk_lstaff.nss rename to src/module/nss/cb_chk_lstaff.nss diff --git a/src/mod/nss/cb_chk_mahead.nss b/src/module/nss/cb_chk_mahead.nss similarity index 100% rename from src/mod/nss/cb_chk_mahead.nss rename to src/module/nss/cb_chk_mahead.nss diff --git a/src/mod/nss/cb_chk_mug.nss b/src/module/nss/cb_chk_mug.nss similarity index 100% rename from src/mod/nss/cb_chk_mug.nss rename to src/module/nss/cb_chk_mug.nss diff --git a/src/mod/nss/cb_chk_redplan.nss b/src/module/nss/cb_chk_redplan.nss similarity index 100% rename from src/mod/nss/cb_chk_redplan.nss rename to src/module/nss/cb_chk_redplan.nss diff --git a/src/mod/nss/cb_chk_scrollals.nss b/src/module/nss/cb_chk_scrollals.nss similarity index 100% rename from src/mod/nss/cb_chk_scrollals.nss rename to src/module/nss/cb_chk_scrollals.nss diff --git a/src/mod/nss/cb_chk_scrolls.nss b/src/module/nss/cb_chk_scrolls.nss similarity index 100% rename from src/mod/nss/cb_chk_scrolls.nss rename to src/module/nss/cb_chk_scrolls.nss diff --git a/src/mod/nss/cb_chk_serum.nss b/src/module/nss/cb_chk_serum.nss similarity index 100% rename from src/mod/nss/cb_chk_serum.nss rename to src/module/nss/cb_chk_serum.nss diff --git a/src/mod/nss/cb_chk_taghead.nss b/src/module/nss/cb_chk_taghead.nss similarity index 100% rename from src/mod/nss/cb_chk_taghead.nss rename to src/module/nss/cb_chk_taghead.nss diff --git a/src/mod/nss/cb_chk_tmbattle.nss b/src/module/nss/cb_chk_tmbattle.nss similarity index 100% rename from src/mod/nss/cb_chk_tmbattle.nss rename to src/module/nss/cb_chk_tmbattle.nss diff --git a/src/mod/nss/cb_chk_yoga.nss b/src/module/nss/cb_chk_yoga.nss similarity index 100% rename from src/mod/nss/cb_chk_yoga.nss rename to src/module/nss/cb_chk_yoga.nss diff --git a/src/mod/nss/cb_chklvl1.nss b/src/module/nss/cb_chklvl1.nss similarity index 100% rename from src/mod/nss/cb_chklvl1.nss rename to src/module/nss/cb_chklvl1.nss diff --git a/src/mod/nss/cb_cloakpotion.nss b/src/module/nss/cb_cloakpotion.nss similarity index 100% rename from src/mod/nss/cb_cloakpotion.nss rename to src/module/nss/cb_cloakpotion.nss diff --git a/src/mod/nss/cb_cloakwall.nss b/src/module/nss/cb_cloakwall.nss similarity index 100% rename from src/mod/nss/cb_cloakwall.nss rename to src/module/nss/cb_cloakwall.nss diff --git a/src/mod/nss/cb_conv_placable.nss b/src/module/nss/cb_conv_placable.nss similarity index 100% rename from src/mod/nss/cb_conv_placable.nss rename to src/module/nss/cb_conv_placable.nss diff --git a/src/mod/nss/cb_cushions1.nss b/src/module/nss/cb_cushions1.nss similarity index 100% rename from src/mod/nss/cb_cushions1.nss rename to src/module/nss/cb_cushions1.nss diff --git a/src/mod/nss/cb_dirthboom.nss b/src/module/nss/cb_dirthboom.nss similarity index 100% rename from src/mod/nss/cb_dirthboom.nss rename to src/module/nss/cb_dirthboom.nss diff --git a/src/mod/nss/cb_dirthport1.nss b/src/module/nss/cb_dirthport1.nss similarity index 100% rename from src/mod/nss/cb_dirthport1.nss rename to src/module/nss/cb_dirthport1.nss diff --git a/src/mod/nss/cb_dirthport10.nss b/src/module/nss/cb_dirthport10.nss similarity index 100% rename from src/mod/nss/cb_dirthport10.nss rename to src/module/nss/cb_dirthport10.nss diff --git a/src/mod/nss/cb_dirthport11.nss b/src/module/nss/cb_dirthport11.nss similarity index 100% rename from src/mod/nss/cb_dirthport11.nss rename to src/module/nss/cb_dirthport11.nss diff --git a/src/mod/nss/cb_dirthport2.nss b/src/module/nss/cb_dirthport2.nss similarity index 100% rename from src/mod/nss/cb_dirthport2.nss rename to src/module/nss/cb_dirthport2.nss diff --git a/src/mod/nss/cb_dirthport3.nss b/src/module/nss/cb_dirthport3.nss similarity index 100% rename from src/mod/nss/cb_dirthport3.nss rename to src/module/nss/cb_dirthport3.nss diff --git a/src/mod/nss/cb_dirthport4.nss b/src/module/nss/cb_dirthport4.nss similarity index 100% rename from src/mod/nss/cb_dirthport4.nss rename to src/module/nss/cb_dirthport4.nss diff --git a/src/mod/nss/cb_dirthport5.nss b/src/module/nss/cb_dirthport5.nss similarity index 100% rename from src/mod/nss/cb_dirthport5.nss rename to src/module/nss/cb_dirthport5.nss diff --git a/src/mod/nss/cb_dirthport6.nss b/src/module/nss/cb_dirthport6.nss similarity index 100% rename from src/mod/nss/cb_dirthport6.nss rename to src/module/nss/cb_dirthport6.nss diff --git a/src/mod/nss/cb_dirthport7.nss b/src/module/nss/cb_dirthport7.nss similarity index 100% rename from src/mod/nss/cb_dirthport7.nss rename to src/module/nss/cb_dirthport7.nss diff --git a/src/mod/nss/cb_dirthport8.nss b/src/module/nss/cb_dirthport8.nss similarity index 100% rename from src/mod/nss/cb_dirthport8.nss rename to src/module/nss/cb_dirthport8.nss diff --git a/src/mod/nss/cb_dirthport9.nss b/src/module/nss/cb_dirthport9.nss similarity index 100% rename from src/mod/nss/cb_dirthport9.nss rename to src/module/nss/cb_dirthport9.nss diff --git a/src/mod/nss/cb_disarmtrap.nss b/src/module/nss/cb_disarmtrap.nss similarity index 100% rename from src/mod/nss/cb_disarmtrap.nss rename to src/module/nss/cb_disarmtrap.nss diff --git a/src/mod/nss/cb_dmstore2.nss b/src/module/nss/cb_dmstore2.nss similarity index 100% rename from src/mod/nss/cb_dmstore2.nss rename to src/module/nss/cb_dmstore2.nss diff --git a/src/mod/nss/cb_dontattacknpc.nss b/src/module/nss/cb_dontattacknpc.nss similarity index 100% rename from src/mod/nss/cb_dontattacknpc.nss rename to src/module/nss/cb_dontattacknpc.nss diff --git a/src/mod/nss/cb_door_conv.nss b/src/module/nss/cb_door_conv.nss similarity index 100% rename from src/mod/nss/cb_door_conv.nss rename to src/module/nss/cb_door_conv.nss diff --git a/src/mod/nss/cb_doorspeak.nss b/src/module/nss/cb_doorspeak.nss similarity index 100% rename from src/mod/nss/cb_doorspeak.nss rename to src/module/nss/cb_doorspeak.nss diff --git a/src/mod/nss/cb_doorspeak1.nss b/src/module/nss/cb_doorspeak1.nss similarity index 100% rename from src/mod/nss/cb_doorspeak1.nss rename to src/module/nss/cb_doorspeak1.nss diff --git a/src/mod/nss/cb_doorspeak2.nss b/src/module/nss/cb_doorspeak2.nss similarity index 100% rename from src/mod/nss/cb_doorspeak2.nss rename to src/module/nss/cb_doorspeak2.nss diff --git a/src/mod/nss/cb_doorspeak3.nss b/src/module/nss/cb_doorspeak3.nss similarity index 100% rename from src/mod/nss/cb_doorspeak3.nss rename to src/module/nss/cb_doorspeak3.nss diff --git a/src/mod/nss/cb_drag_backup.nss b/src/module/nss/cb_drag_backup.nss similarity index 100% rename from src/mod/nss/cb_drag_backup.nss rename to src/module/nss/cb_drag_backup.nss diff --git a/src/mod/nss/cb_dragenergy.nss b/src/module/nss/cb_dragenergy.nss similarity index 100% rename from src/mod/nss/cb_dragenergy.nss rename to src/module/nss/cb_dragenergy.nss diff --git a/src/mod/nss/cb_dragon_light.nss b/src/module/nss/cb_dragon_light.nss similarity index 100% rename from src/mod/nss/cb_dragon_light.nss rename to src/module/nss/cb_dragon_light.nss diff --git a/src/mod/nss/cb_dragonenerpor.nss b/src/module/nss/cb_dragonenerpor.nss similarity index 100% rename from src/mod/nss/cb_dragonenerpor.nss rename to src/module/nss/cb_dragonenerpor.nss diff --git a/src/mod/nss/cb_drowattack.nss b/src/module/nss/cb_drowattack.nss similarity index 100% rename from src/mod/nss/cb_drowattack.nss rename to src/module/nss/cb_drowattack.nss diff --git a/src/mod/nss/cb_drowlight.nss b/src/module/nss/cb_drowlight.nss similarity index 100% rename from src/mod/nss/cb_drowlight.nss rename to src/module/nss/cb_drowlight.nss diff --git a/src/mod/nss/cb_elfattack1.nss b/src/module/nss/cb_elfattack1.nss similarity index 100% rename from src/mod/nss/cb_elfattack1.nss rename to src/module/nss/cb_elfattack1.nss diff --git a/src/mod/nss/cb_elfattack2.nss b/src/module/nss/cb_elfattack2.nss similarity index 100% rename from src/mod/nss/cb_elfattack2.nss rename to src/module/nss/cb_elfattack2.nss diff --git a/src/mod/nss/cb_elfattack3.nss b/src/module/nss/cb_elfattack3.nss similarity index 100% rename from src/mod/nss/cb_elfattack3.nss rename to src/module/nss/cb_elfattack3.nss diff --git a/src/mod/nss/cb_elfmerch.nss b/src/module/nss/cb_elfmerch.nss similarity index 100% rename from src/mod/nss/cb_elfmerch.nss rename to src/module/nss/cb_elfmerch.nss diff --git a/src/mod/nss/cb_elfpile.nss b/src/module/nss/cb_elfpile.nss similarity index 100% rename from src/mod/nss/cb_elfpile.nss rename to src/module/nss/cb_elfpile.nss diff --git a/src/mod/nss/cb_elvendar_ente.nss b/src/module/nss/cb_elvendar_ente.nss similarity index 100% rename from src/mod/nss/cb_elvendar_ente.nss rename to src/module/nss/cb_elvendar_ente.nss diff --git a/src/mod/nss/cb_energydestroy.nss b/src/module/nss/cb_energydestroy.nss similarity index 100% rename from src/mod/nss/cb_energydestroy.nss rename to src/module/nss/cb_energydestroy.nss diff --git a/src/mod/nss/cb_enter_battle.nss b/src/module/nss/cb_enter_battle.nss similarity index 100% rename from src/mod/nss/cb_enter_battle.nss rename to src/module/nss/cb_enter_battle.nss diff --git a/src/mod/nss/cb_equipmelee.nss b/src/module/nss/cb_equipmelee.nss similarity index 100% rename from src/mod/nss/cb_equipmelee.nss rename to src/module/nss/cb_equipmelee.nss diff --git a/src/mod/nss/cb_evil.nss b/src/module/nss/cb_evil.nss similarity index 100% rename from src/mod/nss/cb_evil.nss rename to src/module/nss/cb_evil.nss diff --git a/src/mod/nss/cb_evilport20.nss b/src/module/nss/cb_evilport20.nss similarity index 100% rename from src/mod/nss/cb_evilport20.nss rename to src/module/nss/cb_evilport20.nss diff --git a/src/mod/nss/cb_fizzle.nss b/src/module/nss/cb_fizzle.nss similarity index 100% rename from src/mod/nss/cb_fizzle.nss rename to src/module/nss/cb_fizzle.nss diff --git a/src/mod/nss/cb_forcedoor1.nss b/src/module/nss/cb_forcedoor1.nss similarity index 100% rename from src/mod/nss/cb_forcedoor1.nss rename to src/module/nss/cb_forcedoor1.nss diff --git a/src/mod/nss/cb_forcedoor2.nss b/src/module/nss/cb_forcedoor2.nss similarity index 100% rename from src/mod/nss/cb_forcedoor2.nss rename to src/module/nss/cb_forcedoor2.nss diff --git a/src/mod/nss/cb_forcedoor3.nss b/src/module/nss/cb_forcedoor3.nss similarity index 100% rename from src/mod/nss/cb_forcedoor3.nss rename to src/module/nss/cb_forcedoor3.nss diff --git a/src/mod/nss/cb_giv_50k.nss b/src/module/nss/cb_giv_50k.nss similarity index 100% rename from src/mod/nss/cb_giv_50k.nss rename to src/module/nss/cb_giv_50k.nss diff --git a/src/mod/nss/cb_giv_draggem.nss b/src/module/nss/cb_giv_draggem.nss similarity index 100% rename from src/mod/nss/cb_giv_draggem.nss rename to src/module/nss/cb_giv_draggem.nss diff --git a/src/mod/nss/cb_givebow.nss b/src/module/nss/cb_givebow.nss similarity index 100% rename from src/mod/nss/cb_givebow.nss rename to src/module/nss/cb_givebow.nss diff --git a/src/mod/nss/cb_givehorn.nss b/src/module/nss/cb_givehorn.nss similarity index 100% rename from src/mod/nss/cb_givehorn.nss rename to src/module/nss/cb_givehorn.nss diff --git a/src/mod/nss/cb_good.nss b/src/module/nss/cb_good.nss similarity index 100% rename from src/mod/nss/cb_good.nss rename to src/module/nss/cb_good.nss diff --git a/src/mod/nss/cb_goodport20.nss b/src/module/nss/cb_goodport20.nss similarity index 100% rename from src/mod/nss/cb_goodport20.nss rename to src/module/nss/cb_goodport20.nss diff --git a/src/mod/nss/cb_gotojail.nss b/src/module/nss/cb_gotojail.nss similarity index 100% rename from src/mod/nss/cb_gotojail.nss rename to src/module/nss/cb_gotojail.nss diff --git a/src/mod/nss/cb_gve_atlstone.nss b/src/module/nss/cb_gve_atlstone.nss similarity index 100% rename from src/mod/nss/cb_gve_atlstone.nss rename to src/module/nss/cb_gve_atlstone.nss diff --git a/src/mod/nss/cb_insightmonk.nss b/src/module/nss/cb_insightmonk.nss similarity index 100% rename from src/mod/nss/cb_insightmonk.nss rename to src/module/nss/cb_insightmonk.nss diff --git a/src/mod/nss/cb_janopport.nss b/src/module/nss/cb_janopport.nss similarity index 100% rename from src/mod/nss/cb_janopport.nss rename to src/module/nss/cb_janopport.nss diff --git a/src/mod/nss/cb_jewl_tool.nss b/src/module/nss/cb_jewl_tool.nss similarity index 100% rename from src/mod/nss/cb_jewl_tool.nss rename to src/module/nss/cb_jewl_tool.nss diff --git a/src/mod/nss/cb_jez_death.nss b/src/module/nss/cb_jez_death.nss similarity index 100% rename from src/mod/nss/cb_jez_death.nss rename to src/module/nss/cb_jez_death.nss diff --git a/src/mod/nss/cb_jim_curse.nss b/src/module/nss/cb_jim_curse.nss similarity index 100% rename from src/mod/nss/cb_jim_curse.nss rename to src/module/nss/cb_jim_curse.nss diff --git a/src/mod/nss/cb_kill_cushion.nss b/src/module/nss/cb_kill_cushion.nss similarity index 100% rename from src/mod/nss/cb_kill_cushion.nss rename to src/module/nss/cb_kill_cushion.nss diff --git a/src/mod/nss/cb_kill_drowligh.nss b/src/module/nss/cb_kill_drowligh.nss similarity index 100% rename from src/mod/nss/cb_kill_drowligh.nss rename to src/module/nss/cb_kill_drowligh.nss diff --git a/src/mod/nss/cb_kill_oz1.nss b/src/module/nss/cb_kill_oz1.nss similarity index 100% rename from src/mod/nss/cb_kill_oz1.nss rename to src/module/nss/cb_kill_oz1.nss diff --git a/src/mod/nss/cb_kill_oz2.nss b/src/module/nss/cb_kill_oz2.nss similarity index 100% rename from src/mod/nss/cb_kill_oz2.nss rename to src/module/nss/cb_kill_oz2.nss diff --git a/src/mod/nss/cb_kill_oz3.nss b/src/module/nss/cb_kill_oz3.nss similarity index 100% rename from src/mod/nss/cb_kill_oz3.nss rename to src/module/nss/cb_kill_oz3.nss diff --git a/src/mod/nss/cb_klaumdoor.nss b/src/module/nss/cb_klaumdoor.nss similarity index 100% rename from src/mod/nss/cb_klaumdoor.nss rename to src/module/nss/cb_klaumdoor.nss diff --git a/src/mod/nss/cb_klaumspawn1.nss b/src/module/nss/cb_klaumspawn1.nss similarity index 100% rename from src/mod/nss/cb_klaumspawn1.nss rename to src/module/nss/cb_klaumspawn1.nss diff --git a/src/mod/nss/cb_legionport1.nss b/src/module/nss/cb_legionport1.nss similarity index 100% rename from src/mod/nss/cb_legionport1.nss rename to src/module/nss/cb_legionport1.nss diff --git a/src/mod/nss/cb_lithport1.nss b/src/module/nss/cb_lithport1.nss similarity index 100% rename from src/mod/nss/cb_lithport1.nss rename to src/module/nss/cb_lithport1.nss diff --git a/src/mod/nss/cb_lithport2.nss b/src/module/nss/cb_lithport2.nss similarity index 100% rename from src/mod/nss/cb_lithport2.nss rename to src/module/nss/cb_lithport2.nss diff --git a/src/mod/nss/cb_lithport3.nss b/src/module/nss/cb_lithport3.nss similarity index 100% rename from src/mod/nss/cb_lithport3.nss rename to src/module/nss/cb_lithport3.nss diff --git a/src/mod/nss/cb_lithporttab.nss b/src/module/nss/cb_lithporttab.nss similarity index 100% rename from src/mod/nss/cb_lithporttab.nss rename to src/module/nss/cb_lithporttab.nss diff --git a/src/mod/nss/cb_malnipstore.nss b/src/module/nss/cb_malnipstore.nss similarity index 100% rename from src/mod/nss/cb_malnipstore.nss rename to src/module/nss/cb_malnipstore.nss diff --git a/src/mod/nss/cb_max_lvl5.nss b/src/module/nss/cb_max_lvl5.nss similarity index 100% rename from src/mod/nss/cb_max_lvl5.nss rename to src/module/nss/cb_max_lvl5.nss diff --git a/src/mod/nss/cb_max_lvl8.nss b/src/module/nss/cb_max_lvl8.nss similarity index 100% rename from src/mod/nss/cb_max_lvl8.nss rename to src/module/nss/cb_max_lvl8.nss diff --git a/src/mod/nss/cb_meditate.nss b/src/module/nss/cb_meditate.nss similarity index 100% rename from src/mod/nss/cb_meditate.nss rename to src/module/nss/cb_meditate.nss diff --git a/src/mod/nss/cb_meditate_per.nss b/src/module/nss/cb_meditate_per.nss similarity index 100% rename from src/mod/nss/cb_meditate_per.nss rename to src/module/nss/cb_meditate_per.nss diff --git a/src/mod/nss/cb_mind_spawn.nss b/src/module/nss/cb_mind_spawn.nss similarity index 100% rename from src/mod/nss/cb_mind_spawn.nss rename to src/module/nss/cb_mind_spawn.nss diff --git a/src/mod/nss/cb_mind_spawn2.nss b/src/module/nss/cb_mind_spawn2.nss similarity index 100% rename from src/mod/nss/cb_mind_spawn2.nss rename to src/module/nss/cb_mind_spawn2.nss diff --git a/src/mod/nss/cb_minddeath.nss b/src/module/nss/cb_minddeath.nss similarity index 100% rename from src/mod/nss/cb_minddeath.nss rename to src/module/nss/cb_minddeath.nss diff --git a/src/mod/nss/cb_mindoops.nss b/src/module/nss/cb_mindoops.nss similarity index 100% rename from src/mod/nss/cb_mindoops.nss rename to src/module/nss/cb_mindoops.nss diff --git a/src/mod/nss/cb_monkattack.nss b/src/module/nss/cb_monkattack.nss similarity index 100% rename from src/mod/nss/cb_monkattack.nss rename to src/module/nss/cb_monkattack.nss diff --git a/src/mod/nss/cb_monkkill.nss b/src/module/nss/cb_monkkill.nss similarity index 100% rename from src/mod/nss/cb_monkkill.nss rename to src/module/nss/cb_monkkill.nss diff --git a/src/mod/nss/cb_monkkill2.nss b/src/module/nss/cb_monkkill2.nss similarity index 100% rename from src/mod/nss/cb_monkkill2.nss rename to src/module/nss/cb_monkkill2.nss diff --git a/src/mod/nss/cb_monksattack.nss b/src/module/nss/cb_monksattack.nss similarity index 100% rename from src/mod/nss/cb_monksattack.nss rename to src/module/nss/cb_monksattack.nss diff --git a/src/mod/nss/cb_monkworship.nss b/src/module/nss/cb_monkworship.nss similarity index 100% rename from src/mod/nss/cb_monkworship.nss rename to src/module/nss/cb_monkworship.nss diff --git a/src/mod/nss/cb_neutral.nss b/src/module/nss/cb_neutral.nss similarity index 100% rename from src/mod/nss/cb_neutral.nss rename to src/module/nss/cb_neutral.nss diff --git a/src/mod/nss/cb_newport.nss b/src/module/nss/cb_newport.nss similarity index 100% rename from src/mod/nss/cb_newport.nss rename to src/module/nss/cb_newport.nss diff --git a/src/mod/nss/cb_npc_bash.nss b/src/module/nss/cb_npc_bash.nss similarity index 100% rename from src/mod/nss/cb_npc_bash.nss rename to src/module/nss/cb_npc_bash.nss diff --git a/src/mod/nss/cb_npc_chairsit.nss b/src/module/nss/cb_npc_chairsit.nss similarity index 100% rename from src/mod/nss/cb_npc_chairsit.nss rename to src/module/nss/cb_npc_chairsit.nss diff --git a/src/mod/nss/cb_npc_facedown.nss b/src/module/nss/cb_npc_facedown.nss similarity index 100% rename from src/mod/nss/cb_npc_facedown.nss rename to src/module/nss/cb_npc_facedown.nss diff --git a/src/mod/nss/cb_npc_meditate.nss b/src/module/nss/cb_npc_meditate.nss similarity index 100% rename from src/mod/nss/cb_npc_meditate.nss rename to src/module/nss/cb_npc_meditate.nss diff --git a/src/mod/nss/cb_npc_plead.nss b/src/module/nss/cb_npc_plead.nss similarity index 100% rename from src/mod/nss/cb_npc_plead.nss rename to src/module/nss/cb_npc_plead.nss diff --git a/src/mod/nss/cb_npc_read.nss b/src/module/nss/cb_npc_read.nss similarity index 100% rename from src/mod/nss/cb_npc_read.nss rename to src/module/nss/cb_npc_read.nss diff --git a/src/mod/nss/cb_npc_read2.nss b/src/module/nss/cb_npc_read2.nss similarity index 100% rename from src/mod/nss/cb_npc_read2.nss rename to src/module/nss/cb_npc_read2.nss diff --git a/src/mod/nss/cb_npc_saulte.nss b/src/module/nss/cb_npc_saulte.nss similarity index 100% rename from src/mod/nss/cb_npc_saulte.nss rename to src/module/nss/cb_npc_saulte.nss diff --git a/src/mod/nss/cb_npc_sitdown.nss b/src/module/nss/cb_npc_sitdown.nss similarity index 100% rename from src/mod/nss/cb_npc_sitdown.nss rename to src/module/nss/cb_npc_sitdown.nss diff --git a/src/mod/nss/cb_npc_sleep_hb.nss b/src/module/nss/cb_npc_sleep_hb.nss similarity index 100% rename from src/mod/nss/cb_npc_sleep_hb.nss rename to src/module/nss/cb_npc_sleep_hb.nss diff --git a/src/mod/nss/cb_npc_talkforce.nss b/src/module/nss/cb_npc_talkforce.nss similarity index 100% rename from src/mod/nss/cb_npc_talkforce.nss rename to src/module/nss/cb_npc_talkforce.nss diff --git a/src/mod/nss/cb_npcmeditat_hb.nss b/src/module/nss/cb_npcmeditat_hb.nss similarity index 100% rename from src/mod/nss/cb_npcmeditat_hb.nss rename to src/module/nss/cb_npcmeditat_hb.nss diff --git a/src/mod/nss/cb_npcsitchair.nss b/src/module/nss/cb_npcsitchair.nss similarity index 100% rename from src/mod/nss/cb_npcsitchair.nss rename to src/module/nss/cb_npcsitchair.nss diff --git a/src/mod/nss/cb_npcsitchair2.nss b/src/module/nss/cb_npcsitchair2.nss similarity index 100% rename from src/mod/nss/cb_npcsitchair2.nss rename to src/module/nss/cb_npcsitchair2.nss diff --git a/src/mod/nss/cb_npcsitchair3.nss b/src/module/nss/cb_npcsitchair3.nss similarity index 100% rename from src/mod/nss/cb_npcsitchair3.nss rename to src/module/nss/cb_npcsitchair3.nss diff --git a/src/mod/nss/cb_npcsitchair4.nss b/src/module/nss/cb_npcsitchair4.nss similarity index 100% rename from src/mod/nss/cb_npcsitchair4.nss rename to src/module/nss/cb_npcsitchair4.nss diff --git a/src/mod/nss/cb_npcworship_hb.nss b/src/module/nss/cb_npcworship_hb.nss similarity index 100% rename from src/mod/nss/cb_npcworship_hb.nss rename to src/module/nss/cb_npcworship_hb.nss diff --git a/src/mod/nss/cb_onunequip.nss b/src/module/nss/cb_onunequip.nss similarity index 100% rename from src/mod/nss/cb_onunequip.nss rename to src/module/nss/cb_onunequip.nss diff --git a/src/mod/nss/cb_orcdeath.nss b/src/module/nss/cb_orcdeath.nss similarity index 100% rename from src/mod/nss/cb_orcdeath.nss rename to src/module/nss/cb_orcdeath.nss diff --git a/src/mod/nss/cb_oz_chest.nss b/src/module/nss/cb_oz_chest.nss similarity index 100% rename from src/mod/nss/cb_oz_chest.nss rename to src/module/nss/cb_oz_chest.nss diff --git a/src/mod/nss/cb_oz_heart.nss b/src/module/nss/cb_oz_heart.nss similarity index 100% rename from src/mod/nss/cb_oz_heart.nss rename to src/module/nss/cb_oz_heart.nss diff --git a/src/mod/nss/cb_ozbook1.nss b/src/module/nss/cb_ozbook1.nss similarity index 100% rename from src/mod/nss/cb_ozbook1.nss rename to src/module/nss/cb_ozbook1.nss diff --git a/src/mod/nss/cb_ozbook2.nss b/src/module/nss/cb_ozbook2.nss similarity index 100% rename from src/mod/nss/cb_ozbook2.nss rename to src/module/nss/cb_ozbook2.nss diff --git a/src/mod/nss/cb_ozbook3.nss b/src/module/nss/cb_ozbook3.nss similarity index 100% rename from src/mod/nss/cb_ozbook3.nss rename to src/module/nss/cb_ozbook3.nss diff --git a/src/mod/nss/cb_ozbook4.nss b/src/module/nss/cb_ozbook4.nss similarity index 100% rename from src/mod/nss/cb_ozbook4.nss rename to src/module/nss/cb_ozbook4.nss diff --git a/src/mod/nss/cb_ozchk_1.nss b/src/module/nss/cb_ozchk_1.nss similarity index 100% rename from src/mod/nss/cb_ozchk_1.nss rename to src/module/nss/cb_ozchk_1.nss diff --git a/src/mod/nss/cb_ozchk_2.nss b/src/module/nss/cb_ozchk_2.nss similarity index 100% rename from src/mod/nss/cb_ozchk_2.nss rename to src/module/nss/cb_ozchk_2.nss diff --git a/src/mod/nss/cb_ozchk_3.nss b/src/module/nss/cb_ozchk_3.nss similarity index 100% rename from src/mod/nss/cb_ozchk_3.nss rename to src/module/nss/cb_ozchk_3.nss diff --git a/src/mod/nss/cb_ozchkrodsall.nss b/src/module/nss/cb_ozchkrodsall.nss similarity index 100% rename from src/mod/nss/cb_ozchkrodsall.nss rename to src/module/nss/cb_ozchkrodsall.nss diff --git a/src/mod/nss/cb_ozentervfx.nss b/src/module/nss/cb_ozentervfx.nss similarity index 100% rename from src/mod/nss/cb_ozentervfx.nss rename to src/module/nss/cb_ozentervfx.nss diff --git a/src/mod/nss/cb_ozglyph.nss b/src/module/nss/cb_ozglyph.nss similarity index 100% rename from src/mod/nss/cb_ozglyph.nss rename to src/module/nss/cb_ozglyph.nss diff --git a/src/mod/nss/cb_ozkill_01.nss b/src/module/nss/cb_ozkill_01.nss similarity index 100% rename from src/mod/nss/cb_ozkill_01.nss rename to src/module/nss/cb_ozkill_01.nss diff --git a/src/mod/nss/cb_ozparty.nss b/src/module/nss/cb_ozparty.nss similarity index 100% rename from src/mod/nss/cb_ozparty.nss rename to src/module/nss/cb_ozparty.nss diff --git a/src/mod/nss/cb_ozport_01.nss b/src/module/nss/cb_ozport_01.nss similarity index 100% rename from src/mod/nss/cb_ozport_01.nss rename to src/module/nss/cb_ozport_01.nss diff --git a/src/mod/nss/cb_ozport_33.nss b/src/module/nss/cb_ozport_33.nss similarity index 100% rename from src/mod/nss/cb_ozport_33.nss rename to src/module/nss/cb_ozport_33.nss diff --git a/src/mod/nss/cb_ozrod01.nss b/src/module/nss/cb_ozrod01.nss similarity index 100% rename from src/mod/nss/cb_ozrod01.nss rename to src/module/nss/cb_ozrod01.nss diff --git a/src/mod/nss/cb_ozrod03.nss b/src/module/nss/cb_ozrod03.nss similarity index 100% rename from src/mod/nss/cb_ozrod03.nss rename to src/module/nss/cb_ozrod03.nss diff --git a/src/mod/nss/cb_ozrodblue.nss b/src/module/nss/cb_ozrodblue.nss similarity index 100% rename from src/mod/nss/cb_ozrodblue.nss rename to src/module/nss/cb_ozrodblue.nss diff --git a/src/mod/nss/cb_pally_01.nss b/src/module/nss/cb_pally_01.nss similarity index 100% rename from src/mod/nss/cb_pally_01.nss rename to src/module/nss/cb_pally_01.nss diff --git a/src/mod/nss/cb_part_cain.nss b/src/module/nss/cb_part_cain.nss similarity index 100% rename from src/mod/nss/cb_part_cain.nss rename to src/module/nss/cb_part_cain.nss diff --git a/src/mod/nss/cb_passout.nss b/src/module/nss/cb_passout.nss similarity index 100% rename from src/mod/nss/cb_passout.nss rename to src/module/nss/cb_passout.nss diff --git a/src/mod/nss/cb_perc_orc.nss b/src/module/nss/cb_perc_orc.nss similarity index 100% rename from src/mod/nss/cb_perc_orc.nss rename to src/module/nss/cb_perc_orc.nss diff --git a/src/mod/nss/cb_perc_orc2.nss b/src/module/nss/cb_perc_orc2.nss similarity index 100% rename from src/mod/nss/cb_perc_orc2.nss rename to src/module/nss/cb_perc_orc2.nss diff --git a/src/mod/nss/cb_perc_orc3.nss b/src/module/nss/cb_perc_orc3.nss similarity index 100% rename from src/mod/nss/cb_perc_orc3.nss rename to src/module/nss/cb_perc_orc3.nss diff --git a/src/mod/nss/cb_perc_test.nss b/src/module/nss/cb_perc_test.nss similarity index 100% rename from src/mod/nss/cb_perc_test.nss rename to src/module/nss/cb_perc_test.nss diff --git a/src/mod/nss/cb_port_trin.nss b/src/module/nss/cb_port_trin.nss similarity index 100% rename from src/mod/nss/cb_port_trin.nss rename to src/module/nss/cb_port_trin.nss diff --git a/src/mod/nss/cb_portevil.nss b/src/module/nss/cb_portevil.nss similarity index 100% rename from src/mod/nss/cb_portevil.nss rename to src/module/nss/cb_portevil.nss diff --git a/src/mod/nss/cb_portevil2.nss b/src/module/nss/cb_portevil2.nss similarity index 100% rename from src/mod/nss/cb_portevil2.nss rename to src/module/nss/cb_portevil2.nss diff --git a/src/mod/nss/cb_portgood.nss b/src/module/nss/cb_portgood.nss similarity index 100% rename from src/mod/nss/cb_portgood.nss rename to src/module/nss/cb_portgood.nss diff --git a/src/mod/nss/cb_portgood2.nss b/src/module/nss/cb_portgood2.nss similarity index 100% rename from src/mod/nss/cb_portgood2.nss rename to src/module/nss/cb_portgood2.nss diff --git a/src/mod/nss/cb_pvp_chkitems.nss b/src/module/nss/cb_pvp_chkitems.nss similarity index 100% rename from src/mod/nss/cb_pvp_chkitems.nss rename to src/module/nss/cb_pvp_chkitems.nss diff --git a/src/mod/nss/cb_pvp_hb.nss b/src/module/nss/cb_pvp_hb.nss similarity index 100% rename from src/mod/nss/cb_pvp_hb.nss rename to src/module/nss/cb_pvp_hb.nss diff --git a/src/mod/nss/cb_pvp_portback.nss b/src/module/nss/cb_pvp_portback.nss similarity index 100% rename from src/mod/nss/cb_pvp_portback.nss rename to src/module/nss/cb_pvp_portback.nss diff --git a/src/mod/nss/cb_pvpexit.nss b/src/module/nss/cb_pvpexit.nss similarity index 100% rename from src/mod/nss/cb_pvpexit.nss rename to src/module/nss/cb_pvpexit.nss diff --git a/src/mod/nss/cb_pvpexit2.nss b/src/module/nss/cb_pvpexit2.nss similarity index 100% rename from src/mod/nss/cb_pvpexit2.nss rename to src/module/nss/cb_pvpexit2.nss diff --git a/src/mod/nss/cb_pvptoken.nss b/src/module/nss/cb_pvptoken.nss similarity index 100% rename from src/mod/nss/cb_pvptoken.nss rename to src/module/nss/cb_pvptoken.nss diff --git a/src/mod/nss/cb_pvptoken2.nss b/src/module/nss/cb_pvptoken2.nss similarity index 100% rename from src/mod/nss/cb_pvptoken2.nss rename to src/module/nss/cb_pvptoken2.nss diff --git a/src/mod/nss/cb_questchk_1.nss b/src/module/nss/cb_questchk_1.nss similarity index 100% rename from src/mod/nss/cb_questchk_1.nss rename to src/module/nss/cb_questchk_1.nss diff --git a/src/mod/nss/cb_ranger_r.nss b/src/module/nss/cb_ranger_r.nss similarity index 100% rename from src/mod/nss/cb_ranger_r.nss rename to src/module/nss/cb_ranger_r.nss diff --git a/src/mod/nss/cb_ranger_w.nss b/src/module/nss/cb_ranger_w.nss similarity index 100% rename from src/mod/nss/cb_ranger_w.nss rename to src/module/nss/cb_ranger_w.nss diff --git a/src/mod/nss/cb_reb_monk15.nss b/src/module/nss/cb_reb_monk15.nss similarity index 100% rename from src/mod/nss/cb_reb_monk15.nss rename to src/module/nss/cb_reb_monk15.nss diff --git a/src/mod/nss/cb_reb_party.nss b/src/module/nss/cb_reb_party.nss similarity index 100% rename from src/mod/nss/cb_reb_party.nss rename to src/module/nss/cb_reb_party.nss diff --git a/src/mod/nss/cb_reb_partyport.nss b/src/module/nss/cb_reb_partyport.nss similarity index 100% rename from src/mod/nss/cb_reb_partyport.nss rename to src/module/nss/cb_reb_partyport.nss diff --git a/src/mod/nss/cb_reb_percieve.nss b/src/module/nss/cb_reb_percieve.nss similarity index 100% rename from src/mod/nss/cb_reb_percieve.nss rename to src/module/nss/cb_reb_percieve.nss diff --git a/src/mod/nss/cb_reb_reborn.nss b/src/module/nss/cb_reb_reborn.nss similarity index 100% rename from src/mod/nss/cb_reb_reborn.nss rename to src/module/nss/cb_reb_reborn.nss diff --git a/src/mod/nss/cb_reb_trust.nss b/src/module/nss/cb_reb_trust.nss similarity index 100% rename from src/mod/nss/cb_reb_trust.nss rename to src/module/nss/cb_reb_trust.nss diff --git a/src/mod/nss/cb_reb_vfx.nss b/src/module/nss/cb_reb_vfx.nss similarity index 100% rename from src/mod/nss/cb_reb_vfx.nss rename to src/module/nss/cb_reb_vfx.nss diff --git a/src/mod/nss/cb_rebalter.nss b/src/module/nss/cb_rebalter.nss similarity index 100% rename from src/mod/nss/cb_rebalter.nss rename to src/module/nss/cb_rebalter.nss diff --git a/src/mod/nss/cb_rebkill.nss b/src/module/nss/cb_rebkill.nss similarity index 100% rename from src/mod/nss/cb_rebkill.nss rename to src/module/nss/cb_rebkill.nss diff --git a/src/mod/nss/cb_rebornenter.nss b/src/module/nss/cb_rebornenter.nss similarity index 100% rename from src/mod/nss/cb_rebornenter.nss rename to src/module/nss/cb_rebornenter.nss diff --git a/src/mod/nss/cb_rebspawn.nss b/src/module/nss/cb_rebspawn.nss similarity index 100% rename from src/mod/nss/cb_rebspawn.nss rename to src/module/nss/cb_rebspawn.nss diff --git a/src/mod/nss/cb_regate.nss b/src/module/nss/cb_regate.nss similarity index 100% rename from src/mod/nss/cb_regate.nss rename to src/module/nss/cb_regate.nss diff --git a/src/mod/nss/cb_repentpally.nss b/src/module/nss/cb_repentpally.nss similarity index 100% rename from src/mod/nss/cb_repentpally.nss rename to src/module/nss/cb_repentpally.nss diff --git a/src/mod/nss/cb_repentpally2.nss b/src/module/nss/cb_repentpally2.nss similarity index 100% rename from src/mod/nss/cb_repentpally2.nss rename to src/module/nss/cb_repentpally2.nss diff --git a/src/mod/nss/cb_reward_1000xp.nss b/src/module/nss/cb_reward_1000xp.nss similarity index 100% rename from src/mod/nss/cb_reward_1000xp.nss rename to src/module/nss/cb_reward_1000xp.nss diff --git a/src/mod/nss/cb_reward_1500.nss b/src/module/nss/cb_reward_1500.nss similarity index 100% rename from src/mod/nss/cb_reward_1500.nss rename to src/module/nss/cb_reward_1500.nss diff --git a/src/mod/nss/cb_reward_500.nss b/src/module/nss/cb_reward_500.nss similarity index 100% rename from src/mod/nss/cb_reward_500.nss rename to src/module/nss/cb_reward_500.nss diff --git a/src/mod/nss/cb_reward_500xp.nss b/src/module/nss/cb_reward_500xp.nss similarity index 100% rename from src/mod/nss/cb_reward_500xp.nss rename to src/module/nss/cb_reward_500xp.nss diff --git a/src/mod/nss/cb_rune1.nss b/src/module/nss/cb_rune1.nss similarity index 100% rename from src/mod/nss/cb_rune1.nss rename to src/module/nss/cb_rune1.nss diff --git a/src/mod/nss/cb_rune2.nss b/src/module/nss/cb_rune2.nss similarity index 100% rename from src/mod/nss/cb_rune2.nss rename to src/module/nss/cb_rune2.nss diff --git a/src/mod/nss/cb_runevis.nss b/src/module/nss/cb_runevis.nss similarity index 100% rename from src/mod/nss/cb_runevis.nss rename to src/module/nss/cb_runevis.nss diff --git a/src/mod/nss/cb_setshogun.nss b/src/module/nss/cb_setshogun.nss similarity index 100% rename from src/mod/nss/cb_setshogun.nss rename to src/module/nss/cb_setshogun.nss diff --git a/src/mod/nss/cb_shogunreward.nss b/src/module/nss/cb_shogunreward.nss similarity index 100% rename from src/mod/nss/cb_shogunreward.nss rename to src/module/nss/cb_shogunreward.nss diff --git a/src/mod/nss/cb_shokey.nss b/src/module/nss/cb_shokey.nss similarity index 100% rename from src/mod/nss/cb_shokey.nss rename to src/module/nss/cb_shokey.nss diff --git a/src/mod/nss/cb_shokey2.nss b/src/module/nss/cb_shokey2.nss similarity index 100% rename from src/mod/nss/cb_shokey2.nss rename to src/module/nss/cb_shokey2.nss diff --git a/src/mod/nss/cb_snowport.nss b/src/module/nss/cb_snowport.nss similarity index 100% rename from src/mod/nss/cb_snowport.nss rename to src/module/nss/cb_snowport.nss diff --git a/src/mod/nss/cb_spawn_ambient.nss b/src/module/nss/cb_spawn_ambient.nss similarity index 100% rename from src/mod/nss/cb_spawn_ambient.nss rename to src/module/nss/cb_spawn_ambient.nss diff --git a/src/mod/nss/cb_spawn_reb.nss b/src/module/nss/cb_spawn_reb.nss similarity index 100% rename from src/mod/nss/cb_spawn_reb.nss rename to src/module/nss/cb_spawn_reb.nss diff --git a/src/mod/nss/cb_spawn_search.nss b/src/module/nss/cb_spawn_search.nss similarity index 100% rename from src/mod/nss/cb_spawn_search.nss rename to src/module/nss/cb_spawn_search.nss diff --git a/src/mod/nss/cb_spawn_voice.nss b/src/module/nss/cb_spawn_voice.nss similarity index 100% rename from src/mod/nss/cb_spawn_voice.nss rename to src/module/nss/cb_spawn_voice.nss diff --git a/src/mod/nss/cb_spawn_yield.nss b/src/module/nss/cb_spawn_yield.nss similarity index 100% rename from src/mod/nss/cb_spawn_yield.nss rename to src/module/nss/cb_spawn_yield.nss diff --git a/src/mod/nss/cb_spawncain.nss b/src/module/nss/cb_spawncain.nss similarity index 100% rename from src/mod/nss/cb_spawncain.nss rename to src/module/nss/cb_spawncain.nss diff --git a/src/mod/nss/cb_spawnkidding.nss b/src/module/nss/cb_spawnkidding.nss similarity index 100% rename from src/mod/nss/cb_spawnkidding.nss rename to src/module/nss/cb_spawnkidding.nss diff --git a/src/mod/nss/cb_spawnmonks.nss b/src/module/nss/cb_spawnmonks.nss similarity index 100% rename from src/mod/nss/cb_spawnmonks.nss rename to src/module/nss/cb_spawnmonks.nss diff --git a/src/mod/nss/cb_start_bar.nss b/src/module/nss/cb_start_bar.nss similarity index 100% rename from src/mod/nss/cb_start_bar.nss rename to src/module/nss/cb_start_bar.nss diff --git a/src/mod/nss/cb_startmax.nss b/src/module/nss/cb_startmax.nss similarity index 100% rename from src/mod/nss/cb_startmax.nss rename to src/module/nss/cb_startmax.nss diff --git a/src/mod/nss/cb_takebow.nss b/src/module/nss/cb_takebow.nss similarity index 100% rename from src/mod/nss/cb_takebow.nss rename to src/module/nss/cb_takebow.nss diff --git a/src/mod/nss/cb_tke_25k.nss b/src/module/nss/cb_tke_25k.nss similarity index 100% rename from src/mod/nss/cb_tke_25k.nss rename to src/module/nss/cb_tke_25k.nss diff --git a/src/mod/nss/cb_tke_acidion.nss b/src/module/nss/cb_tke_acidion.nss similarity index 100% rename from src/mod/nss/cb_tke_acidion.nss rename to src/module/nss/cb_tke_acidion.nss diff --git a/src/mod/nss/cb_tke_allplans.nss b/src/module/nss/cb_tke_allplans.nss similarity index 100% rename from src/mod/nss/cb_tke_allplans.nss rename to src/module/nss/cb_tke_allplans.nss diff --git a/src/mod/nss/cb_tke_bookn.nss b/src/module/nss/cb_tke_bookn.nss similarity index 100% rename from src/mod/nss/cb_tke_bookn.nss rename to src/module/nss/cb_tke_bookn.nss diff --git a/src/mod/nss/cb_tke_dickie.nss b/src/module/nss/cb_tke_dickie.nss similarity index 100% rename from src/mod/nss/cb_tke_dickie.nss rename to src/module/nss/cb_tke_dickie.nss diff --git a/src/mod/nss/cb_tke_dragener.nss b/src/module/nss/cb_tke_dragener.nss similarity index 100% rename from src/mod/nss/cb_tke_dragener.nss rename to src/module/nss/cb_tke_dragener.nss diff --git a/src/mod/nss/cb_tke_drownoble.nss b/src/module/nss/cb_tke_drownoble.nss similarity index 100% rename from src/mod/nss/cb_tke_drownoble.nss rename to src/module/nss/cb_tke_drownoble.nss diff --git a/src/mod/nss/cb_tke_evilorb.nss b/src/module/nss/cb_tke_evilorb.nss similarity index 100% rename from src/mod/nss/cb_tke_evilorb.nss rename to src/module/nss/cb_tke_evilorb.nss diff --git a/src/mod/nss/cb_tke_gemtool.nss b/src/module/nss/cb_tke_gemtool.nss similarity index 100% rename from src/mod/nss/cb_tke_gemtool.nss rename to src/module/nss/cb_tke_gemtool.nss diff --git a/src/mod/nss/cb_tke_goodorb.nss b/src/module/nss/cb_tke_goodorb.nss similarity index 100% rename from src/mod/nss/cb_tke_goodorb.nss rename to src/module/nss/cb_tke_goodorb.nss diff --git a/src/mod/nss/cb_tke_grail.nss b/src/module/nss/cb_tke_grail.nss similarity index 100% rename from src/mod/nss/cb_tke_grail.nss rename to src/module/nss/cb_tke_grail.nss diff --git a/src/mod/nss/cb_tke_horn.nss b/src/module/nss/cb_tke_horn.nss similarity index 100% rename from src/mod/nss/cb_tke_horn.nss rename to src/module/nss/cb_tke_horn.nss diff --git a/src/mod/nss/cb_tke_jimkey.nss b/src/module/nss/cb_tke_jimkey.nss similarity index 100% rename from src/mod/nss/cb_tke_jimkey.nss rename to src/module/nss/cb_tke_jimkey.nss diff --git a/src/mod/nss/cb_tke_lgrial.nss b/src/module/nss/cb_tke_lgrial.nss similarity index 100% rename from src/mod/nss/cb_tke_lgrial.nss rename to src/module/nss/cb_tke_lgrial.nss diff --git a/src/mod/nss/cb_tke_lstaff.nss b/src/module/nss/cb_tke_lstaff.nss similarity index 100% rename from src/mod/nss/cb_tke_lstaff.nss rename to src/module/nss/cb_tke_lstaff.nss diff --git a/src/mod/nss/cb_tke_mahead.nss b/src/module/nss/cb_tke_mahead.nss similarity index 100% rename from src/mod/nss/cb_tke_mahead.nss rename to src/module/nss/cb_tke_mahead.nss diff --git a/src/mod/nss/cb_tke_mug.nss b/src/module/nss/cb_tke_mug.nss similarity index 100% rename from src/mod/nss/cb_tke_mug.nss rename to src/module/nss/cb_tke_mug.nss diff --git a/src/mod/nss/cb_tke_ore.nss b/src/module/nss/cb_tke_ore.nss similarity index 100% rename from src/mod/nss/cb_tke_ore.nss rename to src/module/nss/cb_tke_ore.nss diff --git a/src/mod/nss/cb_tke_ozrods.nss b/src/module/nss/cb_tke_ozrods.nss similarity index 100% rename from src/mod/nss/cb_tke_ozrods.nss rename to src/module/nss/cb_tke_ozrods.nss diff --git a/src/mod/nss/cb_tke_serum.nss b/src/module/nss/cb_tke_serum.nss similarity index 100% rename from src/mod/nss/cb_tke_serum.nss rename to src/module/nss/cb_tke_serum.nss diff --git a/src/mod/nss/cb_tke_taghead.nss b/src/module/nss/cb_tke_taghead.nss similarity index 100% rename from src/mod/nss/cb_tke_taghead.nss rename to src/module/nss/cb_tke_taghead.nss diff --git a/src/mod/nss/cb_tke_tmbattle.nss b/src/module/nss/cb_tke_tmbattle.nss similarity index 100% rename from src/mod/nss/cb_tke_tmbattle.nss rename to src/module/nss/cb_tke_tmbattle.nss diff --git a/src/mod/nss/cb_tke_yoga.nss b/src/module/nss/cb_tke_yoga.nss similarity index 100% rename from src/mod/nss/cb_tke_yoga.nss rename to src/module/nss/cb_tke_yoga.nss diff --git a/src/mod/nss/cb_traner1.nss b/src/module/nss/cb_traner1.nss similarity index 100% rename from src/mod/nss/cb_traner1.nss rename to src/module/nss/cb_traner1.nss diff --git a/src/mod/nss/cb_trapstore.nss b/src/module/nss/cb_trapstore.nss similarity index 100% rename from src/mod/nss/cb_trapstore.nss rename to src/module/nss/cb_trapstore.nss diff --git a/src/mod/nss/cb_updates.nss b/src/module/nss/cb_updates.nss similarity index 100% rename from src/mod/nss/cb_updates.nss rename to src/module/nss/cb_updates.nss diff --git a/src/mod/nss/cb_vis_cain.nss b/src/module/nss/cb_vis_cain.nss similarity index 100% rename from src/mod/nss/cb_vis_cain.nss rename to src/module/nss/cb_vis_cain.nss diff --git a/src/mod/nss/cb_vis_cloak.nss b/src/module/nss/cb_vis_cloak.nss similarity index 100% rename from src/mod/nss/cb_vis_cloak.nss rename to src/module/nss/cb_vis_cloak.nss diff --git a/src/mod/nss/cb_vis_dragenerg.nss b/src/module/nss/cb_vis_dragenerg.nss similarity index 100% rename from src/mod/nss/cb_vis_dragenerg.nss rename to src/module/nss/cb_vis_dragenerg.nss diff --git a/src/mod/nss/cb_vis_effect.nss b/src/module/nss/cb_vis_effect.nss similarity index 100% rename from src/mod/nss/cb_vis_effect.nss rename to src/module/nss/cb_vis_effect.nss diff --git a/src/mod/nss/cb_vis_lith.nss b/src/module/nss/cb_vis_lith.nss similarity index 100% rename from src/mod/nss/cb_vis_lith.nss rename to src/module/nss/cb_vis_lith.nss diff --git a/src/mod/nss/cb_vis_monk.nss b/src/module/nss/cb_vis_monk.nss similarity index 100% rename from src/mod/nss/cb_vis_monk.nss rename to src/module/nss/cb_vis_monk.nss diff --git a/src/mod/nss/cb_vis_pally.nss b/src/module/nss/cb_vis_pally.nss similarity index 100% rename from src/mod/nss/cb_vis_pally.nss rename to src/module/nss/cb_vis_pally.nss diff --git a/src/mod/nss/cb_vis_reb2.nss b/src/module/nss/cb_vis_reb2.nss similarity index 100% rename from src/mod/nss/cb_vis_reb2.nss rename to src/module/nss/cb_vis_reb2.nss diff --git a/src/mod/nss/cb_vis_test.nss b/src/module/nss/cb_vis_test.nss similarity index 100% rename from src/mod/nss/cb_vis_test.nss rename to src/module/nss/cb_vis_test.nss diff --git a/src/mod/nss/cb_vis_used.nss b/src/module/nss/cb_vis_used.nss similarity index 100% rename from src/mod/nss/cb_vis_used.nss rename to src/module/nss/cb_vis_used.nss diff --git a/src/mod/nss/cb_welcome.nss b/src/module/nss/cb_welcome.nss similarity index 100% rename from src/mod/nss/cb_welcome.nss rename to src/module/nss/cb_welcome.nss diff --git a/src/mod/nss/cb_wellport.nss b/src/module/nss/cb_wellport.nss similarity index 100% rename from src/mod/nss/cb_wellport.nss rename to src/module/nss/cb_wellport.nss diff --git a/src/mod/nss/cb_x2_per_reb.nss b/src/module/nss/cb_x2_per_reb.nss similarity index 100% rename from src/mod/nss/cb_x2_per_reb.nss rename to src/module/nss/cb_x2_per_reb.nss diff --git a/src/mod/nss/cb_x2_percasy.nss b/src/module/nss/cb_x2_percasy.nss similarity index 100% rename from src/mod/nss/cb_x2_percasy.nss rename to src/module/nss/cb_x2_percasy.nss diff --git a/src/mod/nss/cb_x2_percieve.nss b/src/module/nss/cb_x2_percieve.nss similarity index 100% rename from src/mod/nss/cb_x2_percieve.nss rename to src/module/nss/cb_x2_percieve.nss diff --git a/src/mod/nss/cb_x2_percieve2.nss b/src/module/nss/cb_x2_percieve2.nss similarity index 100% rename from src/mod/nss/cb_x2_percieve2.nss rename to src/module/nss/cb_x2_percieve2.nss diff --git a/src/mod/nss/cb_x2_percieve3.nss b/src/module/nss/cb_x2_percieve3.nss similarity index 100% rename from src/mod/nss/cb_x2_percieve3.nss rename to src/module/nss/cb_x2_percieve3.nss diff --git a/src/mod/nss/cb_x2_percieve4.nss b/src/module/nss/cb_x2_percieve4.nss similarity index 100% rename from src/mod/nss/cb_x2_percieve4.nss rename to src/module/nss/cb_x2_percieve4.nss diff --git a/src/mod/nss/cb_x2_search.nss b/src/module/nss/cb_x2_search.nss similarity index 100% rename from src/mod/nss/cb_x2_search.nss rename to src/module/nss/cb_x2_search.nss diff --git a/src/mod/nss/cb_yield.nss b/src/module/nss/cb_yield.nss similarity index 100% rename from src/mod/nss/cb_yield.nss rename to src/module/nss/cb_yield.nss diff --git a/src/mod/nss/cb_yield_attack.nss b/src/module/nss/cb_yield_attack.nss similarity index 100% rename from src/mod/nss/cb_yield_attack.nss rename to src/module/nss/cb_yield_attack.nss diff --git a/src/mod/nss/chair_sit.nss b/src/module/nss/chair_sit.nss similarity index 100% rename from src/mod/nss/chair_sit.nss rename to src/module/nss/chair_sit.nss diff --git a/src/mod/nss/clan_death.nss b/src/module/nss/clan_death.nss similarity index 100% rename from src/mod/nss/clan_death.nss rename to src/module/nss/clan_death.nss diff --git a/src/mod/nss/clan_death_02.nss b/src/module/nss/clan_death_02.nss similarity index 100% rename from src/mod/nss/clan_death_02.nss rename to src/module/nss/clan_death_02.nss diff --git a/src/mod/nss/clean_store.nss b/src/module/nss/clean_store.nss similarity index 100% rename from src/mod/nss/clean_store.nss rename to src/module/nss/clean_store.nss diff --git a/src/mod/nss/cloakpotion.nss b/src/module/nss/cloakpotion.nss similarity index 100% rename from src/mod/nss/cloakpotion.nss rename to src/module/nss/cloakpotion.nss diff --git a/src/mod/nss/close_field1.nss b/src/module/nss/close_field1.nss similarity index 100% rename from src/mod/nss/close_field1.nss rename to src/module/nss/close_field1.nss diff --git a/src/mod/nss/close_field2.nss b/src/module/nss/close_field2.nss similarity index 100% rename from src/mod/nss/close_field2.nss rename to src/module/nss/close_field2.nss diff --git a/src/mod/nss/close_field3.nss b/src/module/nss/close_field3.nss similarity index 100% rename from src/mod/nss/close_field3.nss rename to src/module/nss/close_field3.nss diff --git a/src/mod/nss/close_field4.nss b/src/module/nss/close_field4.nss similarity index 100% rename from src/mod/nss/close_field4.nss rename to src/module/nss/close_field4.nss diff --git a/src/mod/nss/close_field5.nss b/src/module/nss/close_field5.nss similarity index 100% rename from src/mod/nss/close_field5.nss rename to src/module/nss/close_field5.nss diff --git a/src/mod/nss/close_field6.nss b/src/module/nss/close_field6.nss similarity index 100% rename from src/mod/nss/close_field6.nss rename to src/module/nss/close_field6.nss diff --git a/src/mod/nss/closedoors.nss b/src/module/nss/closedoors.nss similarity index 100% rename from src/mod/nss/closedoors.nss rename to src/module/nss/closedoors.nss diff --git a/src/mod/nss/cn_npc_read.nss b/src/module/nss/cn_npc_read.nss similarity index 100% rename from src/mod/nss/cn_npc_read.nss rename to src/module/nss/cn_npc_read.nss diff --git a/src/mod/nss/cold_trap_enter.nss b/src/module/nss/cold_trap_enter.nss similarity index 100% rename from src/mod/nss/cold_trap_enter.nss rename to src/module/nss/cold_trap_enter.nss diff --git a/src/mod/nss/conv_atlantis_p2.nss b/src/module/nss/conv_atlantis_p2.nss similarity index 100% rename from src/mod/nss/conv_atlantis_p2.nss rename to src/module/nss/conv_atlantis_p2.nss diff --git a/src/mod/nss/conv_bvgrd_rndm1.nss b/src/module/nss/conv_bvgrd_rndm1.nss similarity index 100% rename from src/mod/nss/conv_bvgrd_rndm1.nss rename to src/module/nss/conv_bvgrd_rndm1.nss diff --git a/src/mod/nss/conv_bvgrd_rndm2.nss b/src/module/nss/conv_bvgrd_rndm2.nss similarity index 100% rename from src/mod/nss/conv_bvgrd_rndm2.nss rename to src/module/nss/conv_bvgrd_rndm2.nss diff --git a/src/mod/nss/council_gve_writ.nss b/src/module/nss/council_gve_writ.nss similarity index 100% rename from src/mod/nss/council_gve_writ.nss rename to src/module/nss/council_gve_writ.nss diff --git a/src/mod/nss/council_on_enter.nss b/src/module/nss/council_on_enter.nss similarity index 100% rename from src/mod/nss/council_on_enter.nss rename to src/module/nss/council_on_enter.nss diff --git a/src/mod/nss/council_port.nss b/src/module/nss/council_port.nss similarity index 100% rename from src/mod/nss/council_port.nss rename to src/module/nss/council_port.nss diff --git a/src/mod/nss/council_rndm1.nss b/src/module/nss/council_rndm1.nss similarity index 100% rename from src/mod/nss/council_rndm1.nss rename to src/module/nss/council_rndm1.nss diff --git a/src/mod/nss/council_sit.nss b/src/module/nss/council_sit.nss similarity index 100% rename from src/mod/nss/council_sit.nss rename to src/module/nss/council_sit.nss diff --git a/src/mod/nss/cs_canbuysand.nss b/src/module/nss/cs_canbuysand.nss similarity index 100% rename from src/mod/nss/cs_canbuysand.nss rename to src/module/nss/cs_canbuysand.nss diff --git a/src/mod/nss/cs_d_hasstolen.nss b/src/module/nss/cs_d_hasstolen.nss similarity index 100% rename from src/mod/nss/cs_d_hasstolen.nss rename to src/module/nss/cs_d_hasstolen.nss diff --git a/src/mod/nss/cs_debugoff.nss b/src/module/nss/cs_debugoff.nss similarity index 100% rename from src/mod/nss/cs_debugoff.nss rename to src/module/nss/cs_debugoff.nss diff --git a/src/mod/nss/cs_debugon.nss b/src/module/nss/cs_debugon.nss similarity index 100% rename from src/mod/nss/cs_debugon.nss rename to src/module/nss/cs_debugon.nss diff --git a/src/mod/nss/cs_dmareatrigger.nss b/src/module/nss/cs_dmareatrigger.nss similarity index 100% rename from src/mod/nss/cs_dmareatrigger.nss rename to src/module/nss/cs_dmareatrigger.nss diff --git a/src/mod/nss/cs_invul_toggle.nss b/src/module/nss/cs_invul_toggle.nss similarity index 100% rename from src/mod/nss/cs_invul_toggle.nss rename to src/module/nss/cs_invul_toggle.nss diff --git a/src/mod/nss/cs_loot_high.nss b/src/module/nss/cs_loot_high.nss similarity index 100% rename from src/mod/nss/cs_loot_high.nss rename to src/module/nss/cs_loot_high.nss diff --git a/src/mod/nss/cs_loot_low.nss b/src/module/nss/cs_loot_low.nss similarity index 100% rename from src/mod/nss/cs_loot_low.nss rename to src/module/nss/cs_loot_low.nss diff --git a/src/mod/nss/cs_loot_med.nss b/src/module/nss/cs_loot_med.nss similarity index 100% rename from src/mod/nss/cs_loot_med.nss rename to src/module/nss/cs_loot_med.nss diff --git a/src/mod/nss/cs_loot_monster.nss b/src/module/nss/cs_loot_monster.nss similarity index 100% rename from src/mod/nss/cs_loot_monster.nss rename to src/module/nss/cs_loot_monster.nss diff --git a/src/mod/nss/cs_loot_unique.nss b/src/module/nss/cs_loot_unique.nss similarity index 100% rename from src/mod/nss/cs_loot_unique.nss rename to src/module/nss/cs_loot_unique.nss diff --git a/src/mod/nss/cs_misc_function.nss b/src/module/nss/cs_misc_function.nss similarity index 100% rename from src/mod/nss/cs_misc_function.nss rename to src/module/nss/cs_misc_function.nss diff --git a/src/mod/nss/cs_pctostone.nss b/src/module/nss/cs_pctostone.nss similarity index 100% rename from src/mod/nss/cs_pctostone.nss rename to src/module/nss/cs_pctostone.nss diff --git a/src/mod/nss/cs_port2appraise.nss b/src/module/nss/cs_port2appraise.nss similarity index 100% rename from src/mod/nss/cs_port2appraise.nss rename to src/module/nss/cs_port2appraise.nss diff --git a/src/mod/nss/cs_port2lwrcaves.nss b/src/module/nss/cs_port2lwrcaves.nss similarity index 100% rename from src/mod/nss/cs_port2lwrcaves.nss rename to src/module/nss/cs_port2lwrcaves.nss diff --git a/src/mod/nss/cs_port2trinity.nss b/src/module/nss/cs_port2trinity.nss similarity index 100% rename from src/mod/nss/cs_port2trinity.nss rename to src/module/nss/cs_port2trinity.nss diff --git a/src/mod/nss/cs_resetpcitems.nss b/src/module/nss/cs_resetpcitems.nss similarity index 100% rename from src/mod/nss/cs_resetpcitems.nss rename to src/module/nss/cs_resetpcitems.nss diff --git a/src/mod/nss/cs_serverreset.nss b/src/module/nss/cs_serverreset.nss similarity index 100% rename from src/mod/nss/cs_serverreset.nss rename to src/module/nss/cs_serverreset.nss diff --git a/src/mod/nss/cs_symbolofmight.nss b/src/module/nss/cs_symbolofmight.nss similarity index 100% rename from src/mod/nss/cs_symbolofmight.nss rename to src/module/nss/cs_symbolofmight.nss diff --git a/src/mod/nss/cs_takegold.nss b/src/module/nss/cs_takegold.nss similarity index 100% rename from src/mod/nss/cs_takegold.nss rename to src/module/nss/cs_takegold.nss diff --git a/src/mod/nss/cv_inn_door.nss b/src/module/nss/cv_inn_door.nss similarity index 100% rename from src/mod/nss/cv_inn_door.nss rename to src/module/nss/cv_inn_door.nss diff --git a/src/mod/nss/damage_statue.nss b/src/module/nss/damage_statue.nss similarity index 100% rename from src/mod/nss/damage_statue.nss rename to src/module/nss/damage_statue.nss diff --git a/src/mod/nss/darth_death.nss b/src/module/nss/darth_death.nss similarity index 100% rename from src/mod/nss/darth_death.nss rename to src/module/nss/darth_death.nss diff --git a/src/mod/nss/dexring_gen.nss b/src/module/nss/dexring_gen.nss similarity index 100% rename from src/mod/nss/dexring_gen.nss rename to src/module/nss/dexring_gen.nss diff --git a/src/mod/nss/dm_throne.nss b/src/module/nss/dm_throne.nss similarity index 100% rename from src/mod/nss/dm_throne.nss rename to src/module/nss/dm_throne.nss diff --git a/src/mod/nss/dmc_containergen.nss b/src/module/nss/dmc_containergen.nss similarity index 100% rename from src/mod/nss/dmc_containergen.nss rename to src/module/nss/dmc_containergen.nss diff --git a/src/mod/nss/dmc_inc_array.nss b/src/module/nss/dmc_inc_array.nss similarity index 100% rename from src/mod/nss/dmc_inc_array.nss rename to src/module/nss/dmc_inc_array.nss diff --git a/src/mod/nss/dmc_inc_contgen.nss b/src/module/nss/dmc_inc_contgen.nss similarity index 100% rename from src/mod/nss/dmc_inc_contgen.nss rename to src/module/nss/dmc_inc_contgen.nss diff --git a/src/mod/nss/dmc_inc_copyfunc.nss b/src/module/nss/dmc_inc_copyfunc.nss similarity index 100% rename from src/mod/nss/dmc_inc_copyfunc.nss rename to src/module/nss/dmc_inc_copyfunc.nss diff --git a/src/mod/nss/dmshelper.nss b/src/module/nss/dmshelper.nss similarity index 100% rename from src/mod/nss/dmshelper.nss rename to src/module/nss/dmshelper.nss diff --git a/src/mod/nss/doorforceunlocdc.nss b/src/module/nss/doorforceunlocdc.nss similarity index 100% rename from src/mod/nss/doorforceunlocdc.nss rename to src/module/nss/doorforceunlocdc.nss diff --git a/src/mod/nss/dracula_death.nss b/src/module/nss/dracula_death.nss similarity index 100% rename from src/mod/nss/dracula_death.nss rename to src/module/nss/dracula_death.nss diff --git a/src/mod/nss/dreamcatcher.nss b/src/module/nss/dreamcatcher.nss similarity index 100% rename from src/mod/nss/dreamcatcher.nss rename to src/module/nss/dreamcatcher.nss diff --git a/src/mod/nss/drink_n_explode3.nss b/src/module/nss/drink_n_explode3.nss similarity index 100% rename from src/mod/nss/drink_n_explode3.nss rename to src/module/nss/drink_n_explode3.nss diff --git a/src/mod/nss/elec_trap_enter.nss b/src/module/nss/elec_trap_enter.nss similarity index 100% rename from src/mod/nss/elec_trap_enter.nss rename to src/module/nss/elec_trap_enter.nss diff --git a/src/mod/nss/elrie_stat_trig.nss b/src/module/nss/elrie_stat_trig.nss similarity index 100% rename from src/mod/nss/elrie_stat_trig.nss rename to src/module/nss/elrie_stat_trig.nss diff --git a/src/mod/nss/emote_drunk.nss b/src/module/nss/emote_drunk.nss similarity index 100% rename from src/mod/nss/emote_drunk.nss rename to src/module/nss/emote_drunk.nss diff --git a/src/mod/nss/emote_falldown.nss b/src/module/nss/emote_falldown.nss similarity index 100% rename from src/mod/nss/emote_falldown.nss rename to src/module/nss/emote_falldown.nss diff --git a/src/mod/nss/emote_meditate.nss b/src/module/nss/emote_meditate.nss similarity index 100% rename from src/mod/nss/emote_meditate.nss rename to src/module/nss/emote_meditate.nss diff --git a/src/mod/nss/emote_sitdown.nss b/src/module/nss/emote_sitdown.nss similarity index 100% rename from src/mod/nss/emote_sitdown.nss rename to src/module/nss/emote_sitdown.nss diff --git a/src/mod/nss/emote_worship.nss b/src/module/nss/emote_worship.nss similarity index 100% rename from src/mod/nss/emote_worship.nss rename to src/module/nss/emote_worship.nss diff --git a/src/mod/nss/farmer_give_gold.nss b/src/module/nss/farmer_give_gold.nss similarity index 100% rename from src/mod/nss/farmer_give_gold.nss rename to src/module/nss/farmer_give_gold.nss diff --git a/src/mod/nss/farmer_give_item.nss b/src/module/nss/farmer_give_item.nss similarity index 100% rename from src/mod/nss/farmer_give_item.nss rename to src/module/nss/farmer_give_item.nss diff --git a/src/mod/nss/farmer_gve_align.nss b/src/module/nss/farmer_gve_align.nss similarity index 100% rename from src/mod/nss/farmer_gve_align.nss rename to src/module/nss/farmer_gve_align.nss diff --git a/src/mod/nss/farmer_item_chk.nss b/src/module/nss/farmer_item_chk.nss similarity index 100% rename from src/mod/nss/farmer_item_chk.nss rename to src/module/nss/farmer_item_chk.nss diff --git a/src/mod/nss/farmer_take_item.nss b/src/module/nss/farmer_take_item.nss similarity index 100% rename from src/mod/nss/farmer_take_item.nss rename to src/module/nss/farmer_take_item.nss diff --git a/src/mod/nss/farmer_var_chk.nss b/src/module/nss/farmer_var_chk.nss similarity index 100% rename from src/mod/nss/farmer_var_chk.nss rename to src/module/nss/farmer_var_chk.nss diff --git a/src/mod/nss/farmer_var_set.nss b/src/module/nss/farmer_var_set.nss similarity index 100% rename from src/mod/nss/farmer_var_set.nss rename to src/module/nss/farmer_var_set.nss diff --git a/src/mod/nss/ffx_bounce_inc.nss b/src/module/nss/ffx_bounce_inc.nss similarity index 100% rename from src/mod/nss/ffx_bounce_inc.nss rename to src/module/nss/ffx_bounce_inc.nss diff --git a/src/mod/nss/ffx_fc_exit.nss b/src/module/nss/ffx_fc_exit.nss similarity index 100% rename from src/mod/nss/ffx_fc_exit.nss rename to src/module/nss/ffx_fc_exit.nss diff --git a/src/mod/nss/ffx_fc_lever.nss b/src/module/nss/ffx_fc_lever.nss similarity index 100% rename from src/mod/nss/ffx_fc_lever.nss rename to src/module/nss/ffx_fc_lever.nss diff --git a/src/mod/nss/ffx_fc_lever2.nss b/src/module/nss/ffx_fc_lever2.nss similarity index 100% rename from src/mod/nss/ffx_fc_lever2.nss rename to src/module/nss/ffx_fc_lever2.nss diff --git a/src/mod/nss/ffx_fc_lever3.nss b/src/module/nss/ffx_fc_lever3.nss similarity index 100% rename from src/mod/nss/ffx_fc_lever3.nss rename to src/module/nss/ffx_fc_lever3.nss diff --git a/src/mod/nss/ffx_fc_lever9.nss b/src/module/nss/ffx_fc_lever9.nss similarity index 100% rename from src/mod/nss/ffx_fc_lever9.nss rename to src/module/nss/ffx_fc_lever9.nss diff --git a/src/mod/nss/ffx_fc_outside.nss b/src/module/nss/ffx_fc_outside.nss similarity index 100% rename from src/mod/nss/ffx_fc_outside.nss rename to src/module/nss/ffx_fc_outside.nss diff --git a/src/mod/nss/ffx_inc.nss b/src/module/nss/ffx_inc.nss similarity index 100% rename from src/mod/nss/ffx_inc.nss rename to src/module/nss/ffx_inc.nss diff --git a/src/mod/nss/fire_trap_enter.nss b/src/module/nss/fire_trap_enter.nss similarity index 100% rename from src/mod/nss/fire_trap_enter.nss rename to src/module/nss/fire_trap_enter.nss diff --git a/src/mod/nss/frontgatelocktxt.nss b/src/module/nss/frontgatelocktxt.nss similarity index 100% rename from src/mod/nss/frontgatelocktxt.nss rename to src/module/nss/frontgatelocktxt.nss diff --git a/src/mod/nss/frothic_portal.nss b/src/module/nss/frothic_portal.nss similarity index 100% rename from src/mod/nss/frothic_portal.nss rename to src/module/nss/frothic_portal.nss diff --git a/src/mod/nss/frthrjez_var_chk.nss b/src/module/nss/frthrjez_var_chk.nss similarity index 100% rename from src/mod/nss/frthrjez_var_chk.nss rename to src/module/nss/frthrjez_var_chk.nss diff --git a/src/mod/nss/frthrjez_var_set.nss b/src/module/nss/frthrjez_var_set.nss similarity index 100% rename from src/mod/nss/frthrjez_var_set.nss rename to src/module/nss/frthrjez_var_set.nss diff --git a/src/mod/nss/gen_loot_bodak.nss b/src/module/nss/gen_loot_bodak.nss similarity index 100% rename from src/mod/nss/gen_loot_bodak.nss rename to src/module/nss/gen_loot_bodak.nss diff --git a/src/mod/nss/gen_loot_ck.nss b/src/module/nss/gen_loot_ck.nss similarity index 100% rename from src/mod/nss/gen_loot_ck.nss rename to src/module/nss/gen_loot_ck.nss diff --git a/src/mod/nss/gen_loot_eleven.nss b/src/module/nss/gen_loot_eleven.nss similarity index 100% rename from src/mod/nss/gen_loot_eleven.nss rename to src/module/nss/gen_loot_eleven.nss diff --git a/src/mod/nss/gen_loot_jagang.nss b/src/module/nss/gen_loot_jagang.nss similarity index 100% rename from src/mod/nss/gen_loot_jagang.nss rename to src/module/nss/gen_loot_jagang.nss diff --git a/src/mod/nss/gen_loot_ooze.nss b/src/module/nss/gen_loot_ooze.nss similarity index 100% rename from src/mod/nss/gen_loot_ooze.nss rename to src/module/nss/gen_loot_ooze.nss diff --git a/src/mod/nss/gen_loot_pawn.nss b/src/module/nss/gen_loot_pawn.nss similarity index 100% rename from src/mod/nss/gen_loot_pawn.nss rename to src/module/nss/gen_loot_pawn.nss diff --git a/src/mod/nss/gen_loot_sentros.nss b/src/module/nss/gen_loot_sentros.nss similarity index 100% rename from src/mod/nss/gen_loot_sentros.nss rename to src/module/nss/gen_loot_sentros.nss diff --git a/src/mod/nss/gen_loot_vassi.nss b/src/module/nss/gen_loot_vassi.nss similarity index 100% rename from src/mod/nss/gen_loot_vassi.nss rename to src/module/nss/gen_loot_vassi.nss diff --git a/src/mod/nss/globeofpower.nss b/src/module/nss/globeofpower.nss similarity index 100% rename from src/mod/nss/globeofpower.nss rename to src/module/nss/globeofpower.nss diff --git a/src/mod/nss/glor_stat_trig.nss b/src/module/nss/glor_stat_trig.nss similarity index 100% rename from src/mod/nss/glor_stat_trig.nss rename to src/module/nss/glor_stat_trig.nss diff --git a/src/mod/nss/gratch_zedd_port.nss b/src/module/nss/gratch_zedd_port.nss similarity index 100% rename from src/mod/nss/gratch_zedd_port.nss rename to src/module/nss/gratch_zedd_port.nss diff --git a/src/mod/nss/grend_gve_item.nss b/src/module/nss/grend_gve_item.nss similarity index 100% rename from src/mod/nss/grend_gve_item.nss rename to src/module/nss/grend_gve_item.nss diff --git a/src/mod/nss/grend_gve_item2.nss b/src/module/nss/grend_gve_item2.nss similarity index 100% rename from src/mod/nss/grend_gve_item2.nss rename to src/module/nss/grend_gve_item2.nss diff --git a/src/mod/nss/grend_item_chk.nss b/src/module/nss/grend_item_chk.nss similarity index 100% rename from src/mod/nss/grend_item_chk.nss rename to src/module/nss/grend_item_chk.nss diff --git a/src/mod/nss/grend_item_chk2.nss b/src/module/nss/grend_item_chk2.nss similarity index 100% rename from src/mod/nss/grend_item_chk2.nss rename to src/module/nss/grend_item_chk2.nss diff --git a/src/mod/nss/grend_item_chk3.nss b/src/module/nss/grend_item_chk3.nss similarity index 100% rename from src/mod/nss/grend_item_chk3.nss rename to src/module/nss/grend_item_chk3.nss diff --git a/src/mod/nss/grend_item_take.nss b/src/module/nss/grend_item_take.nss similarity index 100% rename from src/mod/nss/grend_item_take.nss rename to src/module/nss/grend_item_take.nss diff --git a/src/mod/nss/grend_var_chk.nss b/src/module/nss/grend_var_chk.nss similarity index 100% rename from src/mod/nss/grend_var_chk.nss rename to src/module/nss/grend_var_chk.nss diff --git a/src/mod/nss/grend_var_set.nss b/src/module/nss/grend_var_set.nss similarity index 100% rename from src/mod/nss/grend_var_set.nss rename to src/module/nss/grend_var_set.nss diff --git a/src/mod/nss/grndkpr_var_chk.nss b/src/module/nss/grndkpr_var_chk.nss similarity index 100% rename from src/mod/nss/grndkpr_var_chk.nss rename to src/module/nss/grndkpr_var_chk.nss diff --git a/src/mod/nss/grndkpr_var_set.nss b/src/module/nss/grndkpr_var_set.nss similarity index 100% rename from src/mod/nss/grndkpr_var_set.nss rename to src/module/nss/grndkpr_var_set.nss diff --git a/src/mod/nss/hidden_trapdoor.nss b/src/module/nss/hidden_trapdoor.nss similarity index 100% rename from src/mod/nss/hidden_trapdoor.nss rename to src/module/nss/hidden_trapdoor.nss diff --git a/src/mod/nss/hif_onacquireite.nss b/src/module/nss/hif_onacquireite.nss similarity index 100% rename from src/mod/nss/hif_onacquireite.nss rename to src/module/nss/hif_onacquireite.nss diff --git a/src/mod/nss/hif_onactivateit.nss b/src/module/nss/hif_onactivateit.nss similarity index 100% rename from src/mod/nss/hif_onactivateit.nss rename to src/module/nss/hif_onactivateit.nss diff --git a/src/mod/nss/hif_onclientente.nss b/src/module/nss/hif_onclientente.nss similarity index 100% rename from src/mod/nss/hif_onclientente.nss rename to src/module/nss/hif_onclientente.nss diff --git a/src/mod/nss/hif_onheartbeat.nss b/src/module/nss/hif_onheartbeat.nss similarity index 100% rename from src/mod/nss/hif_onheartbeat.nss rename to src/module/nss/hif_onheartbeat.nss diff --git a/src/mod/nss/hif_onmoduleload.nss b/src/module/nss/hif_onmoduleload.nss similarity index 100% rename from src/mod/nss/hif_onmoduleload.nss rename to src/module/nss/hif_onmoduleload.nss diff --git a/src/mod/nss/hif_onplayerdeat.nss b/src/module/nss/hif_onplayerdeat.nss similarity index 100% rename from src/mod/nss/hif_onplayerdeat.nss rename to src/module/nss/hif_onplayerdeat.nss diff --git a/src/mod/nss/hif_onplayerdyin.nss b/src/module/nss/hif_onplayerdyin.nss similarity index 100% rename from src/mod/nss/hif_onplayerdyin.nss rename to src/module/nss/hif_onplayerdyin.nss diff --git a/src/mod/nss/hif_onplayerleve.nss b/src/module/nss/hif_onplayerleve.nss similarity index 100% rename from src/mod/nss/hif_onplayerleve.nss rename to src/module/nss/hif_onplayerleve.nss diff --git a/src/mod/nss/hif_onplayerresp.nss b/src/module/nss/hif_onplayerresp.nss similarity index 100% rename from src/mod/nss/hif_onplayerresp.nss rename to src/module/nss/hif_onplayerresp.nss diff --git a/src/mod/nss/hif_onplayerrest.nss b/src/module/nss/hif_onplayerrest.nss similarity index 100% rename from src/mod/nss/hif_onplayerrest.nss rename to src/module/nss/hif_onplayerrest.nss diff --git a/src/mod/nss/hif_onplayeruneq.nss b/src/module/nss/hif_onplayeruneq.nss similarity index 100% rename from src/mod/nss/hif_onplayeruneq.nss rename to src/module/nss/hif_onplayeruneq.nss diff --git a/src/mod/nss/hif_onunaquireit.nss b/src/module/nss/hif_onunaquireit.nss similarity index 100% rename from src/mod/nss/hif_onunaquireit.nss rename to src/module/nss/hif_onunaquireit.nss diff --git a/src/mod/nss/holywater_on_use.nss b/src/module/nss/holywater_on_use.nss similarity index 100% rename from src/mod/nss/holywater_on_use.nss rename to src/module/nss/holywater_on_use.nss diff --git a/src/mod/nss/jagang_recall.nss b/src/module/nss/jagang_recall.nss similarity index 100% rename from src/mod/nss/jagang_recall.nss rename to src/module/nss/jagang_recall.nss diff --git a/src/mod/nss/jano_activate.nss b/src/module/nss/jano_activate.nss similarity index 100% rename from src/mod/nss/jano_activate.nss rename to src/module/nss/jano_activate.nss diff --git a/src/mod/nss/jano_death.nss b/src/module/nss/jano_death.nss similarity index 100% rename from src/mod/nss/jano_death.nss rename to src/module/nss/jano_death.nss diff --git a/src/mod/nss/jano_heartbeat.nss b/src/module/nss/jano_heartbeat.nss similarity index 100% rename from src/mod/nss/jano_heartbeat.nss rename to src/module/nss/jano_heartbeat.nss diff --git a/src/mod/nss/jano_ondying.nss b/src/module/nss/jano_ondying.nss similarity index 100% rename from src/mod/nss/jano_ondying.nss rename to src/module/nss/jano_ondying.nss diff --git a/src/mod/nss/jano_onenter.nss b/src/module/nss/jano_onenter.nss similarity index 100% rename from src/mod/nss/jano_onenter.nss rename to src/module/nss/jano_onenter.nss diff --git a/src/mod/nss/jano_onrest.nss b/src/module/nss/jano_onrest.nss similarity index 100% rename from src/mod/nss/jano_onrest.nss rename to src/module/nss/jano_onrest.nss diff --git a/src/mod/nss/jano_respawn.nss b/src/module/nss/jano_respawn.nss similarity index 100% rename from src/mod/nss/jano_respawn.nss rename to src/module/nss/jano_respawn.nss diff --git a/src/mod/nss/jwcheshirecatkey.nss b/src/module/nss/jwcheshirecatkey.nss similarity index 100% rename from src/mod/nss/jwcheshirecatkey.nss rename to src/module/nss/jwcheshirecatkey.nss diff --git a/src/mod/nss/keyofcheating.nss b/src/module/nss/keyofcheating.nss similarity index 100% rename from src/mod/nss/keyofcheating.nss rename to src/module/nss/keyofcheating.nss diff --git a/src/mod/nss/librar_gve_lttr.nss b/src/module/nss/librar_gve_lttr.nss similarity index 100% rename from src/mod/nss/librar_gve_lttr.nss rename to src/module/nss/librar_gve_lttr.nss diff --git a/src/mod/nss/librar_item_chk.nss b/src/module/nss/librar_item_chk.nss similarity index 100% rename from src/mod/nss/librar_item_chk.nss rename to src/module/nss/librar_item_chk.nss diff --git a/src/mod/nss/librar_item_chk2.nss b/src/module/nss/librar_item_chk2.nss similarity index 100% rename from src/mod/nss/librar_item_chk2.nss rename to src/module/nss/librar_item_chk2.nss diff --git a/src/mod/nss/librar_item_tak2.nss b/src/module/nss/librar_item_tak2.nss similarity index 100% rename from src/mod/nss/librar_item_tak2.nss rename to src/module/nss/librar_item_tak2.nss diff --git a/src/mod/nss/librar_take_card.nss b/src/module/nss/librar_take_card.nss similarity index 100% rename from src/mod/nss/librar_take_card.nss rename to src/module/nss/librar_take_card.nss diff --git a/src/mod/nss/librar_var_chk2.nss b/src/module/nss/librar_var_chk2.nss similarity index 100% rename from src/mod/nss/librar_var_chk2.nss rename to src/module/nss/librar_var_chk2.nss diff --git a/src/mod/nss/librar_var_set.nss b/src/module/nss/librar_var_set.nss similarity index 100% rename from src/mod/nss/librar_var_set.nss rename to src/module/nss/librar_var_set.nss diff --git a/src/mod/nss/librar_var_set2.nss b/src/module/nss/librar_var_set2.nss similarity index 100% rename from src/mod/nss/librar_var_set2.nss rename to src/module/nss/librar_var_set2.nss diff --git a/src/mod/nss/library_gve_keys.nss b/src/module/nss/library_gve_keys.nss similarity index 100% rename from src/mod/nss/library_gve_keys.nss rename to src/module/nss/library_gve_keys.nss diff --git a/src/mod/nss/library_item_tak.nss b/src/module/nss/library_item_tak.nss similarity index 100% rename from src/mod/nss/library_item_tak.nss rename to src/module/nss/library_item_tak.nss diff --git a/src/mod/nss/library_var_chk.nss b/src/module/nss/library_var_chk.nss similarity index 100% rename from src/mod/nss/library_var_chk.nss rename to src/module/nss/library_var_chk.nss diff --git a/src/mod/nss/lightning_efx.nss b/src/module/nss/lightning_efx.nss similarity index 100% rename from src/mod/nss/lightning_efx.nss rename to src/module/nss/lightning_efx.nss diff --git a/src/mod/nss/loot_notify.nss b/src/module/nss/loot_notify.nss similarity index 100% rename from src/mod/nss/loot_notify.nss rename to src/module/nss/loot_notify.nss diff --git a/src/mod/nss/lwkeygiver.nss b/src/module/nss/lwkeygiver.nss similarity index 100% rename from src/mod/nss/lwkeygiver.nss rename to src/module/nss/lwkeygiver.nss diff --git a/src/mod/nss/m_elfpermale.nss b/src/module/nss/m_elfpermale.nss similarity index 100% rename from src/mod/nss/m_elfpermale.nss rename to src/module/nss/m_elfpermale.nss diff --git a/src/mod/nss/mac_elfperfemale.nss b/src/module/nss/mac_elfperfemale.nss similarity index 100% rename from src/mod/nss/mac_elfperfemale.nss rename to src/module/nss/mac_elfperfemale.nss diff --git a/src/mod/nss/mac_elfpermale2.nss b/src/module/nss/mac_elfpermale2.nss similarity index 100% rename from src/mod/nss/mac_elfpermale2.nss rename to src/module/nss/mac_elfpermale2.nss diff --git a/src/mod/nss/mac_elftakehead.nss b/src/module/nss/mac_elftakehead.nss similarity index 100% rename from src/mod/nss/mac_elftakehead.nss rename to src/module/nss/mac_elftakehead.nss diff --git a/src/mod/nss/mac_givexp2000.nss b/src/module/nss/mac_givexp2000.nss similarity index 100% rename from src/mod/nss/mac_givexp2000.nss rename to src/module/nss/mac_givexp2000.nss diff --git a/src/mod/nss/mac_ladderport.nss b/src/module/nss/mac_ladderport.nss similarity index 100% rename from src/mod/nss/mac_ladderport.nss rename to src/module/nss/mac_ladderport.nss diff --git a/src/mod/nss/mac_orcheadcheck.nss b/src/module/nss/mac_orcheadcheck.nss similarity index 100% rename from src/mod/nss/mac_orcheadcheck.nss rename to src/module/nss/mac_orcheadcheck.nss diff --git a/src/mod/nss/mac_orcportal.nss b/src/module/nss/mac_orcportal.nss similarity index 100% rename from src/mod/nss/mac_orcportal.nss rename to src/module/nss/mac_orcportal.nss diff --git a/src/mod/nss/mac_wellport.nss b/src/module/nss/mac_wellport.nss similarity index 100% rename from src/mod/nss/mac_wellport.nss rename to src/module/nss/mac_wellport.nss diff --git a/src/mod/nss/mac_zeddsmartpor.nss b/src/module/nss/mac_zeddsmartpor.nss similarity index 100% rename from src/mod/nss/mac_zeddsmartpor.nss rename to src/module/nss/mac_zeddsmartpor.nss diff --git a/src/mod/nss/magering_gen.nss b/src/module/nss/magering_gen.nss similarity index 100% rename from src/mod/nss/magering_gen.nss rename to src/module/nss/magering_gen.nss diff --git a/src/mod/nss/mags2_port.nss b/src/module/nss/mags2_port.nss similarity index 100% rename from src/mod/nss/mags2_port.nss rename to src/module/nss/mags2_port.nss diff --git a/src/mod/nss/mags_south_port.nss b/src/module/nss/mags_south_port.nss similarity index 100% rename from src/mod/nss/mags_south_port.nss rename to src/module/nss/mags_south_port.nss diff --git a/src/mod/nss/mared_give_gold.nss b/src/module/nss/mared_give_gold.nss similarity index 100% rename from src/mod/nss/mared_give_gold.nss rename to src/module/nss/mared_give_gold.nss diff --git a/src/mod/nss/mared_give_head.nss b/src/module/nss/mared_give_head.nss similarity index 100% rename from src/mod/nss/mared_give_head.nss rename to src/module/nss/mared_give_head.nss diff --git a/src/mod/nss/mared_give_ring.nss b/src/module/nss/mared_give_ring.nss similarity index 100% rename from src/mod/nss/mared_give_ring.nss rename to src/module/nss/mared_give_ring.nss diff --git a/src/mod/nss/mared_head_check.nss b/src/module/nss/mared_head_check.nss similarity index 100% rename from src/mod/nss/mared_head_check.nss rename to src/module/nss/mared_head_check.nss diff --git a/src/mod/nss/mared_head_take.nss b/src/module/nss/mared_head_take.nss similarity index 100% rename from src/mod/nss/mared_head_take.nss rename to src/module/nss/mared_head_take.nss diff --git a/src/mod/nss/mared_ring_chk.nss b/src/module/nss/mared_ring_chk.nss similarity index 100% rename from src/mod/nss/mared_ring_chk.nss rename to src/module/nss/mared_ring_chk.nss diff --git a/src/mod/nss/mayor_give_card.nss b/src/module/nss/mayor_give_card.nss similarity index 100% rename from src/mod/nss/mayor_give_card.nss rename to src/module/nss/mayor_give_card.nss diff --git a/src/mod/nss/mayor_give_gold.nss b/src/module/nss/mayor_give_gold.nss similarity index 100% rename from src/mod/nss/mayor_give_gold.nss rename to src/module/nss/mayor_give_gold.nss diff --git a/src/mod/nss/mayor_give_item.nss b/src/module/nss/mayor_give_item.nss similarity index 100% rename from src/mod/nss/mayor_give_item.nss rename to src/module/nss/mayor_give_item.nss diff --git a/src/mod/nss/mayor_item_check.nss b/src/module/nss/mayor_item_check.nss similarity index 100% rename from src/mod/nss/mayor_item_check.nss rename to src/module/nss/mayor_item_check.nss diff --git a/src/mod/nss/mayor_item_chk1.nss b/src/module/nss/mayor_item_chk1.nss similarity index 100% rename from src/mod/nss/mayor_item_chk1.nss rename to src/module/nss/mayor_item_chk1.nss diff --git a/src/mod/nss/mayor_item_chk2.nss b/src/module/nss/mayor_item_chk2.nss similarity index 100% rename from src/mod/nss/mayor_item_chk2.nss rename to src/module/nss/mayor_item_chk2.nss diff --git a/src/mod/nss/mayor_item_chk3.nss b/src/module/nss/mayor_item_chk3.nss similarity index 100% rename from src/mod/nss/mayor_item_chk3.nss rename to src/module/nss/mayor_item_chk3.nss diff --git a/src/mod/nss/mayor_item_take.nss b/src/module/nss/mayor_item_take.nss similarity index 100% rename from src/mod/nss/mayor_item_take.nss rename to src/module/nss/mayor_item_take.nss diff --git a/src/mod/nss/mayor_sit.nss b/src/module/nss/mayor_sit.nss similarity index 100% rename from src/mod/nss/mayor_sit.nss rename to src/module/nss/mayor_sit.nss diff --git a/src/mod/nss/mayor_take_lttr.nss b/src/module/nss/mayor_take_lttr.nss similarity index 100% rename from src/mod/nss/mayor_take_lttr.nss rename to src/module/nss/mayor_take_lttr.nss diff --git a/src/mod/nss/mayor_var_chk.nss b/src/module/nss/mayor_var_chk.nss similarity index 100% rename from src/mod/nss/mayor_var_chk.nss rename to src/module/nss/mayor_var_chk.nss diff --git a/src/mod/nss/mayor_var_set.nss b/src/module/nss/mayor_var_set.nss similarity index 100% rename from src/mod/nss/mayor_var_set.nss rename to src/module/nss/mayor_var_set.nss diff --git a/src/mod/nss/mc_jaganghead.nss b/src/module/nss/mc_jaganghead.nss similarity index 100% rename from src/mod/nss/mc_jaganghead.nss rename to src/module/nss/mc_jaganghead.nss diff --git a/src/mod/nss/mcain_on_death.nss b/src/module/nss/mcain_on_death.nss similarity index 100% rename from src/mod/nss/mcain_on_death.nss rename to src/module/nss/mcain_on_death.nss diff --git a/src/mod/nss/midlandringkey.nss b/src/module/nss/midlandringkey.nss similarity index 100% rename from src/mod/nss/midlandringkey.nss rename to src/module/nss/midlandringkey.nss diff --git a/src/mod/nss/mindport.nss b/src/module/nss/mindport.nss similarity index 100% rename from src/mod/nss/mindport.nss rename to src/module/nss/mindport.nss 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/mod/nss/mod_events.nss b/src/module/nss/mod_events.nss similarity index 100% rename from src/mod/nss/mod_events.nss rename to src/module/nss/mod_events.nss diff --git a/src/mod/nss/mod_nuievent.nss b/src/module/nss/mod_nuievent.nss similarity index 100% rename from src/mod/nss/mod_nuievent.nss rename to src/module/nss/mod_nuievent.nss diff --git a/src/mod/nss/mod_onplaytarget.nss b/src/module/nss/mod_onplaytarget.nss similarity index 100% rename from src/mod/nss/mod_onplaytarget.nss rename to src/module/nss/mod_onplaytarget.nss diff --git a/src/mod/nss/monk_attack.nss b/src/module/nss/monk_attack.nss similarity index 100% rename from src/mod/nss/monk_attack.nss rename to src/module/nss/monk_attack.nss diff --git a/src/mod/nss/monk_port_back.nss b/src/module/nss/monk_port_back.nss similarity index 100% rename from src/mod/nss/monk_port_back.nss rename to src/module/nss/monk_port_back.nss diff --git a/src/mod/nss/nui_c_config.nss b/src/module/nss/nui_c_config.nss similarity index 100% rename from src/mod/nss/nui_c_config.nss rename to src/module/nss/nui_c_config.nss diff --git a/src/mod/nss/nui_c_storage.nss b/src/module/nss/nui_c_storage.nss similarity index 96% rename from src/mod/nss/nui_c_storage.nss rename to src/module/nss/nui_c_storage.nss index b866661..903e0aa 100644 --- a/src/mod/nss/nui_c_storage.nss +++ b/src/module/nss/nui_c_storage.nss @@ -19,7 +19,7 @@ /// by the container object's tag. The saved item data includes the UUID /// and CD Key of the PC that deposited the item so the same container can /// be used for multiple PCs. To set a specific (unique) name to use as the -/// table name instead, set a local string called `PS_UNIQUE_ID` on the +/// table name instead, set a local string called `PS_UNIQUE_ID` on the /// container object and set it to any unique string. /// @brief Determines usage of the `Search` button. @@ -51,7 +51,7 @@ const int PS_FORCE_OBJECT_STATE_DEFAULT = PS_TRUE; /// Local Override (int): PS_STORAGE_LIMIT /// -1 = PS_UNLIMITED /// Set to any positive integer to limit item storage to that amount. -const int PS_STORAGE_LIMIT_DEFAULT = 500; +const int PS_STORAGE_LIMIT_DEFAULT = 200; /// @brief Set the maximum distance (meters) a PC can travel from the container /// before the form will auto-close. @@ -101,7 +101,7 @@ const int PS_ACCESS_TYPE_DEFAULT = PS_ACCESS_EXCLUSIVE; /// 1 = PS_CONTAINER_PUBLIC /// 2 = PS_CONTAINER_CHARACTER /// 3 = PS_CONTAINER_CDKEY -const int PS_CONTAINER_TYPE_DEFAULT = PS_CONTAINER_CDKEY; +const int PS_CONTAINER_TYPE_DEFAULT = PS_CONTAINER_PUBLIC; /// @brief Set the default container type, if the container is an item. Containers /// can be of multiple types: @@ -124,10 +124,10 @@ const int PS_CONTAINER_TYPE_DEFAULT = PS_CONTAINER_CDKEY; /// 1 = PS_CONTAINER_PUBLIC /// 2 = PS_CONTAINER_CHARACTER /// 3 = PS_CONTAINER_CDKEY -const int PS_CONTAINER_ITEM_TYPE_DEFAULT = PS_CONTAINER_CDKEY; +const int PS_CONTAINER_ITEM_TYPE_DEFAULT = PS_CONTAINER_CHARACTER; /// @brief Determines whether the player's inventory window will be opened -/// when a container is opened. +/// when a container is opened. /// Configuration File: /// PS_TRUE to open the inventory window. /// PS_FALSE to prevent the window from opening. If the inventory @@ -142,13 +142,13 @@ const int PS_OPEN_INVENTORY_DEFAULT = PS_TRUE; /// manipulate gold storage will not be visible on the form. /// Configuration File: /// PS_UNLIMITED to allow unlimited gold storage. -/// PS_NONE to prevent gold storage. +/// PS_NONE to prevent gold storage. /// Set to any positive integer to limit gold to that amount. /// Local Override (int): PS_MAX_GOLD /// -1 = PS_UNLIMITED /// -2 = PS_NONE /// Set to any positive integer to limit gold to that amount. -const int PS_MAX_GOLD_DEFAULT = 2000000000; +const int PS_MAX_GOLD_DEFAULT = 1000000; /// @note Reference these terms for the following option: /// Container: A persistent storage object in the game, such as a chest. @@ -156,8 +156,8 @@ const int PS_MAX_GOLD_DEFAULT = 2000000000; /// Can have its own inventory /// Can be carried in a player's inventory -/// @brief Determines handling for container objects. Containers can optionally -/// store container items. +/// @brief Determines handling for container objects. Containers can optionally +/// store container items. /// Configuration File: /// PS_UNLIMITED to allow storage of an unlimited number of container items. /// PS_NONE to prevent storage of any container items. diff --git a/src/mod/nss/nui_f_storage.nss b/src/module/nss/nui_f_storage.nss similarity index 99% rename from src/mod/nss/nui_f_storage.nss rename to src/module/nss/nui_f_storage.nss index 0dcfc0b..4a33fff 100644 --- a/src/mod/nss/nui_f_storage.nss +++ b/src/module/nss/nui_f_storage.nss @@ -206,7 +206,7 @@ void ps_InitializeDatabase(object oPC) if (!SqlStep(sql)) { - sQuery = + sQuery = "CREATE TABLE IF NOT EXISTS " + sTable + " (" + "owner TEXT NOT NULL DEFAULT '', " + "item_uuid TEXT NOT NULL DEFAULT '', " + @@ -238,7 +238,7 @@ int ps_CountStoredItems(object oPC) else sOwner = "*:" + ps_GetOwner(oPC, "cdkey"); } - string sQuery = + string sQuery = "SELECT COUNT(*) FROM " + ps_GetTableName(oPC) + " " + "WHERE item_uuid != 'gold'" + sAnd + ";"; sqlquery sql = ps_PrepareQuery(sQuery); @@ -254,11 +254,11 @@ int ps_CountStoredGold(object oPC) int nType = ps_GetContainerType(oPC); string sWhere = (nType == PS_CONTAINER_PUBLIC ? "" : " AND owner GLOB @owner"); - string sQuery = + string sQuery = "SELECT SUM(item_stacksize) FROM " + ps_GetTableName(oPC) + " " + "WHERE item_uuid == 'gold'" + sWhere + ";"; sqlquery sql = ps_PrepareQuery(sQuery); - + if (nType == PS_CONTAINER_CHARACTER) SqlBindString(sql, "@owner", ps_GetOwner(oPC, "uuid") + ":*"); else if (nType == PS_CONTAINER_CDKEY) SqlBindString(sql, "@owner", "*:" + ps_GetOwner(oPC, "cdkey")); @@ -372,7 +372,7 @@ int ps_UpdateGold(object oPC, int nToken, int nGold) if (ps_GetMaxGold(oPC) <= PS_NONE) return FALSE; string sGold = (nGold == 0 ? "@nGold" : "item_stacksize + @nGold"); - string sQuery = + string sQuery = "INSERT INTO " + ps_GetTableName(oPC) + "(owner, item_uuid, item_baseitem, item_stacksize) " + "VALUES (@owner, @item_uuid, @item_baseitem, @item_stacksize) " + @@ -385,7 +385,7 @@ int ps_UpdateGold(object oPC, int nToken, int nGold) SqlBindInt (sql, "@item_baseitem", BASE_ITEM_GOLD); SqlBindInt (sql, "@item_stacksize", nGold); SqlBindInt (sql, "@nGold", nGold); - + SqlStep(sql); ps_UpdateGoldBinds(oPC, nToken); @@ -417,8 +417,8 @@ int ps_WithdrawGold(object oPC, int nToken, int nGold) if (!nRecords || nGold - nRemoved > 0) { - sQuery = - "UPDATE " + sTable + " SET item_stacksize = item_stacksize - @gold " + + sQuery = + "UPDATE " + sTable + " SET item_stacksize = item_stacksize - @gold " + "WHERE ROWID IN (SELECT ROWID FROM " + sTable + " WHERE item_stacksize >= " + "@gold AND item_uuid = 'gold' ORDER BY RANDOM() LIMIT 1);"; sql = ps_PrepareQuery(sQuery); @@ -448,7 +448,7 @@ void ps_UpdateItemList(object oPC, int nFlag = FALSE) string sTable = ps_GetTableName(oPC); - string sQuery = + string sQuery = "WITH gold AS (SELECT SUM(item_stacksize) pieces FROM " + sTable + " WHERE item_uuid == 'gold'$1 ), " + "items AS (SELECT item_uuid, IIF(item_stacksize > 1, item_name || ' (x' || item_stacksize || ')', item_name) name, " + "item_iconresref, json('false') selected FROM " + sTable + " WHERE item_uuid != 'gold'$2 " + @@ -460,9 +460,9 @@ void ps_UpdateItemList(object oPC, int nFlag = FALSE) "FROM gold LEFT JOIN items;"; sqlquery sql = ps_PrepareQuery(SubstituteString(sQuery, jWhere)); - + if (sSearch != "") SqlBindString(sql, "@item", "*" + GetStringLowerCase(sSearch) + "*"); - + if (nType == PS_CONTAINER_CHARACTER) SqlBindString(sql, "@owner", ps_GetOwner(oPC, "uuid") + ":*"); else if (nType == PS_CONTAINER_CDKEY) SqlBindString(sql, "@owner", "*:" + ps_GetOwner(oPC, "cdkey")); @@ -608,7 +608,7 @@ void ps_DepositItem(object oPC, object oItem) SqlBindInt (sql, "@item_stacksize", GetItemStackSize(oItem)); SqlBindString(sql, "@item_iconresref", ps_GetIconResref(oItem, jItemData, nItemBaseItem)); SqlBindJson (sql, "@item_data", jItemData); - + if (SqlStep(sql)) { if (SqlGetString(sql, 0) == "") @@ -631,7 +631,7 @@ void ps_JsonToObject(json jObject, location l, object oOwner, int nObjectState) { object oItem = JsonToObject(jObject, l, oOwner, nObjectState); json jName = JsonObjectGet(jObject, PS_ORIGINAL_NAME); - + if (jName != JsonNull()) SetName(oItem, JsonGetString(jName)); } @@ -704,7 +704,7 @@ void BindForm() { string sValue, sBind = JsonGetString(JsonArrayGet(jBinds, n)); json jValue = JsonNull(); - + if (sBind == "search") sValue = nuiString(""); if (sValue != "") @@ -808,7 +808,7 @@ void DefineForm() NUI_AddRow(); NUI_SetHeight(fRowHeight); NUI_SetMargin(0.0); - + NUI_AddCommandButton("btn_withdraw"); NUI_SetLabel("Withdraw"); NUI_BindEnabled("btn_withdraw"); @@ -926,7 +926,7 @@ void HandleNUIEvents() if (ed.sControlID == "btn_withdraw") ps_WithdrawItems(ed.oPC, ed.nToken); else if (ed.sControlID == "btn_withdraw_all") - ps_WithdrawItems(ed.oPC, ed.nToken, TRUE); + ps_WithdrawItems(ed.oPC, ed.nToken, TRUE); else if (ed.sControlID == "btn_deposit") ps_EnterDepositMode(ed.oPC); else if (ed.sControlID == "btn_deposit_gold") @@ -936,8 +936,8 @@ void HandleNUIEvents() if (sAmount == "") nAmount = nGold; - else - nAmount = clamp(StringToInt(sAmount), 0, nGold); + else + nAmount = clamp(StringToInt(sAmount), 0, nGold); if ((nGold = ps_GetMaxGold(ed.oPC)) > -2) nAmount = min(nAmount, nGold - JsonGetInt(NuiGetBind(ed.oPC, ed.nToken, "gold_stored"))); @@ -956,7 +956,7 @@ void HandleNUIEvents() if (sAmount == "") nAmount = nGold; - else + else nAmount = clamp(StringToInt(sAmount), 0, nGold); if (nAmount <= 0) return; @@ -1078,7 +1078,7 @@ void ps_OnContainerHeartbeat(object oContainer) float fMax = ps_GetLocalFloatOrDefault(oContainer, PS_DISTANCE, PS_DISTANCE_DEFAULT); if (fMax < 0.0) return; - + int nAccess = ps_GetLocalIntOrDefault(oContainer, PS_ACCESS_TYPE, PS_ACCESS_TYPE_DEFAULT); if (nAccess == PS_ACCESS_CONTENTIOUS) { diff --git a/src/module/nss/nui_i_library.nss b/src/module/nss/nui_i_library.nss new file mode 100644 index 0000000..a6fb4f5 --- /dev/null +++ b/src/module/nss/nui_i_library.nss @@ -0,0 +1,44 @@ +/// ---------------------------------------------------------------------------- +/// @file nui_i_library.nss +/// @author Ed Burke (tinygiant98) +/// @brief Boilerplate code for creating a library dispatcher. Should only be +/// included in library scripts as it implements main(). +/// ---------------------------------------------------------------------------- + +#include "nui_i_main" + +// ----------------------------------------------------------------------------- +// Function Protoypes +// ----------------------------------------------------------------------------- + +void DefineForm(); +void BindForm(); +void HandleNUIEvents(); +void HandleModuleEvents(); + +// ----------------------------------------------------------------------------- +// Function Implementations +// ----------------------------------------------------------------------------- + +// These are dummy implementations to prevent nwnsc from complaining that they +// do not exist. If you want to compile in the toolset rather than using nwnsc, +// comment these lines out. +//#pragma default_function(DefineForm) +//#pragma default_function(BindForm) +//#pragma default_function(HandleNUIEvents) +//#pragma default_function(HandleModuleEvents) + +// ----------------------------------------------------------------------------- +// Library Dispatch +// ----------------------------------------------------------------------------- + +void main() +{ + string sOperation = GetScriptParam(NUI_FUNCTION); + + if (sOperation == NUI_DEFINE) DefineForm(); + else if (sOperation == NUI_BIND) BindForm(); + else if (sOperation == NUI_EVENT_NUI) HandleNUIEvents(); + else if (sOperation == NUI_EVENT_MOD) HandleModuleEvents(); + else NUI(); +} diff --git a/src/mod/nss/nui_i_main.nss b/src/module/nss/nui_i_main.nss similarity index 87% rename from src/mod/nss/nui_i_main.nss rename to src/module/nss/nui_i_main.nss index 345014a..f28ab6b 100644 --- a/src/mod/nss/nui_i_main.nss +++ b/src/module/nss/nui_i_main.nss @@ -7,12 +7,13 @@ #include "util_i_csvlists" #include "util_i_color" #include "nui_c_config" +#include "nw_inc_nui" // ----------------------------------------------------------------------------- // Constants // ----------------------------------------------------------------------------- -const string NUI_VERSION = "0.3.0"; +const string NUI_VERSION = "0.5.0"; const string NUI_DATABASE = "nui_form_data"; const int NUI_ORIENTATION_ROW = 0; @@ -28,45 +29,25 @@ const int NUI_DRAW_MOUSELEFT = 3; const int NUI_DRAW_MOUSERIGHT = 4; const int NUI_DRAW_MOUSEMIDDLE = 5; -const int NUI_SCROLLBARS_NONE = 0; -const int NUI_SCROLLBARS_X = 1; -const int NUI_SCROLLBARS_Y = 2; -const int NUI_SCROLLBARS_BOTH = 3; -const int NUI_SCROLLBARS_AUTO = 4; - const int NUI_CHART_LINE = 0; const int NUI_CHART_BAR = 1; -const int NUI_ASPECT_FIT = 0; -const int NUI_ASPECT_FILL = 1; -const int NUI_ASPECT_FIT100 = 2; -const int NUI_ASPECT_EXACT = 3; -const int NUI_ASPECT_EXACTSCALED = 4; -const int NUI_ASPECT_STRETCH = 5; - -const int NUI_HALIGN_CENTER = 0; -const int NUI_HALIGN_LEFT = 1; -const int NUI_HALIGN_RIGHT = 2; - -const int NUI_VALIGN_MIDDLE = 0; -const int NUI_VALIGN_TOP = 1; -const int NUI_VALIGN_BOTTOM = 2; - const string NUI_DEFINE = "DefineForm"; const string NUI_BIND = "BindForm"; const string NUI_EVENT_NUI = "HandleNUIEvents"; const string NUI_EVENT_MOD = "HandleModuleEvents"; const string NUI_OBJECT = "NUI_OBJECT"; +const string NUI_FUNCTION = "NUI_FUNCTION"; +const string NUI_ARGS = "NUI_ARGS"; const int NUI_FI_EVENT_UPDATE_FORMS = 100001; const int NUI_FI_EVENT_UPDATE_EVENTS = 100002; -json jTrue = JsonBool(TRUE); -json jFalse = JsonBool(FALSE); +json jTrue = JSON_TRUE; +json jFalse = JSON_FALSE; -// TODO remove upon debug completion -const int NUI_USE_CAMPAIGN_DATABASE = TRUE; +const int NUI_USE_CAMPAIGN_DATABASE = FALSE; const string NUI_FORMFILE_PREFIX = "nui_f_"; struct NUIEventData { @@ -117,6 +98,8 @@ string nuiNull(); /// @brief Must be called during the module load process. Initializes the /// required nui database tables and loads all available formfiles. +/// Automatically called by the system during the OnModuleLoad event +/// if not specifically called prior. void NUI_Initialize(); /// @brief Creates a form template with all required form properties set to @@ -129,7 +112,7 @@ void NUI_Initialize(); /// resizable: true /// title: bind:"title" /// transparent: false -/// @param sID FormID. +/// @param sID Form ID. /// @param sVersion A local version set into the form's json structure as /// "local_version". This is different than the nui system's required /// version, which should never be changed. @@ -155,7 +138,7 @@ string NUI_DefinePoint(float x, float y); /// @param y2 End point y-coordinate. /// @returns A json-parseable string representing an array of coordinates /// that can be used in NUI_DrawLine(). -/// [x1, y1, x2, y2] +/// [x1.x, y1.y, x2.x, y2.y] string NUI_GetLinePoints(float x1, float y1, float x2, float y2); /// @brief Add a single coordinate set to an empty or existing coordinate array. @@ -165,7 +148,7 @@ string NUI_GetLinePoints(float x1, float y1, float x2, float y2); /// @param y Y-coordinate. /// @returns A json-parseable string representing an array of coordinates /// that can be used in NUI_DrawLine(). -/// [..., x, y] +/// [..., x.x, y.y] string NUI_AddLinePoint(string sPoints, float x, float y); /// @brief Define an nui-usable color vector via rgba values. @@ -202,7 +185,7 @@ string NUI_DefineRandomColor(); /// @param w Width. /// @param h Height. /// @returns A json-parseable string representing a rectangular region. -/// {"x":x, "y":y, "w":w, "h":h} +/// {"x":x.x, "y":y.y, "w":w.w, "h":h.h} string NUI_DefineRectangle(float x, float y, float w, float h); /// @brief Get an array of rectangle corner coordinates. @@ -212,7 +195,7 @@ string NUI_DefineRectangle(float x, float y, float w, float h); /// @param h Height. /// @returns A json-parseable string representing an array of coordinates /// that can be used in NUI_DrawLine. -/// [x, y, x+w, y, x+w, y+h, x, y+h, x, y] +/// [x.x, y.y, x.x+w.w, y.y, x.x+w.w, y.y+h.h, x.x, y.y+h.h, x.x, y.y] string NUI_GetRectanglePoints(float x, float y, float w, float h); /// @brief Get an array of rectangle corner coordinates. @@ -220,7 +203,7 @@ string NUI_GetRectanglePoints(float x, float y, float w, float h); /// region as returned by NUI_DefineRectangle(). /// @returns A json-parseable string representing an array of coordinates /// that can be used in NUI_DrawLine. -/// [x, y, x+w, y, x+w, y+h, x, y+h, x, y] +/// [x.x, y.y, x.x+w.w, y.y, x.x+w.w, y.y+h.h, x.x, y.y+h.h, x.x, y.y] string NUI_GetDefinedRectanglePoints(string sRectangle); /// @brief Define a circle based on coordinates and radius. @@ -229,6 +212,7 @@ string NUI_GetDefinedRectanglePoints(string sRectangle); /// @param r Radius. /// @returns A json-parseable string representing a rectangular region /// that can be used in NUI_DrawDefinedCircle(). +/// [x.x-r.r, y.y-r.r, 2*r.r, 2*r.r] string NUI_DefineCircle(float x, float y, float r); /// @brief Add a column to the form or control group. @@ -283,6 +267,16 @@ void NUI_AddCombobox(string sID = ""); /// ed.sControlID in event data. void NUI_AddCommandButton(string sID = ""); +/// @brief Add a fully-formed custom control. +/// @param sJson Json-parseable string representing a form control with all +/// desired properties defined. +/// @warning This is a very advanced-use function and typically should not be +/// used unless you know what you are doing with respect to how the json +/// definitions are built. Once a custom control is added with this function, +/// the control definition is closed and properties cannot be added or +/// modified. +void NUI_AddCustomControl(string sJson); + /// @brief Add a float-based slider to the form or control group /// @param sID Control id. Returned by NuiGetEventElement() (nwscript) or as /// ed.sControlID in event data. @@ -412,7 +406,7 @@ void NUI_DrawDefinedCircle(string sCircle); /// @param sText Text to be displayed in the drawn textbox. /// @note X and Y coordinates are relative to the top-left corner of the control /// the drawlist element is being added to. -void NUI_DrawText(string sRect, string sText); +void NUI_DrawTextbox(string sRect, string sText); /// @brief Draw an image on the canvas. /// @param sResref Resref of the image to be displayed. @@ -516,6 +510,11 @@ void NUI_BindColor(string sBind, int bWatch = FALSE); /// @param bWatch TRUE to set a bind watch. void NUI_BindDisabledTooltip(string sBind, int bWatch = FALSE); +/// @brief Binds the form's edge constraint property. +/// @param sBind Variable to bind. +/// @param bWatch TRUE to set a bind watch. +void NUI_BindEdgeConstraint(string sBind, int bWatch = FALSE); + /// @brief Binds the control's elements property. /// @param sBind Variable to bind. /// @param bWatch TRUE to set a bind watch. @@ -616,6 +615,11 @@ void NUI_BindRowCount(string sBind, int bWatch = FALSE); /// @param bWatch TRUE to set a bind watch. void NUI_BindScissor(string sBind, int bWatch = FALSE); +/// @brief Binds the form's size constraint property. +/// @param sBind Variable to bind. +/// @param bWatch TRUE to set a bind watch. +void NUI_BindSizeConstraint(string sBind, int bWatch = FALSE); + /// @brief Binds a slider control's bounds. /// @param sUpper Variable to bind. /// @param sLower Variable to bind. @@ -705,6 +709,12 @@ void NUI_SetCollapsible(int bCollapsible = TRUE); /// NUI_DefineRandomColor(). void NUI_SetColor(string sColor); +/// @brief Set a custom key:value pair into the build data for the +/// form or control currently being defined. +/// @param sKey Key. +/// @param sValue Json-parseable string. +void NUI_SetCustomKey(string sKey, string sValue); + /// @brief For bound controls, sets the value that will be initially set /// to the control's value property. /// @param sDefault Default value to set. @@ -740,6 +750,13 @@ void NUI_SetDrawCondition(int nCondition = NUI_DRAW_ALWAYS); /// @param nPosition NUI_POSITION_* constant. void NUI_SetDrawPosition(int nPosition = NUI_DRAW_ABOVE); +/// @brief Sets the form's edge constraint property. +/// @param fLeft Left Margin. +/// @param fRight Right Margin. +/// @param fTop Top Margin. +/// @param fBottom Bottom Margin. +void NUI_SetEdgeConstraint(float fLeft, float fRight, float fTop, float fBottom); + /// @brief Sets the control's elements property. /// @param sElements void NUI_SetElements(string sElements); @@ -864,6 +881,18 @@ void NUI_SetScissor(int bScissor); /// @param nScrollBars NUI_SCROLLBARS_* constant. void NUI_SetScrollbars(int nScrollbars = NUI_SCROLLBARS_AUTO); +/// @brief Sets the form's size constraint property. +/// @param fMinWidth Minimum width. +/// @param fMinHeight Minimum height. +/// @param fMaxWidth Maximum width. +/// @param fMaxHeight Maximum height. +/// @note Set any parameter to 0.0 to ignore that parameter while +/// honoring the remaining parameters. +/// @note Setting a maximum constraint less than or equal to a minimum +/// constraint on the same dimension will prevent the form from +/// being resized in that dimension. +void NUI_SetSizeConstraint(float fMinWidth, float fMinHeight, float fMaxWidth, float fMaxHeight); + /// @brief Sets the control's width and height properties. /// @param fSide Length of one side. void NUI_SetSquare(float fSide); @@ -925,19 +954,21 @@ void NUI_SetWordWrap(int bWrap = TRUE); /// @note If sFormfile is passed, only the specified formfile will be loaded. void NUI_DefineForms(string sFormfile = ""); -/// @brief Display an NUI form. +/// @brief Display a form. /// @param oPC Client to display the form on. -/// @param sFormID ID of the for to display. +/// @param sFormID ID of the form to display. /// @param sProfile Optional form profile. +/// @param bSelfManage If TRUE, call the formfile directly instead of the +/// game's NUI event handler. /// @returns Form's token as assigned by the game engine. -int NUI_DisplayForm(object oPC, string sFormID, string sProfile = "default"); +int NUI_DisplayForm(object oPC, string sFormID, string sProfile = "", int bSelfManage = FALSE); -/// @brief Close an open NUI form. +/// @brief Close an open form. /// @param oPC Client on which to close the form. /// @param sFormID ID of the form to close. void NUI_CloseForm(object oPC, string sFormID); -/// @brief Display a subform onto control group element or form root. +/// @brief Display a subform onto a control group element or form root. /// @param oPC Client to display the subform on. /// @param sFormID Form ID. /// @param sElementID Element ID to replace. @@ -965,7 +996,7 @@ void NUI_SetProfileBindJ(string sBind, json jValue); /// @brief Set multiple profile binds to a single value. /// @param sBinds Comma-delimited list of bind names. -/// @param sJson Json-parseable string representing the binds' profile value. +/// @param sJson Json-parseable string representing the bind's profile value. void NUI_SetProfileBinds(string sBinds, string sJson); /// @brief Set a form's profile. @@ -995,7 +1026,7 @@ void NUI_SetBindJ(object oPC, string sFormID, string sBind, json jValue); /// @param bWatch TRUE to set the watch, FALSE to remove it. void NUI_SetBindWatch(object oPC, string sFormID, string sBind, int bWatch = TRUE); -/// @brief Retireve a bind value. +/// @brief Retrieve a bind value. /// @param oPC Player to set the bind for. /// @param sFormID Form ID. /// @param sBind Bind/property name. @@ -1012,16 +1043,41 @@ void NUI_CreateLayout(); /// @brief Get the temporary layout created with NUI_CreateLayout(). /// @note The json-parseable string can be inserted directly into the current layout /// or used in a layout replacement (tabs). This data will not, however, be -/// saved to the database, so this function and NUI_CreateLayout(). are +/// saved to the database, so this function and NUI_CreateLayout() are /// meant for dynamic form building. string NUI_GetLayout(); +/// @brief Trigger the system to respond to an NUI or module event. +/// @param oPC Optional; the PC triggering the event. +/// @note If the event requires a PC object, the PC object must be +/// specified in this call. For example, in the OnClientEnter handler, +/// this function should be called as NUI_HandleEvents(GetEnteringObject()); +/// For events that do not require a PC object, or for the form to be displayed, +/// such as OnModuleLoad, or if the PC object is the OBJECT_SELF of the running +/// script, oPC does not have to be specified, however, it is a best practice +/// to always include the PC object to ensure the correct object is being passed +/// to the system. +void NUI_HandleEvents(object oPC = OBJECT_SELF); + +/// @brief Convenience funtion for NUI_HandleEvents(). +/// @param oPC Optional. See description above for NUI_HandleEvents(). +void NUI(object oPC = OBJECT_SELF); + /// @brief Determines if a form is currently open. /// @param oPC Players to check for the form. /// @param sFormID The form's ID. /// @returns TRUE if oPC has sFormID open, FALSE otherwise. int NUI_GetIsFormOpen(object oPC, string sFormID); +/// @brief Sends relevant event data to NUI_Debug(). +/// @param ed Event data structure retrieved from NUI_GetEventData(). +void NUI_DumpEventData(struct NUIEventData ed); + +/// @brief Retrieves versioning information. +/// @param bIncludeForms If TRUE, will include the versions for all forms +/// loaded into the module. +string NUI_GetVersions(int bIncludeForms = TRUE); + /// @brief Save all of sFormID's bind values to a local variable. /// @param oPC Player associated with sFormID. /// @param sFormID Form ID to save bind values for. @@ -1032,39 +1088,35 @@ void NUI_SaveBindState(object oPC, string sFormID); /// @param sFormID Form ID to restore bind values for. void NUI_RestoreBindState(object oPC, string sFormID); -/// @brief Returns all events data as a struct NUIEventData. +/// @brief Returns all event data as a struct NUIEventData. /// @note Only valid within HandleNUIEvents() event handler. struct NUIEventData NUI_GetEventData(); -/// @note Temporary prototypes to allow .35 function to work when .35 is not installed. -/// TODO Remove when .35 is stable. -//json RegExpMatch(string sRegExp, string sValue, int nSyntaxFlags = REGEXP_ECMASCRIPT, int nMatchFlags = REGEXP_FORMAT_DEFAULT); -//string RegExpReplace(string sRegExp, string sValue, string sReplacement, int nSyntaxFlags = REGEXP_ECMASCRIPT, int nMatchFlags = REGEXP_FORMAT_DEFAULT); +/// @brief Retrieve the key from a key value pair. +/// @param sPair A key:value... or key=value... pair. +/// @note Returns all characters before the first : or =. +string NUI_GetKey(string sPair); + +/// @brief Retrieve the nNth value from a key value series. +/// @param sPair a key:value:value... or key=:value:value... series. +string NUI_GetValue(string sPair, int nNth = 1); // ----------------------------------------------------------------------------- // Public Functions // Administrative Helpers // ----------------------------------------------------------------------------- -// TODO Need prototypes string NUI_GetKey(string sPair) { - int nIndex; - if ((nIndex = FindSubString(sPair, ":")) == -1) - nIndex = FindSubString(sPair, "="); - - if (nIndex == -1) return sPair; - else return GetSubString(sPair, 0, nIndex); + json jMatch = RegExpMatch("(.*?)[:=].*", sPair); + return JsonGetLength(jMatch) != 2 ? "" : JsonGetString(JsonArrayGet(jMatch, 1)); } -string NUI_GetValue(string sPair) +string NUI_GetValue(string sPair, int nNth = 1) { - int nIndex; - if ((nIndex = FindSubString(sPair, ":")) == -1) - nIndex = FindSubString(sPair, "="); - - if (nIndex == -1) return ""; - else return GetSubString(sPair, ++nIndex, GetStringLength(sPair)); + string sRegex = "(?:.*?[:=]){" + IntToString(nNth) + "}(.*?)(?:[:=]|$)"; + json jMatch = RegExpMatch(sRegex, sPair); + return JsonGetLength(jMatch) != 2 ? "" : JsonGetString(JsonArrayGet(jMatch, 1)); } object nui_GetDataObject() {return GetModule();} @@ -1074,74 +1126,6 @@ object nui_GetDataObject() {return GetModule();} // Build Flags and JSON Pathing // ----------------------------------------------------------------------------- -// TODO -/// CUT LINE FOR .35 - Remove below once .35 is stable - -string nui_ReplaceSubString(string sString, string sSub, int nStart, int nEnd) -{ - int nLength = GetStringLength(sString); - if (nStart < 0 || nStart >= nLength || nStart > nEnd) - return sString; - - return GetSubString(sString, 0, nStart) + sSub + - GetSubString(sString, nEnd + 1, nLength - nEnd); -} - -string nui_SubstituteSubString(string sString, string sToken, string sSub) -{ - int nPos; - if ((nPos = FindSubString(sString, sToken)) == -1) - return sString; - - return nui_ReplaceSubString(sString, sSub, nPos, nPos + GetStringLength(sToken) - 1); -} - -string nui_SubstituteSubStrings(string sString, string sToken, string sSub) -{ - int n; - while ((n = FindSubString(sString, sToken)) >= 0) - sString = nui_SubstituteSubString(sString, sToken, sSub); - - return sString; -} - -int nui_GetMatchesPattern(string sString, string sPattern) -{ - sqlquery q = SqlPrepareQueryObject(GetModule(), - "SELECT @string GLOB @pattern;"); - SqlBindString(q, "@string", sString); - SqlBindString(q, "@pattern", sPattern); - return SqlStep(q) ? SqlGetInt(q, 0) : FALSE; -} - -string nui_RegExpReplace(string sToken, string sString, string sSub) -{ - return nui_SubstituteSubStrings(sString, sToken, sSub); -} - -int nui_RegExpMatch(string sString) -{ - return nui_GetMatchesPattern(sString, "*row_template???") || nui_GetMatchesPattern(sString, "*row_template?????"); -} - -string nui_RegExpReplaceLast(string sToken, string sString, string sSub) -{ - int nCount = GetSubStringCount(sString, sToken); - - if (nCount) - { - int nPos = FindSubStringN(sString, sToken, nCount - 1); - - // Need to delete the rest of the path too! - return nui_ReplaceSubString(sString, sSub, nPos, nPos + GetStringLength(sString)); - //return nui_ReplaceSubString(sString, sSub, nPos, nPos + GetStringLength(sToken) - 1); - } - else - return sString; -} - -/// CUT LINE FOR .35 - Remove above once .35 is stable - void nui_ClearVariables() { object oData = nui_GetDataObject(); @@ -1205,17 +1189,10 @@ string nui_GetFormID() {return GetLocalString(nui_GetDataO void nui_SetFormfile(string sFormfile) {SetLocalString(nui_GetDataObject(), "NUI_FORMFILE", sFormfile);} string nui_GetFormfile() {return GetLocalString(nui_GetDataObject(), "NUI_FORMFILE");} -// TODO When .35 is stable, remove the `nui_` in front of both `nui_RegExpReplace` functions -// to restore .35 functionality. -string nui_SubstitutePath(string sSub) {return nui_SetPath(nui_RegExpReplace("@", nui_GetPath(), sSub));} -string nui_GetSubstitutedPath(string sSub) {return nui_RegExpReplace("@", nui_GetPath(), sSub);} +string nui_SubstitutePath(string sSub) {return nui_SetPath(RegExpReplace("@", nui_GetPath(), sSub));} +string nui_GetSubstitutedPath(string sSub) {return RegExpReplace("@", nui_GetPath(), sSub);} -// TODO Restore `RegExpMatch` when .35 is stable. -string nui_GetGroupKey() -{ - //return JsonGetString(JsonArrayGet(RegExpMatch("\\.(\\w*)\\[(?!.*\\.\\w*\\[)", nui_GetPath()), 1)); - return nui_RegExpMatch(nui_GetPath()) ? "row_template" : ""; -} +string nui_GetGroupKey() {return JsonGetString(JsonArrayGet(RegExpMatch("\\.(\\w*)\\[(?!.*\\.\\w*\\[)", nui_GetPath()), 1));} string nui_IncrementPath(string sElement = "", int bForce = FALSE) { @@ -1249,14 +1226,11 @@ string nui_IncrementPath(string sElement = "", int bForce = FALSE) return nui_SetPath(sPath); } -// TODO Restore .35 functionality - string nui_DecrementPath(int n = 1) { string sPath; while (n-- > 0) - sPath = nui_SetPath(nui_RegExpReplaceLast("[#-1]", nui_GetPath(), "[@]")); - //sPath = nui_SetPath(RegExpReplace("\\[#-1\\](?!.*\\[#-1\\]).*", nui_GetPath(), "[@]")); + sPath = nui_SetPath(RegExpReplace("\\[#-1\\](?!.*\\[#-1\\]).*", nui_GetPath(), "[@]")); return sPath; } @@ -1266,9 +1240,6 @@ string nui_DecrementPath(int n = 1) // Database // ----------------------------------------------------------------------------- -string sQuery; -sqlquery sql; - void nui_BeginTransaction() {SqlStep(SqlPrepareQueryObject(GetModule(), "BEGIN TRANSACTION;"));} void nui_CommitTransaction() {SqlStep(SqlPrepareQueryObject(GetModule(), "COMMIT TRANSACTION;"));} @@ -1283,16 +1254,16 @@ sqlquery nui_PrepareQuery(string sQuery, int bForceModule = FALSE) return SqlPrepareQueryObject(GetModule(), sQuery); } -void nui_InitializeDatabase() +int nui_InitializeDatabase() { - sQuery = "DROP TABLE IF EXISTS nui_forms;"; + string sQuery = "DROP TABLE IF EXISTS nui_forms;"; SqlStep(nui_PrepareQuery(sQuery)); SqlStep(nui_PrepareQuery(sQuery, TRUE)); sQuery = "CREATE TABLE IF NOT EXISTS nui_forms (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "form TEXT NOT NULL UNIQUE, " + - "definition BLOB);"; + "definition NONE);"; SqlStep(nui_PrepareQuery(sQuery)); SqlStep(nui_PrepareQuery(sQuery, TRUE)); @@ -1313,15 +1284,18 @@ void nui_InitializeDatabase() "binds_after STRING, " + "timestamp INTEGER);"; SqlStep(nui_PrepareQuery(sQuery)); + + sQuery = "SELECT COUNT(*) FROM nui_forms;"; + return SqlStep(nui_PrepareQuery(sQuery)); } void nui_SaveForm(string sID, string sJson) { - sQuery = "INSERT INTO nui_forms (form, definition) " + + string sQuery = "INSERT INTO nui_forms (form, definition) " + "VALUES (@form, json(@json)) " + "ON CONFLICT (form) DO UPDATE SET " + "definition = json(@json);"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sID); SqlBindString(sql, "@json", sJson); SqlStep(sql); @@ -1329,7 +1303,7 @@ void nui_SaveForm(string sID, string sJson) void nui_DeleteForm(string sID) { - sql = nui_PrepareQuery("DELETE FROM nui_forms WHERE form = @form;"); + sqlquery sql = nui_PrepareQuery("DELETE FROM nui_forms WHERE form = @form;"); SqlBindString(sql, "@form", sID); SqlStep(sql); } @@ -1339,24 +1313,18 @@ void nui_CopyDefinitions(string sTable = "nui_forms") if (!NUI_USE_CAMPAIGN_DATABASE) return; - sQuery = "WITH forms AS (SELECT json_object('form', form, 'definition', definition) AS f " + + string sQuery = "WITH forms AS (SELECT json_object('form', form, 'definition', definition) AS f " + "FROM " + sTable + ") SELECT json_group_array(json(f)) FROM forms;"; - sql = nui_PrepareQuery(sQuery, TRUE); - json jForms = SqlStep(sql) ? SqlGetJson(sql, 0) : JsonNull(); + sqlquery sql = nui_PrepareQuery(sQuery, TRUE); + json jForms = SqlStep(sql) ? SqlGetJson(sql, 0) : JSON_NULL; - if (jForms == JsonNull()) + if (jForms == JSON_NULL) return; - // ->> only works in .35! D'oh! - /* sQuery = "INSERT OR REPLACE INTO " + sTable + " (form, definition) " + "SELECT value ->> '$.form', value ->> '$.definition' " + "FROM (SELECT value FROM json_each(@forms));"; - */ - // TODO remove when .35 is live - sQuery = "INSERT OR REPLACE INTO " + sTable + " (form, definition) " + - "SELECT json_extract(value, '$.form'), json_extract(value, '$.definition') " + - "FROM (SELECT value FROM json_each(@forms));"; + sql = nui_PrepareQuery(sQuery); SqlBindJson(sql, "@forms", jForms); SqlStep(sql); @@ -1367,10 +1335,10 @@ void nui_CopyDefinitions(string sTable = "nui_forms") string nui_GetDefinitionValue(string sFormID, string sPath = "") { - sQuery = "SELECT json_extract(definition, '$" + (sPath == "" ? "" : "." + sPath) + "') " + + string sQuery = "SELECT json_extract(definition, '$" + (sPath == "" ? "" : "." + sPath) + "') " + "FROM nui_forms WHERE form = @form;"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sFormID); return SqlStep(sql) ? SqlGetString(sql, 0) : ""; } @@ -1421,10 +1389,10 @@ void nui_SetObject(string sProperty, string sValue, string sType = "") sPath = nui_GetSubstitutedPath("#"); } - sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, '" + sPath + + string sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, '" + sPath + "', json(@value)) FROM nui_forms WHERE form = @form) WHERE form = @form;"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sFormID); SqlBindString(sql, "@value", sValue); SqlStep(sql); @@ -1471,7 +1439,7 @@ string nui_CreateCanvasTemplate(string sProperties) // Json-Parseable Creators // ----------------------------------------------------------------------------- -string nuiString(string s) {return "\"" + s + "\"";} +string nuiString(string s) {return JsonDump(JsonParse("\"" + s + "\""));} string nuiInt(int n) {return IntToString(n);} string nuiFloat(float f) {return FloatToString(f);} string nuiBool(int b) {return b ? "true" : "false";} @@ -1494,10 +1462,11 @@ void NUI_Initialize() if (GetLocalInt(GetModule(), "NUI_INITIALIZED")) return; - SetLocalInt(GetModule(), "NUI_INITIALIZED", TRUE); - - nui_InitializeDatabase(); - NUI_DefineForms(); + if (nui_InitializeDatabase()) + { + SetLocalInt(GetModule(), "NUI_INITIALIZED", TRUE); + NUI_DefineForms(); + } } void NUI_CreateForm(string sID, string sVersion = "") @@ -1509,7 +1478,7 @@ void NUI_CreateForm(string sID, string sVersion = "") nuiString("border") + ":true," + nuiString("closable") + ":true," + nuiString("resizable") + ":true," + - nuiString("collapsed") + ":false," + + nuiString("collapsed") + ":null," + nuiString("transparent") + ":false," + nuiString("version") + ":1," + nuiString("user_data") + ":{}," + @@ -1569,7 +1538,7 @@ void NUI_SaveBindState(object oPC, string sFormID) void NUI_RestoreBindState(object oPC, string sFormID) { json jState = GetLocalJson(oPC, "NUI_STATE:" + sFormID); - if (jState == JsonNull()) + if (jState == JSON_NULL) return; json jKeys = JsonObjectKeys(jState); @@ -1580,6 +1549,16 @@ void NUI_RestoreBindState(object oPC, string sFormID) NuiSetBind(oPC, nToken, sBind, JsonObjectGet(jState, sBind)); } +void NUI_RepairGeometry(object oPC, string sFormID) +{ + int nToken = NuiFindWindow(oPC, sFormID); + + json j = NuiGetBind(OBJECT_SELF, nToken, "geometry"); + float h = JsonGetFloat(JsonObjectGet(j, "h")); + h += FloatToInt(h) % 2 == 0 ? 1.0 : -1.0; + NuiSetBind(oPC, nToken, "geometry", JsonObjectSet(j, "h", JsonFloat(h))); +} + // ----------------------------------------------------------------------------- // Vectors // ----------------------------------------------------------------------------- @@ -1735,13 +1714,21 @@ void NUI_CloseColumn() {nui_DecrementPath();} void NUI_AddRow(float fHeight = -1.0) {nui_AddLayout("row", fHeight);} void NUI_CloseRow() {nui_DecrementPath();} +void NUI_CloseLayout() {nui_DecrementPath();} + +void NUI_AddLayout(json jLayout) +{ + nui_SetProperty("root", JsonDump(jLayout)); +} + // Controls -------------------------------------------------------------------- void NUI_AddCheckbox(string sID = "") {nui_CreateControl("check", sID);} void NUI_AddColorPicker(string sID = "") {nui_CreateControl("color_picker", sID);} void NUI_AddCommandButton(string sID = "") {nui_CreateControl("button", sID);} +void NUI_AddCustomControl(string sJson) {nui_SetControl(sJson);} void NUI_AddFloatSlider(string sID = "") {nui_CreateControl("sliderf", sID);} -void NUI_AddIntSpinBar(string sID = "") {nui_CreateControl("spinbar", sID);} +void NUI_AddProperty(string sID = "") {nui_CreateControl("propertyi", sID);} void NUI_AddImage(string sID = "") {nui_CreateControl("image", sID);} void NUI_AddImageButton(string sID = "") {nui_CreateControl("button_image", sID);} void NUI_AddIntSlider(string sID = "") {nui_CreateControl("slider", sID);} @@ -1817,7 +1804,6 @@ void NUI_AddOptionGroup(string sID = "") nui_SetProperty("elements", "[]"); } -// TODO prototype void NUI_AddToggleGroup(string sID = "") { nui_CreateControl("tabbar", sID); @@ -1830,18 +1816,6 @@ void NUI_AddTextbox(string sID = "") nui_SetProperty("wordwrap", nuiBool(TRUE)); } -void NUI_AddTest(string sID = "") -{ - nui_CreateControl("menutest", sID); -} - -void NUI_SetTest(int n) -{ - //nui_SetProperty("label", nuiString(sLabel)); - //nui_SetProperty("image", nuiString(sImage)); - nui_SetProperty("image_rotation", nuiInt(n)); -} - // Drawlist -------------------------------------------------------------------- void NUI_DrawLine(string sPoints) @@ -1991,8 +1965,10 @@ void NUI_BindCurve(string sStart, string sEnd, string sCtrl0, string sCtrl1) void NUI_BindAcceptsInput(string sBind, int bWatch = FALSE) {nui_SetProperty("accepts_input", nuiBind(sBind, bWatch));} void NUI_BindClosable(string sBind, int bWatch = FALSE) {nui_SetProperty("closable", nuiBind(sBind, bWatch));} void NUI_BindCollapsible(string sBind, int bWatch = FALSE) {nui_SetProperty("collapsed", nuiBind(sBind, bWatch));} +void NUI_BindEdgeConstraint(string sBind, int bWatch = FALSE) {nui_SetProperty("edge_constraint", nuiBind(sBind, bWatch));} void NUI_BindGeometry(string sBind, int bWatch = FALSE) {nui_SetProperty("geometry", nuiBind(sBind, bWatch));} void NUI_BindResizable(string sBind, int bWatch = FALSE) {nui_SetProperty("resizable", nuiBind(sBind, bWatch));} +void NUI_BindSizeConstraint(string sBind, int bWatch = FALSE) {nui_SetProperty("size_constraint", nuiBind(sBind, bWatch));} void NUI_BindTitle(string sBind, int bWatch = FALSE) {nui_SetProperty("title", nuiBind(sBind, bWatch));} void NUI_BindTitleColor(string sBind, int bWatch = FALSE) {nui_SetProperty("foreground_color", nuiBind(sBind, bWatch));} void NUI_BindTransparent(string sBind, int bWatch = FALSE) {nui_SetProperty("transparent", nuiBind(sBind, bWatch));} @@ -2020,11 +1996,15 @@ void NUI_BindPoints(string sBind, int bWatch = FALSE) {nui_SetPrope void NUI_BindRadius(string sBind, int bWatch = FALSE) {nui_SetProperty("radius", nuiBind(sBind, bWatch));} void NUI_BindRectangle(string sBind, int bWatch = FALSE) {nui_SetProperty("rect", nuiBind(sBind, bWatch));} void NUI_BindRegion(string sBind, int bWatch = FALSE) {nui_SetProperty("image_region", nuiBind(sBind, bWatch));} +void NUI_BindRotation(string sBind, int bWatch = FALSE) {nui_SetProperty("rotate", nuiBind(sBind, bWatch));} void NUI_BindRowCount(string sBind, int bWatch = FALSE) {nui_SetProperty("row_count", nuiBind(sBind, bWatch));} +void NUI_BindScale(string sBind, int bWatch = FALSE) {nui_SetProperty("scale", nuiBind(sBind, bWatch));} void NUI_BindScissor(string sBind, int bWatch = FALSE) {nui_SetProperty("draw_list_scissor", nuiBind(sBind, bWatch));} +void NUI_BindShear(string sBInd, int bWatch = FALSE) {nui_SetProperty("shear", nuiBind(sBInd, bWatch));} void NUI_BindStartPoint(string sBind, int bWatch = FALSE) {nui_SetProperty("a", nuiBind(sBind, bWatch));} void NUI_BindStep(string sBind, int bWatch = FALSE) {nui_SetProperty("step", nuiBind(sBind, bWatch));} void NUI_BindText(string sBind, int bWatch = FALSE) {nui_SetProperty("text", nuiBind(sBind, bWatch));} +void NUI_BindTranslation(string sBInd, int bWatch = FALSE) {nui_SetProperty("translate", nuiBind(sBInd, bWatch));} void NUI_BindType(string sBind, int bWatch = FALSE) {nui_SetProperty("type", nuiBind(sBind, bWatch));} void NUI_BindValue(string sBind, int bWatch = FALSE) {nui_SetProperty("value", nuiBind(sBind, bWatch));} void NUI_BindVerticalAlignment(string sBind, int bWatch = FALSE) {nui_SetProperty("text_valign", nuiBind(sBind, bWatch));} @@ -2105,9 +2085,20 @@ void NUI_SetGeometry(float x, float y, float w, float h) {nui_SetProperty("geome void NUI_SetResizable(int bResizable = TRUE) {nui_SetProperty("resizable", nuiBool(bResizable));} void NUI_SetTransparent(int bTransparent = TRUE) {nui_SetProperty("transparent", nuiBool(bTransparent));} +void NUI_SetEdgeConstraint(float fLeft, float fRight, float fTop, float fBottom) +{ + nui_SetProperty("edge_constraint", NUI_DefineRectangle(fLeft, fTop, fRight, fBottom)); +} + +void NUI_SetSizeConstraint(float fMinWidth, float fMinHeight, float fMaxWidth, float fMaxHeight) +{ + nui_SetProperty("size_constraint", NUI_DefineRectangle(fMinWidth, fMinHeight, fMaxWidth, fMaxHeight)); +} + // Sets ------------------------------------------------------------------------ // Shared -------------------------------------------------------------------- void NUI_SetBorder(int bVisible = TRUE) {nui_SetProperty("border", nuiBool(bVisible));} +void NUI_SetCustomKey(string sKey, string sValue) {nui_SetProperty(sKey, sValue);} // Sets ------------------------------------------------------------------------ // Controls ------------------------------------------------------------------ @@ -2135,14 +2126,18 @@ void NUI_SetPoints(string sPoints) {nui_SetProperty(" void NUI_SetRadius(float r) {nui_SetProperty("radius", nuiFloat(r));} void NUI_SetRectangle(string sRectangle) {nui_SetProperty("rect", sRectangle);} void NUI_SetRegion(string sRegion) {nui_SetProperty("image_region", sRegion);} +void NUI_SetRotation(float fAngle) {nui_SetProperty("rotate", nuiFloat(fAngle));} void NUI_SetRowCount(int nRowCount) {nui_SetProperty("row_count", nuiInt(nRowCount));} void NUI_SetRowHeight(float fRowHeight) {nui_SetProperty("row_height", nuiFloat(fRowHeight));} +void NUI_SetScale(float x, float y) {nui_SetProperty("scale", NUI_DefinePoint(x, y));} void NUI_SetScissor(int bScissor) {nui_SetProperty("draw_list_scissor", nuiBool(bScissor));} void NUI_SetScrollbars(int nScrollbars = NUI_SCROLLBARS_AUTO) {nui_SetProperty("scrollbars", nuiInt(nScrollbars));} +void NUI_SetShear(float x, float y) {nui_SetProperty("shear", NUI_DefinePoint(x, y));} void NUI_SetStatic() {nui_SetProperty("type", nuiString("text"));} void NUI_SetTemplateVariable(int bVariable) {nui_SetProperty("NUI_TEMPLATE_VARIABLE", nuiBool(bVariable));} void NUI_SetTemplateWidth(float fWidth) {nui_SetProperty("NUI_TEMPLATE_WIDTH", nuiFloat(fWidth));} void NUI_SetText(string sText) {nui_SetProperty("text", nuiString(sText));} +void NUI_SetTranslation(float x, float y) {nui_SetProperty("translate", NUI_DefinePoint(x, y));} void NUI_SetValue(string sValue) {nui_SetProperty("value", sValue);} void NUI_SetVisible(int bVisible = TRUE) {nui_SetProperty("visible", nuiBool(bVisible));} void NUI_SetWidth(float fWidth) {nui_SetProperty("width", nuiFloat(fWidth));} @@ -2260,10 +2255,10 @@ void NUI_SetChartSeries(int nType, string sLegend, string sColor, string sData) json nui_GetForm(string sFormID, int bForceModule = FALSE) { - sql = nui_PrepareQuery("SELECT definition FROM nui_forms WHERE form = @form;", bForceModule); + sqlquery sql = nui_PrepareQuery("SELECT definition FROM nui_forms WHERE form = @form;", bForceModule); SqlBindString(sql, "@form", sFormID); - return SqlStep(sql) ? SqlGetJson(sql, 0) : JsonNull(); + return SqlStep(sql) ? SqlGetJson(sql, 0) : JSON_NULL; } string nui_GetFormsByPrefix(string sForms, string sPrefix, int nResType) @@ -2288,8 +2283,8 @@ int nui_ExecuteFunction(string sFile, string sFunction, object oTarget = OBJECT_ if (ResManFindPrefix(sFile, RESTYPE_NCS) == sFile) { - SetScriptParam("NUI_FUNCTION", sFunction); - SetScriptParam("NUI_ARGS", sArguments); + SetScriptParam(NUI_FUNCTION, sFunction); + SetScriptParam(NUI_ARGS, sArguments); ExecuteScript(sFile, oTarget); return TRUE; } @@ -2303,23 +2298,23 @@ int nui_ExecuteFunction(string sFile, string sFunction, object oTarget = OBJECT_ json nui_GetWatchedBinds(string sFormID) { - sQuery = "SELECT json_group_array(value) FROM (SELECT DISTINCT value FROM nui_forms, " + + string sQuery = "SELECT json_group_array(value) FROM (SELECT DISTINCT value FROM nui_forms, " + "json_tree(nui_forms.definition, '$') WHERE key = 'bind' AND json_extract(" + "nui_forms.definition, path || '.watch') = true AND form = @form);"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sFormID); - return SqlStep(sql) ? SqlGetJson(sql, 0) : JsonArray(); + return SqlStep(sql) ? SqlGetJson(sql, 0) : JSON_ARRAY; } json NUI_GetOrphanBinds(string sFormID) { - sQuery = "SELECT json_group_array(value) FROM (SELECT DISTINCT value FROM nui_forms, " + + string sQuery = "SELECT json_group_array(value) FROM (SELECT DISTINCT value FROM nui_forms, " + "json_tree(nui_forms.definition, '$') WHERE key = 'bind' and form = @form EXCEPT " + "SELECT key FROM (SELECT DISTINCT key FROM nui_forms, json_each(nui_forms.definition, " + "'$.profiles.default') AS value WHERE form = @form));"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sFormID); - return SqlStep(sql) ? SqlGetJson(sql, 0) : JsonArray(); + return SqlStep(sql) ? SqlGetJson(sql, 0) : JSON_ARRAY; } // ----------------------------------------------------------------------------- @@ -2334,10 +2329,10 @@ string nui_GetProfile() {return GetLocalString(nui_GetDataObject( void nui_SetProfileBind(string sProperty, string sJson = "") { string sPath = "$.profiles." + nui_GetProfile() + "." + sProperty; - sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, '" + sPath + + string sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, '" + sPath + "', json(@json)) FROM nui_forms WHERE form = @form) WHERE form = @form;"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", nui_GetFormID()); SqlBindString(sql, "@json", sJson); SqlStep(sql); @@ -2347,12 +2342,12 @@ void nui_SetProfileBind(string sProperty, string sJson = "") /// of potential recursion, just copy the base profile and go from there. void nui_CopyProfile(string sBase) { - sQuery = "WITH base AS (SELECT value FROM nui_forms, json_tree(nui_forms.definition, " + + string sQuery = "WITH base AS (SELECT value FROM nui_forms, json_tree(nui_forms.definition, " + "'$.profiles') WHERE key = @base AND form = @form) UPDATE nui_forms SET definition = " + "(SELECT json_set(definition, '$.profiles." + nui_GetProfile() + "', json_extract(base.value, '$')) " + "FROM nui_forms, base WHERE form = @form) WHERE form = @form;"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@base", sBase); SqlBindString(sql, "@form", nui_GetFormID()); SqlStep(sql); @@ -2362,16 +2357,16 @@ void nui_CopyProfile(string sBase) /// by sProfile. json nui_GetProfileBinds(string sFormID, string sProfile = "") { - sQuery = "WITH def AS (SELECT value FROM nui_forms, json_tree(nui_forms.definition, " + + string sQuery = "WITH def AS (SELECT value FROM nui_forms, json_tree(nui_forms.definition, " + "'$.profiles') WHERE key = 'default' AND form = @form), sel AS (SELECT " + "COALESCE((SELECT value from nui_forms, json_tree(nui_forms.definition, '$.profiles') " + "WHERE key = @profile AND form = @form), json_object()) value FROM nui_forms WHERE form = @form) " + "SELECT json_patch(json_extract(def.value, '$'), json_extract(sel.value, '$')) FROM def, sel;"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", sFormID); SqlBindString(sql, "@profile", sProfile); - return SqlStep(sql) ? SqlGetJson(sql, 0) : JsonObject(); + return SqlStep(sql) ? SqlGetJson(sql, 0) : JSON_OBJECT; } /// @private Called during form opening, sets the initial values for all default binds. @@ -2420,7 +2415,7 @@ void NUI_DefineForms(string sFormfile = "") int n; for (n; n < CountList(NUI_FORMFILE_PREFIX); n++) { string sFormfiles = nui_GetForms(GetListItem(NUI_FORMFILE_PREFIX, n)); - if (sFormfiles == "") return; + if (sFormfiles == "") break; int f; for (f; f < CountList(sFormfiles); f++) { @@ -2437,14 +2432,16 @@ void NUI_DefineForms(string sFormfile = "") nui_CommitTransaction(); } -int NUI_DisplayForm(object oPC, string sFormID, string sProfile = "default") +int NUI_DisplayForm(object oPC, string sFormID, string sProfile = "", int bSelfManage = FALSE) { json jForm = nui_GetForm(sFormID); - if (jForm != JsonNull()) + if (jForm != JSON_NULL) { - int nToken = NuiCreate(oPC, jForm, sFormID); - json jData = JsonObjectSet(JsonObject(), "profile", JsonString(sProfile)); - jData = JsonObjectSet(jData, "formfile", JsonString(nui_GetDefinitionValue(sFormID, "formfile"))); + string sFormfile = nui_GetDefinitionValue(sFormID, "formfile"); + + int nToken = NuiCreate(oPC, jForm, sFormID, (bSelfManage ? sFormfile : "")); + json jData = JsonObjectSet(JSON_OBJECT, "profile", JsonString(sProfile == "" ? "default" : sProfile)); + jData = JsonObjectSet(jData, "formfile", JsonString(sFormfile)); NuiSetUserData(oPC, NuiFindWindow(oPC, sFormID), jData); return nToken; @@ -2484,7 +2481,7 @@ void NUI_CreateProfile(string sProfile, string sBase = "") void NUI_SetProfileBind(string sBind, string sJson) { - if (sBind == "" || sJson == "" || JsonParse(sJson) == JsonNull()) + if (sBind == "" || sJson == "" || JsonParse(sJson) == JSON_NULL) return; nui_SetProfileBind(sBind, sJson); @@ -2497,7 +2494,7 @@ void NUI_SetProfileBindJ(string sBind, json jValue) void NUI_SetProfileBinds(string sBinds, string sJson) { - if (sBinds == "" || sJson == "" || JsonParse(sJson) == JsonNull()) + if (sBinds == "" || sJson == "" || JsonParse(sJson) == JSON_NULL) return; int n; for (n; n < CountList(sBinds); n++) @@ -2530,7 +2527,7 @@ int nui_HandleInspectionEvents(int nEventID = -1) if (ed.sEvent == "close") { - sql = nui_PrepareQuery("DELETE FROM nui_fi_data WHERE nToken = @token;"); + sqlquery sql = nui_PrepareQuery("DELETE FROM nui_fi_data WHERE nToken = @token;"); SqlBindInt(sql, "@token", NuiGetEventWindow()); SqlStep(sql); return -1; @@ -2590,13 +2587,9 @@ void nui_HandleNUIEvents() json jUserData = NuiGetUserData(oPC, NuiGetEventWindow()); string sFormfile = JsonGetString(JsonObjectGet(jUserData, "formfile")); - // TODO integrate form inspection - // Should we check for the inspection window, or just save everything? - // Or hide it behind a configuration option? int nInspectorEventID = nui_HandleInspectionEvents(); - string sEvent = NuiGetEventType(); - if (sEvent == "open") + if (NuiGetEventType() == "open") { string sProfile = JsonGetString(JsonObjectGet(jUserData, "profile")); nui_SetProfileBinds(oPC, sFormID, sProfile); @@ -2608,8 +2601,6 @@ void nui_HandleNUIEvents() if (nInspectorEventID != -1) nui_HandleInspectionEvents(nInspectorEventID); - - } // ----------------------------------------------------------------------------- @@ -2642,6 +2633,46 @@ int NUI_GetIsFormOpen(object oPC, string sFormID) return NuiFindWindow(oPC, sFormID) > 0; } +void NUI_DumpEventData(struct NUIEventData ed) +{ + string sDump = + HexColorString("NUI Event Data Dump:", COLOR_CYAN) + + "\n -> " + HexColorString("PC: ", COLOR_GREEN_LIGHT) + HexColorString(GetName(ed.oPC), COLOR_ORANGE_LIGHT) + + "\n -> " + HexColorString("Form ID: ", COLOR_GREEN_LIGHT) + HexColorString(ed.sFormID, COLOR_ORANGE_LIGHT) + + "\n -> " + HexColorString("Form Token: ", COLOR_GREEN_LIGHT) + HexColorString(IntToString(ed.nToken), COLOR_ORANGE_LIGHT) + + "\n -> " + HexColorString("NUI Event: ", COLOR_GREEN_LIGHT) + HexColorString(ed.sEvent, COLOR_ORANGE_LIGHT) + + (ed.sEvent == "watch" ? + "\n -> " + HexColorString("Watched Bind: ", COLOR_GREEN_LIGHT) + HexColorString(ed.sControlID, COLOR_ORANGE_LIGHT) + + "\n -> " + HexColorString("Watched Bind Value: ", COLOR_GREEN_LIGHT) + + HexColorString(JsonDump(NuiGetBind(ed.oPC, ed.nToken, ed.sControlID)), COLOR_ORANGE_LIGHT) : + "\n -> " + HexColorString("Control ID: ", COLOR_GREEN_LIGHT) + HexColorString(ed.sControlID, COLOR_ORANGE_LIGHT)) + + (ed.nIndex > -1 ? + "\n -> " + HexColorString("Control Array Index: ", COLOR_GREEN_LIGHT) + HexColorString(IntToString(ed.nIndex), COLOR_ORANGE_LIGHT) : "") + + "\n -> " + HexColorString("Event Payload: ", COLOR_GREEN_LIGHT) + HexColorString(JsonDump(ed.jPayload), COLOR_ORANGE_LIGHT); + NUI_Debug(sDump); +} + +string NUI_GetVersions(int bIncludeForms = TRUE) +{ + int nKey = COLOR_BLUE_SKY_DEEP; + int nValue = COLOR_BLUE_LIGHT; + string sVersions = HexColorString("NUI System: ", COLOR_ORANGE_LIGHT) + HexColorString(NUI_VERSION, nValue); + + if (bIncludeForms) + { + string s = + "SELECT form || ': ', IIF(json_extract(definition, '$.local_version') = '', " + + "'', json_extract(definition, '$.local_version')) " + + "FROM nui_forms;"; + sqlquery q = nui_PrepareQuery(s); + + while (SqlStep(q)) + sVersions += "\n " + HexColorString(SqlGetString(q, 0), nKey) + HexColorString(SqlGetString(q, 1), nValue); + } + + return sVersions; +} + struct NUIEventData NUI_GetEventData() { struct NUIEventData ed; @@ -2659,11 +2690,11 @@ struct NUIEventData NUI_GetEventData() void NUI_SubscribeEvent(int nEvent) { - sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, " + + string sQuery = "UPDATE nui_forms SET definition = (SELECT json_set(definition, " + "'$.event_data[#]', json(@value)) FROM nui_forms WHERE form = @form) " + "WHERE form = @form;"; - sql = nui_PrepareQuery(sQuery, TRUE); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindString(sql, "@form", nui_GetFormID()); SqlBindInt (sql, "@value", nEvent); SqlStep(sql); @@ -2672,15 +2703,17 @@ void NUI_SubscribeEvent(int nEvent) void NUI_HandleEvents(object oPC = OBJECT_SELF) { int nEvent = GetCurrentlyRunningEvent(); + if (nEvent == EVENT_SCRIPT_MODULE_ON_MODULE_LOAD) + NUI_Initialize(); if (nEvent == EVENT_SCRIPT_MODULE_ON_NUI_EVENT) nui_HandleNUIEvents(); else { - sQuery = "SELECT json_group_array(json_extract(nui_forms.definition, '$.formfile')) " + + string sQuery = "SELECT json_group_array(json_extract(nui_forms.definition, '$.formfile')) " + "FROM nui_forms WHERE EXISTS (SELECT 1 FROM json_each(nui_forms.definition, " + "'$.event_data') WHERE value = @event);"; - sql = nui_PrepareQuery(sQuery); + sqlquery sql = nui_PrepareQuery(sQuery); SqlBindInt(sql, "@event", nEvent); SetLocalObject(oPC, NUI_OBJECT, OBJECT_SELF); @@ -2695,3 +2728,5 @@ void NUI_HandleEvents(object oPC = OBJECT_SELF) DeleteLocalObject(oPC, NUI_OBJECT); } } + +void NUI(object oPC = OBJECT_SELF) {NUI_HandleEvents(oPC);} diff --git a/src/mod/nss/nw_c2_bossdie.nss b/src/module/nss/nw_c2_bossdie.nss similarity index 100% rename from src/mod/nss/nw_c2_bossdie.nss rename to src/module/nss/nw_c2_bossdie.nss diff --git a/src/mod/nss/nw_c2_bossspawn.nss b/src/module/nss/nw_c2_bossspawn.nss similarity index 100% rename from src/mod/nss/nw_c2_bossspawn.nss rename to src/module/nss/nw_c2_bossspawn.nss diff --git a/src/module/nss/nw_c2_default1.nss b/src/module/nss/nw_c2_default1.nss new file mode 100644 index 0000000..6d717da --- /dev/null +++ b/src/module/nss/nw_c2_default1.nss @@ -0,0 +1,92 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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(OBJECT_SELF) == AI_LEVEL_VERY_LOW) return; + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_hb", oCreature); + 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, oCreature); + } + } + } + // Send the user-defined event signal if specified here so it doesn't get skipped. + if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)) + { + SignalEvent(oCreature, EventUserDefined(EVENT_HEARTBEAT)); + } + 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 new file mode 100644 index 0000000..fa6f5f8 --- /dev/null +++ b/src/module/nss/nw_c2_default2.nss @@ -0,0 +1,138 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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 (GetAILevel() == AI_LEVEL_VERY_LOW) return; + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_percep", oCreature); + 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(); + // 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) + { + if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION)) + { + SpeakOneLinerConversation(); + } + } + if(GetIsEnemy(oLastPerceived, oCreature)) + { + // ************************** 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)) + { + 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 + { + // ************************ NON_ENEMY SEEN ***************************** + if(bSeen) + { + if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature); + else if(GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION) && GetIsPC(oLastPerceived)) + { + ActionStartConversation(oCreature); + } + } + } + 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) && bSeen) + { + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE)); + } +} diff --git a/src/module/nss/nw_c2_default3.nss b/src/module/nss/nw_c2_default3.nss new file mode 100644 index 0000000..6e36412 --- /dev/null +++ b/src/module/nss/nw_c2_default3.nss @@ -0,0 +1,70 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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() +{ + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_combat", oCreature); + 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)); + } + 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 new file mode 100644 index 0000000..38603f1 --- /dev/null +++ b/src/module/nss/nw_c2_default4.nss @@ -0,0 +1,70 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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() +{ + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_conv", oCreature); + 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; + } + object oLastSpeaker = GetLastSpeaker(); + int nMatch = GetListenPatternNumber(); + if(nMatch != -1) + { + if(GetFactionEqual(oLastSpeaker, oCreature)) ai_MonsterCommands(oCreature, oLastSpeaker, nMatch); + } + else + { + ai_ClearCreatureActions(); + BeginConversation(); + } + // Send the user-defined event if appropriate + if(GetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DIALOGUE)); + } +} +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 new file mode 100644 index 0000000..c2e663d --- /dev/null +++ b/src/module/nss/nw_c2_default5.nss @@ -0,0 +1,37 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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() +{ + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_physatt", oCreature); + 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(oCreature, EventUserDefined(EVENT_ATTACKED)); + } + 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 new file mode 100644 index 0000000..60aef49 --- /dev/null +++ b/src/module/nss/nw_c2_default6.nss @@ -0,0 +1,34 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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 oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_damaged", oCreature); + // Send the user-defined event signal + if(GetSpawnInCondition(NW_FLAG_DAMAGED_EVENT)) + { + SignalEvent(oCreature, EventUserDefined(EVENT_DAMAGED)); + return; + } + 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 new file mode 100644 index 0000000..ef07c73 --- /dev/null +++ b/src/module/nss/nw_c2_default8.nss @@ -0,0 +1,26 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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 oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_disturb", oCreature); + if(AI_DEBUG) ai_Debug("nw_c2_default8", "13", GetName(oCreature) + " 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)) + { + SignalEvent(oCreature, EventUserDefined(EVENT_DISTURBED)); + } +} diff --git a/src/module/nss/nw_c2_defaultb.nss b/src/module/nss/nw_c2_defaultb.nss new file mode 100644 index 0000000..050a3ea --- /dev/null +++ b/src/module/nss/nw_c2_defaultb.nss @@ -0,0 +1,42 @@ +/*////////////////////////////////////////////////////////////////////////////// + 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; + ExecuteScript("prc_npc_spellat", oCreature); + object oCaster = GetLastSpellCaster(); + 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)); + } + // 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 new file mode 100644 index 0000000..98e4364 --- /dev/null +++ b/src/module/nss/nw_c2_defaulte.nss @@ -0,0 +1,54 @@ +/*////////////////////////////////////////////////////////////////////////////// + Script: nw_c2_defaulte + Programmer: Philos +//////////////////////////////////////////////////////////////////////////////// + Monsters OnBlocked event script; + Can be blocked by a creature or door. +*/////////////////////////////////////////////////////////////////////////////// +#include "0i_associates" +void main() +{ + object oCreature = OBJECT_SELF; + ExecuteScript("prc_npc_blocked", oCreature); + // 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) + { + if(GetIsEnemy(oObject, oCreature)) + { + if(ai_CanIAttack(oCreature) && ai_GetIsInCombat(oCreature)) + { + ai_DoMonsterCombatRound(oCreature); + 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 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; + } +} + + 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/mod/nss/nw_d2_gen_check.nss b/src/module/nss/nw_d2_gen_check.nss similarity index 100% rename from src/mod/nss/nw_d2_gen_check.nss rename to src/module/nss/nw_d2_gen_check.nss diff --git a/src/mod/nss/nw_o2_boss.nss b/src/module/nss/nw_o2_boss.nss similarity index 100% rename from src/mod/nss/nw_o2_boss.nss rename to src/module/nss/nw_o2_boss.nss diff --git a/src/mod/nss/nw_o2_classhig.nss b/src/module/nss/nw_o2_classhig.nss similarity index 100% rename from src/mod/nss/nw_o2_classhig.nss rename to src/module/nss/nw_o2_classhig.nss diff --git a/src/mod/nss/nw_o2_classlow.nss b/src/module/nss/nw_o2_classlow.nss similarity index 100% rename from src/mod/nss/nw_o2_classlow.nss rename to src/module/nss/nw_o2_classlow.nss diff --git a/src/mod/nss/nw_o2_classmed.nss b/src/module/nss/nw_o2_classmed.nss similarity index 100% rename from src/mod/nss/nw_o2_classmed.nss rename to src/module/nss/nw_o2_classmed.nss diff --git a/src/mod/nss/nw_o2_classweap.nss b/src/module/nss/nw_o2_classweap.nss similarity index 100% rename from src/mod/nss/nw_o2_classweap.nss rename to src/module/nss/nw_o2_classweap.nss diff --git a/src/mod/nss/nw_o2_generalhig.nss b/src/module/nss/nw_o2_generalhig.nss similarity index 100% rename from src/mod/nss/nw_o2_generalhig.nss rename to src/module/nss/nw_o2_generalhig.nss diff --git a/src/mod/nss/nw_o2_generallow.nss b/src/module/nss/nw_o2_generallow.nss similarity index 100% rename from src/mod/nss/nw_o2_generallow.nss rename to src/module/nss/nw_o2_generallow.nss diff --git a/src/mod/nss/nw_o2_generalmed.nss b/src/module/nss/nw_o2_generalmed.nss similarity index 100% rename from src/mod/nss/nw_o2_generalmed.nss rename to src/module/nss/nw_o2_generalmed.nss diff --git a/src/mod/nss/nw_o2_generalmid.nss b/src/module/nss/nw_o2_generalmid.nss similarity index 100% rename from src/mod/nss/nw_o2_generalmid.nss rename to src/module/nss/nw_o2_generalmid.nss diff --git a/src/mod/nss/nw_s1_aurablnda.nss b/src/module/nss/nw_s1_aurablnda.nss similarity index 100% rename from src/mod/nss/nw_s1_aurablnda.nss rename to src/module/nss/nw_s1_aurablnda.nss diff --git a/src/mod/nss/nw_s1_auracoldc.nss b/src/module/nss/nw_s1_auracoldc.nss similarity index 100% rename from src/mod/nss/nw_s1_auracoldc.nss rename to src/module/nss/nw_s1_auracoldc.nss diff --git a/src/mod/nss/nw_s1_auraelecc.nss b/src/module/nss/nw_s1_auraelecc.nss similarity index 100% rename from src/mod/nss/nw_s1_auraelecc.nss rename to src/module/nss/nw_s1_auraelecc.nss diff --git a/src/mod/nss/nw_s1_aurafirec.nss b/src/module/nss/nw_s1_aurafirec.nss similarity index 100% rename from src/mod/nss/nw_s1_aurafirec.nss rename to src/module/nss/nw_s1_aurafirec.nss diff --git a/src/mod/nss/nw_s1_auramenca.nss b/src/module/nss/nw_s1_auramenca.nss similarity index 100% rename from src/mod/nss/nw_s1_auramenca.nss rename to src/module/nss/nw_s1_auramenca.nss diff --git a/src/mod/nss/nw_s1_auraprota.nss b/src/module/nss/nw_s1_auraprota.nss similarity index 100% rename from src/mod/nss/nw_s1_auraprota.nss rename to src/module/nss/nw_s1_auraprota.nss diff --git a/src/mod/nss/nw_s1_aurastuna.nss b/src/module/nss/nw_s1_aurastuna.nss similarity index 100% rename from src/mod/nss/nw_s1_aurastuna.nss rename to src/module/nss/nw_s1_aurastuna.nss diff --git a/src/mod/nss/nw_s1_auraunata.nss b/src/module/nss/nw_s1_auraunata.nss similarity index 100% rename from src/mod/nss/nw_s1_auraunata.nss rename to src/module/nss/nw_s1_auraunata.nss diff --git a/src/mod/nss/nw_s1_aurauneaa.nss b/src/module/nss/nw_s1_aurauneaa.nss similarity index 100% rename from src/mod/nss/nw_s1_aurauneaa.nss rename to src/module/nss/nw_s1_aurauneaa.nss diff --git a/src/mod/nss/nw_s1_bltacid.nss b/src/module/nss/nw_s1_bltacid.nss similarity index 100% rename from src/mod/nss/nw_s1_bltacid.nss rename to src/module/nss/nw_s1_bltacid.nss diff --git a/src/mod/nss/nw_s1_bltcharm.nss b/src/module/nss/nw_s1_bltcharm.nss similarity index 100% rename from src/mod/nss/nw_s1_bltcharm.nss rename to src/module/nss/nw_s1_bltcharm.nss diff --git a/src/mod/nss/nw_s1_bltchrdr.nss b/src/module/nss/nw_s1_bltchrdr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltchrdr.nss rename to src/module/nss/nw_s1_bltchrdr.nss diff --git a/src/mod/nss/nw_s1_bltcold.nss b/src/module/nss/nw_s1_bltcold.nss similarity index 100% rename from src/mod/nss/nw_s1_bltcold.nss rename to src/module/nss/nw_s1_bltcold.nss diff --git a/src/mod/nss/nw_s1_bltcondr.nss b/src/module/nss/nw_s1_bltcondr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltcondr.nss rename to src/module/nss/nw_s1_bltcondr.nss diff --git a/src/mod/nss/nw_s1_bltconf.nss b/src/module/nss/nw_s1_bltconf.nss similarity index 100% rename from src/mod/nss/nw_s1_bltconf.nss rename to src/module/nss/nw_s1_bltconf.nss diff --git a/src/mod/nss/nw_s1_bltdaze.nss b/src/module/nss/nw_s1_bltdaze.nss similarity index 100% rename from src/mod/nss/nw_s1_bltdaze.nss rename to src/module/nss/nw_s1_bltdaze.nss diff --git a/src/mod/nss/nw_s1_bltdeath.nss b/src/module/nss/nw_s1_bltdeath.nss similarity index 100% rename from src/mod/nss/nw_s1_bltdeath.nss rename to src/module/nss/nw_s1_bltdeath.nss diff --git a/src/mod/nss/nw_s1_bltdexdr.nss b/src/module/nss/nw_s1_bltdexdr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltdexdr.nss rename to src/module/nss/nw_s1_bltdexdr.nss diff --git a/src/mod/nss/nw_s1_bltdisese.nss b/src/module/nss/nw_s1_bltdisese.nss similarity index 100% rename from src/mod/nss/nw_s1_bltdisese.nss rename to src/module/nss/nw_s1_bltdisese.nss diff --git a/src/mod/nss/nw_s1_bltdomn.nss b/src/module/nss/nw_s1_bltdomn.nss similarity index 100% rename from src/mod/nss/nw_s1_bltdomn.nss rename to src/module/nss/nw_s1_bltdomn.nss diff --git a/src/mod/nss/nw_s1_bltfire.nss b/src/module/nss/nw_s1_bltfire.nss similarity index 100% rename from src/mod/nss/nw_s1_bltfire.nss rename to src/module/nss/nw_s1_bltfire.nss diff --git a/src/mod/nss/nw_s1_bltintdr.nss b/src/module/nss/nw_s1_bltintdr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltintdr.nss rename to src/module/nss/nw_s1_bltintdr.nss diff --git a/src/mod/nss/nw_s1_bltknckd.nss b/src/module/nss/nw_s1_bltknckd.nss similarity index 100% rename from src/mod/nss/nw_s1_bltknckd.nss rename to src/module/nss/nw_s1_bltknckd.nss diff --git a/src/mod/nss/nw_s1_bltlightn.nss b/src/module/nss/nw_s1_bltlightn.nss similarity index 100% rename from src/mod/nss/nw_s1_bltlightn.nss rename to src/module/nss/nw_s1_bltlightn.nss diff --git a/src/mod/nss/nw_s1_bltlvldr.nss b/src/module/nss/nw_s1_bltlvldr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltlvldr.nss rename to src/module/nss/nw_s1_bltlvldr.nss diff --git a/src/mod/nss/nw_s1_bltparal.nss b/src/module/nss/nw_s1_bltparal.nss similarity index 100% rename from src/mod/nss/nw_s1_bltparal.nss rename to src/module/nss/nw_s1_bltparal.nss diff --git a/src/mod/nss/nw_s1_bltpoison.nss b/src/module/nss/nw_s1_bltpoison.nss similarity index 100% rename from src/mod/nss/nw_s1_bltpoison.nss rename to src/module/nss/nw_s1_bltpoison.nss diff --git a/src/mod/nss/nw_s1_bltshards.nss b/src/module/nss/nw_s1_bltshards.nss similarity index 100% rename from src/mod/nss/nw_s1_bltshards.nss rename to src/module/nss/nw_s1_bltshards.nss diff --git a/src/mod/nss/nw_s1_bltslow.nss b/src/module/nss/nw_s1_bltslow.nss similarity index 100% rename from src/mod/nss/nw_s1_bltslow.nss rename to src/module/nss/nw_s1_bltslow.nss diff --git a/src/mod/nss/nw_s1_bltstrdr.nss b/src/module/nss/nw_s1_bltstrdr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltstrdr.nss rename to src/module/nss/nw_s1_bltstrdr.nss diff --git a/src/mod/nss/nw_s1_bltstun.nss b/src/module/nss/nw_s1_bltstun.nss similarity index 100% rename from src/mod/nss/nw_s1_bltstun.nss rename to src/module/nss/nw_s1_bltstun.nss diff --git a/src/mod/nss/nw_s1_bltweb.nss b/src/module/nss/nw_s1_bltweb.nss similarity index 100% rename from src/mod/nss/nw_s1_bltweb.nss rename to src/module/nss/nw_s1_bltweb.nss diff --git a/src/mod/nss/nw_s1_bltwisdr.nss b/src/module/nss/nw_s1_bltwisdr.nss similarity index 100% rename from src/mod/nss/nw_s1_bltwisdr.nss rename to src/module/nss/nw_s1_bltwisdr.nss diff --git a/src/mod/nss/nw_s1_coneacid.nss b/src/module/nss/nw_s1_coneacid.nss similarity index 100% rename from src/mod/nss/nw_s1_coneacid.nss rename to src/module/nss/nw_s1_coneacid.nss diff --git a/src/mod/nss/nw_s1_conecold.nss b/src/module/nss/nw_s1_conecold.nss similarity index 100% rename from src/mod/nss/nw_s1_conecold.nss rename to src/module/nss/nw_s1_conecold.nss diff --git a/src/mod/nss/nw_s1_conedisea.nss b/src/module/nss/nw_s1_conedisea.nss similarity index 100% rename from src/mod/nss/nw_s1_conedisea.nss rename to src/module/nss/nw_s1_conedisea.nss diff --git a/src/mod/nss/nw_s1_coneelec.nss b/src/module/nss/nw_s1_coneelec.nss similarity index 100% rename from src/mod/nss/nw_s1_coneelec.nss rename to src/module/nss/nw_s1_coneelec.nss diff --git a/src/mod/nss/nw_s1_conesonic.nss b/src/module/nss/nw_s1_conesonic.nss similarity index 100% rename from src/mod/nss/nw_s1_conesonic.nss rename to src/module/nss/nw_s1_conesonic.nss diff --git a/src/mod/nss/nw_s1_dragfear.nss b/src/module/nss/nw_s1_dragfear.nss similarity index 100% rename from src/mod/nss/nw_s1_dragfear.nss rename to src/module/nss/nw_s1_dragfear.nss diff --git a/src/mod/nss/nw_s1_dragfeara.nss b/src/module/nss/nw_s1_dragfeara.nss similarity index 100% rename from src/mod/nss/nw_s1_dragfeara.nss rename to src/module/nss/nw_s1_dragfeara.nss diff --git a/src/mod/nss/nw_s1_feroc3.nss b/src/module/nss/nw_s1_feroc3.nss similarity index 100% rename from src/mod/nss/nw_s1_feroc3.nss rename to src/module/nss/nw_s1_feroc3.nss diff --git a/src/mod/nss/nw_s1_gazechaos.nss b/src/module/nss/nw_s1_gazechaos.nss similarity index 100% rename from src/mod/nss/nw_s1_gazechaos.nss rename to src/module/nss/nw_s1_gazechaos.nss diff --git a/src/mod/nss/nw_s1_gazecharm.nss b/src/module/nss/nw_s1_gazecharm.nss similarity index 100% rename from src/mod/nss/nw_s1_gazecharm.nss rename to src/module/nss/nw_s1_gazecharm.nss diff --git a/src/mod/nss/nw_s1_gazeconfu.nss b/src/module/nss/nw_s1_gazeconfu.nss similarity index 100% rename from src/mod/nss/nw_s1_gazeconfu.nss rename to src/module/nss/nw_s1_gazeconfu.nss diff --git a/src/mod/nss/nw_s1_gazedaze.nss b/src/module/nss/nw_s1_gazedaze.nss similarity index 100% rename from src/mod/nss/nw_s1_gazedaze.nss rename to src/module/nss/nw_s1_gazedaze.nss diff --git a/src/mod/nss/nw_s1_gazedeath.nss b/src/module/nss/nw_s1_gazedeath.nss similarity index 100% rename from src/mod/nss/nw_s1_gazedeath.nss rename to src/module/nss/nw_s1_gazedeath.nss diff --git a/src/mod/nss/nw_s1_gazedomn.nss b/src/module/nss/nw_s1_gazedomn.nss similarity index 100% rename from src/mod/nss/nw_s1_gazedomn.nss rename to src/module/nss/nw_s1_gazedomn.nss diff --git a/src/mod/nss/nw_s1_gazedoom.nss b/src/module/nss/nw_s1_gazedoom.nss similarity index 100% rename from src/mod/nss/nw_s1_gazedoom.nss rename to src/module/nss/nw_s1_gazedoom.nss diff --git a/src/mod/nss/nw_s1_gazeevil.nss b/src/module/nss/nw_s1_gazeevil.nss similarity index 100% rename from src/mod/nss/nw_s1_gazeevil.nss rename to src/module/nss/nw_s1_gazeevil.nss diff --git a/src/mod/nss/nw_s1_gazefear.nss b/src/module/nss/nw_s1_gazefear.nss similarity index 100% rename from src/mod/nss/nw_s1_gazefear.nss rename to src/module/nss/nw_s1_gazefear.nss diff --git a/src/mod/nss/nw_s1_gazegood.nss b/src/module/nss/nw_s1_gazegood.nss similarity index 100% rename from src/mod/nss/nw_s1_gazegood.nss rename to src/module/nss/nw_s1_gazegood.nss diff --git a/src/mod/nss/nw_s1_gazelaw.nss b/src/module/nss/nw_s1_gazelaw.nss similarity index 100% rename from src/mod/nss/nw_s1_gazelaw.nss rename to src/module/nss/nw_s1_gazelaw.nss diff --git a/src/mod/nss/nw_s1_gazestun.nss b/src/module/nss/nw_s1_gazestun.nss similarity index 100% rename from src/mod/nss/nw_s1_gazestun.nss rename to src/module/nss/nw_s1_gazestun.nss diff --git a/src/mod/nss/nw_s1_golemgas.nss b/src/module/nss/nw_s1_golemgas.nss similarity index 100% rename from src/mod/nss/nw_s1_golemgas.nss rename to src/module/nss/nw_s1_golemgas.nss diff --git a/src/mod/nss/nw_s1_hndbreath.nss b/src/module/nss/nw_s1_hndbreath.nss similarity index 100% rename from src/mod/nss/nw_s1_hndbreath.nss rename to src/module/nss/nw_s1_hndbreath.nss diff --git a/src/mod/nss/nw_s1_howlconf.nss b/src/module/nss/nw_s1_howlconf.nss similarity index 100% rename from src/mod/nss/nw_s1_howlconf.nss rename to src/module/nss/nw_s1_howlconf.nss diff --git a/src/mod/nss/nw_s1_howldaze.nss b/src/module/nss/nw_s1_howldaze.nss similarity index 100% rename from src/mod/nss/nw_s1_howldaze.nss rename to src/module/nss/nw_s1_howldaze.nss diff --git a/src/mod/nss/nw_s1_howldeath.nss b/src/module/nss/nw_s1_howldeath.nss similarity index 100% rename from src/mod/nss/nw_s1_howldeath.nss rename to src/module/nss/nw_s1_howldeath.nss diff --git a/src/mod/nss/nw_s1_howlfear.nss b/src/module/nss/nw_s1_howlfear.nss similarity index 100% rename from src/mod/nss/nw_s1_howlfear.nss rename to src/module/nss/nw_s1_howlfear.nss diff --git a/src/mod/nss/nw_s1_howlparal.nss b/src/module/nss/nw_s1_howlparal.nss similarity index 100% rename from src/mod/nss/nw_s1_howlparal.nss rename to src/module/nss/nw_s1_howlparal.nss diff --git a/src/mod/nss/nw_s1_howlsonic.nss b/src/module/nss/nw_s1_howlsonic.nss similarity index 100% rename from src/mod/nss/nw_s1_howlsonic.nss rename to src/module/nss/nw_s1_howlsonic.nss diff --git a/src/mod/nss/nw_s1_howlstun.nss b/src/module/nss/nw_s1_howlstun.nss similarity index 100% rename from src/mod/nss/nw_s1_howlstun.nss rename to src/module/nss/nw_s1_howlstun.nss diff --git a/src/mod/nss/nw_s1_krenscare.nss b/src/module/nss/nw_s1_krenscare.nss similarity index 100% rename from src/mod/nss/nw_s1_krenscare.nss rename to src/module/nss/nw_s1_krenscare.nss diff --git a/src/mod/nss/nw_s1_mephsalt.nss b/src/module/nss/nw_s1_mephsalt.nss similarity index 100% rename from src/mod/nss/nw_s1_mephsalt.nss rename to src/module/nss/nw_s1_mephsalt.nss diff --git a/src/mod/nss/nw_s1_mephsteam.nss b/src/module/nss/nw_s1_mephsteam.nss similarity index 100% rename from src/mod/nss/nw_s1_mephsteam.nss rename to src/module/nss/nw_s1_mephsteam.nss diff --git a/src/mod/nss/nw_s1_mumundead.nss b/src/module/nss/nw_s1_mumundead.nss similarity index 100% rename from src/mod/nss/nw_s1_mumundead.nss rename to src/module/nss/nw_s1_mumundead.nss diff --git a/src/mod/nss/nw_s1_pulschrdr.nss b/src/module/nss/nw_s1_pulschrdr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulschrdr.nss rename to src/module/nss/nw_s1_pulschrdr.nss diff --git a/src/mod/nss/nw_s1_pulscold.nss b/src/module/nss/nw_s1_pulscold.nss similarity index 100% rename from src/mod/nss/nw_s1_pulscold.nss rename to src/module/nss/nw_s1_pulscold.nss diff --git a/src/mod/nss/nw_s1_pulscondr.nss b/src/module/nss/nw_s1_pulscondr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulscondr.nss rename to src/module/nss/nw_s1_pulscondr.nss diff --git a/src/mod/nss/nw_s1_pulsdeath.nss b/src/module/nss/nw_s1_pulsdeath.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsdeath.nss rename to src/module/nss/nw_s1_pulsdeath.nss diff --git a/src/mod/nss/nw_s1_pulsdexdr.nss b/src/module/nss/nw_s1_pulsdexdr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsdexdr.nss rename to src/module/nss/nw_s1_pulsdexdr.nss diff --git a/src/mod/nss/nw_s1_pulsdis.nss b/src/module/nss/nw_s1_pulsdis.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsdis.nss rename to src/module/nss/nw_s1_pulsdis.nss diff --git a/src/mod/nss/nw_s1_pulselec.nss b/src/module/nss/nw_s1_pulselec.nss similarity index 100% rename from src/mod/nss/nw_s1_pulselec.nss rename to src/module/nss/nw_s1_pulselec.nss diff --git a/src/mod/nss/nw_s1_pulsfire.nss b/src/module/nss/nw_s1_pulsfire.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsfire.nss rename to src/module/nss/nw_s1_pulsfire.nss diff --git a/src/mod/nss/nw_s1_pulsholy.nss b/src/module/nss/nw_s1_pulsholy.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsholy.nss rename to src/module/nss/nw_s1_pulsholy.nss diff --git a/src/mod/nss/nw_s1_pulsintdr.nss b/src/module/nss/nw_s1_pulsintdr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsintdr.nss rename to src/module/nss/nw_s1_pulsintdr.nss diff --git a/src/mod/nss/nw_s1_pulslvldr.nss b/src/module/nss/nw_s1_pulslvldr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulslvldr.nss rename to src/module/nss/nw_s1_pulslvldr.nss diff --git a/src/mod/nss/nw_s1_pulsneg.nss b/src/module/nss/nw_s1_pulsneg.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsneg.nss rename to src/module/nss/nw_s1_pulsneg.nss diff --git a/src/mod/nss/nw_s1_pulspois.nss b/src/module/nss/nw_s1_pulspois.nss similarity index 100% rename from src/mod/nss/nw_s1_pulspois.nss rename to src/module/nss/nw_s1_pulspois.nss diff --git a/src/mod/nss/nw_s1_pulsspore.nss b/src/module/nss/nw_s1_pulsspore.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsspore.nss rename to src/module/nss/nw_s1_pulsspore.nss diff --git a/src/mod/nss/nw_s1_pulsstrdr.nss b/src/module/nss/nw_s1_pulsstrdr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulsstrdr.nss rename to src/module/nss/nw_s1_pulsstrdr.nss diff --git a/src/mod/nss/nw_s1_pulswind.nss b/src/module/nss/nw_s1_pulswind.nss similarity index 100% rename from src/mod/nss/nw_s1_pulswind.nss rename to src/module/nss/nw_s1_pulswind.nss diff --git a/src/mod/nss/nw_s1_pulswisdr.nss b/src/module/nss/nw_s1_pulswisdr.nss similarity index 100% rename from src/mod/nss/nw_s1_pulswisdr.nss rename to src/module/nss/nw_s1_pulswisdr.nss diff --git a/src/mod/nss/nw_s1_smokeclaw.nss b/src/module/nss/nw_s1_smokeclaw.nss similarity index 100% rename from src/mod/nss/nw_s1_smokeclaw.nss rename to src/module/nss/nw_s1_smokeclaw.nss diff --git a/src/mod/nss/nw_s1_stink_a.nss b/src/module/nss/nw_s1_stink_a.nss similarity index 100% rename from src/mod/nss/nw_s1_stink_a.nss rename to src/module/nss/nw_s1_stink_a.nss diff --git a/src/mod/nss/nw_s1_tyrantfga.nss b/src/module/nss/nw_s1_tyrantfga.nss similarity index 100% rename from src/mod/nss/nw_s1_tyrantfga.nss rename to src/module/nss/nw_s1_tyrantfga.nss diff --git a/src/mod/nss/nw_s1_tyrantfog.nss b/src/module/nss/nw_s1_tyrantfog.nss similarity index 100% rename from src/mod/nss/nw_s1_tyrantfog.nss rename to src/module/nss/nw_s1_tyrantfog.nss diff --git a/src/mod/nss/nw_s2_divprot.nss b/src/module/nss/nw_s2_divprot.nss similarity index 100% rename from src/mod/nss/nw_s2_divprot.nss rename to src/module/nss/nw_s2_divprot.nss diff --git a/src/mod/nss/nw_s3_balordeth.nss b/src/module/nss/nw_s3_balordeth.nss similarity index 100% rename from src/mod/nss/nw_s3_balordeth.nss rename to src/module/nss/nw_s3_balordeth.nss diff --git a/src/mod/nss/obj_hb_bubble.nss b/src/module/nss/obj_hb_bubble.nss similarity index 100% rename from src/mod/nss/obj_hb_bubble.nss rename to src/module/nss/obj_hb_bubble.nss diff --git a/src/mod/nss/omw_ppis_disturb.nss b/src/module/nss/omw_ppis_disturb.nss similarity index 100% rename from src/mod/nss/omw_ppis_disturb.nss rename to src/module/nss/omw_ppis_disturb.nss diff --git a/src/mod/nss/omw_ppis_start.nss b/src/module/nss/omw_ppis_start.nss similarity index 100% rename from src/mod/nss/omw_ppis_start.nss rename to src/module/nss/omw_ppis_start.nss diff --git a/src/mod/nss/open_field1.nss b/src/module/nss/open_field1.nss similarity index 100% rename from src/mod/nss/open_field1.nss rename to src/module/nss/open_field1.nss diff --git a/src/mod/nss/open_field2.nss b/src/module/nss/open_field2.nss similarity index 100% rename from src/mod/nss/open_field2.nss rename to src/module/nss/open_field2.nss diff --git a/src/mod/nss/open_field3.nss b/src/module/nss/open_field3.nss similarity index 100% rename from src/mod/nss/open_field3.nss rename to src/module/nss/open_field3.nss diff --git a/src/mod/nss/open_field4.nss b/src/module/nss/open_field4.nss similarity index 100% rename from src/mod/nss/open_field4.nss rename to src/module/nss/open_field4.nss diff --git a/src/mod/nss/open_field5.nss b/src/module/nss/open_field5.nss similarity index 100% rename from src/mod/nss/open_field5.nss rename to src/module/nss/open_field5.nss diff --git a/src/mod/nss/open_field6.nss b/src/module/nss/open_field6.nss similarity index 100% rename from src/mod/nss/open_field6.nss rename to src/module/nss/open_field6.nss diff --git a/src/mod/nss/pc_room_onexit.nss b/src/module/nss/pc_room_onexit.nss similarity index 100% rename from src/mod/nss/pc_room_onexit.nss rename to src/module/nss/pc_room_onexit.nss 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..a1a8fac --- /dev/null +++ b/src/module/nss/pe_crafting.nss @@ -0,0 +1,2155 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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); + SetColorPalletPointer(oPC, nToken, oNewItem); + } + // 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)); + SetLocalJson(oPC, CRAFT_JSON, jCraft); + // 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/mod/nss/perdition_forge.nss b/src/module/nss/perdition_forge.nss similarity index 100% rename from src/mod/nss/perdition_forge.nss rename to src/module/nss/perdition_forge.nss diff --git a/src/mod/nss/perup_gve_armor.nss b/src/module/nss/perup_gve_armor.nss similarity index 100% rename from src/mod/nss/perup_gve_armor.nss rename to src/module/nss/perup_gve_armor.nss diff --git a/src/mod/nss/perup_gve_belt.nss b/src/module/nss/perup_gve_belt.nss similarity index 100% rename from src/mod/nss/perup_gve_belt.nss rename to src/module/nss/perup_gve_belt.nss diff --git a/src/mod/nss/perup_gve_helm.nss b/src/module/nss/perup_gve_helm.nss similarity index 100% rename from src/mod/nss/perup_gve_helm.nss rename to src/module/nss/perup_gve_helm.nss diff --git a/src/mod/nss/perup_gve_sword.nss b/src/module/nss/perup_gve_sword.nss similarity index 100% rename from src/mod/nss/perup_gve_sword.nss rename to src/module/nss/perup_gve_sword.nss diff --git a/src/mod/nss/peruppi_clss_chk.nss b/src/module/nss/peruppi_clss_chk.nss similarity index 100% rename from src/mod/nss/peruppi_clss_chk.nss rename to src/module/nss/peruppi_clss_chk.nss diff --git a/src/mod/nss/phw_death.nss b/src/module/nss/phw_death.nss similarity index 100% rename from src/mod/nss/phw_death.nss rename to src/module/nss/phw_death.nss 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..8647328 --- /dev/null +++ b/src/module/nss/pi_crafting.nss @@ -0,0 +1,720 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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" +#include "nw_inc_nui" + +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); + if(JsonGetType(jCraft) == JSON_TYPE_NULL) jCraft = JsonObject(); + // 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,0,0), 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_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/pinc_henchmen.nss b/src/module/nss/pinc_henchmen.nss new file mode 100644 index 0000000..a65adf4 --- /dev/null +++ b/src/module/nss/pinc_henchmen.nss @@ -0,0 +1,1541 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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, Creating LvlStatList for " + 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. + WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for 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, 982, Adding racial feat: " + + Get2DAString("feat", "LABEL", nRaceFeat)); + nRaceRow++; + } + // Give class feats. + WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for 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, 1005, Adding class feat: " + + Get2DAString("feat", "LABEL", nClassFeat)); + } + } + nClassRow++; + } + // Give any bonus feats from package. + WriteTimestampedLogEntry("pinc_henchmen, 1012, Checking for selectable feats."); + 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. + WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for select feats."); + nNumOfFeats = 1; + if(GetHasFeat(FEAT_QUICK_TO_MASTER, oHenchman)) nNumOfFeats++; + nPackageRow = 0; + while(nPackageRow < nPackageMaxRow || nNumOfFeats > 0) + { + 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++; + } + WriteTimestampedLogEntry("pinc_henchmen, 1071, Adding feat list."); + 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. + WriteTimestampedLogEntry("pinc_henchmen, 1087, Generating 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. + WriteTimestampedLogEntry("pinc_henchmen, 1097, Gets " + IntToString(nSkillPoints) + " skill points."); + 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, 1126, Adding " + IntToString(nNewRanks) + + " ranks to " + Get2DAString("skills", "Label", nPackageSkill) + + " CrossClass: " + IntToString(bCrossClass)); + nSkillPoints -= nNewRanks; + } + nPackageRow++; + } + jHenchman = GffReplaceList(jHenchman, "SkillList", jSkillList); + return jHenchman; +} +json ResetSpellsKnown(json jClass, object oHenchman) +{ + WriteTimestampedLogEntry("pinc_henchmen, 1138, Checking for spells known."); + int nClass = GetClassByPosition(1, oHenchman); + WriteTimestampedLogEntry("pinc_henchmen, 1140, SpellCaster: " + Get2DAString("classes", "SpellCaster", nClass)); + 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/mod/nss/pqj_inc.nss b/src/module/nss/pqj_inc.nss similarity index 100% rename from src/mod/nss/pqj_inc.nss rename to src/module/nss/pqj_inc.nss diff --git a/src/prc8/include/prc_nui_consts.nss b/src/module/nss/prc_nui_consts.nss similarity index 100% rename from src/prc8/include/prc_nui_consts.nss rename to src/module/nss/prc_nui_consts.nss diff --git a/src/prc8/include/prc_nui_sb_inc.nss b/src/module/nss/prc_nui_sb_inc.nss similarity index 100% rename from src/prc8/include/prc_nui_sb_inc.nss rename to src/module/nss/prc_nui_sb_inc.nss diff --git a/src/module/nss/prc_nui_sbd_inc.nss b/src/module/nss/prc_nui_sbd_inc.nss new file mode 100644 index 0000000..4f84658 --- /dev/null +++ b/src/module/nss/prc_nui_sbd_inc.nss @@ -0,0 +1,98 @@ +//:://///////////////////////////////////////////// +//:: PRC Spellbook Description NUI +//:: prc_nui_sbd_inc +//::////////////////////////////////////////////// +/* + This is the view for the Spell Description NUI +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 29.05.2005 +//::////////////////////////////////////////////// +#include "nw_inc_nui" +#include "prc_nui_consts" +#include "inc_2dacache" + +// +// CreateSpellDescriptionNUI +// Creates a Spell Description NUI mimicing the description GUI of NWN +// +// Arguments: +// oPlayer:Object the player object +// featID:int the FeatID +// spellId:int the SpellID +// realSpellId:int the RealSpellID +// +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0); + +void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0) +{ + // look for existing window and destroy + int nPreviousToken = NuiFindWindow(OBJECT_SELF, NUI_SPELL_DESCRIPTION_WINDOW_ID); + if(nPreviousToken != 0) + { + NuiDestroy(OBJECT_SELF, nPreviousToken); + } + + // in order of accuracy for names it goes RealSpellID > SpellID > FeatID + string spellName; + if (realSpellId) + spellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellId))); + else if (spellId) + spellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId))); + else + spellName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featID))); + // Descriptions and Icons are accuratly stored on the feat + string spellDesc = GetStringByStrRef(StringToInt(Get2DACache("feat", "DESCRIPTION", featID))); + string spellIcon = Get2DACache("feat", "ICON", featID); + + json jRoot = JsonArray(); + json jGroup = JsonArray(); + + json jRow = JsonArray(); + + json jImage = NuiImage(JsonString(spellIcon), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_TOP)); + jImage = NuiWidth(jImage, 32.0f); + jRow = JsonArrayInsert(jRow, jImage); + jRow = NuiCol(jRow); + jGroup = JsonArrayInsert(jGroup, jRow); + + jRow = JsonArray(); + json jText = NuiText(JsonString(spellDesc), FALSE, NUI_SCROLLBARS_AUTO); + jRow = JsonArrayInsert(jRow, jText); + jRow = NuiCol(jRow); + jGroup = JsonArrayInsert(jGroup, jRow); + + jGroup = NuiRow(jGroup); + jGroup = NuiGroup(jGroup, TRUE, NUI_SCROLLBARS_NONE); + jRoot = JsonArrayInsert(jRoot, jGroup); + + jRow = JsonArray(); + jRow = JsonArrayInsert(jRow, NuiSpacer()); + json jButton = NuiId(NuiButton(JsonString("OK")), NUI_SPELL_DESCRIPTION_OK_BUTTON); + jButton = NuiWidth(jButton, 175.0f); + jButton = NuiHeight(jButton, 48.0f); + jRow = JsonArrayInsert(jRow, jButton); + jRow = NuiRow(jRow); + + jRoot = JsonArrayInsert(jRoot, jRow); + jRoot = NuiCol(jRoot); + + + // This is the main window with jRoot as the main pane. It includes titles and parameters (more on those later) + json nui = NuiWindow(jRoot, JsonString(spellName), NuiBind("geometry"), NuiBind("resizable"), JsonBool(FALSE), NuiBind("closable"), NuiBind("transparent"), NuiBind("border")); + + // finally create it and it'll return us a non-zero token. + int nToken = NuiCreate(oPlayer, nui, NUI_SPELL_DESCRIPTION_WINDOW_ID); + + // get the geometry of the window in case we opened this before and have a + // preference for location + json geometry = NuiRect(893.0f,346.0f, 426.0f, 446.0f); + + // Set the binds to their default values + NuiSetBind(oPlayer, nToken, "geometry", geometry); + NuiSetBind(oPlayer, nToken, "resizable", JsonBool(FALSE)); + NuiSetBind(oPlayer, nToken, "closable", JsonBool(FALSE)); + NuiSetBind(oPlayer, nToken, "transparent", JsonBool(FALSE)); + NuiSetBind(oPlayer, nToken, "border", JsonBool(TRUE)); +} diff --git a/src/mod/nss/prc_pwondeath.nss b/src/module/nss/prc_pwondeath.nss similarity index 100% rename from src/mod/nss/prc_pwondeath.nss rename to src/module/nss/prc_pwondeath.nss diff --git a/src/mod/nss/prc_pwonspawn.nss b/src/module/nss/prc_pwonspawn.nss similarity index 100% rename from src/mod/nss/prc_pwonspawn.nss rename to src/module/nss/prc_pwonspawn.nss diff --git a/src/module/nss/prc_string_inc.nss b/src/module/nss/prc_string_inc.nss new file mode 100644 index 0000000..f590b4c --- /dev/null +++ b/src/module/nss/prc_string_inc.nss @@ -0,0 +1,74 @@ +//:://///////////////////////////////////////////// +//:: String Util +//:: prc_string_inc +//::////////////////////////////////////////////// +/* + A util class for providing useful string functions. +*/ +//::////////////////////////////////////////////// +//:: Created By: Rakiov +//:: Created On: 22.05.2005 +//::////////////////////////////////////////////// + +#include "inc_utility" + +// +// StringSplit +// Takes a string and splits it by " " into a json list of strings +// i.e. "this is a test" returns +// { +// "this", +// "is", +// "a", +// "test" +// } +// +// Parameters: +// string input the string input +// +// Returns: +// json the json list of words +// +json StringSplit(string input); + +json StringSplit(string input) +{ + json retValue = JsonArray(); + + string subString = ""; + //trim any whitespace characters first + string currString = PRCTrimString(input); + + // loop until we process the whole string + while(currString != "") + { + string currChar = GetStringLeft(currString, 1); + if (currChar != "" && currChar != " ") + { + // if the current character isn't nothing or whitespace, then add it + // to the current sub string. + subString += currChar; + } + else + { + // otherwise if the substring is not empty, then add it to the list + // of words to return + if(subString != "") + { + retValue = JsonArrayInsert(retValue, JsonString(subString)); + subString = ""; + } + } + + // pop and move to next character + currString = GetStringRight(currString, GetStringLength(currString)-1); + } + + // if there is any sub string left at the end of the loop, add it to the list + if(subString != "") + { + retValue = JsonArrayInsert(retValue, JsonString(subString)); + } + + return retValue; +} diff --git a/src/mod/nss/pvp_evil_flag.nss b/src/module/nss/pvp_evil_flag.nss similarity index 100% rename from src/mod/nss/pvp_evil_flag.nss rename to src/module/nss/pvp_evil_flag.nss diff --git a/src/mod/nss/pvp_giveevilorb.nss b/src/module/nss/pvp_giveevilorb.nss similarity index 100% rename from src/mod/nss/pvp_giveevilorb.nss rename to src/module/nss/pvp_giveevilorb.nss diff --git a/src/mod/nss/pvp_givegoodorb.nss b/src/module/nss/pvp_givegoodorb.nss similarity index 100% rename from src/mod/nss/pvp_givegoodorb.nss rename to src/module/nss/pvp_givegoodorb.nss diff --git a/src/mod/nss/pvp_good_flag.nss b/src/module/nss/pvp_good_flag.nss similarity index 100% rename from src/mod/nss/pvp_good_flag.nss rename to src/module/nss/pvp_good_flag.nss diff --git a/src/mod/nss/pvp_returnevil.nss b/src/module/nss/pvp_returnevil.nss similarity index 100% rename from src/mod/nss/pvp_returnevil.nss rename to src/module/nss/pvp_returnevil.nss diff --git a/src/mod/nss/pvp_returngood.nss b/src/module/nss/pvp_returngood.nss similarity index 100% rename from src/mod/nss/pvp_returngood.nss rename to src/module/nss/pvp_returngood.nss diff --git a/src/mod/nss/pvp_tke_token.nss b/src/module/nss/pvp_tke_token.nss similarity index 100% rename from src/mod/nss/pvp_tke_token.nss rename to src/module/nss/pvp_tke_token.nss diff --git a/src/mod/nss/pws_nodropunique.nss b/src/module/nss/pws_nodropunique.nss similarity index 100% rename from src/mod/nss/pws_nodropunique.nss rename to src/module/nss/pws_nodropunique.nss diff --git a/src/mod/nss/pws_onacquire.nss b/src/module/nss/pws_onacquire.nss similarity index 100% rename from src/mod/nss/pws_onacquire.nss rename to src/module/nss/pws_onacquire.nss diff --git a/src/mod/nss/pws_onunacquire.nss b/src/module/nss/pws_onunacquire.nss similarity index 100% rename from src/mod/nss/pws_onunacquire.nss rename to src/module/nss/pws_onunacquire.nss diff --git a/src/mod/nss/q2b_hb_pillar.nss b/src/module/nss/q2b_hb_pillar.nss similarity index 100% rename from src/mod/nss/q2b_hb_pillar.nss rename to src/module/nss/q2b_hb_pillar.nss diff --git a/src/mod/nss/quest_bay1.nss b/src/module/nss/quest_bay1.nss similarity index 100% rename from src/mod/nss/quest_bay1.nss rename to src/module/nss/quest_bay1.nss diff --git a/src/mod/nss/quest_bay2.nss b/src/module/nss/quest_bay2.nss similarity index 100% rename from src/mod/nss/quest_bay2.nss rename to src/module/nss/quest_bay2.nss diff --git a/src/mod/nss/quest_brew1.nss b/src/module/nss/quest_brew1.nss similarity index 100% rename from src/mod/nss/quest_brew1.nss rename to src/module/nss/quest_brew1.nss diff --git a/src/mod/nss/quest_brew2.nss b/src/module/nss/quest_brew2.nss similarity index 100% rename from src/mod/nss/quest_brew2.nss rename to src/module/nss/quest_brew2.nss diff --git a/src/mod/nss/quest_cloak1.nss b/src/module/nss/quest_cloak1.nss similarity index 100% rename from src/mod/nss/quest_cloak1.nss rename to src/module/nss/quest_cloak1.nss diff --git a/src/mod/nss/quest_cloak2.nss b/src/module/nss/quest_cloak2.nss similarity index 100% rename from src/mod/nss/quest_cloak2.nss rename to src/module/nss/quest_cloak2.nss diff --git a/src/mod/nss/quest_cloak3.nss b/src/module/nss/quest_cloak3.nss similarity index 100% rename from src/mod/nss/quest_cloak3.nss rename to src/module/nss/quest_cloak3.nss diff --git a/src/mod/nss/quest_cloak4.nss b/src/module/nss/quest_cloak4.nss similarity index 100% rename from src/mod/nss/quest_cloak4.nss rename to src/module/nss/quest_cloak4.nss diff --git a/src/mod/nss/quest_cloak6.nss b/src/module/nss/quest_cloak6.nss similarity index 100% rename from src/mod/nss/quest_cloak6.nss rename to src/module/nss/quest_cloak6.nss diff --git a/src/mod/nss/quest_cloak7.nss b/src/module/nss/quest_cloak7.nss similarity index 100% rename from src/mod/nss/quest_cloak7.nss rename to src/module/nss/quest_cloak7.nss diff --git a/src/mod/nss/quest_dic1.nss b/src/module/nss/quest_dic1.nss similarity index 100% rename from src/mod/nss/quest_dic1.nss rename to src/module/nss/quest_dic1.nss diff --git a/src/mod/nss/quest_dic2.nss b/src/module/nss/quest_dic2.nss similarity index 100% rename from src/mod/nss/quest_dic2.nss rename to src/module/nss/quest_dic2.nss diff --git a/src/mod/nss/quest_dic3.nss b/src/module/nss/quest_dic3.nss similarity index 100% rename from src/mod/nss/quest_dic3.nss rename to src/module/nss/quest_dic3.nss diff --git a/src/mod/nss/quest_elf1.nss b/src/module/nss/quest_elf1.nss similarity index 100% rename from src/mod/nss/quest_elf1.nss rename to src/module/nss/quest_elf1.nss diff --git a/src/mod/nss/quest_elv1.nss b/src/module/nss/quest_elv1.nss similarity index 100% rename from src/mod/nss/quest_elv1.nss rename to src/module/nss/quest_elv1.nss diff --git a/src/mod/nss/quest_elv2.nss b/src/module/nss/quest_elv2.nss similarity index 100% rename from src/mod/nss/quest_elv2.nss rename to src/module/nss/quest_elv2.nss diff --git a/src/mod/nss/quest_elv3.nss b/src/module/nss/quest_elv3.nss similarity index 100% rename from src/mod/nss/quest_elv3.nss rename to src/module/nss/quest_elv3.nss diff --git a/src/mod/nss/quest_elv4.nss b/src/module/nss/quest_elv4.nss similarity index 100% rename from src/mod/nss/quest_elv4.nss rename to src/module/nss/quest_elv4.nss diff --git a/src/mod/nss/quest_elv5.nss b/src/module/nss/quest_elv5.nss similarity index 100% rename from src/mod/nss/quest_elv5.nss rename to src/module/nss/quest_elv5.nss diff --git a/src/mod/nss/quest_elv6.nss b/src/module/nss/quest_elv6.nss similarity index 100% rename from src/mod/nss/quest_elv6.nss rename to src/module/nss/quest_elv6.nss diff --git a/src/mod/nss/quest_elv8.nss b/src/module/nss/quest_elv8.nss similarity index 100% rename from src/mod/nss/quest_elv8.nss rename to src/module/nss/quest_elv8.nss diff --git a/src/mod/nss/quest_elv9.nss b/src/module/nss/quest_elv9.nss similarity index 100% rename from src/mod/nss/quest_elv9.nss rename to src/module/nss/quest_elv9.nss diff --git a/src/mod/nss/quest_jerkin1.nss b/src/module/nss/quest_jerkin1.nss similarity index 100% rename from src/mod/nss/quest_jerkin1.nss rename to src/module/nss/quest_jerkin1.nss diff --git a/src/mod/nss/quest_jerkin3.nss b/src/module/nss/quest_jerkin3.nss similarity index 100% rename from src/mod/nss/quest_jerkin3.nss rename to src/module/nss/quest_jerkin3.nss diff --git a/src/mod/nss/quest_jerkin4.nss b/src/module/nss/quest_jerkin4.nss similarity index 100% rename from src/mod/nss/quest_jerkin4.nss rename to src/module/nss/quest_jerkin4.nss diff --git a/src/mod/nss/quest_jerkindone.nss b/src/module/nss/quest_jerkindone.nss similarity index 100% rename from src/mod/nss/quest_jerkindone.nss rename to src/module/nss/quest_jerkindone.nss diff --git a/src/mod/nss/quest_jerkins5.nss b/src/module/nss/quest_jerkins5.nss similarity index 100% rename from src/mod/nss/quest_jerkins5.nss rename to src/module/nss/quest_jerkins5.nss diff --git a/src/mod/nss/quest_jim1.nss b/src/module/nss/quest_jim1.nss similarity index 100% rename from src/mod/nss/quest_jim1.nss rename to src/module/nss/quest_jim1.nss diff --git a/src/mod/nss/quest_jim2.nss b/src/module/nss/quest_jim2.nss similarity index 100% rename from src/mod/nss/quest_jim2.nss rename to src/module/nss/quest_jim2.nss diff --git a/src/mod/nss/quest_jim5.nss b/src/module/nss/quest_jim5.nss similarity index 100% rename from src/mod/nss/quest_jim5.nss rename to src/module/nss/quest_jim5.nss diff --git a/src/mod/nss/quest_jim6.nss b/src/module/nss/quest_jim6.nss similarity index 100% rename from src/mod/nss/quest_jim6.nss rename to src/module/nss/quest_jim6.nss diff --git a/src/mod/nss/quest_jimmy8.nss b/src/module/nss/quest_jimmy8.nss similarity index 100% rename from src/mod/nss/quest_jimmy8.nss rename to src/module/nss/quest_jimmy8.nss diff --git a/src/mod/nss/quest_jimmy9.nss b/src/module/nss/quest_jimmy9.nss similarity index 100% rename from src/mod/nss/quest_jimmy9.nss rename to src/module/nss/quest_jimmy9.nss diff --git a/src/mod/nss/quest_lib2.nss b/src/module/nss/quest_lib2.nss similarity index 100% rename from src/mod/nss/quest_lib2.nss rename to src/module/nss/quest_lib2.nss diff --git a/src/mod/nss/quest_library.nss b/src/module/nss/quest_library.nss similarity index 100% rename from src/mod/nss/quest_library.nss rename to src/module/nss/quest_library.nss diff --git a/src/mod/nss/quest_library2.nss b/src/module/nss/quest_library2.nss similarity index 100% rename from src/mod/nss/quest_library2.nss rename to src/module/nss/quest_library2.nss diff --git a/src/mod/nss/quest_library3.nss b/src/module/nss/quest_library3.nss similarity index 100% rename from src/mod/nss/quest_library3.nss rename to src/module/nss/quest_library3.nss diff --git a/src/mod/nss/quest_lith1.nss b/src/module/nss/quest_lith1.nss similarity index 100% rename from src/mod/nss/quest_lith1.nss rename to src/module/nss/quest_lith1.nss diff --git a/src/mod/nss/quest_lith2.nss b/src/module/nss/quest_lith2.nss similarity index 100% rename from src/mod/nss/quest_lith2.nss rename to src/module/nss/quest_lith2.nss diff --git a/src/mod/nss/quest_mayor1.nss b/src/module/nss/quest_mayor1.nss similarity index 100% rename from src/mod/nss/quest_mayor1.nss rename to src/module/nss/quest_mayor1.nss diff --git a/src/mod/nss/quest_mayor2.nss b/src/module/nss/quest_mayor2.nss similarity index 100% rename from src/mod/nss/quest_mayor2.nss rename to src/module/nss/quest_mayor2.nss diff --git a/src/mod/nss/quest_mayor3.nss b/src/module/nss/quest_mayor3.nss similarity index 100% rename from src/mod/nss/quest_mayor3.nss rename to src/module/nss/quest_mayor3.nss diff --git a/src/mod/nss/quest_night1.nss b/src/module/nss/quest_night1.nss similarity index 100% rename from src/mod/nss/quest_night1.nss rename to src/module/nss/quest_night1.nss diff --git a/src/mod/nss/quest_night2.nss b/src/module/nss/quest_night2.nss similarity index 100% rename from src/mod/nss/quest_night2.nss rename to src/module/nss/quest_night2.nss diff --git a/src/mod/nss/quest_repent1.nss b/src/module/nss/quest_repent1.nss similarity index 100% rename from src/mod/nss/quest_repent1.nss rename to src/module/nss/quest_repent1.nss diff --git a/src/mod/nss/quest_repent2.nss b/src/module/nss/quest_repent2.nss similarity index 100% rename from src/mod/nss/quest_repent2.nss rename to src/module/nss/quest_repent2.nss diff --git a/src/mod/nss/quest_repent3.nss b/src/module/nss/quest_repent3.nss similarity index 100% rename from src/mod/nss/quest_repent3.nss rename to src/module/nss/quest_repent3.nss diff --git a/src/mod/nss/quest_tm1.nss b/src/module/nss/quest_tm1.nss similarity index 100% rename from src/mod/nss/quest_tm1.nss rename to src/module/nss/quest_tm1.nss diff --git a/src/mod/nss/quest_tm2.nss b/src/module/nss/quest_tm2.nss similarity index 100% rename from src/mod/nss/quest_tm2.nss rename to src/module/nss/quest_tm2.nss diff --git a/src/mod/nss/quest_tm3.nss b/src/module/nss/quest_tm3.nss similarity index 100% rename from src/mod/nss/quest_tm3.nss rename to src/module/nss/quest_tm3.nss diff --git a/src/mod/nss/quest_trin1.nss b/src/module/nss/quest_trin1.nss similarity index 100% rename from src/mod/nss/quest_trin1.nss rename to src/module/nss/quest_trin1.nss diff --git a/src/mod/nss/quest_trin2.nss b/src/module/nss/quest_trin2.nss similarity index 100% rename from src/mod/nss/quest_trin2.nss rename to src/module/nss/quest_trin2.nss diff --git a/src/mod/nss/quest_unen1.nss b/src/module/nss/quest_unen1.nss similarity index 100% rename from src/mod/nss/quest_unen1.nss rename to src/module/nss/quest_unen1.nss diff --git a/src/mod/nss/quest_unen2.nss b/src/module/nss/quest_unen2.nss similarity index 100% rename from src/mod/nss/quest_unen2.nss rename to src/module/nss/quest_unen2.nss diff --git a/src/mod/nss/quest_unen3.nss b/src/module/nss/quest_unen3.nss similarity index 100% rename from src/mod/nss/quest_unen3.nss rename to src/module/nss/quest_unen3.nss diff --git a/src/mod/nss/ra_close_door.nss b/src/module/nss/ra_close_door.nss similarity index 100% rename from src/mod/nss/ra_close_door.nss rename to src/module/nss/ra_close_door.nss diff --git a/src/mod/nss/raja_open_store.nss b/src/module/nss/raja_open_store.nss similarity index 100% rename from src/mod/nss/raja_open_store.nss rename to src/module/nss/raja_open_store.nss diff --git a/src/mod/nss/reaperkeygiver.nss b/src/module/nss/reaperkeygiver.nss similarity index 100% rename from src/mod/nss/reaperkeygiver.nss rename to src/module/nss/reaperkeygiver.nss diff --git a/src/mod/nss/reb_die_portal.nss b/src/module/nss/reb_die_portal.nss similarity index 100% rename from src/mod/nss/reb_die_portal.nss rename to src/module/nss/reb_die_portal.nss diff --git a/src/mod/nss/res_death.nss b/src/module/nss/res_death.nss similarity index 100% rename from src/mod/nss/res_death.nss rename to src/module/nss/res_death.nss diff --git a/src/mod/nss/res_heartbeat.nss b/src/module/nss/res_heartbeat.nss similarity index 100% rename from src/mod/nss/res_heartbeat.nss rename to src/module/nss/res_heartbeat.nss diff --git a/src/mod/nss/runwaypoints.nss b/src/module/nss/runwaypoints.nss similarity index 100% rename from src/mod/nss/runwaypoints.nss rename to src/module/nss/runwaypoints.nss diff --git a/src/mod/nss/sc_headless01.nss b/src/module/nss/sc_headless01.nss similarity index 100% rename from src/mod/nss/sc_headless01.nss rename to src/module/nss/sc_headless01.nss diff --git a/src/mod/nss/sc_headless02.nss b/src/module/nss/sc_headless02.nss similarity index 100% rename from src/mod/nss/sc_headless02.nss rename to src/module/nss/sc_headless02.nss diff --git a/src/mod/nss/sc_mared05.nss b/src/module/nss/sc_mared05.nss similarity index 100% rename from src/mod/nss/sc_mared05.nss rename to src/module/nss/sc_mared05.nss diff --git a/src/mod/nss/se_door_death.nss b/src/module/nss/se_door_death.nss similarity index 100% rename from src/mod/nss/se_door_death.nss rename to src/module/nss/se_door_death.nss diff --git a/src/mod/nss/sei_sit.nss b/src/module/nss/sei_sit.nss similarity index 100% rename from src/mod/nss/sei_sit.nss rename to src/module/nss/sei_sit.nss diff --git a/src/mod/nss/shiter.nss b/src/module/nss/shiter.nss similarity index 100% rename from src/mod/nss/shiter.nss rename to src/module/nss/shiter.nss diff --git a/src/mod/nss/shogun_portal.nss b/src/module/nss/shogun_portal.nss similarity index 100% rename from src/mod/nss/shogun_portal.nss rename to src/module/nss/shogun_portal.nss diff --git a/src/mod/nss/shower.nss b/src/module/nss/shower.nss similarity index 100% rename from src/mod/nss/shower.nss rename to src/module/nss/shower.nss diff --git a/src/mod/nss/sign_level_check.nss b/src/module/nss/sign_level_check.nss similarity index 100% rename from src/mod/nss/sign_level_check.nss rename to src/module/nss/sign_level_check.nss diff --git a/src/mod/nss/skeldoor_lock.nss b/src/module/nss/skeldoor_lock.nss similarity index 100% rename from src/mod/nss/skeldoor_lock.nss rename to src/module/nss/skeldoor_lock.nss diff --git a/src/mod/nss/sob_examine002.nss b/src/module/nss/sob_examine002.nss similarity index 100% rename from src/mod/nss/sob_examine002.nss rename to src/module/nss/sob_examine002.nss diff --git a/src/mod/nss/spirit_give_meat.nss b/src/module/nss/spirit_give_meat.nss similarity index 100% rename from src/mod/nss/spirit_give_meat.nss rename to src/module/nss/spirit_give_meat.nss diff --git a/src/mod/nss/spirit_item_chk.nss b/src/module/nss/spirit_item_chk.nss similarity index 100% rename from src/mod/nss/spirit_item_chk.nss rename to src/module/nss/spirit_item_chk.nss diff --git a/src/mod/nss/spirit_item_take.nss b/src/module/nss/spirit_item_take.nss similarity index 100% rename from src/mod/nss/spirit_item_take.nss rename to src/module/nss/spirit_item_take.nss diff --git a/src/mod/nss/spirit_lev_chk.nss b/src/module/nss/spirit_lev_chk.nss similarity index 100% rename from src/mod/nss/spirit_lev_chk.nss rename to src/module/nss/spirit_lev_chk.nss diff --git a/src/mod/nss/spirit_magic_giv.nss b/src/module/nss/spirit_magic_giv.nss similarity index 100% rename from src/mod/nss/spirit_magic_giv.nss rename to src/module/nss/spirit_magic_giv.nss diff --git a/src/mod/nss/spirit_monk_chk.nss b/src/module/nss/spirit_monk_chk.nss similarity index 100% rename from src/mod/nss/spirit_monk_chk.nss rename to src/module/nss/spirit_monk_chk.nss diff --git a/src/mod/nss/spirit_rewrd_chk.nss b/src/module/nss/spirit_rewrd_chk.nss similarity index 100% rename from src/mod/nss/spirit_rewrd_chk.nss rename to src/module/nss/spirit_rewrd_chk.nss diff --git a/src/mod/nss/spirit_staf_give.nss b/src/module/nss/spirit_staf_give.nss similarity index 100% rename from src/mod/nss/spirit_staf_give.nss rename to src/module/nss/spirit_staf_give.nss diff --git a/src/mod/nss/spirit_var_set.nss b/src/module/nss/spirit_var_set.nss similarity index 100% rename from src/mod/nss/spirit_var_set.nss rename to src/module/nss/spirit_var_set.nss diff --git a/src/mod/nss/sr_dragontail.nss b/src/module/nss/sr_dragontail.nss similarity index 100% rename from src/mod/nss/sr_dragontail.nss rename to src/module/nss/sr_dragontail.nss diff --git a/src/mod/nss/sr_oce_hdragon.nss b/src/module/nss/sr_oce_hdragon.nss similarity index 100% rename from src/mod/nss/sr_oce_hdragon.nss rename to src/module/nss/sr_oce_hdragon.nss diff --git a/src/mod/nss/statue_conv.nss b/src/module/nss/statue_conv.nss similarity index 100% rename from src/mod/nss/statue_conv.nss rename to src/module/nss/statue_conv.nss diff --git a/src/mod/nss/stoneofreturn.nss b/src/module/nss/stoneofreturn.nss similarity index 100% rename from src/mod/nss/stoneofreturn.nss rename to src/module/nss/stoneofreturn.nss diff --git a/src/mod/nss/strring_gen.nss b/src/module/nss/strring_gen.nss similarity index 100% rename from src/mod/nss/strring_gen.nss rename to src/module/nss/strring_gen.nss diff --git a/src/mod/nss/tab_activateitem.nss b/src/module/nss/tab_activateitem.nss similarity index 100% rename from src/mod/nss/tab_activateitem.nss rename to src/module/nss/tab_activateitem.nss diff --git a/src/mod/nss/tab_array.nss b/src/module/nss/tab_array.nss similarity index 100% rename from src/mod/nss/tab_array.nss rename to src/module/nss/tab_array.nss diff --git a/src/mod/nss/tab_boulder1.nss b/src/module/nss/tab_boulder1.nss similarity index 100% rename from src/mod/nss/tab_boulder1.nss rename to src/module/nss/tab_boulder1.nss diff --git a/src/mod/nss/tab_chest.nss b/src/module/nss/tab_chest.nss similarity index 100% rename from src/mod/nss/tab_chest.nss rename to src/module/nss/tab_chest.nss diff --git a/src/mod/nss/tab_coldscript.nss b/src/module/nss/tab_coldscript.nss similarity index 100% rename from src/mod/nss/tab_coldscript.nss rename to src/module/nss/tab_coldscript.nss diff --git a/src/mod/nss/tab_containregen.nss b/src/module/nss/tab_containregen.nss similarity index 100% rename from src/mod/nss/tab_containregen.nss rename to src/module/nss/tab_containregen.nss diff --git a/src/mod/nss/tab_copyfunction.nss b/src/module/nss/tab_copyfunction.nss similarity index 100% rename from src/mod/nss/tab_copyfunction.nss rename to src/module/nss/tab_copyfunction.nss diff --git a/src/mod/nss/tab_custom_db.nss b/src/module/nss/tab_custom_db.nss similarity index 100% rename from src/mod/nss/tab_custom_db.nss rename to src/module/nss/tab_custom_db.nss diff --git a/src/mod/nss/tab_glow.nss b/src/module/nss/tab_glow.nss similarity index 100% rename from src/mod/nss/tab_glow.nss rename to src/module/nss/tab_glow.nss diff --git a/src/mod/nss/tab_glow_blue.nss b/src/module/nss/tab_glow_blue.nss similarity index 100% rename from src/mod/nss/tab_glow_blue.nss rename to src/module/nss/tab_glow_blue.nss diff --git a/src/mod/nss/tab_glow_red.nss b/src/module/nss/tab_glow_red.nss similarity index 100% rename from src/mod/nss/tab_glow_red.nss rename to src/module/nss/tab_glow_red.nss diff --git a/src/mod/nss/tab_heartbeat.nss b/src/module/nss/tab_heartbeat.nss similarity index 100% rename from src/mod/nss/tab_heartbeat.nss rename to src/module/nss/tab_heartbeat.nss diff --git a/src/mod/nss/tab_main_data.nss b/src/module/nss/tab_main_data.nss similarity index 100% rename from src/mod/nss/tab_main_data.nss rename to src/module/nss/tab_main_data.nss diff --git a/src/mod/nss/tab_monkkill.nss b/src/module/nss/tab_monkkill.nss similarity index 100% rename from src/mod/nss/tab_monkkill.nss rename to src/module/nss/tab_monkkill.nss diff --git a/src/mod/nss/tab_newply_port.nss b/src/module/nss/tab_newply_port.nss similarity index 100% rename from src/mod/nss/tab_newply_port.nss rename to src/module/nss/tab_newply_port.nss diff --git a/src/mod/nss/tab_newply_port2.nss b/src/module/nss/tab_newply_port2.nss similarity index 100% rename from src/mod/nss/tab_newply_port2.nss rename to src/module/nss/tab_newply_port2.nss diff --git a/src/mod/nss/tab_onarea_enter.nss b/src/module/nss/tab_onarea_enter.nss similarity index 100% rename from src/mod/nss/tab_onarea_enter.nss rename to src/module/nss/tab_onarea_enter.nss diff --git a/src/mod/nss/tab_onenter.nss b/src/module/nss/tab_onenter.nss similarity index 100% rename from src/mod/nss/tab_onenter.nss rename to src/module/nss/tab_onenter.nss diff --git a/src/mod/nss/tab_onlevelup.nss b/src/module/nss/tab_onlevelup.nss similarity index 100% rename from src/mod/nss/tab_onlevelup.nss rename to src/module/nss/tab_onlevelup.nss diff --git a/src/mod/nss/tab_onrest.nss b/src/module/nss/tab_onrest.nss similarity index 100% rename from src/mod/nss/tab_onrest.nss rename to src/module/nss/tab_onrest.nss diff --git a/src/mod/nss/tab_respawn.nss b/src/module/nss/tab_respawn.nss similarity index 100% rename from src/mod/nss/tab_respawn.nss rename to src/module/nss/tab_respawn.nss diff --git a/src/mod/nss/tab_spawn_animat.nss b/src/module/nss/tab_spawn_animat.nss similarity index 100% rename from src/mod/nss/tab_spawn_animat.nss rename to src/module/nss/tab_spawn_animat.nss diff --git a/src/mod/nss/tab_spawnplacabl.nss b/src/module/nss/tab_spawnplacabl.nss similarity index 100% rename from src/mod/nss/tab_spawnplacabl.nss rename to src/module/nss/tab_spawnplacabl.nss diff --git a/src/mod/nss/tab_stat_trig.nss b/src/module/nss/tab_stat_trig.nss similarity index 100% rename from src/mod/nss/tab_stat_trig.nss rename to src/module/nss/tab_stat_trig.nss diff --git a/src/mod/nss/tab_tell_age.nss b/src/module/nss/tab_tell_age.nss similarity index 100% rename from src/mod/nss/tab_tell_age.nss rename to src/module/nss/tab_tell_age.nss diff --git a/src/mod/nss/tab_xp_multi.nss b/src/module/nss/tab_xp_multi.nss similarity index 100% rename from src/mod/nss/tab_xp_multi.nss rename to src/module/nss/tab_xp_multi.nss diff --git a/src/mod/nss/tab_xpscript.nss b/src/module/nss/tab_xpscript.nss similarity index 100% rename from src/mod/nss/tab_xpscript.nss rename to src/module/nss/tab_xpscript.nss diff --git a/src/mod/nss/tab_xpscript2.nss b/src/module/nss/tab_xpscript2.nss similarity index 100% rename from src/mod/nss/tab_xpscript2.nss rename to src/module/nss/tab_xpscript2.nss diff --git a/src/mod/nss/tab_xpscript3.nss b/src/module/nss/tab_xpscript3.nss similarity index 100% rename from src/mod/nss/tab_xpscript3.nss rename to src/module/nss/tab_xpscript3.nss diff --git a/src/mod/nss/tab_xpscript4.nss b/src/module/nss/tab_xpscript4.nss similarity index 100% rename from src/mod/nss/tab_xpscript4.nss rename to src/module/nss/tab_xpscript4.nss diff --git a/src/mod/nss/tkguildkeygiver.nss b/src/module/nss/tkguildkeygiver.nss similarity index 100% rename from src/mod/nss/tkguildkeygiver.nss rename to src/module/nss/tkguildkeygiver.nss diff --git a/src/mod/nss/tm_chest.nss b/src/module/nss/tm_chest.nss similarity index 100% rename from src/mod/nss/tm_chest.nss rename to src/module/nss/tm_chest.nss diff --git a/src/mod/nss/trap_dis_1k.nss b/src/module/nss/trap_dis_1k.nss similarity index 100% rename from src/mod/nss/trap_dis_1k.nss rename to src/module/nss/trap_dis_1k.nss diff --git a/src/mod/nss/trap_dis_2k.nss b/src/module/nss/trap_dis_2k.nss similarity index 100% rename from src/mod/nss/trap_dis_2k.nss rename to src/module/nss/trap_dis_2k.nss diff --git a/src/mod/nss/trap_dis_5k.nss b/src/module/nss/trap_dis_5k.nss similarity index 100% rename from src/mod/nss/trap_dis_5k.nss rename to src/module/nss/trap_dis_5k.nss diff --git a/src/mod/nss/trin_modload.nss b/src/module/nss/trin_modload.nss similarity index 100% rename from src/mod/nss/trin_modload.nss rename to src/module/nss/trin_modload.nss diff --git a/src/mod/nss/trinity_activate.nss b/src/module/nss/trinity_activate.nss similarity index 100% rename from src/mod/nss/trinity_activate.nss rename to src/module/nss/trinity_activate.nss diff --git a/src/mod/nss/ttl_campaign_inc.nss b/src/module/nss/ttl_campaign_inc.nss similarity index 100% rename from src/mod/nss/ttl_campaign_inc.nss rename to src/module/nss/ttl_campaign_inc.nss diff --git a/src/mod/nss/util_c_color.nss b/src/module/nss/util_c_color.nss similarity index 100% rename from src/mod/nss/util_c_color.nss rename to src/module/nss/util_c_color.nss diff --git a/src/mod/nss/util_c_debug.nss b/src/module/nss/util_c_debug.nss similarity index 100% rename from src/mod/nss/util_c_debug.nss rename to src/module/nss/util_c_debug.nss diff --git a/src/mod/nss/util_c_strftime.nss b/src/module/nss/util_c_strftime.nss similarity index 100% rename from src/mod/nss/util_c_strftime.nss rename to src/module/nss/util_c_strftime.nss diff --git a/src/mod/nss/util_c_targeting.nss b/src/module/nss/util_c_targeting.nss similarity index 100% rename from src/mod/nss/util_c_targeting.nss rename to src/module/nss/util_c_targeting.nss diff --git a/src/mod/nss/util_c_unittest.nss b/src/module/nss/util_c_unittest.nss similarity index 100% rename from src/mod/nss/util_c_unittest.nss rename to src/module/nss/util_c_unittest.nss diff --git a/src/mod/nss/util_c_variables.nss b/src/module/nss/util_c_variables.nss similarity index 100% rename from src/mod/nss/util_c_variables.nss rename to src/module/nss/util_c_variables.nss diff --git a/src/mod/nss/util_i_argstack.nss b/src/module/nss/util_i_argstack.nss similarity index 100% rename from src/mod/nss/util_i_argstack.nss rename to src/module/nss/util_i_argstack.nss diff --git a/src/mod/nss/util_i_color.nss b/src/module/nss/util_i_color.nss similarity index 100% rename from src/mod/nss/util_i_color.nss rename to src/module/nss/util_i_color.nss diff --git a/src/mod/nss/util_i_constants.nss b/src/module/nss/util_i_constants.nss similarity index 100% rename from src/mod/nss/util_i_constants.nss rename to src/module/nss/util_i_constants.nss diff --git a/src/mod/nss/util_i_csvlists.nss b/src/module/nss/util_i_csvlists.nss similarity index 100% rename from src/mod/nss/util_i_csvlists.nss rename to src/module/nss/util_i_csvlists.nss diff --git a/src/mod/nss/util_i_datapoint.nss b/src/module/nss/util_i_datapoint.nss similarity index 100% rename from src/mod/nss/util_i_datapoint.nss rename to src/module/nss/util_i_datapoint.nss diff --git a/src/mod/nss/util_i_debug.nss b/src/module/nss/util_i_debug.nss similarity index 100% rename from src/mod/nss/util_i_debug.nss rename to src/module/nss/util_i_debug.nss diff --git a/src/mod/nss/util_i_libraries.nss b/src/module/nss/util_i_libraries.nss similarity index 100% rename from src/mod/nss/util_i_libraries.nss rename to src/module/nss/util_i_libraries.nss diff --git a/src/mod/nss/util_i_lists.nss b/src/module/nss/util_i_lists.nss similarity index 100% rename from src/mod/nss/util_i_lists.nss rename to src/module/nss/util_i_lists.nss diff --git a/src/mod/nss/util_i_matching.nss b/src/module/nss/util_i_matching.nss similarity index 100% rename from src/mod/nss/util_i_matching.nss rename to src/module/nss/util_i_matching.nss diff --git a/src/mod/nss/util_i_math.nss b/src/module/nss/util_i_math.nss similarity index 100% rename from src/mod/nss/util_i_math.nss rename to src/module/nss/util_i_math.nss diff --git a/src/mod/nss/util_i_nss.nss b/src/module/nss/util_i_nss.nss similarity index 100% rename from src/mod/nss/util_i_nss.nss rename to src/module/nss/util_i_nss.nss diff --git a/src/mod/nss/util_i_sqlite.nss b/src/module/nss/util_i_sqlite.nss similarity index 100% rename from src/mod/nss/util_i_sqlite.nss rename to src/module/nss/util_i_sqlite.nss diff --git a/src/mod/nss/util_i_strftime.nss b/src/module/nss/util_i_strftime.nss similarity index 100% rename from src/mod/nss/util_i_strftime.nss rename to src/module/nss/util_i_strftime.nss diff --git a/src/mod/nss/util_i_strings.nss b/src/module/nss/util_i_strings.nss similarity index 100% rename from src/mod/nss/util_i_strings.nss rename to src/module/nss/util_i_strings.nss diff --git a/src/mod/nss/util_i_targeting.nss b/src/module/nss/util_i_targeting.nss similarity index 100% rename from src/mod/nss/util_i_targeting.nss rename to src/module/nss/util_i_targeting.nss diff --git a/src/mod/nss/util_i_timers.nss b/src/module/nss/util_i_timers.nss similarity index 100% rename from src/mod/nss/util_i_timers.nss rename to src/module/nss/util_i_timers.nss diff --git a/src/mod/nss/util_i_times.nss b/src/module/nss/util_i_times.nss similarity index 100% rename from src/mod/nss/util_i_times.nss rename to src/module/nss/util_i_times.nss diff --git a/src/mod/nss/util_i_unittest.nss b/src/module/nss/util_i_unittest.nss similarity index 100% rename from src/mod/nss/util_i_unittest.nss rename to src/module/nss/util_i_unittest.nss diff --git a/src/mod/nss/util_i_variables.nss b/src/module/nss/util_i_variables.nss similarity index 100% rename from src/mod/nss/util_i_variables.nss rename to src/module/nss/util_i_variables.nss diff --git a/src/mod/nss/util_i_varlists.nss b/src/module/nss/util_i_varlists.nss similarity index 100% rename from src/mod/nss/util_i_varlists.nss rename to src/module/nss/util_i_varlists.nss diff --git a/src/mod/nss/ww_ch_ac9.nss b/src/module/nss/ww_ch_ac9.nss similarity index 100% rename from src/mod/nss/ww_ch_ac9.nss rename to src/module/nss/ww_ch_ac9.nss diff --git a/src/module/nss/x0_ch_hen_block.nss b/src/module/nss/x0_ch_hen_block.nss new file mode 100644 index 0000000..d7d86a3 --- /dev/null +++ b/src/module/nss/x0_ch_hen_block.nss @@ -0,0 +1,14 @@ +//::////////////////////////////////////////////////// +//:: X0_CH_HEN_BLOCK +/* + OnBlocked handler for henchmen/associates. + */ +//::////////////////////////////////////////////////// +//:: Copyright (c) 2002 Floodgate Entertainment +//:: Created By: Naomi Novik +//:: Created On: 01/06/2003 +//::////////////////////////////////////////////////// +void main() +{ + ExecuteScript("nw_ch_ace"); +} diff --git a/src/module/nss/x0_ch_hen_combat.nss b/src/module/nss/x0_ch_hen_combat.nss new file mode 100644 index 0000000..d3e359b --- /dev/null +++ b/src/module/nss/x0_ch_hen_combat.nss @@ -0,0 +1,36 @@ +//:://///////////////////////////////////////////// +//:: Associate: End of Combat End +//:: NW_CH_AC3 +//:: Copyright (c) 2001 Bioware Corp. +//::////////////////////////////////////////////// +/* + Calls the end of combat script every round +*/ +//::////////////////////////////////////////////// +//:: Created By: Preston Watamaniuk +//:: Created On: Oct 16, 2001 +//::////////////////////////////////////////////// +//::////////////////////////////////////////////// +//:: Modified By: Deva Winblood +//:: Modified On: Jan 16th, 2008 +//:: Added Support for Mounted Combat Feat Support +//::////////////////////////////////////////////// +#include "x0_inc_henai" + +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"); + } // set variables on target for mounted combat + if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS)) + { + ExecuteScript("nw_ch_ac3"); + } + if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT)) + { + SignalEvent(OBJECT_SELF, EventUserDefined(1003)); + } +} diff --git a/src/module/nss/x0_ch_hen_conv.nss b/src/module/nss/x0_ch_hen_conv.nss new file mode 100644 index 0000000..6943250 --- /dev/null +++ b/src/module/nss/x0_ch_hen_conv.nss @@ -0,0 +1,91 @@ +//::////////////////////////////////////////////////// +//:: X0_CH_HEN_CONV +// OnDialogue event handler for henchmen/associates. +//::////////////////////////////////////////////////// +//:: Copyright (c) 2002 Floodgate Entertainment +//:: Created By: Naomi Novik +//:: Created On: 01/05/2003 +//::////////////////////////////////////////////////// +#include "x0_inc_henai" +#include "x0_i0_henchman" +#include "0i_associates" +//* GeorgZ - Put in a fix for henchmen talking even if they are petrified +int AbleToTalk(object oSelf) +{ + if (GetHasEffect(EFFECT_TYPE_CONFUSED, oSelf) || GetHasEffect(EFFECT_TYPE_DOMINATED, oSelf) || + GetHasEffect(EFFECT_TYPE_PETRIFY, oSelf) || GetHasEffect(EFFECT_TYPE_PARALYZE, oSelf) || + GetHasEffect(EFFECT_TYPE_STUNNED, oSelf) || GetHasEffect(EFFECT_TYPE_FRIGHTENED, oSelf) + ) + { + return FALSE; + } + + return TRUE; +} +void main() +{ + object oCreature = OBJECT_SELF; + // * XP2, special handling code for interjections + // * This script only fires if someone inits with me. + // * with that in mind, I am now clearing any interjections + // * that the character might have on themselves. + if (GetLocalInt(GetModule(), "X2_L_XP2") == TRUE) + { + SetLocalInt(oCreature, "X2_BANTER_TRY", 0); + SetHasInterjection(GetMaster(oCreature), FALSE); + SetLocalInt(oCreature, "X0_L_BUSY_SPEAKING_ONE_LINER", 0); + SetOneLiner(FALSE, 0); + } + object oLastSpeaker = GetLastSpeaker(); + if (GetTag(oCreature) == "x0_hen_dee") + { + string sCall = GetCampaignString("Deekin", "q6_Deekin_Call"+ GetName(oLastSpeaker), oLastSpeaker); + if (sCall == "") SetCustomToken(1001, GetStringByStrRef(40570)); + else SetCustomToken(1001, sCall); + } + // If we are disabled then we can't listen or talk, Busy is checked in ai_SelectAssociateCommand(). + if (GetIsHenchmanDying(oCreature) || ai_Disabled(oCreature)) return; + object oMaster = GetMaster(); + int nMatch = GetListenPatternNumber(); + object oIntruder; + if (nMatch == -1) + { + if (!ai_GetIsBusy(oCreature)) + { + ai_ClearCreatureActions(); + string sDialogFileToUse = GetDialogFileToUse(GetLastSpeaker()); + BeginConversation(sDialogFileToUse); + } + } + else + { + // listening pattern matched + if (GetIsObjectValid(oMaster)) ai_SelectAssociateCommand(oCreature, oLastSpeaker, nMatch); + // we don't have a master, behave in default way + else if (GetIsObjectValid(oLastSpeaker) && + !GetIsPC(oLastSpeaker) && + GetIsFriend(oLastSpeaker)) + { + object oIntruder = OBJECT_INVALID; + // Determine the intruder if any + if(nMatch == 4) oIntruder = GetLocalObject(oLastSpeaker, "NW_BLOCKER_INTRUDER"); + else if (nMatch == 5) + { + oIntruder = GetLastHostileActor(oLastSpeaker); + if(!GetIsObjectValid(oIntruder)) + { + oIntruder = GetAttemptedAttackTarget(); + if(!GetIsObjectValid(oIntruder)) oIntruder = GetAttemptedSpellTarget(); + } + } + // Actually respond to the shout + RespondToShout(oLastSpeaker, nMatch, oIntruder); + } + } + // Signal user-defined event + if(GetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT)) + { + SignalEvent(oCreature, EventUserDefined(EVENT_DIALOGUE)); + } +} + diff --git a/src/module/nss/x0_ch_hen_rest.nss b/src/module/nss/x0_ch_hen_rest.nss new file mode 100644 index 0000000..8d2fc78 --- /dev/null +++ b/src/module/nss/x0_ch_hen_rest.nss @@ -0,0 +1,15 @@ +//::////////////////////////////////////////////////// +//:: X0_CH_HEN_REST +/* + OnRest event handler for henchmen/associates. + */ +//::////////////////////////////////////////////////// +//:: Copyright (c) 2002 Floodgate Entertainment +//:: Created By: Naomi Novik +//:: Created On: 01/06/2003 +//::////////////////////////////////////////////////// + +void main() +{ + ExecuteScript("nw_ch_aca"); +} diff --git a/src/mod/nss/x2_def_ondeath.nss b/src/module/nss/x2_def_ondeath.nss similarity index 100% rename from src/mod/nss/x2_def_ondeath.nss rename to src/module/nss/x2_def_ondeath.nss diff --git a/src/mod/nss/x2_im_cancel.nss b/src/module/nss/x2_im_cancel.nss similarity index 100% rename from src/mod/nss/x2_im_cancel.nss rename to src/module/nss/x2_im_cancel.nss diff --git a/src/mod/nss/x2_tab_stealth.nss b/src/module/nss/x2_tab_stealth.nss similarity index 100% rename from src/mod/nss/x2_tab_stealth.nss rename to src/module/nss/x2_tab_stealth.nss diff --git a/src/mod/nss/x_ench_boots.nss b/src/module/nss/x_ench_boots.nss similarity index 100% rename from src/mod/nss/x_ench_boots.nss rename to src/module/nss/x_ench_boots.nss diff --git a/src/mod/nss/x_ench_cloak.nss b/src/module/nss/x_ench_cloak.nss similarity index 100% rename from src/mod/nss/x_ench_cloak.nss rename to src/module/nss/x_ench_cloak.nss diff --git a/src/mod/nss/x_ench_gem.nss b/src/module/nss/x_ench_gem.nss similarity index 100% rename from src/mod/nss/x_ench_gem.nss rename to src/module/nss/x_ench_gem.nss diff --git a/src/mod/nss/x_ench_helmet.nss b/src/module/nss/x_ench_helmet.nss similarity index 100% rename from src/mod/nss/x_ench_helmet.nss rename to src/module/nss/x_ench_helmet.nss diff --git a/src/mod/nss/x_ench_robe.nss b/src/module/nss/x_ench_robe.nss similarity index 100% rename from src/mod/nss/x_ench_robe.nss rename to src/module/nss/x_ench_robe.nss diff --git a/src/mod/nss/x_ench_rod.nss b/src/module/nss/x_ench_rod.nss similarity index 100% rename from src/mod/nss/x_ench_rod.nss rename to src/module/nss/x_ench_rod.nss diff --git a/src/mod/nss/x_ench_shield.nss b/src/module/nss/x_ench_shield.nss similarity index 100% rename from src/mod/nss/x_ench_shield.nss rename to src/module/nss/x_ench_shield.nss diff --git a/src/mod/nss/x_ench_staff.nss b/src/module/nss/x_ench_staff.nss similarity index 100% rename from src/mod/nss/x_ench_staff.nss rename to src/module/nss/x_ench_staff.nss diff --git a/src/mod/nss/x_ench_sword.nss b/src/module/nss/x_ench_sword.nss similarity index 100% rename from src/mod/nss/x_ench_sword.nss rename to src/module/nss/x_ench_sword.nss diff --git a/src/mod/nss/x_foreged_short.nss b/src/module/nss/x_foreged_short.nss similarity index 100% rename from src/mod/nss/x_foreged_short.nss rename to src/module/nss/x_foreged_short.nss diff --git a/src/mod/nss/x_forge_armor.nss b/src/module/nss/x_forge_armor.nss similarity index 100% rename from src/mod/nss/x_forge_armor.nss rename to src/module/nss/x_forge_armor.nss diff --git a/src/mod/nss/x_forge_boots.nss b/src/module/nss/x_forge_boots.nss similarity index 100% rename from src/mod/nss/x_forge_boots.nss rename to src/module/nss/x_forge_boots.nss diff --git a/src/mod/nss/x_forge_cloak.nss b/src/module/nss/x_forge_cloak.nss similarity index 100% rename from src/mod/nss/x_forge_cloak.nss rename to src/module/nss/x_forge_cloak.nss diff --git a/src/mod/nss/x_forge_helmet.nss b/src/module/nss/x_forge_helmet.nss similarity index 100% rename from src/mod/nss/x_forge_helmet.nss rename to src/module/nss/x_forge_helmet.nss diff --git a/src/mod/nss/x_forge_long.nss b/src/module/nss/x_forge_long.nss similarity index 100% rename from src/mod/nss/x_forge_long.nss rename to src/module/nss/x_forge_long.nss diff --git a/src/mod/nss/x_forge_morkain.nss b/src/module/nss/x_forge_morkain.nss similarity index 100% rename from src/mod/nss/x_forge_morkain.nss rename to src/module/nss/x_forge_morkain.nss diff --git a/src/mod/nss/x_forge_shield.nss b/src/module/nss/x_forge_shield.nss similarity index 100% rename from src/mod/nss/x_forge_shield.nss rename to src/module/nss/x_forge_shield.nss diff --git a/src/mod/nss/x_research.nss b/src/module/nss/x_research.nss similarity index 100% rename from src/mod/nss/x_research.nss rename to src/module/nss/x_research.nss diff --git a/src/mod/nss/xx.nss b/src/module/nss/xx.nss similarity index 100% rename from src/mod/nss/xx.nss rename to src/module/nss/xx.nss diff --git a/src/mod/nss/xx_atlport.nss b/src/module/nss/xx_atlport.nss similarity index 100% rename from src/mod/nss/xx_atlport.nss rename to src/module/nss/xx_atlport.nss diff --git a/src/mod/nss/xx_cb_bleed.nss b/src/module/nss/xx_cb_bleed.nss similarity index 100% rename from src/mod/nss/xx_cb_bleed.nss rename to src/module/nss/xx_cb_bleed.nss diff --git a/src/mod/nss/xx_cb_death.nss b/src/module/nss/xx_cb_death.nss similarity index 100% rename from src/mod/nss/xx_cb_death.nss rename to src/module/nss/xx_cb_death.nss diff --git a/src/mod/nss/xx_cb_enter.nss b/src/module/nss/xx_cb_enter.nss similarity index 97% rename from src/mod/nss/xx_cb_enter.nss rename to src/module/nss/xx_cb_enter.nss index d177971..8dd451f 100644 --- a/src/mod/nss/xx_cb_enter.nss +++ b/src/module/nss/xx_cb_enter.nss @@ -13,6 +13,8 @@ void main () AddJournalQuestEntry("xprules", 1, oPlayer, FALSE, FALSE, FALSE); AddJournalQuestEntry("lvl_adj", 1, oPlayer, FALSE, FALSE, FALSE); AddJournalQuestEntry("JRNL_PRC8", 1, oPlayer, FALSE, FALSE, FALSE); + + ExecuteScript("0e_onclientload", oPlayer); cs_DestroyStolenItems(oPlayer); // Destroy any stolen items cs_LimitGoldInBank(oPlayer, 20000000); // Limit gold in bank diff --git a/src/mod/nss/xx_cb_exit.nss b/src/module/nss/xx_cb_exit.nss similarity index 100% rename from src/mod/nss/xx_cb_exit.nss rename to src/module/nss/xx_cb_exit.nss diff --git a/src/mod/nss/xx_cb_hb.nss b/src/module/nss/xx_cb_hb.nss similarity index 100% rename from src/mod/nss/xx_cb_hb.nss rename to src/module/nss/xx_cb_hb.nss diff --git a/src/mod/nss/xx_cb_pvp_respaw.nss b/src/module/nss/xx_cb_pvp_respaw.nss similarity index 100% rename from src/mod/nss/xx_cb_pvp_respaw.nss rename to src/module/nss/xx_cb_pvp_respaw.nss diff --git a/src/mod/nss/xx_cb_respawn.nss b/src/module/nss/xx_cb_respawn.nss similarity index 100% rename from src/mod/nss/xx_cb_respawn.nss rename to src/module/nss/xx_cb_respawn.nss diff --git a/src/mod/nss/xx_cb_rest.nss b/src/module/nss/xx_cb_rest.nss similarity index 100% rename from src/mod/nss/xx_cb_rest.nss rename to src/module/nss/xx_cb_rest.nss diff --git a/src/mod/nss/xx_cb_solar.nss b/src/module/nss/xx_cb_solar.nss similarity index 100% rename from src/mod/nss/xx_cb_solar.nss rename to src/module/nss/xx_cb_solar.nss diff --git a/src/mod/nss/xx_chk_lvl15.nss b/src/module/nss/xx_chk_lvl15.nss similarity index 100% rename from src/mod/nss/xx_chk_lvl15.nss rename to src/module/nss/xx_chk_lvl15.nss diff --git a/src/mod/nss/xx_dragonport.nss b/src/module/nss/xx_dragonport.nss similarity index 100% rename from src/mod/nss/xx_dragonport.nss rename to src/module/nss/xx_dragonport.nss diff --git a/src/mod/nss/xx_dwarfport.nss b/src/module/nss/xx_dwarfport.nss similarity index 100% rename from src/mod/nss/xx_dwarfport.nss rename to src/module/nss/xx_dwarfport.nss diff --git a/src/mod/nss/xx_emotewand.nss b/src/module/nss/xx_emotewand.nss similarity index 100% rename from src/mod/nss/xx_emotewand.nss rename to src/module/nss/xx_emotewand.nss diff --git a/src/mod/nss/xx_manyport.nss b/src/module/nss/xx_manyport.nss similarity index 100% rename from src/mod/nss/xx_manyport.nss rename to src/module/nss/xx_manyport.nss diff --git a/src/mod/nss/xx_nordicport.nss b/src/module/nss/xx_nordicport.nss similarity index 100% rename from src/mod/nss/xx_nordicport.nss rename to src/module/nss/xx_nordicport.nss diff --git a/src/mod/nss/xx_persist_quest.nss b/src/module/nss/xx_persist_quest.nss similarity index 100% rename from src/mod/nss/xx_persist_quest.nss rename to src/module/nss/xx_persist_quest.nss diff --git a/src/mod/nss/xx_ques_add.nss b/src/module/nss/xx_ques_add.nss similarity index 100% rename from src/mod/nss/xx_ques_add.nss rename to src/module/nss/xx_ques_add.nss diff --git a/src/mod/nss/xx_ques_chest.nss b/src/module/nss/xx_ques_chest.nss similarity index 100% rename from src/mod/nss/xx_ques_chest.nss rename to src/module/nss/xx_ques_chest.nss diff --git a/src/mod/nss/xx_ques_finished.nss b/src/module/nss/xx_ques_finished.nss similarity index 100% rename from src/mod/nss/xx_ques_finished.nss rename to src/module/nss/xx_ques_finished.nss diff --git a/src/mod/nss/xx_ques_progress.nss b/src/module/nss/xx_ques_progress.nss similarity index 100% rename from src/mod/nss/xx_ques_progress.nss rename to src/module/nss/xx_ques_progress.nss diff --git a/src/mod/nss/xx_ques_retrieve.nss b/src/module/nss/xx_ques_retrieve.nss similarity index 100% rename from src/mod/nss/xx_ques_retrieve.nss rename to src/module/nss/xx_ques_retrieve.nss diff --git a/src/mod/nss/xx_quest_start.nss b/src/module/nss/xx_quest_start.nss similarity index 100% rename from src/mod/nss/xx_quest_start.nss rename to src/module/nss/xx_quest_start.nss diff --git a/src/mod/nss/xx_remove_quest.nss b/src/module/nss/xx_remove_quest.nss similarity index 100% rename from src/mod/nss/xx_remove_quest.nss rename to src/module/nss/xx_remove_quest.nss diff --git a/src/mod/nss/xx_reward10k.nss b/src/module/nss/xx_reward10k.nss similarity index 100% rename from src/mod/nss/xx_reward10k.nss rename to src/module/nss/xx_reward10k.nss diff --git a/src/mod/nss/xx_reward2k.nss b/src/module/nss/xx_reward2k.nss similarity index 100% rename from src/mod/nss/xx_reward2k.nss rename to src/module/nss/xx_reward2k.nss diff --git a/src/mod/nss/xx_tempcain.nss b/src/module/nss/xx_tempcain.nss similarity index 100% rename from src/mod/nss/xx_tempcain.nss rename to src/module/nss/xx_tempcain.nss diff --git a/src/mod/nss/xx_test2.nss b/src/module/nss/xx_test2.nss similarity index 100% rename from src/mod/nss/xx_test2.nss rename to src/module/nss/xx_test2.nss diff --git a/src/mod/nss/xx_test_all.nss b/src/module/nss/xx_test_all.nss similarity index 100% rename from src/mod/nss/xx_test_all.nss rename to src/module/nss/xx_test_all.nss diff --git a/src/mod/nss/xx_testreward.nss b/src/module/nss/xx_testreward.nss similarity index 100% rename from src/mod/nss/xx_testreward.nss rename to src/module/nss/xx_testreward.nss diff --git a/src/mod/nss/xx_trinport.nss b/src/module/nss/xx_trinport.nss similarity index 100% rename from src/mod/nss/xx_trinport.nss rename to src/module/nss/xx_trinport.nss diff --git a/src/mod/nss/zach_stat_trig.nss b/src/module/nss/zach_stat_trig.nss similarity index 100% rename from src/mod/nss/zach_stat_trig.nss rename to src/module/nss/zach_stat_trig.nss diff --git a/src/mod/nss/zedd_check.nss b/src/module/nss/zedd_check.nss similarity index 100% rename from src/mod/nss/zedd_check.nss rename to src/module/nss/zedd_check.nss diff --git a/src/mod/nss/zedd_mc_port.nss b/src/module/nss/zedd_mc_port.nss similarity index 100% rename from src/mod/nss/zedd_mc_port.nss rename to src/module/nss/zedd_mc_port.nss diff --git a/src/mod/utc/aaaaah.utc.json b/src/module/utc/aaaaah.utc.json similarity index 100% rename from src/mod/utc/aaaaah.utc.json rename to src/module/utc/aaaaah.utc.json diff --git a/src/mod/utc/agadenreachgaurd.utc.json b/src/module/utc/agadenreachgaurd.utc.json similarity index 100% rename from src/mod/utc/agadenreachgaurd.utc.json rename to src/module/utc/agadenreachgaurd.utc.json diff --git a/src/mod/utc/alien.utc.json b/src/module/utc/alien.utc.json similarity index 100% rename from src/mod/utc/alien.utc.json rename to src/module/utc/alien.utc.json diff --git a/src/mod/utc/ancientguardian.utc.json b/src/module/utc/ancientguardian.utc.json similarity index 100% rename from src/mod/utc/ancientguardian.utc.json rename to src/module/utc/ancientguardian.utc.json diff --git a/src/mod/utc/anguis.utc.json b/src/module/utc/anguis.utc.json similarity index 100% rename from src/mod/utc/anguis.utc.json rename to src/module/utc/anguis.utc.json diff --git a/src/mod/utc/animalmaster001.utc.json b/src/module/utc/animalmaster001.utc.json similarity index 100% rename from src/mod/utc/animalmaster001.utc.json rename to src/module/utc/animalmaster001.utc.json diff --git a/src/mod/utc/animalmaster002.utc.json b/src/module/utc/animalmaster002.utc.json similarity index 100% rename from src/mod/utc/animalmaster002.utc.json rename to src/module/utc/animalmaster002.utc.json diff --git a/src/mod/utc/assassincpt.utc.json b/src/module/utc/assassincpt.utc.json similarity index 100% rename from src/mod/utc/assassincpt.utc.json rename to src/module/utc/assassincpt.utc.json diff --git a/src/mod/utc/asyglobe.utc.json b/src/module/utc/asyglobe.utc.json similarity index 100% rename from src/mod/utc/asyglobe.utc.json rename to src/module/utc/asyglobe.utc.json diff --git a/src/mod/utc/asyrianambassado.utc.json b/src/module/utc/asyrianambassado.utc.json similarity index 100% rename from src/mod/utc/asyrianambassado.utc.json rename to src/module/utc/asyrianambassado.utc.json diff --git a/src/mod/utc/asyrianaxeman.utc.json b/src/module/utc/asyrianaxeman.utc.json similarity index 100% rename from src/mod/utc/asyrianaxeman.utc.json rename to src/module/utc/asyrianaxeman.utc.json diff --git a/src/mod/utc/asyrianholyman.utc.json b/src/module/utc/asyrianholyman.utc.json similarity index 100% rename from src/mod/utc/asyrianholyman.utc.json rename to src/module/utc/asyrianholyman.utc.json diff --git a/src/mod/utc/asyrianlady.utc.json b/src/module/utc/asyrianlady.utc.json similarity index 100% rename from src/mod/utc/asyrianlady.utc.json rename to src/module/utc/asyrianlady.utc.json diff --git a/src/mod/utc/asyriannoble.utc.json b/src/module/utc/asyriannoble.utc.json similarity index 100% rename from src/mod/utc/asyriannoble.utc.json rename to src/module/utc/asyriannoble.utc.json diff --git a/src/mod/utc/asyriannoble002.utc.json b/src/module/utc/asyriannoble002.utc.json similarity index 100% rename from src/mod/utc/asyriannoble002.utc.json rename to src/module/utc/asyriannoble002.utc.json diff --git a/src/mod/utc/asyriannobleman.utc.json b/src/module/utc/asyriannobleman.utc.json similarity index 100% rename from src/mod/utc/asyriannobleman.utc.json rename to src/module/utc/asyriannobleman.utc.json diff --git a/src/mod/utc/asyrianpixie.utc.json b/src/module/utc/asyrianpixie.utc.json similarity index 100% rename from src/mod/utc/asyrianpixie.utc.json rename to src/module/utc/asyrianpixie.utc.json diff --git a/src/mod/utc/asyrianseniorhol.utc.json b/src/module/utc/asyrianseniorhol.utc.json similarity index 100% rename from src/mod/utc/asyrianseniorhol.utc.json rename to src/module/utc/asyrianseniorhol.utc.json diff --git a/src/mod/utc/asyrianspearman.utc.json b/src/module/utc/asyrianspearman.utc.json similarity index 100% rename from src/mod/utc/asyrianspearman.utc.json rename to src/module/utc/asyrianspearman.utc.json diff --git a/src/mod/utc/asyriantreasureg.utc.json b/src/module/utc/asyriantreasureg.utc.json similarity index 100% rename from src/mod/utc/asyriantreasureg.utc.json rename to src/module/utc/asyriantreasureg.utc.json diff --git a/src/mod/utc/asytreasmas.utc.json b/src/module/utc/asytreasmas.utc.json similarity index 100% rename from src/mod/utc/asytreasmas.utc.json rename to src/module/utc/asytreasmas.utc.json diff --git a/src/mod/utc/atlantian.utc.json b/src/module/utc/atlantian.utc.json similarity index 100% rename from src/mod/utc/atlantian.utc.json rename to src/module/utc/atlantian.utc.json diff --git a/src/mod/utc/atlantiandruid.utc.json b/src/module/utc/atlantiandruid.utc.json similarity index 100% rename from src/mod/utc/atlantiandruid.utc.json rename to src/module/utc/atlantiandruid.utc.json diff --git a/src/mod/utc/atlantianmale.utc.json b/src/module/utc/atlantianmale.utc.json similarity index 100% rename from src/mod/utc/atlantianmale.utc.json rename to src/module/utc/atlantianmale.utc.json diff --git a/src/mod/utc/atlantianmale001.utc.json b/src/module/utc/atlantianmale001.utc.json similarity index 100% rename from src/mod/utc/atlantianmale001.utc.json rename to src/module/utc/atlantianmale001.utc.json diff --git a/src/mod/utc/atlantianmale002.utc.json b/src/module/utc/atlantianmale002.utc.json similarity index 100% rename from src/mod/utc/atlantianmale002.utc.json rename to src/module/utc/atlantianmale002.utc.json diff --git a/src/mod/utc/atlantianmale003.utc.json b/src/module/utc/atlantianmale003.utc.json similarity index 100% rename from src/mod/utc/atlantianmale003.utc.json rename to src/module/utc/atlantianmale003.utc.json diff --git a/src/mod/utc/atlantianmale004.utc.json b/src/module/utc/atlantianmale004.utc.json similarity index 100% rename from src/mod/utc/atlantianmale004.utc.json rename to src/module/utc/atlantianmale004.utc.json diff --git a/src/mod/utc/awbeholderbos001.utc.json b/src/module/utc/awbeholderbos001.utc.json similarity index 100% rename from src/mod/utc/awbeholderbos001.utc.json rename to src/module/utc/awbeholderbos001.utc.json diff --git a/src/mod/utc/awbeholderboss.utc.json b/src/module/utc/awbeholderboss.utc.json similarity index 100% rename from src/mod/utc/awbeholderboss.utc.json rename to src/module/utc/awbeholderboss.utc.json diff --git a/src/mod/utc/awbeholdereyebal.utc.json b/src/module/utc/awbeholdereyebal.utc.json similarity index 100% rename from src/mod/utc/awbeholdereyebal.utc.json rename to src/module/utc/awbeholdereyebal.utc.json diff --git a/src/mod/utc/awbeholdereyecel.utc.json b/src/module/utc/awbeholdereyecel.utc.json similarity index 100% rename from src/mod/utc/awbeholdereyecel.utc.json rename to src/module/utc/awbeholdereyecel.utc.json diff --git a/src/mod/utc/awbeholdrebasic.utc.json b/src/module/utc/awbeholdrebasic.utc.json similarity index 100% rename from src/mod/utc/awbeholdrebasic.utc.json rename to src/module/utc/awbeholdrebasic.utc.json diff --git a/src/mod/utc/awbeholdreyeball.utc.json b/src/module/utc/awbeholdreyeball.utc.json similarity index 100% rename from src/mod/utc/awbeholdreyeball.utc.json rename to src/module/utc/awbeholdreyeball.utc.json diff --git a/src/mod/utc/awdrider.utc.json b/src/module/utc/awdrider.utc.json similarity index 100% rename from src/mod/utc/awdrider.utc.json rename to src/module/utc/awdrider.utc.json diff --git a/src/mod/utc/awdrider001.utc.json b/src/module/utc/awdrider001.utc.json similarity index 100% rename from src/mod/utc/awdrider001.utc.json rename to src/module/utc/awdrider001.utc.json diff --git a/src/mod/utc/awdridercheif.utc.json b/src/module/utc/awdridercheif.utc.json similarity index 100% rename from src/mod/utc/awdridercheif.utc.json rename to src/module/utc/awdridercheif.utc.json diff --git a/src/mod/utc/awdrowapprent001.utc.json b/src/module/utc/awdrowapprent001.utc.json similarity index 100% rename from src/mod/utc/awdrowapprent001.utc.json rename to src/module/utc/awdrowapprent001.utc.json diff --git a/src/mod/utc/awdrowapprent002.utc.json b/src/module/utc/awdrowapprent002.utc.json similarity index 100% rename from src/mod/utc/awdrowapprent002.utc.json rename to src/module/utc/awdrowapprent002.utc.json diff --git a/src/mod/utc/awdrowapprent003.utc.json b/src/module/utc/awdrowapprent003.utc.json similarity index 100% rename from src/mod/utc/awdrowapprent003.utc.json rename to src/module/utc/awdrowapprent003.utc.json diff --git a/src/mod/utc/awdrowapprentice.utc.json b/src/module/utc/awdrowapprentice.utc.json similarity index 100% rename from src/mod/utc/awdrowapprentice.utc.json rename to src/module/utc/awdrowapprentice.utc.json diff --git a/src/mod/utc/awdrowarmsmercha.utc.json b/src/module/utc/awdrowarmsmercha.utc.json similarity index 100% rename from src/mod/utc/awdrowarmsmercha.utc.json rename to src/module/utc/awdrowarmsmercha.utc.json diff --git a/src/mod/utc/awdrowassassi001.utc.json b/src/module/utc/awdrowassassi001.utc.json similarity index 100% rename from src/mod/utc/awdrowassassi001.utc.json rename to src/module/utc/awdrowassassi001.utc.json diff --git a/src/mod/utc/awdrowassassicel.utc.json b/src/module/utc/awdrowassassicel.utc.json similarity index 100% rename from src/mod/utc/awdrowassassicel.utc.json rename to src/module/utc/awdrowassassicel.utc.json diff --git a/src/mod/utc/awdrowassassin.utc.json b/src/module/utc/awdrowassassin.utc.json similarity index 100% rename from src/mod/utc/awdrowassassin.utc.json rename to src/module/utc/awdrowassassin.utc.json diff --git a/src/mod/utc/awdrowbowman.utc.json b/src/module/utc/awdrowbowman.utc.json similarity index 100% rename from src/mod/utc/awdrowbowman.utc.json rename to src/module/utc/awdrowbowman.utc.json diff --git a/src/mod/utc/awdrowshapchange.utc.json b/src/module/utc/awdrowshapchange.utc.json similarity index 100% rename from src/mod/utc/awdrowshapchange.utc.json rename to src/module/utc/awdrowshapchange.utc.json diff --git a/src/mod/utc/awdrowwarrior.utc.json b/src/module/utc/awdrowwarrior.utc.json similarity index 100% rename from src/mod/utc/awdrowwarrior.utc.json rename to src/module/utc/awdrowwarrior.utc.json diff --git a/src/mod/utc/awdrowwizard.utc.json b/src/module/utc/awdrowwizard.utc.json similarity index 100% rename from src/mod/utc/awdrowwizard.utc.json rename to src/module/utc/awdrowwizard.utc.json diff --git a/src/mod/utc/awdrowwizcelapp.utc.json b/src/module/utc/awdrowwizcelapp.utc.json similarity index 100% rename from src/mod/utc/awdrowwizcelapp.utc.json rename to src/module/utc/awdrowwizcelapp.utc.json diff --git a/src/mod/utc/awelfslave.utc.json b/src/module/utc/awelfslave.utc.json similarity index 100% rename from src/mod/utc/awelfslave.utc.json rename to src/module/utc/awelfslave.utc.json diff --git a/src/mod/utc/awgiantspider.utc.json b/src/module/utc/awgiantspider.utc.json similarity index 100% rename from src/mod/utc/awgiantspider.utc.json rename to src/module/utc/awgiantspider.utc.json diff --git a/src/mod/utc/awgiantspider001.utc.json b/src/module/utc/awgiantspider001.utc.json similarity index 100% rename from src/mod/utc/awgiantspider001.utc.json rename to src/module/utc/awgiantspider001.utc.json diff --git a/src/mod/utc/awgiantspider002.utc.json b/src/module/utc/awgiantspider002.utc.json similarity index 100% rename from src/mod/utc/awgiantspider002.utc.json rename to src/module/utc/awgiantspider002.utc.json diff --git a/src/mod/utc/awmindflayer.utc.json b/src/module/utc/awmindflayer.utc.json similarity index 100% rename from src/mod/utc/awmindflayer.utc.json rename to src/module/utc/awmindflayer.utc.json diff --git a/src/mod/utc/awmindflayerboss.utc.json b/src/module/utc/awmindflayerboss.utc.json similarity index 100% rename from src/mod/utc/awmindflayerboss.utc.json rename to src/module/utc/awmindflayerboss.utc.json diff --git a/src/mod/utc/awmindflayerlvlu.utc.json b/src/module/utc/awmindflayerlvlu.utc.json similarity index 100% rename from src/mod/utc/awmindflayerlvlu.utc.json rename to src/module/utc/awmindflayerlvlu.utc.json diff --git a/src/mod/utc/awservernttov2.utc.json b/src/module/utc/awservernttov2.utc.json similarity index 100% rename from src/mod/utc/awservernttov2.utc.json rename to src/module/utc/awservernttov2.utc.json diff --git a/src/mod/utc/awservernttov3.utc.json b/src/module/utc/awservernttov3.utc.json similarity index 100% rename from src/mod/utc/awservernttov3.utc.json rename to src/module/utc/awservernttov3.utc.json diff --git a/src/mod/utc/awservernttovera.utc.json b/src/module/utc/awservernttovera.utc.json similarity index 100% rename from src/mod/utc/awservernttovera.utc.json rename to src/module/utc/awservernttovera.utc.json diff --git a/src/mod/utc/awskeleton.utc.json b/src/module/utc/awskeleton.utc.json similarity index 100% rename from src/mod/utc/awskeleton.utc.json rename to src/module/utc/awskeleton.utc.json diff --git a/src/mod/utc/awskeletonmage.utc.json b/src/module/utc/awskeletonmage.utc.json similarity index 100% rename from src/mod/utc/awskeletonmage.utc.json rename to src/module/utc/awskeletonmage.utc.json diff --git a/src/mod/utc/awskeletonwarrio.utc.json b/src/module/utc/awskeletonwarrio.utc.json similarity index 100% rename from src/mod/utc/awskeletonwarrio.utc.json rename to src/module/utc/awskeletonwarrio.utc.json diff --git a/src/mod/utc/awtroll.utc.json b/src/module/utc/awtroll.utc.json similarity index 100% rename from src/mod/utc/awtroll.utc.json rename to src/module/utc/awtroll.utc.json diff --git a/src/mod/utc/awtrollcheif.utc.json b/src/module/utc/awtrollcheif.utc.json similarity index 100% rename from src/mod/utc/awtrollcheif.utc.json rename to src/module/utc/awtrollcheif.utc.json diff --git a/src/mod/utc/awtrollshaman.utc.json b/src/module/utc/awtrollshaman.utc.json similarity index 100% rename from src/mod/utc/awtrollshaman.utc.json rename to src/module/utc/awtrollshaman.utc.json diff --git a/src/mod/utc/awtrollspiter.utc.json b/src/module/utc/awtrollspiter.utc.json similarity index 100% rename from src/mod/utc/awtrollspiter.utc.json rename to src/module/utc/awtrollspiter.utc.json diff --git a/src/mod/utc/awveraspawn.utc.json b/src/module/utc/awveraspawn.utc.json similarity index 100% rename from src/mod/utc/awveraspawn.utc.json rename to src/module/utc/awveraspawn.utc.json diff --git a/src/mod/utc/awveraspawn2.utc.json b/src/module/utc/awveraspawn2.utc.json similarity index 100% rename from src/mod/utc/awveraspawn2.utc.json rename to src/module/utc/awveraspawn2.utc.json diff --git a/src/mod/utc/awveratrueform.utc.json b/src/module/utc/awveratrueform.utc.json similarity index 100% rename from src/mod/utc/awveratrueform.utc.json rename to src/module/utc/awveratrueform.utc.json diff --git a/src/mod/utc/awzombie.utc.json b/src/module/utc/awzombie.utc.json similarity index 100% rename from src/mod/utc/awzombie.utc.json rename to src/module/utc/awzombie.utc.json diff --git a/src/mod/utc/awzombiegreat.utc.json b/src/module/utc/awzombiegreat.utc.json similarity index 100% rename from src/mod/utc/awzombiegreat.utc.json rename to src/module/utc/awzombiegreat.utc.json diff --git a/src/mod/utc/awzombiekama.utc.json b/src/module/utc/awzombiekama.utc.json similarity index 100% rename from src/mod/utc/awzombiekama.utc.json rename to src/module/utc/awzombiekama.utc.json diff --git a/src/mod/utc/awzombielord.utc.json b/src/module/utc/awzombielord.utc.json similarity index 100% rename from src/mod/utc/awzombielord.utc.json rename to src/module/utc/awzombielord.utc.json diff --git a/src/mod/utc/awzombieplague.utc.json b/src/module/utc/awzombieplague.utc.json similarity index 100% rename from src/mod/utc/awzombieplague.utc.json rename to src/module/utc/awzombieplague.utc.json diff --git a/src/mod/utc/bandit.utc.json b/src/module/utc/bandit.utc.json similarity index 100% rename from src/mod/utc/bandit.utc.json rename to src/module/utc/bandit.utc.json diff --git a/src/mod/utc/bandit001.utc.json b/src/module/utc/bandit001.utc.json similarity index 100% rename from src/mod/utc/bandit001.utc.json rename to src/module/utc/bandit001.utc.json diff --git a/src/mod/utc/banditarcher001.utc.json b/src/module/utc/banditarcher001.utc.json similarity index 100% rename from src/mod/utc/banditarcher001.utc.json rename to src/module/utc/banditarcher001.utc.json diff --git a/src/mod/utc/banditchief001.utc.json b/src/module/utc/banditchief001.utc.json similarity index 100% rename from src/mod/utc/banditchief001.utc.json rename to src/module/utc/banditchief001.utc.json diff --git a/src/mod/utc/banditchief002.utc.json b/src/module/utc/banditchief002.utc.json similarity index 100% rename from src/mod/utc/banditchief002.utc.json rename to src/module/utc/banditchief002.utc.json diff --git a/src/mod/utc/banditmage.utc.json b/src/module/utc/banditmage.utc.json similarity index 100% rename from src/mod/utc/banditmage.utc.json rename to src/module/utc/banditmage.utc.json diff --git a/src/mod/utc/banditmage001.utc.json b/src/module/utc/banditmage001.utc.json similarity index 100% rename from src/mod/utc/banditmage001.utc.json rename to src/module/utc/banditmage001.utc.json diff --git a/src/mod/utc/banditrogue001.utc.json b/src/module/utc/banditrogue001.utc.json similarity index 100% rename from src/mod/utc/banditrogue001.utc.json rename to src/module/utc/banditrogue001.utc.json diff --git a/src/mod/utc/bat001.utc.json b/src/module/utc/bat001.utc.json similarity index 100% rename from src/mod/utc/bat001.utc.json rename to src/module/utc/bat001.utc.json diff --git a/src/mod/utc/battlebot.utc.json b/src/module/utc/battlebot.utc.json similarity index 100% rename from src/mod/utc/battlebot.utc.json rename to src/module/utc/battlebot.utc.json diff --git a/src/mod/utc/battletrainer.utc.json b/src/module/utc/battletrainer.utc.json similarity index 100% rename from src/mod/utc/battletrainer.utc.json rename to src/module/utc/battletrainer.utc.json diff --git a/src/mod/utc/beingchannele005.utc.json b/src/module/utc/beingchannele005.utc.json similarity index 100% rename from src/mod/utc/beingchannele005.utc.json rename to src/module/utc/beingchannele005.utc.json diff --git a/src/mod/utc/beingchannele006.utc.json b/src/module/utc/beingchannele006.utc.json similarity index 100% rename from src/mod/utc/beingchannele006.utc.json rename to src/module/utc/beingchannele006.utc.json diff --git a/src/mod/utc/beingchannele007.utc.json b/src/module/utc/beingchannele007.utc.json similarity index 100% rename from src/mod/utc/beingchannele007.utc.json rename to src/module/utc/beingchannele007.utc.json diff --git a/src/mod/utc/beingchannele008.utc.json b/src/module/utc/beingchannele008.utc.json similarity index 100% rename from src/mod/utc/beingchannele008.utc.json rename to src/module/utc/beingchannele008.utc.json diff --git a/src/mod/utc/beingchanneler.utc.json b/src/module/utc/beingchanneler.utc.json similarity index 100% rename from src/mod/utc/beingchanneler.utc.json rename to src/module/utc/beingchanneler.utc.json diff --git a/src/mod/utc/bikinimonk.utc.json b/src/module/utc/bikinimonk.utc.json similarity index 100% rename from src/mod/utc/bikinimonk.utc.json rename to src/module/utc/bikinimonk.utc.json diff --git a/src/mod/utc/blackbear.utc.json b/src/module/utc/blackbear.utc.json similarity index 100% rename from src/mod/utc/blackbear.utc.json rename to src/module/utc/blackbear.utc.json diff --git a/src/mod/utc/blackbear001.utc.json b/src/module/utc/blackbear001.utc.json similarity index 100% rename from src/mod/utc/blackbear001.utc.json rename to src/module/utc/blackbear001.utc.json diff --git a/src/mod/utc/blackbear002.utc.json b/src/module/utc/blackbear002.utc.json similarity index 100% rename from src/mod/utc/blackbear002.utc.json rename to src/module/utc/blackbear002.utc.json diff --git a/src/mod/utc/blinkdog001.utc.json b/src/module/utc/blinkdog001.utc.json similarity index 100% rename from src/mod/utc/blinkdog001.utc.json rename to src/module/utc/blinkdog001.utc.json diff --git a/src/mod/utc/bluedwarf001.utc.json b/src/module/utc/bluedwarf001.utc.json similarity index 100% rename from src/mod/utc/bluedwarf001.utc.json rename to src/module/utc/bluedwarf001.utc.json diff --git a/src/mod/utc/bodyguard.utc.json b/src/module/utc/bodyguard.utc.json similarity index 100% rename from src/mod/utc/bodyguard.utc.json rename to src/module/utc/bodyguard.utc.json diff --git a/src/mod/utc/boney.utc.json b/src/module/utc/boney.utc.json similarity index 100% rename from src/mod/utc/boney.utc.json rename to src/module/utc/boney.utc.json diff --git a/src/mod/utc/boneydude.utc.json b/src/module/utc/boneydude.utc.json similarity index 100% rename from src/mod/utc/boneydude.utc.json rename to src/module/utc/boneydude.utc.json diff --git a/src/mod/utc/boogieman.utc.json b/src/module/utc/boogieman.utc.json similarity index 100% rename from src/mod/utc/boogieman.utc.json rename to src/module/utc/boogieman.utc.json diff --git a/src/mod/utc/brewmaster.utc.json b/src/module/utc/brewmaster.utc.json similarity index 100% rename from src/mod/utc/brewmaster.utc.json rename to src/module/utc/brewmaster.utc.json diff --git a/src/mod/utc/briggs.utc.json b/src/module/utc/briggs.utc.json similarity index 100% rename from src/mod/utc/briggs.utc.json rename to src/module/utc/briggs.utc.json diff --git a/src/mod/utc/briggs001.utc.json b/src/module/utc/briggs001.utc.json similarity index 100% rename from src/mod/utc/briggs001.utc.json rename to src/module/utc/briggs001.utc.json diff --git a/src/mod/utc/buurk.utc.json b/src/module/utc/buurk.utc.json similarity index 100% rename from src/mod/utc/buurk.utc.json rename to src/module/utc/buurk.utc.json diff --git a/src/mod/utc/cainarcher001.utc.json b/src/module/utc/cainarcher001.utc.json similarity index 100% rename from src/mod/utc/cainarcher001.utc.json rename to src/module/utc/cainarcher001.utc.json diff --git a/src/mod/utc/cainbattlegolem.utc.json b/src/module/utc/cainbattlegolem.utc.json similarity index 100% rename from src/mod/utc/cainbattlegolem.utc.json rename to src/module/utc/cainbattlegolem.utc.json diff --git a/src/mod/utc/caincastleguard.utc.json b/src/module/utc/caincastleguard.utc.json similarity index 100% rename from src/mod/utc/caincastleguard.utc.json rename to src/module/utc/caincastleguard.utc.json diff --git a/src/mod/utc/cainsummoner.utc.json b/src/module/utc/cainsummoner.utc.json similarity index 100% rename from src/mod/utc/cainsummoner.utc.json rename to src/module/utc/cainsummoner.utc.json diff --git a/src/mod/utc/calimanson.utc.json b/src/module/utc/calimanson.utc.json similarity index 100% rename from src/mod/utc/calimanson.utc.json rename to src/module/utc/calimanson.utc.json diff --git a/src/mod/utc/carrionbird.utc.json b/src/module/utc/carrionbird.utc.json similarity index 100% rename from src/mod/utc/carrionbird.utc.json rename to src/module/utc/carrionbird.utc.json diff --git a/src/mod/utc/caveman.utc.json b/src/module/utc/caveman.utc.json similarity index 100% rename from src/mod/utc/caveman.utc.json rename to src/module/utc/caveman.utc.json diff --git a/src/mod/utc/chicken001.utc.json b/src/module/utc/chicken001.utc.json similarity index 100% rename from src/mod/utc/chicken001.utc.json rename to src/module/utc/chicken001.utc.json diff --git a/src/mod/utc/choir2.utc.json b/src/module/utc/choir2.utc.json similarity index 100% rename from src/mod/utc/choir2.utc.json rename to src/module/utc/choir2.utc.json diff --git a/src/mod/utc/choirboy.utc.json b/src/module/utc/choirboy.utc.json similarity index 100% rename from src/mod/utc/choirboy.utc.json rename to src/module/utc/choirboy.utc.json diff --git a/src/mod/utc/clanleader.utc.json b/src/module/utc/clanleader.utc.json similarity index 100% rename from src/mod/utc/clanleader.utc.json rename to src/module/utc/clanleader.utc.json diff --git a/src/mod/utc/clantern001.utc.json b/src/module/utc/clantern001.utc.json similarity index 100% rename from src/mod/utc/clantern001.utc.json rename to src/module/utc/clantern001.utc.json diff --git a/src/mod/utc/cloaklich.utc.json b/src/module/utc/cloaklich.utc.json similarity index 100% rename from src/mod/utc/cloaklich.utc.json rename to src/module/utc/cloaklich.utc.json diff --git a/src/mod/utc/cloaklich001.utc.json b/src/module/utc/cloaklich001.utc.json similarity index 100% rename from src/mod/utc/cloaklich001.utc.json rename to src/module/utc/cloaklich001.utc.json diff --git a/src/mod/utc/closetmonster.utc.json b/src/module/utc/closetmonster.utc.json similarity index 100% rename from src/mod/utc/closetmonster.utc.json rename to src/module/utc/closetmonster.utc.json diff --git a/src/mod/utc/combatdroid.utc.json b/src/module/utc/combatdroid.utc.json similarity index 100% rename from src/mod/utc/combatdroid.utc.json rename to src/module/utc/combatdroid.utc.json diff --git a/src/mod/utc/cow001.utc.json b/src/module/utc/cow001.utc.json similarity index 100% rename from src/mod/utc/cow001.utc.json rename to src/module/utc/cow001.utc.json diff --git a/src/mod/utc/crawly.utc.json b/src/module/utc/crawly.utc.json similarity index 100% rename from src/mod/utc/crawly.utc.json rename to src/module/utc/crawly.utc.json diff --git a/src/mod/utc/crawly001.utc.json b/src/module/utc/crawly001.utc.json similarity index 100% rename from src/mod/utc/crawly001.utc.json rename to src/module/utc/crawly001.utc.json diff --git a/src/mod/utc/creature002.utc.json b/src/module/utc/creature002.utc.json similarity index 100% rename from src/mod/utc/creature002.utc.json rename to src/module/utc/creature002.utc.json diff --git a/src/mod/utc/creepy.utc.json b/src/module/utc/creepy.utc.json similarity index 100% rename from src/mod/utc/creepy.utc.json rename to src/module/utc/creepy.utc.json diff --git a/src/mod/utc/cultdiciple.utc.json b/src/module/utc/cultdiciple.utc.json similarity index 100% rename from src/mod/utc/cultdiciple.utc.json rename to src/module/utc/cultdiciple.utc.json diff --git a/src/mod/utc/cultdiciplescout.utc.json b/src/module/utc/cultdiciplescout.utc.json similarity index 100% rename from src/mod/utc/cultdiciplescout.utc.json rename to src/module/utc/cultdiciplescout.utc.json diff --git a/src/mod/utc/cultofminimage.utc.json b/src/module/utc/cultofminimage.utc.json similarity index 100% rename from src/mod/utc/cultofminimage.utc.json rename to src/module/utc/cultofminimage.utc.json diff --git a/src/mod/utc/cultofminiwar001.utc.json b/src/module/utc/cultofminiwar001.utc.json similarity index 100% rename from src/mod/utc/cultofminiwar001.utc.json rename to src/module/utc/cultofminiwar001.utc.json diff --git a/src/mod/utc/cultofminiwarrio.utc.json b/src/module/utc/cultofminiwarrio.utc.json similarity index 100% rename from src/mod/utc/cultofminiwarrio.utc.json rename to src/module/utc/cultofminiwarrio.utc.json diff --git a/src/mod/utc/culttaskmaster.utc.json b/src/module/utc/culttaskmaster.utc.json similarity index 100% rename from src/mod/utc/culttaskmaster.utc.json rename to src/module/utc/culttaskmaster.utc.json diff --git a/src/mod/utc/darth.utc.json b/src/module/utc/darth.utc.json similarity index 100% rename from src/mod/utc/darth.utc.json rename to src/module/utc/darth.utc.json diff --git a/src/mod/utc/ddblademaster.utc.json b/src/module/utc/ddblademaster.utc.json similarity index 100% rename from src/mod/utc/ddblademaster.utc.json rename to src/module/utc/ddblademaster.utc.json diff --git a/src/mod/utc/ddboss.utc.json b/src/module/utc/ddboss.utc.json similarity index 100% rename from src/mod/utc/ddboss.utc.json rename to src/module/utc/ddboss.utc.json diff --git a/src/mod/utc/ddcleric.utc.json b/src/module/utc/ddcleric.utc.json similarity index 100% rename from src/mod/utc/ddcleric.utc.json rename to src/module/utc/ddcleric.utc.json diff --git a/src/mod/utc/ddmonk.utc.json b/src/module/utc/ddmonk.utc.json similarity index 100% rename from src/mod/utc/ddmonk.utc.json rename to src/module/utc/ddmonk.utc.json diff --git a/src/mod/utc/ddwizard.utc.json b/src/module/utc/ddwizard.utc.json similarity index 100% rename from src/mod/utc/ddwizard.utc.json rename to src/module/utc/ddwizard.utc.json diff --git a/src/mod/utc/deadhead.utc.json b/src/module/utc/deadhead.utc.json similarity index 100% rename from src/mod/utc/deadhead.utc.json rename to src/module/utc/deadhead.utc.json diff --git a/src/mod/utc/deer001.utc.json b/src/module/utc/deer001.utc.json similarity index 100% rename from src/mod/utc/deer001.utc.json rename to src/module/utc/deer001.utc.json diff --git a/src/mod/utc/defendermonk.utc.json b/src/module/utc/defendermonk.utc.json similarity index 100% rename from src/mod/utc/defendermonk.utc.json rename to src/module/utc/defendermonk.utc.json diff --git a/src/mod/utc/delianu.utc.json b/src/module/utc/delianu.utc.json similarity index 100% rename from src/mod/utc/delianu.utc.json rename to src/module/utc/delianu.utc.json diff --git a/src/mod/utc/desertbomber.utc.json b/src/module/utc/desertbomber.utc.json similarity index 100% rename from src/mod/utc/desertbomber.utc.json rename to src/module/utc/desertbomber.utc.json diff --git a/src/mod/utc/desertdwarf.utc.json b/src/module/utc/desertdwarf.utc.json similarity index 100% rename from src/mod/utc/desertdwarf.utc.json rename to src/module/utc/desertdwarf.utc.json diff --git a/src/mod/utc/dinosaur.utc.json b/src/module/utc/dinosaur.utc.json similarity index 100% rename from src/mod/utc/dinosaur.utc.json rename to src/module/utc/dinosaur.utc.json diff --git a/src/mod/utc/direpenguin.utc.json b/src/module/utc/direpenguin.utc.json similarity index 100% rename from src/mod/utc/direpenguin.utc.json rename to src/module/utc/direpenguin.utc.json diff --git a/src/mod/utc/dirthbattlebo001.utc.json b/src/module/utc/dirthbattlebo001.utc.json similarity index 100% rename from src/mod/utc/dirthbattlebo001.utc.json rename to src/module/utc/dirthbattlebo001.utc.json diff --git a/src/mod/utc/dirthbattlebo002.utc.json b/src/module/utc/dirthbattlebo002.utc.json similarity index 100% rename from src/mod/utc/dirthbattlebo002.utc.json rename to src/module/utc/dirthbattlebo002.utc.json diff --git a/src/mod/utc/dirthbattlebot.utc.json b/src/module/utc/dirthbattlebot.utc.json similarity index 100% rename from src/mod/utc/dirthbattlebot.utc.json rename to src/module/utc/dirthbattlebot.utc.json diff --git a/src/mod/utc/dirthranger.utc.json b/src/module/utc/dirthranger.utc.json similarity index 100% rename from src/mod/utc/dirthranger.utc.json rename to src/module/utc/dirthranger.utc.json diff --git a/src/mod/utc/dirthwarrior.utc.json b/src/module/utc/dirthwarrior.utc.json similarity index 100% rename from src/mod/utc/dirthwarrior.utc.json rename to src/module/utc/dirthwarrior.utc.json diff --git a/src/mod/utc/dirthwarrior001.utc.json b/src/module/utc/dirthwarrior001.utc.json similarity index 100% rename from src/mod/utc/dirthwarrior001.utc.json rename to src/module/utc/dirthwarrior001.utc.json diff --git a/src/mod/utc/dirthwarrior002.utc.json b/src/module/utc/dirthwarrior002.utc.json similarity index 100% rename from src/mod/utc/dirthwarrior002.utc.json rename to src/module/utc/dirthwarrior002.utc.json diff --git a/src/mod/utc/dracmistress.utc.json b/src/module/utc/dracmistress.utc.json similarity index 100% rename from src/mod/utc/dracmistress.utc.json rename to src/module/utc/dracmistress.utc.json diff --git a/src/mod/utc/dracoblake001.utc.json b/src/module/utc/dracoblake001.utc.json similarity index 100% rename from src/mod/utc/dracoblake001.utc.json rename to src/module/utc/dracoblake001.utc.json diff --git a/src/mod/utc/dracula.utc.json b/src/module/utc/dracula.utc.json similarity index 100% rename from src/mod/utc/dracula.utc.json rename to src/module/utc/dracula.utc.json diff --git a/src/mod/utc/dragon_black002.utc.json b/src/module/utc/dragon_black002.utc.json similarity index 100% rename from src/mod/utc/dragon_black002.utc.json rename to src/module/utc/dragon_black002.utc.json diff --git a/src/mod/utc/dragoncultmag001.utc.json b/src/module/utc/dragoncultmag001.utc.json similarity index 100% rename from src/mod/utc/dragoncultmag001.utc.json rename to src/module/utc/dragoncultmag001.utc.json diff --git a/src/mod/utc/dragoncultmag002.utc.json b/src/module/utc/dragoncultmag002.utc.json similarity index 100% rename from src/mod/utc/dragoncultmag002.utc.json rename to src/module/utc/dragoncultmag002.utc.json diff --git a/src/mod/utc/dragoncultmag003.utc.json b/src/module/utc/dragoncultmag003.utc.json similarity index 100% rename from src/mod/utc/dragoncultmag003.utc.json rename to src/module/utc/dragoncultmag003.utc.json diff --git a/src/mod/utc/dragoncultmage.utc.json b/src/module/utc/dragoncultmage.utc.json similarity index 100% rename from src/mod/utc/dragoncultmage.utc.json rename to src/module/utc/dragoncultmage.utc.json diff --git a/src/mod/utc/dragoncultseeker.utc.json b/src/module/utc/dragoncultseeker.utc.json similarity index 100% rename from src/mod/utc/dragoncultseeker.utc.json rename to src/module/utc/dragoncultseeker.utc.json diff --git a/src/mod/utc/dragoncultwar001.utc.json b/src/module/utc/dragoncultwar001.utc.json similarity index 100% rename from src/mod/utc/dragoncultwar001.utc.json rename to src/module/utc/dragoncultwar001.utc.json diff --git a/src/mod/utc/dragoncultwarrio.utc.json b/src/module/utc/dragoncultwarrio.utc.json similarity index 100% rename from src/mod/utc/dragoncultwarrio.utc.json rename to src/module/utc/dragoncultwarrio.utc.json diff --git a/src/mod/utc/dragonslingblade.utc.json b/src/module/utc/dragonslingblade.utc.json similarity index 100% rename from src/mod/utc/dragonslingblade.utc.json rename to src/module/utc/dragonslingblade.utc.json diff --git a/src/mod/utc/dragonweaponm001.utc.json b/src/module/utc/dragonweaponm001.utc.json similarity index 100% rename from src/mod/utc/dragonweaponm001.utc.json rename to src/module/utc/dragonweaponm001.utc.json diff --git a/src/mod/utc/dragonweaponmast.utc.json b/src/module/utc/dragonweaponmast.utc.json similarity index 100% rename from src/mod/utc/dragonweaponmast.utc.json rename to src/module/utc/dragonweaponmast.utc.json diff --git a/src/mod/utc/dreamweaver.utc.json b/src/module/utc/dreamweaver.utc.json similarity index 100% rename from src/mod/utc/dreamweaver.utc.json rename to src/module/utc/dreamweaver.utc.json diff --git a/src/mod/utc/drgbrnz004.utc.json b/src/module/utc/drgbrnz004.utc.json similarity index 100% rename from src/mod/utc/drgbrnz004.utc.json rename to src/module/utc/drgbrnz004.utc.json diff --git a/src/mod/utc/drgcopp004.utc.json b/src/module/utc/drgcopp004.utc.json similarity index 100% rename from src/mod/utc/drgcopp004.utc.json rename to src/module/utc/drgcopp004.utc.json diff --git a/src/mod/utc/drgcopp005.utc.json b/src/module/utc/drgcopp005.utc.json similarity index 100% rename from src/mod/utc/drgcopp005.utc.json rename to src/module/utc/drgcopp005.utc.json diff --git a/src/mod/utc/drggreen004.utc.json b/src/module/utc/drggreen004.utc.json similarity index 100% rename from src/mod/utc/drggreen004.utc.json rename to src/module/utc/drggreen004.utc.json diff --git a/src/mod/utc/drggreen005.utc.json b/src/module/utc/drggreen005.utc.json similarity index 100% rename from src/mod/utc/drggreen005.utc.json rename to src/module/utc/drggreen005.utc.json diff --git a/src/mod/utc/drgred004.utc.json b/src/module/utc/drgred004.utc.json similarity index 100% rename from src/mod/utc/drgred004.utc.json rename to src/module/utc/drgred004.utc.json diff --git a/src/mod/utc/drgred005.utc.json b/src/module/utc/drgred005.utc.json similarity index 100% rename from src/mod/utc/drgred005.utc.json rename to src/module/utc/drgred005.utc.json diff --git a/src/mod/utc/drgsilv004.utc.json b/src/module/utc/drgsilv004.utc.json similarity index 100% rename from src/mod/utc/drgsilv004.utc.json rename to src/module/utc/drgsilv004.utc.json diff --git a/src/mod/utc/drgwhite004.utc.json b/src/module/utc/drgwhite004.utc.json similarity index 100% rename from src/mod/utc/drgwhite004.utc.json rename to src/module/utc/drgwhite004.utc.json diff --git a/src/mod/utc/drgwhite005.utc.json b/src/module/utc/drgwhite005.utc.json similarity index 100% rename from src/mod/utc/drgwhite005.utc.json rename to src/module/utc/drgwhite005.utc.json diff --git a/src/mod/utc/drgwhite006.utc.json b/src/module/utc/drgwhite006.utc.json similarity index 100% rename from src/mod/utc/drgwhite006.utc.json rename to src/module/utc/drgwhite006.utc.json diff --git a/src/mod/utc/drgwhite007.utc.json b/src/module/utc/drgwhite007.utc.json similarity index 100% rename from src/mod/utc/drgwhite007.utc.json rename to src/module/utc/drgwhite007.utc.json diff --git a/src/mod/utc/drowcleric.utc.json b/src/module/utc/drowcleric.utc.json similarity index 100% rename from src/mod/utc/drowcleric.utc.json rename to src/module/utc/drowcleric.utc.json diff --git a/src/mod/utc/drowcleric001.utc.json b/src/module/utc/drowcleric001.utc.json similarity index 100% rename from src/mod/utc/drowcleric001.utc.json rename to src/module/utc/drowcleric001.utc.json diff --git a/src/mod/utc/drowdefender.utc.json b/src/module/utc/drowdefender.utc.json similarity index 100% rename from src/mod/utc/drowdefender.utc.json rename to src/module/utc/drowdefender.utc.json diff --git a/src/mod/utc/drowguard.utc.json b/src/module/utc/drowguard.utc.json similarity index 100% rename from src/mod/utc/drowguard.utc.json rename to src/module/utc/drowguard.utc.json diff --git a/src/mod/utc/drudoc.utc.json b/src/module/utc/drudoc.utc.json similarity index 100% rename from src/mod/utc/drudoc.utc.json rename to src/module/utc/drudoc.utc.json diff --git a/src/mod/utc/druidelder.utc.json b/src/module/utc/druidelder.utc.json similarity index 100% rename from src/mod/utc/druidelder.utc.json rename to src/module/utc/druidelder.utc.json diff --git a/src/mod/utc/druidelder001.utc.json b/src/module/utc/druidelder001.utc.json similarity index 100% rename from src/mod/utc/druidelder001.utc.json rename to src/module/utc/druidelder001.utc.json diff --git a/src/mod/utc/dungeonmaster001.utc.json b/src/module/utc/dungeonmaster001.utc.json similarity index 100% rename from src/mod/utc/dungeonmaster001.utc.json rename to src/module/utc/dungeonmaster001.utc.json diff --git a/src/mod/utc/dwarfbladeslinge.utc.json b/src/module/utc/dwarfbladeslinge.utc.json similarity index 100% rename from src/mod/utc/dwarfbladeslinge.utc.json rename to src/module/utc/dwarfbladeslinge.utc.json diff --git a/src/mod/utc/dwarfgaurd.utc.json b/src/module/utc/dwarfgaurd.utc.json similarity index 100% rename from src/mod/utc/dwarfgaurd.utc.json rename to src/module/utc/dwarfgaurd.utc.json diff --git a/src/mod/utc/dwarfhighwiza001.utc.json b/src/module/utc/dwarfhighwiza001.utc.json similarity index 100% rename from src/mod/utc/dwarfhighwiza001.utc.json rename to src/module/utc/dwarfhighwiza001.utc.json diff --git a/src/mod/utc/dwarfhighwiza002.utc.json b/src/module/utc/dwarfhighwiza002.utc.json similarity index 100% rename from src/mod/utc/dwarfhighwiza002.utc.json rename to src/module/utc/dwarfhighwiza002.utc.json diff --git a/src/mod/utc/dwarfhighwizard.utc.json b/src/module/utc/dwarfhighwizard.utc.json similarity index 100% rename from src/mod/utc/dwarfhighwizard.utc.json rename to src/module/utc/dwarfhighwizard.utc.json diff --git a/src/mod/utc/dwarfpriest.utc.json b/src/module/utc/dwarfpriest.utc.json similarity index 100% rename from src/mod/utc/dwarfpriest.utc.json rename to src/module/utc/dwarfpriest.utc.json diff --git a/src/mod/utc/elevenmage.utc.json b/src/module/utc/elevenmage.utc.json similarity index 100% rename from src/mod/utc/elevenmage.utc.json rename to src/module/utc/elevenmage.utc.json diff --git a/src/mod/utc/elevenmage001.utc.json b/src/module/utc/elevenmage001.utc.json similarity index 100% rename from src/mod/utc/elevenmage001.utc.json rename to src/module/utc/elevenmage001.utc.json diff --git a/src/mod/utc/elevenwarrior.utc.json b/src/module/utc/elevenwarrior.utc.json similarity index 100% rename from src/mod/utc/elevenwarrior.utc.json rename to src/module/utc/elevenwarrior.utc.json diff --git a/src/mod/utc/elevenwarrior001.utc.json b/src/module/utc/elevenwarrior001.utc.json similarity index 100% rename from src/mod/utc/elevenwarrior001.utc.json rename to src/module/utc/elevenwarrior001.utc.json diff --git a/src/mod/utc/elvendarman001.utc.json b/src/module/utc/elvendarman001.utc.json similarity index 100% rename from src/mod/utc/elvendarman001.utc.json rename to src/module/utc/elvendarman001.utc.json diff --git a/src/mod/utc/elvendarman002.utc.json b/src/module/utc/elvendarman002.utc.json similarity index 100% rename from src/mod/utc/elvendarman002.utc.json rename to src/module/utc/elvendarman002.utc.json diff --git a/src/mod/utc/elvendarman003.utc.json b/src/module/utc/elvendarman003.utc.json similarity index 100% rename from src/mod/utc/elvendarman003.utc.json rename to src/module/utc/elvendarman003.utc.json diff --git a/src/mod/utc/elvendarman004.utc.json b/src/module/utc/elvendarman004.utc.json similarity index 100% rename from src/mod/utc/elvendarman004.utc.json rename to src/module/utc/elvendarman004.utc.json diff --git a/src/mod/utc/elvendarman005.utc.json b/src/module/utc/elvendarman005.utc.json similarity index 100% rename from src/mod/utc/elvendarman005.utc.json rename to src/module/utc/elvendarman005.utc.json diff --git a/src/mod/utc/elvendarman006.utc.json b/src/module/utc/elvendarman006.utc.json similarity index 100% rename from src/mod/utc/elvendarman006.utc.json rename to src/module/utc/elvendarman006.utc.json diff --git a/src/mod/utc/elvendarman007.utc.json b/src/module/utc/elvendarman007.utc.json similarity index 100% rename from src/mod/utc/elvendarman007.utc.json rename to src/module/utc/elvendarman007.utc.json diff --git a/src/mod/utc/elvendarman008.utc.json b/src/module/utc/elvendarman008.utc.json similarity index 100% rename from src/mod/utc/elvendarman008.utc.json rename to src/module/utc/elvendarman008.utc.json diff --git a/src/mod/utc/elvendarman009.utc.json b/src/module/utc/elvendarman009.utc.json similarity index 100% rename from src/mod/utc/elvendarman009.utc.json rename to src/module/utc/elvendarman009.utc.json diff --git a/src/mod/utc/embodiedfear.utc.json b/src/module/utc/embodiedfear.utc.json similarity index 100% rename from src/mod/utc/embodiedfear.utc.json rename to src/module/utc/embodiedfear.utc.json diff --git a/src/mod/utc/embodiedfeargrea.utc.json b/src/module/utc/embodiedfeargrea.utc.json similarity index 100% rename from src/mod/utc/embodiedfeargrea.utc.json rename to src/module/utc/embodiedfeargrea.utc.json diff --git a/src/mod/utc/enchancientguard.utc.json b/src/module/utc/enchancientguard.utc.json similarity index 100% rename from src/mod/utc/enchancientguard.utc.json rename to src/module/utc/enchancientguard.utc.json diff --git a/src/mod/utc/evillibrarian.utc.json b/src/module/utc/evillibrarian.utc.json similarity index 100% rename from src/mod/utc/evillibrarian.utc.json rename to src/module/utc/evillibrarian.utc.json diff --git a/src/mod/utc/falcon.utc.json b/src/module/utc/falcon.utc.json similarity index 100% rename from src/mod/utc/falcon.utc.json rename to src/module/utc/falcon.utc.json diff --git a/src/mod/utc/fallencleric.utc.json b/src/module/utc/fallencleric.utc.json similarity index 100% rename from src/mod/utc/fallencleric.utc.json rename to src/module/utc/fallencleric.utc.json diff --git a/src/mod/utc/fallenpaladin.utc.json b/src/module/utc/fallenpaladin.utc.json similarity index 100% rename from src/mod/utc/fallenpaladin.utc.json rename to src/module/utc/fallenpaladin.utc.json diff --git a/src/mod/utc/febrith.utc.json b/src/module/utc/febrith.utc.json similarity index 100% rename from src/mod/utc/febrith.utc.json rename to src/module/utc/febrith.utc.json diff --git a/src/mod/utc/firedragon.utc.json b/src/module/utc/firedragon.utc.json similarity index 100% rename from src/mod/utc/firedragon.utc.json rename to src/module/utc/firedragon.utc.json diff --git a/src/mod/utc/forestdruid.utc.json b/src/module/utc/forestdruid.utc.json similarity index 100% rename from src/mod/utc/forestdruid.utc.json rename to src/module/utc/forestdruid.utc.json diff --git a/src/mod/utc/frostwolf.utc.json b/src/module/utc/frostwolf.utc.json similarity index 100% rename from src/mod/utc/frostwolf.utc.json rename to src/module/utc/frostwolf.utc.json diff --git a/src/mod/utc/gaseousform.utc.json b/src/module/utc/gaseousform.utc.json similarity index 100% rename from src/mod/utc/gaseousform.utc.json rename to src/module/utc/gaseousform.utc.json diff --git a/src/mod/utc/gaseousform001.utc.json b/src/module/utc/gaseousform001.utc.json similarity index 100% rename from src/mod/utc/gaseousform001.utc.json rename to src/module/utc/gaseousform001.utc.json diff --git a/src/mod/utc/gelcube001.utc.json b/src/module/utc/gelcube001.utc.json similarity index 100% rename from src/mod/utc/gelcube001.utc.json rename to src/module/utc/gelcube001.utc.json diff --git a/src/mod/utc/gelcube002.utc.json b/src/module/utc/gelcube002.utc.json similarity index 100% rename from src/mod/utc/gelcube002.utc.json rename to src/module/utc/gelcube002.utc.json diff --git a/src/mod/utc/ghostlyimage.utc.json b/src/module/utc/ghostlyimage.utc.json similarity index 100% rename from src/mod/utc/ghostlyimage.utc.json rename to src/module/utc/ghostlyimage.utc.json diff --git a/src/mod/utc/gnomegaurdian.utc.json b/src/module/utc/gnomegaurdian.utc.json similarity index 100% rename from src/mod/utc/gnomegaurdian.utc.json rename to src/module/utc/gnomegaurdian.utc.json diff --git a/src/mod/utc/gobchiefa002.utc.json b/src/module/utc/gobchiefa002.utc.json similarity index 100% rename from src/mod/utc/gobchiefa002.utc.json rename to src/module/utc/gobchiefa002.utc.json diff --git a/src/mod/utc/gobchiefa004.utc.json b/src/module/utc/gobchiefa004.utc.json similarity index 100% rename from src/mod/utc/gobchiefa004.utc.json rename to src/module/utc/gobchiefa004.utc.json diff --git a/src/mod/utc/golstone001.utc.json b/src/module/utc/golstone001.utc.json similarity index 100% rename from src/mod/utc/golstone001.utc.json rename to src/module/utc/golstone001.utc.json diff --git a/src/mod/utc/golstone002.utc.json b/src/module/utc/golstone002.utc.json similarity index 100% rename from src/mod/utc/golstone002.utc.json rename to src/module/utc/golstone002.utc.json diff --git a/src/mod/utc/granola.utc.json b/src/module/utc/granola.utc.json similarity index 100% rename from src/mod/utc/granola.utc.json rename to src/module/utc/granola.utc.json diff --git a/src/mod/utc/halforcinvade.utc.json b/src/module/utc/halforcinvade.utc.json similarity index 100% rename from src/mod/utc/halforcinvade.utc.json rename to src/module/utc/halforcinvade.utc.json diff --git a/src/mod/utc/hancientguardian.utc.json b/src/module/utc/hancientguardian.utc.json similarity index 100% rename from src/mod/utc/hancientguardian.utc.json rename to src/module/utc/hancientguardian.utc.json diff --git a/src/mod/utc/heavingwoman.utc.json b/src/module/utc/heavingwoman.utc.json similarity index 100% rename from src/mod/utc/heavingwoman.utc.json rename to src/module/utc/heavingwoman.utc.json diff --git a/src/mod/utc/heavingwoman001.utc.json b/src/module/utc/heavingwoman001.utc.json similarity index 100% rename from src/mod/utc/heavingwoman001.utc.json rename to src/module/utc/heavingwoman001.utc.json diff --git a/src/mod/utc/hillsideantcleri.utc.json b/src/module/utc/hillsideantcleri.utc.json similarity index 100% rename from src/mod/utc/hillsideantcleri.utc.json rename to src/module/utc/hillsideantcleri.utc.json diff --git a/src/mod/utc/hillsideantdigge.utc.json b/src/module/utc/hillsideantdigge.utc.json similarity index 100% rename from src/mod/utc/hillsideantdigge.utc.json rename to src/module/utc/hillsideantdigge.utc.json diff --git a/src/mod/utc/hillsideantwa001.utc.json b/src/module/utc/hillsideantwa001.utc.json similarity index 100% rename from src/mod/utc/hillsideantwa001.utc.json rename to src/module/utc/hillsideantwa001.utc.json diff --git a/src/mod/utc/hillsideantwarch.utc.json b/src/module/utc/hillsideantwarch.utc.json similarity index 100% rename from src/mod/utc/hillsideantwarch.utc.json rename to src/module/utc/hillsideantwarch.utc.json diff --git a/src/mod/utc/hillsideantwarri.utc.json b/src/module/utc/hillsideantwarri.utc.json similarity index 100% rename from src/mod/utc/hillsideantwarri.utc.json rename to src/module/utc/hillsideantwarri.utc.json diff --git a/src/mod/utc/hillsidebadger.utc.json b/src/module/utc/hillsidebadger.utc.json similarity index 100% rename from src/mod/utc/hillsidebadger.utc.json rename to src/module/utc/hillsidebadger.utc.json diff --git a/src/mod/utc/hillsidekobolche.utc.json b/src/module/utc/hillsidekobolche.utc.json similarity index 100% rename from src/mod/utc/hillsidekobolche.utc.json rename to src/module/utc/hillsidekobolche.utc.json diff --git a/src/mod/utc/hillsidekobold2.utc.json b/src/module/utc/hillsidekobold2.utc.json similarity index 100% rename from src/mod/utc/hillsidekobold2.utc.json rename to src/module/utc/hillsidekobold2.utc.json diff --git a/src/mod/utc/hillsidekoboldwi.utc.json b/src/module/utc/hillsidekoboldwi.utc.json similarity index 100% rename from src/mod/utc/hillsidekoboldwi.utc.json rename to src/module/utc/hillsidekoboldwi.utc.json diff --git a/src/mod/utc/hillsidesting001.utc.json b/src/module/utc/hillsidesting001.utc.json similarity index 100% rename from src/mod/utc/hillsidesting001.utc.json rename to src/module/utc/hillsidesting001.utc.json diff --git a/src/mod/utc/hillsidesting002.utc.json b/src/module/utc/hillsidesting002.utc.json similarity index 100% rename from src/mod/utc/hillsidesting002.utc.json rename to src/module/utc/hillsidesting002.utc.json diff --git a/src/mod/utc/hillsidesting003.utc.json b/src/module/utc/hillsidesting003.utc.json similarity index 100% rename from src/mod/utc/hillsidesting003.utc.json rename to src/module/utc/hillsidesting003.utc.json diff --git a/src/mod/utc/hillsidestingcha.utc.json b/src/module/utc/hillsidestingcha.utc.json similarity index 100% rename from src/mod/utc/hillsidestingcha.utc.json rename to src/module/utc/hillsidestingcha.utc.json diff --git a/src/mod/utc/hillsidestinger.utc.json b/src/module/utc/hillsidestinger.utc.json similarity index 100% rename from src/mod/utc/hillsidestinger.utc.json rename to src/module/utc/hillsidestinger.utc.json diff --git a/src/mod/utc/hillsidestingerw.utc.json b/src/module/utc/hillsidestingerw.utc.json similarity index 100% rename from src/mod/utc/hillsidestingerw.utc.json rename to src/module/utc/hillsidestingerw.utc.json diff --git a/src/mod/utc/hillsidestingmag.utc.json b/src/module/utc/hillsidestingmag.utc.json similarity index 100% rename from src/mod/utc/hillsidestingmag.utc.json rename to src/module/utc/hillsidestingmag.utc.json diff --git a/src/mod/utc/hillsidestorm.utc.json b/src/module/utc/hillsidestorm.utc.json similarity index 100% rename from src/mod/utc/hillsidestorm.utc.json rename to src/module/utc/hillsidestorm.utc.json diff --git a/src/mod/utc/hillsidetroll.utc.json b/src/module/utc/hillsidetroll.utc.json similarity index 100% rename from src/mod/utc/hillsidetroll.utc.json rename to src/module/utc/hillsidetroll.utc.json diff --git a/src/mod/utc/holo.utc.json b/src/module/utc/holo.utc.json similarity index 100% rename from src/mod/utc/holo.utc.json rename to src/module/utc/holo.utc.json diff --git a/src/mod/utc/hologaurd.utc.json b/src/module/utc/hologaurd.utc.json similarity index 100% rename from src/mod/utc/hologaurd.utc.json rename to src/module/utc/hologaurd.utc.json diff --git a/src/mod/utc/iceleopard.utc.json b/src/module/utc/iceleopard.utc.json similarity index 100% rename from src/mod/utc/iceleopard.utc.json rename to src/module/utc/iceleopard.utc.json diff --git a/src/mod/utc/inferno.utc.json b/src/module/utc/inferno.utc.json similarity index 100% rename from src/mod/utc/inferno.utc.json rename to src/module/utc/inferno.utc.json diff --git a/src/mod/utc/inferno001.utc.json b/src/module/utc/inferno001.utc.json similarity index 100% rename from src/mod/utc/inferno001.utc.json rename to src/module/utc/inferno001.utc.json diff --git a/src/mod/utc/inferno002.utc.json b/src/module/utc/inferno002.utc.json similarity index 100% rename from src/mod/utc/inferno002.utc.json rename to src/module/utc/inferno002.utc.json diff --git a/src/mod/utc/inferno003.utc.json b/src/module/utc/inferno003.utc.json similarity index 100% rename from src/mod/utc/inferno003.utc.json rename to src/module/utc/inferno003.utc.json diff --git a/src/mod/utc/insight2.utc.json b/src/module/utc/insight2.utc.json similarity index 100% rename from src/mod/utc/insight2.utc.json rename to src/module/utc/insight2.utc.json diff --git a/src/mod/utc/insightmonk.utc.json b/src/module/utc/insightmonk.utc.json similarity index 100% rename from src/mod/utc/insightmonk.utc.json rename to src/module/utc/insightmonk.utc.json diff --git a/src/mod/utc/ironclaw.utc.json b/src/module/utc/ironclaw.utc.json similarity index 100% rename from src/mod/utc/ironclaw.utc.json rename to src/module/utc/ironclaw.utc.json diff --git a/src/mod/utc/ironclaw001.utc.json b/src/module/utc/ironclaw001.utc.json similarity index 100% rename from src/mod/utc/ironclaw001.utc.json rename to src/module/utc/ironclaw001.utc.json diff --git a/src/mod/utc/ironclaw002.utc.json b/src/module/utc/ironclaw002.utc.json similarity index 100% rename from src/mod/utc/ironclaw002.utc.json rename to src/module/utc/ironclaw002.utc.json diff --git a/src/mod/utc/ironclaw003.utc.json b/src/module/utc/ironclaw003.utc.json similarity index 100% rename from src/mod/utc/ironclaw003.utc.json rename to src/module/utc/ironclaw003.utc.json diff --git a/src/mod/utc/ironclawdragon.utc.json b/src/module/utc/ironclawdragon.utc.json similarity index 100% rename from src/mod/utc/ironclawdragon.utc.json rename to src/module/utc/ironclawdragon.utc.json diff --git a/src/mod/utc/ironclawgaurd.utc.json b/src/module/utc/ironclawgaurd.utc.json similarity index 100% rename from src/mod/utc/ironclawgaurd.utc.json rename to src/module/utc/ironclawgaurd.utc.json diff --git a/src/mod/utc/ironclawgaurd001.utc.json b/src/module/utc/ironclawgaurd001.utc.json similarity index 100% rename from src/mod/utc/ironclawgaurd001.utc.json rename to src/module/utc/ironclawgaurd001.utc.json diff --git a/src/mod/utc/ironclawgaurd002.utc.json b/src/module/utc/ironclawgaurd002.utc.json similarity index 100% rename from src/mod/utc/ironclawgaurd002.utc.json rename to src/module/utc/ironclawgaurd002.utc.json diff --git a/src/mod/utc/ironclawgaurd003.utc.json b/src/module/utc/ironclawgaurd003.utc.json similarity index 100% rename from src/mod/utc/ironclawgaurd003.utc.json rename to src/module/utc/ironclawgaurd003.utc.json diff --git a/src/mod/utc/ironclawmage.utc.json b/src/module/utc/ironclawmage.utc.json similarity index 100% rename from src/mod/utc/ironclawmage.utc.json rename to src/module/utc/ironclawmage.utc.json diff --git a/src/mod/utc/ironclawprote002.utc.json b/src/module/utc/ironclawprote002.utc.json similarity index 100% rename from src/mod/utc/ironclawprote002.utc.json rename to src/module/utc/ironclawprote002.utc.json diff --git a/src/mod/utc/ironclawprotecto.utc.json b/src/module/utc/ironclawprotecto.utc.json similarity index 100% rename from src/mod/utc/ironclawprotecto.utc.json rename to src/module/utc/ironclawprotecto.utc.json diff --git a/src/mod/utc/ironenergeycreat.utc.json b/src/module/utc/ironenergeycreat.utc.json similarity index 100% rename from src/mod/utc/ironenergeycreat.utc.json rename to src/module/utc/ironenergeycreat.utc.json diff --git a/src/mod/utc/irongoblinleader.utc.json b/src/module/utc/irongoblinleader.utc.json similarity index 100% rename from src/mod/utc/irongoblinleader.utc.json rename to src/module/utc/irongoblinleader.utc.json diff --git a/src/mod/utc/ironkeybalor.utc.json b/src/module/utc/ironkeybalor.utc.json similarity index 100% rename from src/mod/utc/ironkeybalor.utc.json rename to src/module/utc/ironkeybalor.utc.json diff --git a/src/mod/utc/ironkeybalor001.utc.json b/src/module/utc/ironkeybalor001.utc.json similarity index 100% rename from src/mod/utc/ironkeybalor001.utc.json rename to src/module/utc/ironkeybalor001.utc.json diff --git a/src/mod/utc/ironminotaur.utc.json b/src/module/utc/ironminotaur.utc.json similarity index 100% rename from src/mod/utc/ironminotaur.utc.json rename to src/module/utc/ironminotaur.utc.json diff --git a/src/mod/utc/jagangthemercile.utc.json b/src/module/utc/jagangthemercile.utc.json similarity index 100% rename from src/mod/utc/jagangthemercile.utc.json rename to src/module/utc/jagangthemercile.utc.json diff --git a/src/mod/utc/jez.utc.json b/src/module/utc/jez.utc.json similarity index 100% rename from src/mod/utc/jez.utc.json rename to src/module/utc/jez.utc.json diff --git a/src/mod/utc/kaleta.utc.json b/src/module/utc/kaleta.utc.json similarity index 100% rename from src/mod/utc/kaleta.utc.json rename to src/module/utc/kaleta.utc.json diff --git a/src/mod/utc/kluam.utc.json b/src/module/utc/kluam.utc.json similarity index 100% rename from src/mod/utc/kluam.utc.json rename to src/module/utc/kluam.utc.json diff --git a/src/mod/utc/kluam001.utc.json b/src/module/utc/kluam001.utc.json similarity index 100% rename from src/mod/utc/kluam001.utc.json rename to src/module/utc/kluam001.utc.json diff --git a/src/mod/utc/ladyofnight.utc.json b/src/module/utc/ladyofnight.utc.json similarity index 100% rename from src/mod/utc/ladyofnight.utc.json rename to src/module/utc/ladyofnight.utc.json diff --git a/src/mod/utc/legionarcher.utc.json b/src/module/utc/legionarcher.utc.json similarity index 100% rename from src/mod/utc/legionarcher.utc.json rename to src/module/utc/legionarcher.utc.json diff --git a/src/mod/utc/legionassassin.utc.json b/src/module/utc/legionassassin.utc.json similarity index 100% rename from src/mod/utc/legionassassin.utc.json rename to src/module/utc/legionassassin.utc.json diff --git a/src/mod/utc/legionghost.utc.json b/src/module/utc/legionghost.utc.json similarity index 100% rename from src/mod/utc/legionghost.utc.json rename to src/module/utc/legionghost.utc.json diff --git a/src/mod/utc/legionking1.utc.json b/src/module/utc/legionking1.utc.json similarity index 100% rename from src/mod/utc/legionking1.utc.json rename to src/module/utc/legionking1.utc.json diff --git a/src/mod/utc/legionking2.utc.json b/src/module/utc/legionking2.utc.json similarity index 100% rename from src/mod/utc/legionking2.utc.json rename to src/module/utc/legionking2.utc.json diff --git a/src/mod/utc/legionking3.utc.json b/src/module/utc/legionking3.utc.json similarity index 100% rename from src/mod/utc/legionking3.utc.json rename to src/module/utc/legionking3.utc.json diff --git a/src/mod/utc/legionkinggeorge.utc.json b/src/module/utc/legionkinggeorge.utc.json similarity index 100% rename from src/mod/utc/legionkinggeorge.utc.json rename to src/module/utc/legionkinggeorge.utc.json diff --git a/src/mod/utc/legionshadow.utc.json b/src/module/utc/legionshadow.utc.json similarity index 100% rename from src/mod/utc/legionshadow.utc.json rename to src/module/utc/legionshadow.utc.json diff --git a/src/mod/utc/legionwarrior.utc.json b/src/module/utc/legionwarrior.utc.json similarity index 100% rename from src/mod/utc/legionwarrior.utc.json rename to src/module/utc/legionwarrior.utc.json diff --git a/src/mod/utc/lightingdrago001.utc.json b/src/module/utc/lightingdrago001.utc.json similarity index 100% rename from src/mod/utc/lightingdrago001.utc.json rename to src/module/utc/lightingdrago001.utc.json diff --git a/src/mod/utc/lightingdragon.utc.json b/src/module/utc/lightingdragon.utc.json similarity index 100% rename from src/mod/utc/lightingdragon.utc.json rename to src/module/utc/lightingdragon.utc.json diff --git a/src/mod/utc/littlefighter.utc.json b/src/module/utc/littlefighter.utc.json similarity index 100% rename from src/mod/utc/littlefighter.utc.json rename to src/module/utc/littlefighter.utc.json diff --git a/src/mod/utc/lostspirit.utc.json b/src/module/utc/lostspirit.utc.json similarity index 100% rename from src/mod/utc/lostspirit.utc.json rename to src/module/utc/lostspirit.utc.json diff --git a/src/mod/utc/lucephcpt.utc.json b/src/module/utc/lucephcpt.utc.json similarity index 100% rename from src/mod/utc/lucephcpt.utc.json rename to src/module/utc/lucephcpt.utc.json diff --git a/src/mod/utc/magmamephit.utc.json b/src/module/utc/magmamephit.utc.json similarity index 100% rename from src/mod/utc/magmamephit.utc.json rename to src/module/utc/magmamephit.utc.json diff --git a/src/mod/utc/mastercain001.utc.json b/src/module/utc/mastercain001.utc.json similarity index 100% rename from src/mod/utc/mastercain001.utc.json rename to src/module/utc/mastercain001.utc.json diff --git a/src/mod/utc/maxinfuser.utc.json b/src/module/utc/maxinfuser.utc.json similarity index 100% rename from src/mod/utc/maxinfuser.utc.json rename to src/module/utc/maxinfuser.utc.json diff --git a/src/mod/utc/mcnasty.utc.json b/src/module/utc/mcnasty.utc.json similarity index 100% rename from src/mod/utc/mcnasty.utc.json rename to src/module/utc/mcnasty.utc.json diff --git a/src/mod/utc/mercenary.utc.json b/src/module/utc/mercenary.utc.json similarity index 100% rename from src/mod/utc/mercenary.utc.json rename to src/module/utc/mercenary.utc.json diff --git a/src/mod/utc/metalmonk.utc.json b/src/module/utc/metalmonk.utc.json similarity index 100% rename from src/mod/utc/metalmonk.utc.json rename to src/module/utc/metalmonk.utc.json diff --git a/src/mod/utc/metalmonk001.utc.json b/src/module/utc/metalmonk001.utc.json similarity index 100% rename from src/mod/utc/metalmonk001.utc.json rename to src/module/utc/metalmonk001.utc.json diff --git a/src/mod/utc/mindflaertab.utc.json b/src/module/utc/mindflaertab.utc.json similarity index 100% rename from src/mod/utc/mindflaertab.utc.json rename to src/module/utc/mindflaertab.utc.json diff --git a/src/mod/utc/mingtao001.utc.json b/src/module/utc/mingtao001.utc.json similarity index 100% rename from src/mod/utc/mingtao001.utc.json rename to src/module/utc/mingtao001.utc.json diff --git a/src/mod/utc/minimonk.utc.json b/src/module/utc/minimonk.utc.json similarity index 100% rename from src/mod/utc/minimonk.utc.json rename to src/module/utc/minimonk.utc.json diff --git a/src/mod/utc/minotaurshaman.utc.json b/src/module/utc/minotaurshaman.utc.json similarity index 100% rename from src/mod/utc/minotaurshaman.utc.json rename to src/module/utc/minotaurshaman.utc.json diff --git a/src/mod/utc/monkosaurus.utc.json b/src/module/utc/monkosaurus.utc.json similarity index 100% rename from src/mod/utc/monkosaurus.utc.json rename to src/module/utc/monkosaurus.utc.json diff --git a/src/mod/utc/monxie.utc.json b/src/module/utc/monxie.utc.json similarity index 100% rename from src/mod/utc/monxie.utc.json rename to src/module/utc/monxie.utc.json diff --git a/src/mod/utc/mosquito001.utc.json b/src/module/utc/mosquito001.utc.json similarity index 100% rename from src/mod/utc/mosquito001.utc.json rename to src/module/utc/mosquito001.utc.json diff --git a/src/mod/utc/mrissac.utc.json b/src/module/utc/mrissac.utc.json similarity index 100% rename from src/mod/utc/mrissac.utc.json rename to src/module/utc/mrissac.utc.json diff --git a/src/mod/utc/naturebeast.utc.json b/src/module/utc/naturebeast.utc.json similarity index 100% rename from src/mod/utc/naturebeast.utc.json rename to src/module/utc/naturebeast.utc.json diff --git a/src/mod/utc/nico.utc.json b/src/module/utc/nico.utc.json similarity index 100% rename from src/mod/utc/nico.utc.json rename to src/module/utc/nico.utc.json diff --git a/src/mod/utc/nordicdwarf.utc.json b/src/module/utc/nordicdwarf.utc.json similarity index 100% rename from src/mod/utc/nordicdwarf.utc.json rename to src/module/utc/nordicdwarf.utc.json diff --git a/src/mod/utc/nudeasyrian.utc.json b/src/module/utc/nudeasyrian.utc.json similarity index 100% rename from src/mod/utc/nudeasyrian.utc.json rename to src/module/utc/nudeasyrian.utc.json diff --git a/src/mod/utc/ogre.utc.json b/src/module/utc/ogre.utc.json similarity index 100% rename from src/mod/utc/ogre.utc.json rename to src/module/utc/ogre.utc.json diff --git a/src/mod/utc/ogrechief.utc.json b/src/module/utc/ogrechief.utc.json similarity index 100% rename from src/mod/utc/ogrechief.utc.json rename to src/module/utc/ogrechief.utc.json diff --git a/src/mod/utc/ogremage002.utc.json b/src/module/utc/ogremage002.utc.json similarity index 100% rename from src/mod/utc/ogremage002.utc.json rename to src/module/utc/ogremage002.utc.json diff --git a/src/mod/utc/oozeimp.utc.json b/src/module/utc/oozeimp.utc.json similarity index 100% rename from src/mod/utc/oozeimp.utc.json rename to src/module/utc/oozeimp.utc.json diff --git a/src/mod/utc/orchighshaman.utc.json b/src/module/utc/orchighshaman.utc.json similarity index 100% rename from src/mod/utc/orchighshaman.utc.json rename to src/module/utc/orchighshaman.utc.json diff --git a/src/mod/utc/orcleader.utc.json b/src/module/utc/orcleader.utc.json similarity index 100% rename from src/mod/utc/orcleader.utc.json rename to src/module/utc/orcleader.utc.json diff --git a/src/mod/utc/orcleader001.utc.json b/src/module/utc/orcleader001.utc.json similarity index 100% rename from src/mod/utc/orcleader001.utc.json rename to src/module/utc/orcleader001.utc.json diff --git a/src/mod/utc/orcleader002.utc.json b/src/module/utc/orcleader002.utc.json similarity index 100% rename from src/mod/utc/orcleader002.utc.json rename to src/module/utc/orcleader002.utc.json diff --git a/src/mod/utc/orcleader003.utc.json b/src/module/utc/orcleader003.utc.json similarity index 100% rename from src/mod/utc/orcleader003.utc.json rename to src/module/utc/orcleader003.utc.json diff --git a/src/mod/utc/orcleader004.utc.json b/src/module/utc/orcleader004.utc.json similarity index 100% rename from src/mod/utc/orcleader004.utc.json rename to src/module/utc/orcleader004.utc.json diff --git a/src/mod/utc/orcmaster.utc.json b/src/module/utc/orcmaster.utc.json similarity index 100% rename from src/mod/utc/orcmaster.utc.json rename to src/module/utc/orcmaster.utc.json diff --git a/src/mod/utc/orcraider.utc.json b/src/module/utc/orcraider.utc.json similarity index 100% rename from src/mod/utc/orcraider.utc.json rename to src/module/utc/orcraider.utc.json diff --git a/src/mod/utc/orcraider001.utc.json b/src/module/utc/orcraider001.utc.json similarity index 100% rename from src/mod/utc/orcraider001.utc.json rename to src/module/utc/orcraider001.utc.json diff --git a/src/mod/utc/orcraider002.utc.json b/src/module/utc/orcraider002.utc.json similarity index 100% rename from src/mod/utc/orcraider002.utc.json rename to src/module/utc/orcraider002.utc.json diff --git a/src/mod/utc/orcwizard.utc.json b/src/module/utc/orcwizard.utc.json similarity index 100% rename from src/mod/utc/orcwizard.utc.json rename to src/module/utc/orcwizard.utc.json diff --git a/src/mod/utc/ozdragon001.utc.json b/src/module/utc/ozdragon001.utc.json similarity index 100% rename from src/mod/utc/ozdragon001.utc.json rename to src/module/utc/ozdragon001.utc.json diff --git a/src/mod/utc/ozghostlygaurd.utc.json b/src/module/utc/ozghostlygaurd.utc.json similarity index 100% rename from src/mod/utc/ozghostlygaurd.utc.json rename to src/module/utc/ozghostlygaurd.utc.json diff --git a/src/mod/utc/ozintellect.utc.json b/src/module/utc/ozintellect.utc.json similarity index 100% rename from src/mod/utc/ozintellect.utc.json rename to src/module/utc/ozintellect.utc.json diff --git a/src/mod/utc/ozjailor.utc.json b/src/module/utc/ozjailor.utc.json similarity index 100% rename from src/mod/utc/ozjailor.utc.json rename to src/module/utc/ozjailor.utc.json diff --git a/src/mod/utc/ozking.utc.json b/src/module/utc/ozking.utc.json similarity index 100% rename from src/mod/utc/ozking.utc.json rename to src/module/utc/ozking.utc.json diff --git a/src/mod/utc/ozknight.utc.json b/src/module/utc/ozknight.utc.json similarity index 100% rename from src/mod/utc/ozknight.utc.json rename to src/module/utc/ozknight.utc.json diff --git a/src/mod/utc/ozlibrarian.utc.json b/src/module/utc/ozlibrarian.utc.json similarity index 100% rename from src/mod/utc/ozlibrarian.utc.json rename to src/module/utc/ozlibrarian.utc.json diff --git a/src/mod/utc/ozlibrarian001.utc.json b/src/module/utc/ozlibrarian001.utc.json similarity index 100% rename from src/mod/utc/ozlibrarian001.utc.json rename to src/module/utc/ozlibrarian001.utc.json diff --git a/src/mod/utc/ozmaniac.utc.json b/src/module/utc/ozmaniac.utc.json similarity index 100% rename from src/mod/utc/ozmaniac.utc.json rename to src/module/utc/ozmaniac.utc.json diff --git a/src/mod/utc/ozqueen.utc.json b/src/module/utc/ozqueen.utc.json similarity index 100% rename from src/mod/utc/ozqueen.utc.json rename to src/module/utc/ozqueen.utc.json diff --git a/src/mod/utc/parchedbodak.utc.json b/src/module/utc/parchedbodak.utc.json similarity index 100% rename from src/mod/utc/parchedbodak.utc.json rename to src/module/utc/parchedbodak.utc.json diff --git a/src/mod/utc/pawntaker.utc.json b/src/module/utc/pawntaker.utc.json similarity index 100% rename from src/mod/utc/pawntaker.utc.json rename to src/module/utc/pawntaker.utc.json diff --git a/src/mod/utc/penguin002.utc.json b/src/module/utc/penguin002.utc.json similarity index 100% rename from src/mod/utc/penguin002.utc.json rename to src/module/utc/penguin002.utc.json diff --git a/src/mod/utc/polarbear.utc.json b/src/module/utc/polarbear.utc.json similarity index 100% rename from src/mod/utc/polarbear.utc.json rename to src/module/utc/polarbear.utc.json diff --git a/src/mod/utc/polarbear001.utc.json b/src/module/utc/polarbear001.utc.json similarity index 100% rename from src/mod/utc/polarbear001.utc.json rename to src/module/utc/polarbear001.utc.json diff --git a/src/mod/utc/prehistoricbird.utc.json b/src/module/utc/prehistoricbird.utc.json similarity index 100% rename from src/mod/utc/prehistoricbird.utc.json rename to src/module/utc/prehistoricbird.utc.json diff --git a/src/mod/utc/purpleheadedwarr.utc.json b/src/module/utc/purpleheadedwarr.utc.json similarity index 100% rename from src/mod/utc/purpleheadedwarr.utc.json rename to src/module/utc/purpleheadedwarr.utc.json diff --git a/src/mod/utc/rat_cloak.utc.json b/src/module/utc/rat_cloak.utc.json similarity index 100% rename from src/mod/utc/rat_cloak.utc.json rename to src/module/utc/rat_cloak.utc.json diff --git a/src/mod/utc/rat_cloak001.utc.json b/src/module/utc/rat_cloak001.utc.json similarity index 100% rename from src/mod/utc/rat_cloak001.utc.json rename to src/module/utc/rat_cloak001.utc.json diff --git a/src/mod/utc/raven001.utc.json b/src/module/utc/raven001.utc.json similarity index 100% rename from src/mod/utc/raven001.utc.json rename to src/module/utc/raven001.utc.json diff --git a/src/mod/utc/reaperofsouls.utc.json b/src/module/utc/reaperofsouls.utc.json similarity index 100% rename from src/mod/utc/reaperofsouls.utc.json rename to src/module/utc/reaperofsouls.utc.json diff --git a/src/mod/utc/reb004.utc.json b/src/module/utc/reb004.utc.json similarity index 100% rename from src/mod/utc/reb004.utc.json rename to src/module/utc/reb004.utc.json diff --git a/src/mod/utc/reb005.utc.json b/src/module/utc/reb005.utc.json similarity index 100% rename from src/mod/utc/reb005.utc.json rename to src/module/utc/reb005.utc.json diff --git a/src/mod/utc/repentguardian.utc.json b/src/module/utc/repentguardian.utc.json similarity index 100% rename from src/mod/utc/repentguardian.utc.json rename to src/module/utc/repentguardian.utc.json diff --git a/src/mod/utc/restlesssoul.utc.json b/src/module/utc/restlesssoul.utc.json similarity index 100% rename from src/mod/utc/restlesssoul.utc.json rename to src/module/utc/restlesssoul.utc.json diff --git a/src/mod/utc/retiredfighter.utc.json b/src/module/utc/retiredfighter.utc.json similarity index 100% rename from src/mod/utc/retiredfighter.utc.json rename to src/module/utc/retiredfighter.utc.json diff --git a/src/mod/utc/riftgaurdian001.utc.json b/src/module/utc/riftgaurdian001.utc.json similarity index 100% rename from src/mod/utc/riftgaurdian001.utc.json rename to src/module/utc/riftgaurdian001.utc.json diff --git a/src/mod/utc/risenwarrior.utc.json b/src/module/utc/risenwarrior.utc.json similarity index 100% rename from src/mod/utc/risenwarrior.utc.json rename to src/module/utc/risenwarrior.utc.json diff --git a/src/mod/utc/ronus001.utc.json b/src/module/utc/ronus001.utc.json similarity index 100% rename from src/mod/utc/ronus001.utc.json rename to src/module/utc/ronus001.utc.json diff --git a/src/mod/utc/santaelf.utc.json b/src/module/utc/santaelf.utc.json similarity index 100% rename from src/mod/utc/santaelf.utc.json rename to src/module/utc/santaelf.utc.json diff --git a/src/mod/utc/seacaptain001.utc.json b/src/module/utc/seacaptain001.utc.json similarity index 100% rename from src/mod/utc/seacaptain001.utc.json rename to src/module/utc/seacaptain001.utc.json diff --git a/src/mod/utc/seniormetmnk.utc.json b/src/module/utc/seniormetmnk.utc.json similarity index 100% rename from src/mod/utc/seniormetmnk.utc.json rename to src/module/utc/seniormetmnk.utc.json diff --git a/src/mod/utc/sentrossi.utc.json b/src/module/utc/sentrossi.utc.json similarity index 100% rename from src/mod/utc/sentrossi.utc.json rename to src/module/utc/sentrossi.utc.json diff --git a/src/mod/utc/serf.utc.json b/src/module/utc/serf.utc.json similarity index 100% rename from src/mod/utc/serf.utc.json rename to src/module/utc/serf.utc.json diff --git a/src/mod/utc/seth.utc.json b/src/module/utc/seth.utc.json similarity index 100% rename from src/mod/utc/seth.utc.json rename to src/module/utc/seth.utc.json diff --git a/src/mod/utc/sewerrat.utc.json b/src/module/utc/sewerrat.utc.json similarity index 100% rename from src/mod/utc/sewerrat.utc.json rename to src/module/utc/sewerrat.utc.json diff --git a/src/mod/utc/shadowlegionrang.utc.json b/src/module/utc/shadowlegionrang.utc.json similarity index 100% rename from src/mod/utc/shadowlegionrang.utc.json rename to src/module/utc/shadowlegionrang.utc.json diff --git a/src/mod/utc/shadowwalker.utc.json b/src/module/utc/shadowwalker.utc.json similarity index 100% rename from src/mod/utc/shadowwalker.utc.json rename to src/module/utc/shadowwalker.utc.json diff --git a/src/mod/utc/shadowwalker001.utc.json b/src/module/utc/shadowwalker001.utc.json similarity index 100% rename from src/mod/utc/shadowwalker001.utc.json rename to src/module/utc/shadowwalker001.utc.json diff --git a/src/mod/utc/shogun.utc.json b/src/module/utc/shogun.utc.json similarity index 100% rename from src/mod/utc/shogun.utc.json rename to src/module/utc/shogun.utc.json diff --git a/src/mod/utc/shogun001.utc.json b/src/module/utc/shogun001.utc.json similarity index 100% rename from src/mod/utc/shogun001.utc.json rename to src/module/utc/shogun001.utc.json diff --git a/src/mod/utc/shogun_kiddingme.utc.json b/src/module/utc/shogun_kiddingme.utc.json similarity index 100% rename from src/mod/utc/shogun_kiddingme.utc.json rename to src/module/utc/shogun_kiddingme.utc.json diff --git a/src/mod/utc/shogunmaster.utc.json b/src/module/utc/shogunmaster.utc.json similarity index 100% rename from src/mod/utc/shogunmaster.utc.json rename to src/module/utc/shogunmaster.utc.json diff --git a/src/mod/utc/shogunmuscle.utc.json b/src/module/utc/shogunmuscle.utc.json similarity index 100% rename from src/mod/utc/shogunmuscle.utc.json rename to src/module/utc/shogunmuscle.utc.json diff --git a/src/mod/utc/shogunpre2.utc.json b/src/module/utc/shogunpre2.utc.json similarity index 100% rename from src/mod/utc/shogunpre2.utc.json rename to src/module/utc/shogunpre2.utc.json diff --git a/src/mod/utc/shogunprisone004.utc.json b/src/module/utc/shogunprisone004.utc.json similarity index 100% rename from src/mod/utc/shogunprisone004.utc.json rename to src/module/utc/shogunprisone004.utc.json diff --git a/src/mod/utc/shogunprisone2.utc.json b/src/module/utc/shogunprisone2.utc.json similarity index 100% rename from src/mod/utc/shogunprisone2.utc.json rename to src/module/utc/shogunprisone2.utc.json diff --git a/src/mod/utc/shogunprisone3.utc.json b/src/module/utc/shogunprisone3.utc.json similarity index 100% rename from src/mod/utc/shogunprisone3.utc.json rename to src/module/utc/shogunprisone3.utc.json diff --git a/src/mod/utc/shogunprisoner.utc.json b/src/module/utc/shogunprisoner.utc.json similarity index 100% rename from src/mod/utc/shogunprisoner.utc.json rename to src/module/utc/shogunprisoner.utc.json diff --git a/src/mod/utc/shoguntiger.utc.json b/src/module/utc/shoguntiger.utc.json similarity index 100% rename from src/mod/utc/shoguntiger.utc.json rename to src/module/utc/shoguntiger.utc.json diff --git a/src/mod/utc/sisteroftheda001.utc.json b/src/module/utc/sisteroftheda001.utc.json similarity index 100% rename from src/mod/utc/sisteroftheda001.utc.json rename to src/module/utc/sisteroftheda001.utc.json diff --git a/src/mod/utc/sisteroftheda002.utc.json b/src/module/utc/sisteroftheda002.utc.json similarity index 100% rename from src/mod/utc/sisteroftheda002.utc.json rename to src/module/utc/sisteroftheda002.utc.json diff --git a/src/mod/utc/sisterofthedark.utc.json b/src/module/utc/sisterofthedark.utc.json similarity index 100% rename from src/mod/utc/sisterofthedark.utc.json rename to src/module/utc/sisterofthedark.utc.json diff --git a/src/mod/utc/sludgeking.utc.json b/src/module/utc/sludgeking.utc.json similarity index 100% rename from src/mod/utc/sludgeking.utc.json rename to src/module/utc/sludgeking.utc.json diff --git a/src/mod/utc/stinkbeetle.utc.json b/src/module/utc/stinkbeetle.utc.json similarity index 100% rename from src/mod/utc/stinkbeetle.utc.json rename to src/module/utc/stinkbeetle.utc.json diff --git a/src/mod/utc/strappingyoungla.utc.json b/src/module/utc/strappingyoungla.utc.json similarity index 100% rename from src/mod/utc/strappingyoungla.utc.json rename to src/module/utc/strappingyoungla.utc.json diff --git a/src/mod/utc/subzeroarcher.utc.json b/src/module/utc/subzeroarcher.utc.json similarity index 100% rename from src/mod/utc/subzeroarcher.utc.json rename to src/module/utc/subzeroarcher.utc.json diff --git a/src/mod/utc/subzeroking.utc.json b/src/module/utc/subzeroking.utc.json similarity index 100% rename from src/mod/utc/subzeroking.utc.json rename to src/module/utc/subzeroking.utc.json diff --git a/src/mod/utc/subzeromage.utc.json b/src/module/utc/subzeromage.utc.json similarity index 100% rename from src/mod/utc/subzeromage.utc.json rename to src/module/utc/subzeromage.utc.json diff --git a/src/mod/utc/subzerowarrior.utc.json b/src/module/utc/subzerowarrior.utc.json similarity index 100% rename from src/mod/utc/subzerowarrior.utc.json rename to src/module/utc/subzerowarrior.utc.json diff --git a/src/mod/utc/superreddragon.utc.json b/src/module/utc/superreddragon.utc.json similarity index 100% rename from src/mod/utc/superreddragon.utc.json rename to src/module/utc/superreddragon.utc.json diff --git a/src/mod/utc/templeguard.utc.json b/src/module/utc/templeguard.utc.json similarity index 100% rename from src/mod/utc/templeguard.utc.json rename to src/module/utc/templeguard.utc.json diff --git a/src/mod/utc/terrifiedlibrari.utc.json b/src/module/utc/terrifiedlibrari.utc.json similarity index 100% rename from src/mod/utc/terrifiedlibrari.utc.json rename to src/module/utc/terrifiedlibrari.utc.json diff --git a/src/mod/utc/testdragonscript.utc.json b/src/module/utc/testdragonscript.utc.json similarity index 100% rename from src/mod/utc/testdragonscript.utc.json rename to src/module/utc/testdragonscript.utc.json diff --git a/src/mod/utc/thundercleric.utc.json b/src/module/utc/thundercleric.utc.json similarity index 100% rename from src/mod/utc/thundercleric.utc.json rename to src/module/utc/thundercleric.utc.json diff --git a/src/mod/utc/thunderlord.utc.json b/src/module/utc/thunderlord.utc.json similarity index 100% rename from src/mod/utc/thunderlord.utc.json rename to src/module/utc/thunderlord.utc.json diff --git a/src/mod/utc/thunderlord001.utc.json b/src/module/utc/thunderlord001.utc.json similarity index 100% rename from src/mod/utc/thunderlord001.utc.json rename to src/module/utc/thunderlord001.utc.json diff --git a/src/mod/utc/thundermounti001.utc.json b/src/module/utc/thundermounti001.utc.json similarity index 100% rename from src/mod/utc/thundermounti001.utc.json rename to src/module/utc/thundermounti001.utc.json diff --git a/src/mod/utc/thundermountiang.utc.json b/src/module/utc/thundermountiang.utc.json similarity index 100% rename from src/mod/utc/thundermountiang.utc.json rename to src/module/utc/thundermountiang.utc.json diff --git a/src/mod/utc/tmarcher.utc.json b/src/module/utc/tmarcher.utc.json similarity index 100% rename from src/mod/utc/tmarcher.utc.json rename to src/module/utc/tmarcher.utc.json diff --git a/src/mod/utc/tmjailor001.utc.json b/src/module/utc/tmjailor001.utc.json similarity index 100% rename from src/mod/utc/tmjailor001.utc.json rename to src/module/utc/tmjailor001.utc.json diff --git a/src/mod/utc/tmspearmen.utc.json b/src/module/utc/tmspearmen.utc.json similarity index 100% rename from src/mod/utc/tmspearmen.utc.json rename to src/module/utc/tmspearmen.utc.json diff --git a/src/mod/utc/toli.utc.json b/src/module/utc/toli.utc.json similarity index 100% rename from src/mod/utc/toli.utc.json rename to src/module/utc/toli.utc.json diff --git a/src/mod/utc/tormentedsoul.utc.json b/src/module/utc/tormentedsoul.utc.json similarity index 100% rename from src/mod/utc/tormentedsoul.utc.json rename to src/module/utc/tormentedsoul.utc.json diff --git a/src/mod/utc/trooper.utc.json b/src/module/utc/trooper.utc.json similarity index 100% rename from src/mod/utc/trooper.utc.json rename to src/module/utc/trooper.utc.json diff --git a/src/mod/utc/tundrabear.utc.json b/src/module/utc/tundrabear.utc.json similarity index 100% rename from src/mod/utc/tundrabear.utc.json rename to src/module/utc/tundrabear.utc.json diff --git a/src/mod/utc/umberhulk001.utc.json b/src/module/utc/umberhulk001.utc.json similarity index 100% rename from src/mod/utc/umberhulk001.utc.json rename to src/module/utc/umberhulk001.utc.json diff --git a/src/mod/utc/vampirehaunt.utc.json b/src/module/utc/vampirehaunt.utc.json similarity index 100% rename from src/mod/utc/vampirehaunt.utc.json rename to src/module/utc/vampirehaunt.utc.json diff --git a/src/mod/utc/vampirewarrior.utc.json b/src/module/utc/vampirewarrior.utc.json similarity index 100% rename from src/mod/utc/vampirewarrior.utc.json rename to src/module/utc/vampirewarrior.utc.json diff --git a/src/mod/utc/vampirewizard.utc.json b/src/module/utc/vampirewizard.utc.json similarity index 100% rename from src/mod/utc/vampirewizard.utc.json rename to src/module/utc/vampirewizard.utc.json diff --git a/src/mod/utc/vassi.utc.json b/src/module/utc/vassi.utc.json similarity index 100% rename from src/mod/utc/vassi.utc.json rename to src/module/utc/vassi.utc.json diff --git a/src/mod/utc/vera.utc.json b/src/module/utc/vera.utc.json similarity index 100% rename from src/mod/utc/vera.utc.json rename to src/module/utc/vera.utc.json diff --git a/src/mod/utc/verasapprentice.utc.json b/src/module/utc/verasapprentice.utc.json similarity index 100% rename from src/mod/utc/verasapprentice.utc.json rename to src/module/utc/verasapprentice.utc.json diff --git a/src/mod/utc/voidmonk.utc.json b/src/module/utc/voidmonk.utc.json similarity index 100% rename from src/mod/utc/voidmonk.utc.json rename to src/module/utc/voidmonk.utc.json diff --git a/src/mod/utc/voidmonk1.utc.json b/src/module/utc/voidmonk1.utc.json similarity index 100% rename from src/mod/utc/voidmonk1.utc.json rename to src/module/utc/voidmonk1.utc.json diff --git a/src/mod/utc/wanderingshadow.utc.json b/src/module/utc/wanderingshadow.utc.json similarity index 100% rename from src/mod/utc/wanderingshadow.utc.json rename to src/module/utc/wanderingshadow.utc.json diff --git a/src/mod/utc/wastelandhunter.utc.json b/src/module/utc/wastelandhunter.utc.json similarity index 100% rename from src/mod/utc/wastelandhunter.utc.json rename to src/module/utc/wastelandhunter.utc.json diff --git a/src/mod/utc/wastelandhuntres.utc.json b/src/module/utc/wastelandhuntres.utc.json similarity index 100% rename from src/mod/utc/wastelandhuntres.utc.json rename to src/module/utc/wastelandhuntres.utc.json diff --git a/src/mod/utc/whitedwarf001.utc.json b/src/module/utc/whitedwarf001.utc.json similarity index 100% rename from src/mod/utc/whitedwarf001.utc.json rename to src/module/utc/whitedwarf001.utc.json diff --git a/src/mod/utc/wildmage.utc.json b/src/module/utc/wildmage.utc.json similarity index 100% rename from src/mod/utc/wildmage.utc.json rename to src/module/utc/wildmage.utc.json diff --git a/src/mod/utc/wildmage001.utc.json b/src/module/utc/wildmage001.utc.json similarity index 100% rename from src/mod/utc/wildmage001.utc.json rename to src/module/utc/wildmage001.utc.json diff --git a/src/mod/utc/wildmage002.utc.json b/src/module/utc/wildmage002.utc.json similarity index 100% rename from src/mod/utc/wildmage002.utc.json rename to src/module/utc/wildmage002.utc.json diff --git a/src/mod/utc/wildwererat.utc.json b/src/module/utc/wildwererat.utc.json similarity index 100% rename from src/mod/utc/wildwererat.utc.json rename to src/module/utc/wildwererat.utc.json diff --git a/src/mod/utc/wildwererat001.utc.json b/src/module/utc/wildwererat001.utc.json similarity index 100% rename from src/mod/utc/wildwererat001.utc.json rename to src/module/utc/wildwererat001.utc.json diff --git a/src/mod/utc/wildwererat002.utc.json b/src/module/utc/wildwererat002.utc.json similarity index 100% rename from src/mod/utc/wildwererat002.utc.json rename to src/module/utc/wildwererat002.utc.json diff --git a/src/mod/utc/wizardsspirt.utc.json b/src/module/utc/wizardsspirt.utc.json similarity index 100% rename from src/mod/utc/wizardsspirt.utc.json rename to src/module/utc/wizardsspirt.utc.json diff --git a/src/mod/utc/wolf.utc.json b/src/module/utc/wolf.utc.json similarity index 100% rename from src/mod/utc/wolf.utc.json rename to src/module/utc/wolf.utc.json diff --git a/src/mod/utc/wwp_animatedarmo.utc.json b/src/module/utc/wwp_animatedarmo.utc.json similarity index 100% rename from src/mod/utc/wwp_animatedarmo.utc.json rename to src/module/utc/wwp_animatedarmo.utc.json diff --git a/src/mod/utc/wwp_bonewarrior.utc.json b/src/module/utc/wwp_bonewarrior.utc.json similarity index 100% rename from src/mod/utc/wwp_bonewarrior.utc.json rename to src/module/utc/wwp_bonewarrior.utc.json diff --git a/src/mod/utc/wwp_dreadstaff.utc.json b/src/module/utc/wwp_dreadstaff.utc.json similarity index 100% rename from src/mod/utc/wwp_dreadstaff.utc.json rename to src/module/utc/wwp_dreadstaff.utc.json diff --git a/src/mod/utc/wwp_floatingbow.utc.json b/src/module/utc/wwp_floatingbow.utc.json similarity index 100% rename from src/mod/utc/wwp_floatingbow.utc.json rename to src/module/utc/wwp_floatingbow.utc.json diff --git a/src/mod/utc/wwp_sanguineswor.utc.json b/src/module/utc/wwp_sanguineswor.utc.json similarity index 100% rename from src/mod/utc/wwp_sanguineswor.utc.json rename to src/module/utc/wwp_sanguineswor.utc.json diff --git a/src/mod/utc/wwp_shadowdragon.utc.json b/src/module/utc/wwp_shadowdragon.utc.json similarity index 100% rename from src/mod/utc/wwp_shadowdragon.utc.json rename to src/module/utc/wwp_shadowdragon.utc.json diff --git a/src/mod/utc/wwp_spellweaver.utc.json b/src/module/utc/wwp_spellweaver.utc.json similarity index 100% rename from src/mod/utc/wwp_spellweaver.utc.json rename to src/module/utc/wwp_spellweaver.utc.json diff --git a/src/mod/utc/wyrdragonblac001.utc.json b/src/module/utc/wyrdragonblac001.utc.json similarity index 100% rename from src/mod/utc/wyrdragonblac001.utc.json rename to src/module/utc/wyrdragonblac001.utc.json diff --git a/src/mod/utc/wyrdragonblack.utc.json b/src/module/utc/wyrdragonblack.utc.json similarity index 100% rename from src/mod/utc/wyrdragonblack.utc.json rename to src/module/utc/wyrdragonblack.utc.json diff --git a/src/mod/utc/wyrdragonblue.utc.json b/src/module/utc/wyrdragonblue.utc.json similarity index 100% rename from src/mod/utc/wyrdragonblue.utc.json rename to src/module/utc/wyrdragonblue.utc.json diff --git a/src/mod/utc/wyrmling_red001.utc.json b/src/module/utc/wyrmling_red001.utc.json similarity index 100% rename from src/mod/utc/wyrmling_red001.utc.json rename to src/module/utc/wyrmling_red001.utc.json diff --git a/src/mod/utd/basicdoor001.utd.json b/src/module/utd/basicdoor001.utd.json similarity index 100% rename from src/mod/utd/basicdoor001.utd.json rename to src/module/utd/basicdoor001.utd.json diff --git a/src/mod/utd/doorhard002.utd.json b/src/module/utd/doorhard002.utd.json similarity index 100% rename from src/mod/utd/doorhard002.utd.json rename to src/module/utd/doorhard002.utd.json diff --git a/src/mod/utd/inn2pcrooms.utd.json b/src/module/utd/inn2pcrooms.utd.json similarity index 100% rename from src/mod/utd/inn2pcrooms.utd.json rename to src/module/utd/inn2pcrooms.utd.json diff --git a/src/mod/utd/lockedstonerdoor.utd.json b/src/module/utd/lockedstonerdoor.utd.json similarity index 100% rename from src/mod/utd/lockedstonerdoor.utd.json rename to src/module/utd/lockedstonerdoor.utd.json diff --git a/src/mod/utd/normalmetaldoor.utd.json b/src/module/utd/normalmetaldoor.utd.json similarity index 100% rename from src/mod/utd/normalmetaldoor.utd.json rename to src/module/utd/normalmetaldoor.utd.json diff --git a/src/mod/utd/normalstonedo001.utd.json b/src/module/utd/normalstonedo001.utd.json similarity index 100% rename from src/mod/utd/normalstonedo001.utd.json rename to src/module/utd/normalstonedo001.utd.json diff --git a/src/mod/utd/normalstonedo002.utd.json b/src/module/utd/normalstonedo002.utd.json similarity index 100% rename from src/mod/utd/normalstonedo002.utd.json rename to src/module/utd/normalstonedo002.utd.json diff --git a/src/mod/utd/normalstonedo003.utd.json b/src/module/utd/normalstonedo003.utd.json similarity index 100% rename from src/mod/utd/normalstonedo003.utd.json rename to src/module/utd/normalstonedo003.utd.json diff --git a/src/mod/utd/normalstonedo004.utd.json b/src/module/utd/normalstonedo004.utd.json similarity index 100% rename from src/mod/utd/normalstonedo004.utd.json rename to src/module/utd/normalstonedo004.utd.json diff --git a/src/mod/utd/normalstonedoor.utd.json b/src/module/utd/normalstonedoor.utd.json similarity index 100% rename from src/mod/utd/normalstonedoor.utd.json rename to src/module/utd/normalstonedoor.utd.json diff --git a/src/mod/ute/ancientcopper.ute.json b/src/module/ute/ancientcopper.ute.json similarity index 100% rename from src/mod/ute/ancientcopper.ute.json rename to src/module/ute/ancientcopper.ute.json diff --git a/src/mod/ute/asyprismatic.ute.json b/src/module/ute/asyprismatic.ute.json similarity index 100% rename from src/mod/ute/asyprismatic.ute.json rename to src/module/ute/asyprismatic.ute.json diff --git a/src/mod/ute/asyred.ute.json b/src/module/ute/asyred.ute.json similarity index 100% rename from src/mod/ute/asyred.ute.json rename to src/module/ute/asyred.ute.json diff --git a/src/mod/ute/asyshadow.ute.json b/src/module/ute/asyshadow.ute.json similarity index 100% rename from src/mod/ute/asyshadow.ute.json rename to src/module/ute/asyshadow.ute.json diff --git a/src/mod/ute/atlantianfelmale.ute.json b/src/module/ute/atlantianfelmale.ute.json similarity index 100% rename from src/mod/ute/atlantianfelmale.ute.json rename to src/module/ute/atlantianfelmale.ute.json diff --git a/src/mod/ute/atlantianmale.ute.json b/src/module/ute/atlantianmale.ute.json similarity index 100% rename from src/mod/ute/atlantianmale.ute.json rename to src/module/ute/atlantianmale.ute.json diff --git a/src/mod/ute/atlantianministe.ute.json b/src/module/ute/atlantianministe.ute.json similarity index 100% rename from src/mod/ute/atlantianministe.ute.json rename to src/module/ute/atlantianministe.ute.json diff --git a/src/mod/ute/atlcleric.ute.json b/src/module/ute/atlcleric.ute.json similarity index 100% rename from src/mod/ute/atlcleric.ute.json rename to src/module/ute/atlcleric.ute.json diff --git a/src/mod/ute/atldruid.ute.json b/src/module/ute/atldruid.ute.json similarity index 100% rename from src/mod/ute/atldruid.ute.json rename to src/module/ute/atldruid.ute.json diff --git a/src/mod/ute/atlwizard.ute.json b/src/module/ute/atlwizard.ute.json similarity index 100% rename from src/mod/ute/atlwizard.ute.json rename to src/module/ute/atlwizard.ute.json diff --git a/src/mod/ute/awdieasedzombies.ute.json b/src/module/ute/awdieasedzombies.ute.json similarity index 100% rename from src/mod/ute/awdieasedzombies.ute.json rename to src/module/ute/awdieasedzombies.ute.json diff --git a/src/mod/ute/awfebrith.ute.json b/src/module/ute/awfebrith.ute.json similarity index 100% rename from src/mod/ute/awfebrith.ute.json rename to src/module/ute/awfebrith.ute.json diff --git a/src/mod/ute/awskeleton.ute.json b/src/module/ute/awskeleton.ute.json similarity index 100% rename from src/mod/ute/awskeleton.ute.json rename to src/module/ute/awskeleton.ute.json diff --git a/src/mod/ute/awskeletonmage.ute.json b/src/module/ute/awskeletonmage.ute.json similarity index 100% rename from src/mod/ute/awskeletonmage.ute.json rename to src/module/ute/awskeletonmage.ute.json diff --git a/src/mod/ute/awskeletonwar.ute.json b/src/module/ute/awskeletonwar.ute.json similarity index 100% rename from src/mod/ute/awskeletonwar.ute.json rename to src/module/ute/awskeletonwar.ute.json diff --git a/src/mod/ute/awspideres.ute.json b/src/module/ute/awspideres.ute.json similarity index 100% rename from src/mod/ute/awspideres.ute.json rename to src/module/ute/awspideres.ute.json diff --git a/src/mod/ute/awspideresgiant.ute.json b/src/module/ute/awspideresgiant.ute.json similarity index 100% rename from src/mod/ute/awspideresgiant.ute.json rename to src/module/ute/awspideresgiant.ute.json diff --git a/src/mod/ute/awspideresword.ute.json b/src/module/ute/awspideresword.ute.json similarity index 100% rename from src/mod/ute/awspideresword.ute.json rename to src/module/ute/awspideresword.ute.json diff --git a/src/mod/ute/awtoli.ute.json b/src/module/ute/awtoli.ute.json similarity index 100% rename from src/mod/ute/awtoli.ute.json rename to src/module/ute/awtoli.ute.json diff --git a/src/mod/ute/awtrollcheif.ute.json b/src/module/ute/awtrollcheif.ute.json similarity index 100% rename from src/mod/ute/awtrollcheif.ute.json rename to src/module/ute/awtrollcheif.ute.json diff --git a/src/mod/ute/awtrolls.ute.json b/src/module/ute/awtrolls.ute.json similarity index 100% rename from src/mod/ute/awtrolls.ute.json rename to src/module/ute/awtrolls.ute.json diff --git a/src/mod/ute/awtrollshaman.ute.json b/src/module/ute/awtrollshaman.ute.json similarity index 100% rename from src/mod/ute/awtrollshaman.ute.json rename to src/module/ute/awtrollshaman.ute.json diff --git a/src/mod/ute/awtrollspit.ute.json b/src/module/ute/awtrollspit.ute.json similarity index 100% rename from src/mod/ute/awtrollspit.ute.json rename to src/module/ute/awtrollspit.ute.json diff --git a/src/mod/ute/awvera.ute.json b/src/module/ute/awvera.ute.json similarity index 100% rename from src/mod/ute/awvera.ute.json rename to src/module/ute/awvera.ute.json diff --git a/src/mod/ute/awveraguards.ute.json b/src/module/ute/awveraguards.ute.json similarity index 100% rename from src/mod/ute/awveraguards.ute.json rename to src/module/ute/awveraguards.ute.json diff --git a/src/mod/ute/awveraguardsbarb.ute.json b/src/module/ute/awveraguardsbarb.ute.json similarity index 100% rename from src/mod/ute/awveraguardsbarb.ute.json rename to src/module/ute/awveraguardsbarb.ute.json diff --git a/src/mod/ute/awveraguardsmonk.ute.json b/src/module/ute/awveraguardsmonk.ute.json similarity index 100% rename from src/mod/ute/awveraguardsmonk.ute.json rename to src/module/ute/awveraguardsmonk.ute.json diff --git a/src/mod/ute/awveraspawn.ute.json b/src/module/ute/awveraspawn.ute.json similarity index 100% rename from src/mod/ute/awveraspawn.ute.json rename to src/module/ute/awveraspawn.ute.json diff --git a/src/mod/ute/awveraspawn2.ute.json b/src/module/ute/awveraspawn2.ute.json similarity index 100% rename from src/mod/ute/awveraspawn2.ute.json rename to src/module/ute/awveraspawn2.ute.json diff --git a/src/mod/ute/awzombies.ute.json b/src/module/ute/awzombies.ute.json similarity index 100% rename from src/mod/ute/awzombies.ute.json rename to src/module/ute/awzombies.ute.json diff --git a/src/mod/ute/awzombiesgreat.ute.json b/src/module/ute/awzombiesgreat.ute.json similarity index 100% rename from src/mod/ute/awzombiesgreat.ute.json rename to src/module/ute/awzombiesgreat.ute.json diff --git a/src/mod/ute/awzombieskama.ute.json b/src/module/ute/awzombieskama.ute.json similarity index 100% rename from src/mod/ute/awzombieskama.ute.json rename to src/module/ute/awzombieskama.ute.json diff --git a/src/mod/ute/awzombiesuw.ute.json b/src/module/ute/awzombiesuw.ute.json similarity index 100% rename from src/mod/ute/awzombiesuw.ute.json rename to src/module/ute/awzombiesuw.ute.json diff --git a/src/mod/ute/babyblack.ute.json b/src/module/ute/babyblack.ute.json similarity index 100% rename from src/mod/ute/babyblack.ute.json rename to src/module/ute/babyblack.ute.json diff --git a/src/mod/ute/babyblueddrag.ute.json b/src/module/ute/babyblueddrag.ute.json similarity index 100% rename from src/mod/ute/babyblueddrag.ute.json rename to src/module/ute/babyblueddrag.ute.json diff --git a/src/mod/ute/babybrass.ute.json b/src/module/ute/babybrass.ute.json similarity index 100% rename from src/mod/ute/babybrass.ute.json rename to src/module/ute/babybrass.ute.json diff --git a/src/mod/ute/babygreen.ute.json b/src/module/ute/babygreen.ute.json similarity index 100% rename from src/mod/ute/babygreen.ute.json rename to src/module/ute/babygreen.ute.json diff --git a/src/mod/ute/battleorc.ute.json b/src/module/ute/battleorc.ute.json similarity index 100% rename from src/mod/ute/battleorc.ute.json rename to src/module/ute/battleorc.ute.json diff --git a/src/mod/ute/bearelf.ute.json b/src/module/ute/bearelf.ute.json similarity index 100% rename from src/mod/ute/bearelf.ute.json rename to src/module/ute/bearelf.ute.json diff --git a/src/mod/ute/beholdboss.ute.json b/src/module/ute/beholdboss.ute.json similarity index 100% rename from src/mod/ute/beholdboss.ute.json rename to src/module/ute/beholdboss.ute.json diff --git a/src/mod/ute/beholdertyrant.ute.json b/src/module/ute/beholdertyrant.ute.json similarity index 100% rename from src/mod/ute/beholdertyrant.ute.json rename to src/module/ute/beholdertyrant.ute.json diff --git a/src/mod/ute/beholdeyeball.ute.json b/src/module/ute/beholdeyeball.ute.json similarity index 100% rename from src/mod/ute/beholdeyeball.ute.json rename to src/module/ute/beholdeyeball.ute.json diff --git a/src/mod/ute/blackbear2.ute.json b/src/module/ute/blackbear2.ute.json similarity index 100% rename from src/mod/ute/blackbear2.ute.json rename to src/module/ute/blackbear2.ute.json diff --git a/src/mod/ute/boney.ute.json b/src/module/ute/boney.ute.json similarity index 100% rename from src/mod/ute/boney.ute.json rename to src/module/ute/boney.ute.json diff --git a/src/mod/ute/borgold.ute.json b/src/module/ute/borgold.ute.json similarity index 100% rename from src/mod/ute/borgold.ute.json rename to src/module/ute/borgold.ute.json diff --git a/src/mod/ute/broadtwinbros.ute.json b/src/module/ute/broadtwinbros.ute.json similarity index 100% rename from src/mod/ute/broadtwinbros.ute.json rename to src/module/ute/broadtwinbros.ute.json diff --git a/src/mod/ute/cainsummoner.ute.json b/src/module/ute/cainsummoner.ute.json similarity index 100% rename from src/mod/ute/cainsummoner.ute.json rename to src/module/ute/cainsummoner.ute.json diff --git a/src/mod/ute/caliman.ute.json b/src/module/ute/caliman.ute.json similarity index 100% rename from src/mod/ute/caliman.ute.json rename to src/module/ute/caliman.ute.json diff --git a/src/mod/ute/candelabra.ute.json b/src/module/ute/candelabra.ute.json similarity index 100% rename from src/mod/ute/candelabra.ute.json rename to src/module/ute/candelabra.ute.json diff --git a/src/mod/ute/cavewoman.ute.json b/src/module/ute/cavewoman.ute.json similarity index 100% rename from src/mod/ute/cavewoman.ute.json rename to src/module/ute/cavewoman.ute.json diff --git a/src/mod/ute/chicken.ute.json b/src/module/ute/chicken.ute.json similarity index 100% rename from src/mod/ute/chicken.ute.json rename to src/module/ute/chicken.ute.json diff --git a/src/mod/ute/cloakghost.ute.json b/src/module/ute/cloakghost.ute.json similarity index 100% rename from src/mod/ute/cloakghost.ute.json rename to src/module/ute/cloakghost.ute.json diff --git a/src/mod/ute/cloakphantom.ute.json b/src/module/ute/cloakphantom.ute.json similarity index 100% rename from src/mod/ute/cloakphantom.ute.json rename to src/module/ute/cloakphantom.ute.json diff --git a/src/mod/ute/coldkiller.ute.json b/src/module/ute/coldkiller.ute.json similarity index 100% rename from src/mod/ute/coldkiller.ute.json rename to src/module/ute/coldkiller.ute.json diff --git a/src/mod/ute/darkqueen.ute.json b/src/module/ute/darkqueen.ute.json similarity index 100% rename from src/mod/ute/darkqueen.ute.json rename to src/module/ute/darkqueen.ute.json diff --git a/src/mod/ute/ddblademaster.ute.json b/src/module/ute/ddblademaster.ute.json similarity index 100% rename from src/mod/ute/ddblademaster.ute.json rename to src/module/ute/ddblademaster.ute.json diff --git a/src/mod/ute/ddmonk.ute.json b/src/module/ute/ddmonk.ute.json similarity index 100% rename from src/mod/ute/ddmonk.ute.json rename to src/module/ute/ddmonk.ute.json diff --git a/src/mod/ute/ddofjihad.ute.json b/src/module/ute/ddofjihad.ute.json similarity index 100% rename from src/mod/ute/ddofjihad.ute.json rename to src/module/ute/ddofjihad.ute.json diff --git a/src/mod/ute/ddwizard.ute.json b/src/module/ute/ddwizard.ute.json similarity index 100% rename from src/mod/ute/ddwizard.ute.json rename to src/module/ute/ddwizard.ute.json diff --git a/src/mod/ute/defendermonk.ute.json b/src/module/ute/defendermonk.ute.json similarity index 100% rename from src/mod/ute/defendermonk.ute.json rename to src/module/ute/defendermonk.ute.json diff --git a/src/mod/ute/deseertsting.ute.json b/src/module/ute/deseertsting.ute.json similarity index 100% rename from src/mod/ute/deseertsting.ute.json rename to src/module/ute/deseertsting.ute.json diff --git a/src/mod/ute/desertbomber.ute.json b/src/module/ute/desertbomber.ute.json similarity index 100% rename from src/mod/ute/desertbomber.ute.json rename to src/module/ute/desertbomber.ute.json diff --git a/src/mod/ute/desertdwarf.ute.json b/src/module/ute/desertdwarf.ute.json similarity index 100% rename from src/mod/ute/desertdwarf.ute.json rename to src/module/ute/desertdwarf.ute.json diff --git a/src/mod/ute/desertdwarfcleri.ute.json b/src/module/ute/desertdwarfcleri.ute.json similarity index 100% rename from src/mod/ute/desertdwarfcleri.ute.json rename to src/module/ute/desertdwarfcleri.ute.json diff --git a/src/mod/ute/desertdwarfwarri.ute.json b/src/module/ute/desertdwarfwarri.ute.json similarity index 100% rename from src/mod/ute/desertdwarfwarri.ute.json rename to src/module/ute/desertdwarfwarri.ute.json diff --git a/src/mod/ute/desertstingerwar.ute.json b/src/module/ute/desertstingerwar.ute.json similarity index 100% rename from src/mod/ute/desertstingerwar.ute.json rename to src/module/ute/desertstingerwar.ute.json diff --git a/src/mod/ute/desertstingmage.ute.json b/src/module/ute/desertstingmage.ute.json similarity index 100% rename from src/mod/ute/desertstingmage.ute.json rename to src/module/ute/desertstingmage.ute.json diff --git a/src/mod/ute/dirtharcher.ute.json b/src/module/ute/dirtharcher.ute.json similarity index 100% rename from src/mod/ute/dirtharcher.ute.json rename to src/module/ute/dirtharcher.ute.json diff --git a/src/mod/ute/dirthbattlebot.ute.json b/src/module/ute/dirthbattlebot.ute.json similarity index 100% rename from src/mod/ute/dirthbattlebot.ute.json rename to src/module/ute/dirthbattlebot.ute.json diff --git a/src/mod/ute/dirthmage.ute.json b/src/module/ute/dirthmage.ute.json similarity index 100% rename from src/mod/ute/dirthmage.ute.json rename to src/module/ute/dirthmage.ute.json diff --git a/src/mod/ute/dirthprincess.ute.json b/src/module/ute/dirthprincess.ute.json similarity index 100% rename from src/mod/ute/dirthprincess.ute.json rename to src/module/ute/dirthprincess.ute.json diff --git a/src/mod/ute/dirthwarrior.ute.json b/src/module/ute/dirthwarrior.ute.json similarity index 100% rename from src/mod/ute/dirthwarrior.ute.json rename to src/module/ute/dirthwarrior.ute.json diff --git a/src/mod/ute/dirthwarrior001.ute.json b/src/module/ute/dirthwarrior001.ute.json similarity index 100% rename from src/mod/ute/dirthwarrior001.ute.json rename to src/module/ute/dirthwarrior001.ute.json diff --git a/src/mod/ute/dracsmistress.ute.json b/src/module/ute/dracsmistress.ute.json similarity index 100% rename from src/mod/ute/dracsmistress.ute.json rename to src/module/ute/dracsmistress.ute.json diff --git a/src/mod/ute/dragoncultmage.ute.json b/src/module/ute/dragoncultmage.ute.json similarity index 100% rename from src/mod/ute/dragoncultmage.ute.json rename to src/module/ute/dragoncultmage.ute.json diff --git a/src/mod/ute/dragonculttraine.ute.json b/src/module/ute/dragonculttraine.ute.json similarity index 100% rename from src/mod/ute/dragonculttraine.ute.json rename to src/module/ute/dragonculttraine.ute.json diff --git a/src/mod/ute/dragoncultwarrio.ute.json b/src/module/ute/dragoncultwarrio.ute.json similarity index 100% rename from src/mod/ute/dragoncultwarrio.ute.json rename to src/module/ute/dragoncultwarrio.ute.json diff --git a/src/mod/ute/dreamfollower.ute.json b/src/module/ute/dreamfollower.ute.json similarity index 100% rename from src/mod/ute/dreamfollower.ute.json rename to src/module/ute/dreamfollower.ute.json diff --git a/src/mod/ute/drowcleric.ute.json b/src/module/ute/drowcleric.ute.json similarity index 100% rename from src/mod/ute/drowcleric.ute.json rename to src/module/ute/drowcleric.ute.json diff --git a/src/mod/ute/drowcommander.ute.json b/src/module/ute/drowcommander.ute.json similarity index 100% rename from src/mod/ute/drowcommander.ute.json rename to src/module/ute/drowcommander.ute.json diff --git a/src/mod/ute/drowdefender.ute.json b/src/module/ute/drowdefender.ute.json similarity index 100% rename from src/mod/ute/drowdefender.ute.json rename to src/module/ute/drowdefender.ute.json diff --git a/src/mod/ute/drowguard.ute.json b/src/module/ute/drowguard.ute.json similarity index 100% rename from src/mod/ute/drowguard.ute.json rename to src/module/ute/drowguard.ute.json diff --git a/src/mod/ute/drowhighcleric.ute.json b/src/module/ute/drowhighcleric.ute.json similarity index 100% rename from src/mod/ute/drowhighcleric.ute.json rename to src/module/ute/drowhighcleric.ute.json diff --git a/src/mod/ute/drowwarrior.ute.json b/src/module/ute/drowwarrior.ute.json similarity index 100% rename from src/mod/ute/drowwarrior.ute.json rename to src/module/ute/drowwarrior.ute.json diff --git a/src/mod/ute/drowwizzyguy.ute.json b/src/module/ute/drowwizzyguy.ute.json similarity index 100% rename from src/mod/ute/drowwizzyguy.ute.json rename to src/module/ute/drowwizzyguy.ute.json diff --git a/src/mod/ute/drudoc.ute.json b/src/module/ute/drudoc.ute.json similarity index 100% rename from src/mod/ute/drudoc.ute.json rename to src/module/ute/drudoc.ute.json diff --git a/src/mod/ute/druidelder.ute.json b/src/module/ute/druidelder.ute.json similarity index 100% rename from src/mod/ute/druidelder.ute.json rename to src/module/ute/druidelder.ute.json diff --git a/src/mod/ute/dwarfbarb.ute.json b/src/module/ute/dwarfbarb.ute.json similarity index 100% rename from src/mod/ute/dwarfbarb.ute.json rename to src/module/ute/dwarfbarb.ute.json diff --git a/src/mod/ute/dwarfgaurd.ute.json b/src/module/ute/dwarfgaurd.ute.json similarity index 100% rename from src/mod/ute/dwarfgaurd.ute.json rename to src/module/ute/dwarfgaurd.ute.json diff --git a/src/mod/ute/dwarfinfantry.ute.json b/src/module/ute/dwarfinfantry.ute.json similarity index 100% rename from src/mod/ute/dwarfinfantry.ute.json rename to src/module/ute/dwarfinfantry.ute.json diff --git a/src/mod/ute/dwarfpreist.ute.json b/src/module/ute/dwarfpreist.ute.json similarity index 100% rename from src/mod/ute/dwarfpreist.ute.json rename to src/module/ute/dwarfpreist.ute.json diff --git a/src/mod/ute/dwarfstaffmaster.ute.json b/src/module/ute/dwarfstaffmaster.ute.json similarity index 100% rename from src/mod/ute/dwarfstaffmaster.ute.json rename to src/module/ute/dwarfstaffmaster.ute.json diff --git a/src/mod/ute/dwarfwizard.ute.json b/src/module/ute/dwarfwizard.ute.json similarity index 100% rename from src/mod/ute/dwarfwizard.ute.json rename to src/module/ute/dwarfwizard.ute.json diff --git a/src/mod/ute/elvendardefender.ute.json b/src/module/ute/elvendardefender.ute.json similarity index 100% rename from src/mod/ute/elvendardefender.ute.json rename to src/module/ute/elvendardefender.ute.json diff --git a/src/mod/ute/elvendarelite.ute.json b/src/module/ute/elvendarelite.ute.json similarity index 100% rename from src/mod/ute/elvendarelite.ute.json rename to src/module/ute/elvendarelite.ute.json diff --git a/src/mod/ute/evillibrarian.ute.json b/src/module/ute/evillibrarian.ute.json similarity index 100% rename from src/mod/ute/evillibrarian.ute.json rename to src/module/ute/evillibrarian.ute.json diff --git a/src/mod/ute/falcon.ute.json b/src/module/ute/falcon.ute.json similarity index 100% rename from src/mod/ute/falcon.ute.json rename to src/module/ute/falcon.ute.json diff --git a/src/mod/ute/fallencleric.ute.json b/src/module/ute/fallencleric.ute.json similarity index 100% rename from src/mod/ute/fallencleric.ute.json rename to src/module/ute/fallencleric.ute.json diff --git a/src/mod/ute/fallenpaladin.ute.json b/src/module/ute/fallenpaladin.ute.json similarity index 100% rename from src/mod/ute/fallenpaladin.ute.json rename to src/module/ute/fallenpaladin.ute.json diff --git a/src/mod/ute/fianlpriest.ute.json b/src/module/ute/fianlpriest.ute.json similarity index 100% rename from src/mod/ute/fianlpriest.ute.json rename to src/module/ute/fianlpriest.ute.json diff --git a/src/mod/ute/firendlyblackbea.ute.json b/src/module/ute/firendlyblackbea.ute.json similarity index 100% rename from src/mod/ute/firendlyblackbea.ute.json rename to src/module/ute/firendlyblackbea.ute.json diff --git a/src/mod/ute/forestdruid.ute.json b/src/module/ute/forestdruid.ute.json similarity index 100% rename from src/mod/ute/forestdruid.ute.json rename to src/module/ute/forestdruid.ute.json diff --git a/src/mod/ute/forestwolf.ute.json b/src/module/ute/forestwolf.ute.json similarity index 100% rename from src/mod/ute/forestwolf.ute.json rename to src/module/ute/forestwolf.ute.json diff --git a/src/mod/ute/friendlyblackbea.ute.json b/src/module/ute/friendlyblackbea.ute.json similarity index 100% rename from src/mod/ute/friendlyblackbea.ute.json rename to src/module/ute/friendlyblackbea.ute.json diff --git a/src/mod/ute/friendlypolarbea.ute.json b/src/module/ute/friendlypolarbea.ute.json similarity index 100% rename from src/mod/ute/friendlypolarbea.ute.json rename to src/module/ute/friendlypolarbea.ute.json diff --git a/src/mod/ute/friendlyraven.ute.json b/src/module/ute/friendlyraven.ute.json similarity index 100% rename from src/mod/ute/friendlyraven.ute.json rename to src/module/ute/friendlyraven.ute.json diff --git a/src/mod/ute/friendlywolf.ute.json b/src/module/ute/friendlywolf.ute.json similarity index 100% rename from src/mod/ute/friendlywolf.ute.json rename to src/module/ute/friendlywolf.ute.json diff --git a/src/mod/ute/gaseosform.ute.json b/src/module/ute/gaseosform.ute.json similarity index 100% rename from src/mod/ute/gaseosform.ute.json rename to src/module/ute/gaseosform.ute.json diff --git a/src/mod/ute/gaseousform2.ute.json b/src/module/ute/gaseousform2.ute.json similarity index 100% rename from src/mod/ute/gaseousform2.ute.json rename to src/module/ute/gaseousform2.ute.json diff --git a/src/mod/ute/ghostlyimage.ute.json b/src/module/ute/ghostlyimage.ute.json similarity index 100% rename from src/mod/ute/ghostlyimage.ute.json rename to src/module/ute/ghostlyimage.ute.json diff --git a/src/mod/ute/granoladefender.ute.json b/src/module/ute/granoladefender.ute.json similarity index 100% rename from src/mod/ute/granoladefender.ute.json rename to src/module/ute/granoladefender.ute.json diff --git a/src/mod/ute/halforcaxe.ute.json b/src/module/ute/halforcaxe.ute.json similarity index 100% rename from src/mod/ute/halforcaxe.ute.json rename to src/module/ute/halforcaxe.ute.json diff --git a/src/mod/ute/halforcinvader.ute.json b/src/module/ute/halforcinvader.ute.json similarity index 100% rename from src/mod/ute/halforcinvader.ute.json rename to src/module/ute/halforcinvader.ute.json diff --git a/src/mod/ute/halforcinvadetuf.ute.json b/src/module/ute/halforcinvadetuf.ute.json similarity index 100% rename from src/mod/ute/halforcinvadetuf.ute.json rename to src/module/ute/halforcinvadetuf.ute.json diff --git a/src/mod/ute/hasbeen.ute.json b/src/module/ute/hasbeen.ute.json similarity index 100% rename from src/mod/ute/hasbeen.ute.json rename to src/module/ute/hasbeen.ute.json diff --git a/src/mod/ute/hlaforcbasher.ute.json b/src/module/ute/hlaforcbasher.ute.json similarity index 100% rename from src/mod/ute/hlaforcbasher.ute.json rename to src/module/ute/hlaforcbasher.ute.json diff --git a/src/mod/ute/holo.ute.json b/src/module/ute/holo.ute.json similarity index 100% rename from src/mod/ute/holo.ute.json rename to src/module/ute/holo.ute.json diff --git a/src/mod/ute/iceprincess.ute.json b/src/module/ute/iceprincess.ute.json similarity index 100% rename from src/mod/ute/iceprincess.ute.json rename to src/module/ute/iceprincess.ute.json diff --git a/src/mod/ute/ironcalwblackgua.ute.json b/src/module/ute/ironcalwblackgua.ute.json similarity index 100% rename from src/mod/ute/ironcalwblackgua.ute.json rename to src/module/ute/ironcalwblackgua.ute.json diff --git a/src/mod/ute/ironclawdefender.ute.json b/src/module/ute/ironclawdefender.ute.json similarity index 100% rename from src/mod/ute/ironclawdefender.ute.json rename to src/module/ute/ironclawdefender.ute.json diff --git a/src/mod/ute/ironclawguard.ute.json b/src/module/ute/ironclawguard.ute.json similarity index 100% rename from src/mod/ute/ironclawguard.ute.json rename to src/module/ute/ironclawguard.ute.json diff --git a/src/mod/ute/ironclawrange.ute.json b/src/module/ute/ironclawrange.ute.json similarity index 100% rename from src/mod/ute/ironclawrange.ute.json rename to src/module/ute/ironclawrange.ute.json diff --git a/src/mod/ute/ironclawsorc.ute.json b/src/module/ute/ironclawsorc.ute.json similarity index 100% rename from src/mod/ute/ironclawsorc.ute.json rename to src/module/ute/ironclawsorc.ute.json diff --git a/src/mod/ute/irongoblin.ute.json b/src/module/ute/irongoblin.ute.json similarity index 100% rename from src/mod/ute/irongoblin.ute.json rename to src/module/ute/irongoblin.ute.json diff --git a/src/mod/ute/ironkobold.ute.json b/src/module/ute/ironkobold.ute.json similarity index 100% rename from src/mod/ute/ironkobold.ute.json rename to src/module/ute/ironkobold.ute.json diff --git a/src/mod/ute/ironkoboldmage.ute.json b/src/module/ute/ironkoboldmage.ute.json similarity index 100% rename from src/mod/ute/ironkoboldmage.ute.json rename to src/module/ute/ironkoboldmage.ute.json diff --git a/src/mod/ute/jagangguard.ute.json b/src/module/ute/jagangguard.ute.json similarity index 100% rename from src/mod/ute/jagangguard.ute.json rename to src/module/ute/jagangguard.ute.json diff --git a/src/mod/ute/jez.ute.json b/src/module/ute/jez.ute.json similarity index 100% rename from src/mod/ute/jez.ute.json rename to src/module/ute/jez.ute.json diff --git a/src/mod/ute/keydefender.ute.json b/src/module/ute/keydefender.ute.json similarity index 100% rename from src/mod/ute/keydefender.ute.json rename to src/module/ute/keydefender.ute.json diff --git a/src/mod/ute/klaum.ute.json b/src/module/ute/klaum.ute.json similarity index 100% rename from src/mod/ute/klaum.ute.json rename to src/module/ute/klaum.ute.json diff --git a/src/mod/ute/ladyofnight.ute.json b/src/module/ute/ladyofnight.ute.json similarity index 100% rename from src/mod/ute/ladyofnight.ute.json rename to src/module/ute/ladyofnight.ute.json diff --git a/src/mod/ute/ladyofthenight.ute.json b/src/module/ute/ladyofthenight.ute.json similarity index 100% rename from src/mod/ute/ladyofthenight.ute.json rename to src/module/ute/ladyofthenight.ute.json diff --git a/src/mod/ute/legionassassin.ute.json b/src/module/ute/legionassassin.ute.json similarity index 100% rename from src/mod/ute/legionassassin.ute.json rename to src/module/ute/legionassassin.ute.json diff --git a/src/mod/ute/legionbodyguard.ute.json b/src/module/ute/legionbodyguard.ute.json similarity index 100% rename from src/mod/ute/legionbodyguard.ute.json rename to src/module/ute/legionbodyguard.ute.json diff --git a/src/mod/ute/lucephscpt.ute.json b/src/module/ute/lucephscpt.ute.json similarity index 100% rename from src/mod/ute/lucephscpt.ute.json rename to src/module/ute/lucephscpt.ute.json diff --git a/src/mod/ute/magmamephit.ute.json b/src/module/ute/magmamephit.ute.json similarity index 100% rename from src/mod/ute/magmamephit.ute.json rename to src/module/ute/magmamephit.ute.json diff --git a/src/mod/ute/metalmonk.ute.json b/src/module/ute/metalmonk.ute.json similarity index 100% rename from src/mod/ute/metalmonk.ute.json rename to src/module/ute/metalmonk.ute.json diff --git a/src/mod/ute/mindflayer.ute.json b/src/module/ute/mindflayer.ute.json similarity index 100% rename from src/mod/ute/mindflayer.ute.json rename to src/module/ute/mindflayer.ute.json diff --git a/src/mod/ute/miningbot.ute.json b/src/module/ute/miningbot.ute.json similarity index 100% rename from src/mod/ute/miningbot.ute.json rename to src/module/ute/miningbot.ute.json diff --git a/src/mod/ute/naturebeast.ute.json b/src/module/ute/naturebeast.ute.json similarity index 100% rename from src/mod/ute/naturebeast.ute.json rename to src/module/ute/naturebeast.ute.json diff --git a/src/mod/ute/nordicdwarf.ute.json b/src/module/ute/nordicdwarf.ute.json similarity index 100% rename from src/mod/ute/nordicdwarf.ute.json rename to src/module/ute/nordicdwarf.ute.json diff --git a/src/mod/ute/nudeasyrian.ute.json b/src/module/ute/nudeasyrian.ute.json similarity index 100% rename from src/mod/ute/nudeasyrian.ute.json rename to src/module/ute/nudeasyrian.ute.json diff --git a/src/mod/ute/ogre.ute.json b/src/module/ute/ogre.ute.json similarity index 100% rename from src/mod/ute/ogre.ute.json rename to src/module/ute/ogre.ute.json diff --git a/src/mod/ute/ogrechief.ute.json b/src/module/ute/ogrechief.ute.json similarity index 100% rename from src/mod/ute/ogrechief.ute.json rename to src/module/ute/ogrechief.ute.json diff --git a/src/mod/ute/ogremage.ute.json b/src/module/ute/ogremage.ute.json similarity index 100% rename from src/mod/ute/ogremage.ute.json rename to src/module/ute/ogremage.ute.json diff --git a/src/mod/ute/orcarcher.ute.json b/src/module/ute/orcarcher.ute.json similarity index 100% rename from src/mod/ute/orcarcher.ute.json rename to src/module/ute/orcarcher.ute.json diff --git a/src/mod/ute/orcbattleplanner.ute.json b/src/module/ute/orcbattleplanner.ute.json similarity index 100% rename from src/mod/ute/orcbattleplanner.ute.json rename to src/module/ute/orcbattleplanner.ute.json diff --git a/src/mod/ute/orchighshaman.ute.json b/src/module/ute/orchighshaman.ute.json similarity index 100% rename from src/mod/ute/orchighshaman.ute.json rename to src/module/ute/orchighshaman.ute.json diff --git a/src/mod/ute/orcmage.ute.json b/src/module/ute/orcmage.ute.json similarity index 100% rename from src/mod/ute/orcmage.ute.json rename to src/module/ute/orcmage.ute.json diff --git a/src/mod/ute/orcmaster.ute.json b/src/module/ute/orcmaster.ute.json similarity index 100% rename from src/mod/ute/orcmaster.ute.json rename to src/module/ute/orcmaster.ute.json diff --git a/src/mod/ute/orcshaman.ute.json b/src/module/ute/orcshaman.ute.json similarity index 100% rename from src/mod/ute/orcshaman.ute.json rename to src/module/ute/orcshaman.ute.json diff --git a/src/mod/ute/ozdefender.ute.json b/src/module/ute/ozdefender.ute.json similarity index 100% rename from src/mod/ute/ozdefender.ute.json rename to src/module/ute/ozdefender.ute.json diff --git a/src/mod/ute/ozeast.ute.json b/src/module/ute/ozeast.ute.json similarity index 100% rename from src/mod/ute/ozeast.ute.json rename to src/module/ute/ozeast.ute.json diff --git a/src/mod/ute/ozenergydude.ute.json b/src/module/ute/ozenergydude.ute.json similarity index 100% rename from src/mod/ute/ozenergydude.ute.json rename to src/module/ute/ozenergydude.ute.json diff --git a/src/mod/ute/ozintellect.ute.json b/src/module/ute/ozintellect.ute.json similarity index 100% rename from src/mod/ute/ozintellect.ute.json rename to src/module/ute/ozintellect.ute.json diff --git a/src/mod/ute/ozlibrary_02.ute.json b/src/module/ute/ozlibrary_02.ute.json similarity index 100% rename from src/mod/ute/ozlibrary_02.ute.json rename to src/module/ute/ozlibrary_02.ute.json diff --git a/src/mod/ute/ozsoulseeker.ute.json b/src/module/ute/ozsoulseeker.ute.json similarity index 100% rename from src/mod/ute/ozsoulseeker.ute.json rename to src/module/ute/ozsoulseeker.ute.json diff --git a/src/mod/ute/ozwestkey.ute.json b/src/module/ute/ozwestkey.ute.json similarity index 100% rename from src/mod/ute/ozwestkey.ute.json rename to src/module/ute/ozwestkey.ute.json diff --git a/src/mod/ute/penguin.ute.json b/src/module/ute/penguin.ute.json similarity index 100% rename from src/mod/ute/penguin.ute.json rename to src/module/ute/penguin.ute.json diff --git a/src/mod/ute/phw.ute.json b/src/module/ute/phw.ute.json similarity index 100% rename from src/mod/ute/phw.ute.json rename to src/module/ute/phw.ute.json diff --git a/src/mod/ute/raiderelitemage.ute.json b/src/module/ute/raiderelitemage.ute.json similarity index 100% rename from src/mod/ute/raiderelitemage.ute.json rename to src/module/ute/raiderelitemage.ute.json diff --git a/src/mod/ute/raiderorcs.ute.json b/src/module/ute/raiderorcs.ute.json similarity index 100% rename from src/mod/ute/raiderorcs.ute.json rename to src/module/ute/raiderorcs.ute.json diff --git a/src/mod/ute/raiderrogue.ute.json b/src/module/ute/raiderrogue.ute.json similarity index 100% rename from src/mod/ute/raiderrogue.ute.json rename to src/module/ute/raiderrogue.ute.json diff --git a/src/mod/ute/reb.ute.json b/src/module/ute/reb.ute.json similarity index 100% rename from src/mod/ute/reb.ute.json rename to src/module/ute/reb.ute.json diff --git a/src/mod/ute/reb001.ute.json b/src/module/ute/reb001.ute.json similarity index 100% rename from src/mod/ute/reb001.ute.json rename to src/module/ute/reb001.ute.json diff --git a/src/mod/ute/repentguardian.ute.json b/src/module/ute/repentguardian.ute.json similarity index 100% rename from src/mod/ute/repentguardian.ute.json rename to src/module/ute/repentguardian.ute.json diff --git a/src/mod/ute/roadsidebandit.ute.json b/src/module/ute/roadsidebandit.ute.json similarity index 100% rename from src/mod/ute/roadsidebandit.ute.json rename to src/module/ute/roadsidebandit.ute.json diff --git a/src/mod/ute/roamingdroid.ute.json b/src/module/ute/roamingdroid.ute.json similarity index 100% rename from src/mod/ute/roamingdroid.ute.json rename to src/module/ute/roamingdroid.ute.json diff --git a/src/mod/ute/shadowwalker.ute.json b/src/module/ute/shadowwalker.ute.json similarity index 100% rename from src/mod/ute/shadowwalker.ute.json rename to src/module/ute/shadowwalker.ute.json diff --git a/src/mod/ute/shogunbeliever.ute.json b/src/module/ute/shogunbeliever.ute.json similarity index 100% rename from src/mod/ute/shogunbeliever.ute.json rename to src/module/ute/shogunbeliever.ute.json diff --git a/src/mod/ute/shoguncleanser.ute.json b/src/module/ute/shoguncleanser.ute.json similarity index 100% rename from src/mod/ute/shoguncleanser.ute.json rename to src/module/ute/shoguncleanser.ute.json diff --git a/src/mod/ute/shogunhighpre001.ute.json b/src/module/ute/shogunhighpre001.ute.json similarity index 100% rename from src/mod/ute/shogunhighpre001.ute.json rename to src/module/ute/shogunhighpre001.ute.json diff --git a/src/mod/ute/shogunhighpreist.ute.json b/src/module/ute/shogunhighpreist.ute.json similarity index 100% rename from src/mod/ute/shogunhighpreist.ute.json rename to src/module/ute/shogunhighpreist.ute.json diff --git a/src/mod/ute/shoguninsightmon.ute.json b/src/module/ute/shoguninsightmon.ute.json similarity index 100% rename from src/mod/ute/shoguninsightmon.ute.json rename to src/module/ute/shoguninsightmon.ute.json diff --git a/src/mod/ute/shogunkiddingme.ute.json b/src/module/ute/shogunkiddingme.ute.json similarity index 100% rename from src/mod/ute/shogunkiddingme.ute.json rename to src/module/ute/shogunkiddingme.ute.json diff --git a/src/mod/ute/shogunmuscle.ute.json b/src/module/ute/shogunmuscle.ute.json similarity index 100% rename from src/mod/ute/shogunmuscle.ute.json rename to src/module/ute/shogunmuscle.ute.json diff --git a/src/mod/ute/shogunreb2.ute.json b/src/module/ute/shogunreb2.ute.json similarity index 100% rename from src/mod/ute/shogunreb2.ute.json rename to src/module/ute/shogunreb2.ute.json diff --git a/src/mod/ute/shogunshurkin.ute.json b/src/module/ute/shogunshurkin.ute.json similarity index 100% rename from src/mod/ute/shogunshurkin.ute.json rename to src/module/ute/shogunshurkin.ute.json diff --git a/src/mod/ute/shoguntempleguar.ute.json b/src/module/ute/shoguntempleguar.ute.json similarity index 100% rename from src/mod/ute/shoguntempleguar.ute.json rename to src/module/ute/shoguntempleguar.ute.json diff --git a/src/mod/ute/shoguntemplekey.ute.json b/src/module/ute/shoguntemplekey.ute.json similarity index 100% rename from src/mod/ute/shoguntemplekey.ute.json rename to src/module/ute/shoguntemplekey.ute.json diff --git a/src/mod/ute/shoguntiger.ute.json b/src/module/ute/shoguntiger.ute.json similarity index 100% rename from src/mod/ute/shoguntiger.ute.json rename to src/module/ute/shoguntiger.ute.json diff --git a/src/mod/ute/shogunwarrior.ute.json b/src/module/ute/shogunwarrior.ute.json similarity index 100% rename from src/mod/ute/shogunwarrior.ute.json rename to src/module/ute/shogunwarrior.ute.json diff --git a/src/mod/ute/slave.ute.json b/src/module/ute/slave.ute.json similarity index 100% rename from src/mod/ute/slave.ute.json rename to src/module/ute/slave.ute.json diff --git a/src/mod/ute/sludgeking.ute.json b/src/module/ute/sludgeking.ute.json similarity index 100% rename from src/mod/ute/sludgeking.ute.json rename to src/module/ute/sludgeking.ute.json diff --git a/src/mod/ute/sludgemonster.ute.json b/src/module/ute/sludgemonster.ute.json similarity index 100% rename from src/mod/ute/sludgemonster.ute.json rename to src/module/ute/sludgemonster.ute.json diff --git a/src/mod/ute/sludgemonster1.ute.json b/src/module/ute/sludgemonster1.ute.json similarity index 100% rename from src/mod/ute/sludgemonster1.ute.json rename to src/module/ute/sludgemonster1.ute.json diff --git a/src/mod/ute/stinkbeetle.ute.json b/src/module/ute/stinkbeetle.ute.json similarity index 100% rename from src/mod/ute/stinkbeetle.ute.json rename to src/module/ute/stinkbeetle.ute.json diff --git a/src/mod/ute/tagner.ute.json b/src/module/ute/tagner.ute.json similarity index 100% rename from src/mod/ute/tagner.ute.json rename to src/module/ute/tagner.ute.json diff --git a/src/mod/ute/tmarcher.ute.json b/src/module/ute/tmarcher.ute.json similarity index 100% rename from src/mod/ute/tmarcher.ute.json rename to src/module/ute/tmarcher.ute.json diff --git a/src/mod/ute/tmcleric.ute.json b/src/module/ute/tmcleric.ute.json similarity index 100% rename from src/mod/ute/tmcleric.ute.json rename to src/module/ute/tmcleric.ute.json diff --git a/src/mod/ute/tmjailmaster.ute.json b/src/module/ute/tmjailmaster.ute.json similarity index 100% rename from src/mod/ute/tmjailmaster.ute.json rename to src/module/ute/tmjailmaster.ute.json diff --git a/src/mod/ute/tmspearmen.ute.json b/src/module/ute/tmspearmen.ute.json similarity index 100% rename from src/mod/ute/tmspearmen.ute.json rename to src/module/ute/tmspearmen.ute.json diff --git a/src/mod/ute/tumbler.ute.json b/src/module/ute/tumbler.ute.json similarity index 100% rename from src/mod/ute/tumbler.ute.json rename to src/module/ute/tumbler.ute.json diff --git a/src/mod/ute/tundrabear.ute.json b/src/module/ute/tundrabear.ute.json similarity index 100% rename from src/mod/ute/tundrabear.ute.json rename to src/module/ute/tundrabear.ute.json diff --git a/src/mod/ute/vampricwarrio001.ute.json b/src/module/ute/vampricwarrio001.ute.json similarity index 100% rename from src/mod/ute/vampricwarrio001.ute.json rename to src/module/ute/vampricwarrio001.ute.json diff --git a/src/mod/ute/vampricwarrior.ute.json b/src/module/ute/vampricwarrior.ute.json similarity index 100% rename from src/mod/ute/vampricwarrior.ute.json rename to src/module/ute/vampricwarrior.ute.json diff --git a/src/mod/ute/vampricwizzy.ute.json b/src/module/ute/vampricwizzy.ute.json similarity index 100% rename from src/mod/ute/vampricwizzy.ute.json rename to src/module/ute/vampricwizzy.ute.json diff --git a/src/mod/ute/wastelandhunter.ute.json b/src/module/ute/wastelandhunter.ute.json similarity index 100% rename from src/mod/ute/wastelandhunter.ute.json rename to src/module/ute/wastelandhunter.ute.json diff --git a/src/mod/ute/wastelandhuntres.ute.json b/src/module/ute/wastelandhuntres.ute.json similarity index 100% rename from src/mod/ute/wastelandhuntres.ute.json rename to src/module/ute/wastelandhuntres.ute.json diff --git a/src/mod/ute/wastelandicecrus.ute.json b/src/module/ute/wastelandicecrus.ute.json similarity index 100% rename from src/mod/ute/wastelandicecrus.ute.json rename to src/module/ute/wastelandicecrus.ute.json diff --git a/src/mod/ute/wealthyman.ute.json b/src/module/ute/wealthyman.ute.json similarity index 100% rename from src/mod/ute/wealthyman.ute.json rename to src/module/ute/wealthyman.ute.json diff --git a/src/mod/ute/werecat.ute.json b/src/module/ute/werecat.ute.json similarity index 100% rename from src/mod/ute/werecat.ute.json rename to src/module/ute/werecat.ute.json diff --git a/src/mod/ute/wererate.ute.json b/src/module/ute/wererate.ute.json similarity index 100% rename from src/mod/ute/wererate.ute.json rename to src/module/ute/wererate.ute.json diff --git a/src/mod/ute/werewolf.ute.json b/src/module/ute/werewolf.ute.json similarity index 100% rename from src/mod/ute/werewolf.ute.json rename to src/module/ute/werewolf.ute.json diff --git a/src/mod/ute/wizardmonk.ute.json b/src/module/ute/wizardmonk.ute.json similarity index 100% rename from src/mod/ute/wizardmonk.ute.json rename to src/module/ute/wizardmonk.ute.json diff --git a/src/mod/uti/50gp.uti.json b/src/module/uti/50gp.uti.json similarity index 100% rename from src/mod/uti/50gp.uti.json rename to src/module/uti/50gp.uti.json diff --git a/src/mod/uti/aaaaabite.uti.json b/src/module/uti/aaaaabite.uti.json similarity index 100% rename from src/mod/uti/aaaaabite.uti.json rename to src/module/uti/aaaaabite.uti.json diff --git a/src/mod/uti/aaaaahclaw.uti.json b/src/module/uti/aaaaahclaw.uti.json similarity index 100% rename from src/mod/uti/aaaaahclaw.uti.json rename to src/module/uti/aaaaahclaw.uti.json diff --git a/src/mod/uti/aaaaahclaw001.uti.json b/src/module/uti/aaaaahclaw001.uti.json similarity index 100% rename from src/mod/uti/aaaaahclaw001.uti.json rename to src/module/uti/aaaaahclaw001.uti.json diff --git a/src/mod/uti/aaaaahskin.uti.json b/src/module/uti/aaaaahskin.uti.json similarity index 100% rename from src/mod/uti/aaaaahskin.uti.json rename to src/module/uti/aaaaahskin.uti.json diff --git a/src/mod/uti/aciddart.uti.json b/src/module/uti/aciddart.uti.json similarity index 100% rename from src/mod/uti/aciddart.uti.json rename to src/module/uti/aciddart.uti.json diff --git a/src/mod/uti/acidionstick.uti.json b/src/module/uti/acidionstick.uti.json similarity index 100% rename from src/mod/uti/acidionstick.uti.json rename to src/module/uti/acidionstick.uti.json diff --git a/src/mod/uti/adventureslighta.uti.json b/src/module/uti/adventureslighta.uti.json similarity index 100% rename from src/mod/uti/adventureslighta.uti.json rename to src/module/uti/adventureslighta.uti.json diff --git a/src/mod/uti/agadenarmor.uti.json b/src/module/uti/agadenarmor.uti.json similarity index 100% rename from src/mod/uti/agadenarmor.uti.json rename to src/module/uti/agadenarmor.uti.json diff --git a/src/mod/uti/agadenboots.uti.json b/src/module/uti/agadenboots.uti.json similarity index 100% rename from src/mod/uti/agadenboots.uti.json rename to src/module/uti/agadenboots.uti.json diff --git a/src/mod/uti/agadengaurdarmor.uti.json b/src/module/uti/agadengaurdarmor.uti.json similarity index 100% rename from src/mod/uti/agadengaurdarmor.uti.json rename to src/module/uti/agadengaurdarmor.uti.json diff --git a/src/mod/uti/agadengaurdhelm.uti.json b/src/module/uti/agadengaurdhelm.uti.json similarity index 100% rename from src/mod/uti/agadengaurdhelm.uti.json rename to src/module/uti/agadengaurdhelm.uti.json diff --git a/src/mod/uti/agadenhelm.uti.json b/src/module/uti/agadenhelm.uti.json similarity index 100% rename from src/mod/uti/agadenhelm.uti.json rename to src/module/uti/agadenhelm.uti.json diff --git a/src/mod/uti/agadenreachkey.uti.json b/src/module/uti/agadenreachkey.uti.json similarity index 100% rename from src/mod/uti/agadenreachkey.uti.json rename to src/module/uti/agadenreachkey.uti.json diff --git a/src/mod/uti/alienammo.uti.json b/src/module/uti/alienammo.uti.json similarity index 100% rename from src/mod/uti/alienammo.uti.json rename to src/module/uti/alienammo.uti.json diff --git a/src/mod/uti/alienammo001.uti.json b/src/module/uti/alienammo001.uti.json similarity index 100% rename from src/mod/uti/alienammo001.uti.json rename to src/module/uti/alienammo001.uti.json diff --git a/src/mod/uti/alienarmor.uti.json b/src/module/uti/alienarmor.uti.json similarity index 100% rename from src/mod/uti/alienarmor.uti.json rename to src/module/uti/alienarmor.uti.json diff --git a/src/mod/uti/aliengun.uti.json b/src/module/uti/aliengun.uti.json similarity index 100% rename from src/mod/uti/aliengun.uti.json rename to src/module/uti/aliengun.uti.json diff --git a/src/mod/uti/ammyofcult.uti.json b/src/module/uti/ammyofcult.uti.json similarity index 100% rename from src/mod/uti/ammyofcult.uti.json rename to src/module/uti/ammyofcult.uti.json diff --git a/src/mod/uti/amuletofthewarri.uti.json b/src/module/uti/amuletofthewarri.uti.json similarity index 100% rename from src/mod/uti/amuletofthewarri.uti.json rename to src/module/uti/amuletofthewarri.uti.json diff --git a/src/mod/uti/ancientguardclaw.uti.json b/src/module/uti/ancientguardclaw.uti.json similarity index 100% rename from src/mod/uti/ancientguardclaw.uti.json rename to src/module/uti/ancientguardclaw.uti.json diff --git a/src/mod/uti/ancientroguehelm.uti.json b/src/module/uti/ancientroguehelm.uti.json similarity index 100% rename from src/mod/uti/ancientroguehelm.uti.json rename to src/module/uti/ancientroguehelm.uti.json diff --git a/src/mod/uti/ancientshogun001.uti.json b/src/module/uti/ancientshogun001.uti.json similarity index 100% rename from src/mod/uti/ancientshogun001.uti.json rename to src/module/uti/ancientshogun001.uti.json diff --git a/src/mod/uti/ancientshogun002.uti.json b/src/module/uti/ancientshogun002.uti.json similarity index 100% rename from src/mod/uti/ancientshogun002.uti.json rename to src/module/uti/ancientshogun002.uti.json diff --git a/src/mod/uti/ancientshogunamm.uti.json b/src/module/uti/ancientshogunamm.uti.json similarity index 100% rename from src/mod/uti/ancientshogunamm.uti.json rename to src/module/uti/ancientshogunamm.uti.json diff --git a/src/mod/uti/ancientshogunarm.uti.json b/src/module/uti/ancientshogunarm.uti.json similarity index 100% rename from src/mod/uti/ancientshogunarm.uti.json rename to src/module/uti/ancientshogunarm.uti.json diff --git a/src/mod/uti/ancientshogungau.uti.json b/src/module/uti/ancientshogungau.uti.json similarity index 100% rename from src/mod/uti/ancientshogungau.uti.json rename to src/module/uti/ancientshogungau.uti.json diff --git a/src/mod/uti/ancientshogunhel.uti.json b/src/module/uti/ancientshogunhel.uti.json similarity index 100% rename from src/mod/uti/ancientshogunhel.uti.json rename to src/module/uti/ancientshogunhel.uti.json diff --git a/src/mod/uti/ancientwarrio001.uti.json b/src/module/uti/ancientwarrio001.uti.json similarity index 100% rename from src/mod/uti/ancientwarrio001.uti.json rename to src/module/uti/ancientwarrio001.uti.json diff --git a/src/mod/uti/angekey001.uti.json b/src/module/uti/angekey001.uti.json similarity index 100% rename from src/mod/uti/angekey001.uti.json rename to src/module/uti/angekey001.uti.json diff --git a/src/mod/uti/angekey002.uti.json b/src/module/uti/angekey002.uti.json similarity index 100% rename from src/mod/uti/angekey002.uti.json rename to src/module/uti/angekey002.uti.json diff --git a/src/mod/uti/angelring.uti.json b/src/module/uti/angelring.uti.json similarity index 100% rename from src/mod/uti/angelring.uti.json rename to src/module/uti/angelring.uti.json diff --git a/src/mod/uti/anguisclaw.uti.json b/src/module/uti/anguisclaw.uti.json similarity index 100% rename from src/mod/uti/anguisclaw.uti.json rename to src/module/uti/anguisclaw.uti.json diff --git a/src/mod/uti/antiquespear.uti.json b/src/module/uti/antiquespear.uti.json similarity index 100% rename from src/mod/uti/antiquespear.uti.json rename to src/module/uti/antiquespear.uti.json diff --git a/src/mod/uti/armorofdarkness.uti.json b/src/module/uti/armorofdarkness.uti.json similarity index 100% rename from src/mod/uti/armorofdarkness.uti.json rename to src/module/uti/armorofdarkness.uti.json diff --git a/src/mod/uti/armoroffear.uti.json b/src/module/uti/armoroffear.uti.json similarity index 100% rename from src/mod/uti/armoroffear.uti.json rename to src/module/uti/armoroffear.uti.json diff --git a/src/mod/uti/armoroffebrith.uti.json b/src/module/uti/armoroffebrith.uti.json similarity index 100% rename from src/mod/uti/armoroffebrith.uti.json rename to src/module/uti/armoroffebrith.uti.json diff --git a/src/mod/uti/armorofseduction.uti.json b/src/module/uti/armorofseduction.uti.json similarity index 100% rename from src/mod/uti/armorofseduction.uti.json rename to src/module/uti/armorofseduction.uti.json diff --git a/src/mod/uti/armorofthelich.uti.json b/src/module/uti/armorofthelich.uti.json similarity index 100% rename from src/mod/uti/armorofthelich.uti.json rename to src/module/uti/armorofthelich.uti.json diff --git a/src/mod/uti/armorofthorns.uti.json b/src/module/uti/armorofthorns.uti.json similarity index 100% rename from src/mod/uti/armorofthorns.uti.json rename to src/module/uti/armorofthorns.uti.json diff --git a/src/mod/uti/armoroftoli.uti.json b/src/module/uti/armoroftoli.uti.json similarity index 100% rename from src/mod/uti/armoroftoli.uti.json rename to src/module/uti/armoroftoli.uti.json diff --git a/src/mod/uti/assassidagger.uti.json b/src/module/uti/assassidagger.uti.json similarity index 100% rename from src/mod/uti/assassidagger.uti.json rename to src/module/uti/assassidagger.uti.json diff --git a/src/mod/uti/assassinacid.uti.json b/src/module/uti/assassinacid.uti.json similarity index 100% rename from src/mod/uti/assassinacid.uti.json rename to src/module/uti/assassinacid.uti.json diff --git a/src/mod/uti/assassinbow.uti.json b/src/module/uti/assassinbow.uti.json similarity index 100% rename from src/mod/uti/assassinbow.uti.json rename to src/module/uti/assassinbow.uti.json diff --git a/src/mod/uti/assassincptkey.uti.json b/src/module/uti/assassincptkey.uti.json similarity index 100% rename from src/mod/uti/assassincptkey.uti.json rename to src/module/uti/assassincptkey.uti.json diff --git a/src/mod/uti/assassinhelm.uti.json b/src/module/uti/assassinhelm.uti.json similarity index 100% rename from src/mod/uti/assassinhelm.uti.json rename to src/module/uti/assassinhelm.uti.json diff --git a/src/mod/uti/assassinshort.uti.json b/src/module/uti/assassinshort.uti.json similarity index 100% rename from src/mod/uti/assassinshort.uti.json rename to src/module/uti/assassinshort.uti.json diff --git a/src/mod/uti/assassintunic.uti.json b/src/module/uti/assassintunic.uti.json similarity index 100% rename from src/mod/uti/assassintunic.uti.json rename to src/module/uti/assassintunic.uti.json diff --git a/src/mod/uti/assassintunic001.uti.json b/src/module/uti/assassintunic001.uti.json similarity index 100% rename from src/mod/uti/assassintunic001.uti.json rename to src/module/uti/assassintunic001.uti.json diff --git a/src/mod/uti/asykey.uti.json b/src/module/uti/asykey.uti.json similarity index 100% rename from src/mod/uti/asykey.uti.json rename to src/module/uti/asykey.uti.json diff --git a/src/mod/uti/asyrianaxe.uti.json b/src/module/uti/asyrianaxe.uti.json similarity index 100% rename from src/mod/uti/asyrianaxe.uti.json rename to src/module/uti/asyrianaxe.uti.json diff --git a/src/mod/uti/asyrianbolt.uti.json b/src/module/uti/asyrianbolt.uti.json similarity index 100% rename from src/mod/uti/asyrianbolt.uti.json rename to src/module/uti/asyrianbolt.uti.json diff --git a/src/mod/uti/asyriancrossbow.uti.json b/src/module/uti/asyriancrossbow.uti.json similarity index 100% rename from src/mod/uti/asyriancrossbow.uti.json rename to src/module/uti/asyriancrossbow.uti.json diff --git a/src/mod/uti/asyriandoubleaxe.uti.json b/src/module/uti/asyriandoubleaxe.uti.json similarity index 100% rename from src/mod/uti/asyriandoubleaxe.uti.json rename to src/module/uti/asyriandoubleaxe.uti.json diff --git a/src/mod/uti/asyrianholymanar.uti.json b/src/module/uti/asyrianholymanar.uti.json similarity index 100% rename from src/mod/uti/asyrianholymanar.uti.json rename to src/module/uti/asyrianholymanar.uti.json diff --git a/src/mod/uti/asyrianholymanhe.uti.json b/src/module/uti/asyrianholymanhe.uti.json similarity index 100% rename from src/mod/uti/asyrianholymanhe.uti.json rename to src/module/uti/asyrianholymanhe.uti.json diff --git a/src/mod/uti/asyrianholyscyth.uti.json b/src/module/uti/asyrianholyscyth.uti.json similarity index 100% rename from src/mod/uti/asyrianholyscyth.uti.json rename to src/module/uti/asyrianholyscyth.uti.json diff --git a/src/mod/uti/asyrianladyarmor.uti.json b/src/module/uti/asyrianladyarmor.uti.json similarity index 100% rename from src/mod/uti/asyrianladyarmor.uti.json rename to src/module/uti/asyrianladyarmor.uti.json diff --git a/src/mod/uti/asyrianmasterarm.uti.json b/src/module/uti/asyrianmasterarm.uti.json similarity index 100% rename from src/mod/uti/asyrianmasterarm.uti.json rename to src/module/uti/asyrianmasterarm.uti.json diff --git a/src/mod/uti/asyrianmorningst.uti.json b/src/module/uti/asyrianmorningst.uti.json similarity index 100% rename from src/mod/uti/asyrianmorningst.uti.json rename to src/module/uti/asyrianmorningst.uti.json diff --git a/src/mod/uti/asyriannoblea001.uti.json b/src/module/uti/asyriannoblea001.uti.json similarity index 100% rename from src/mod/uti/asyriannoblea001.uti.json rename to src/module/uti/asyriannoblea001.uti.json diff --git a/src/mod/uti/asyriannoblearmo.uti.json b/src/module/uti/asyriannoblearmo.uti.json similarity index 100% rename from src/mod/uti/asyriannoblearmo.uti.json rename to src/module/uti/asyriannoblearmo.uti.json diff --git a/src/mod/uti/asyriannoblerobe.uti.json b/src/module/uti/asyriannoblerobe.uti.json similarity index 100% rename from src/mod/uti/asyriannoblerobe.uti.json rename to src/module/uti/asyriannoblerobe.uti.json diff --git a/src/mod/uti/asyrianreddragon.uti.json b/src/module/uti/asyrianreddragon.uti.json similarity index 100% rename from src/mod/uti/asyrianreddragon.uti.json rename to src/module/uti/asyrianreddragon.uti.json diff --git a/src/mod/uti/asyrianshield.uti.json b/src/module/uti/asyrianshield.uti.json similarity index 100% rename from src/mod/uti/asyrianshield.uti.json rename to src/module/uti/asyrianshield.uti.json diff --git a/src/mod/uti/asyrianskin.uti.json b/src/module/uti/asyrianskin.uti.json similarity index 100% rename from src/mod/uti/asyrianskin.uti.json rename to src/module/uti/asyrianskin.uti.json diff --git a/src/mod/uti/asyrianskin001.uti.json b/src/module/uti/asyrianskin001.uti.json similarity index 100% rename from src/mod/uti/asyrianskin001.uti.json rename to src/module/uti/asyrianskin001.uti.json diff --git a/src/mod/uti/asyrianspear.uti.json b/src/module/uti/asyrianspear.uti.json similarity index 100% rename from src/mod/uti/asyrianspear.uti.json rename to src/module/uti/asyrianspear.uti.json diff --git a/src/mod/uti/asyrianstaff.uti.json b/src/module/uti/asyrianstaff.uti.json similarity index 100% rename from src/mod/uti/asyrianstaff.uti.json rename to src/module/uti/asyrianstaff.uti.json diff --git a/src/mod/uti/asyrianwarrio001.uti.json b/src/module/uti/asyrianwarrio001.uti.json similarity index 100% rename from src/mod/uti/asyrianwarrio001.uti.json rename to src/module/uti/asyrianwarrio001.uti.json diff --git a/src/mod/uti/asyrianwarrio002.uti.json b/src/module/uti/asyrianwarrio002.uti.json similarity index 100% rename from src/mod/uti/asyrianwarrio002.uti.json rename to src/module/uti/asyrianwarrio002.uti.json diff --git a/src/mod/uti/asyrianwarriorar.uti.json b/src/module/uti/asyrianwarriorar.uti.json similarity index 100% rename from src/mod/uti/asyrianwarriorar.uti.json rename to src/module/uti/asyrianwarriorar.uti.json diff --git a/src/mod/uti/asyrianwarriorhe.uti.json b/src/module/uti/asyrianwarriorhe.uti.json similarity index 100% rename from src/mod/uti/asyrianwarriorhe.uti.json rename to src/module/uti/asyrianwarriorhe.uti.json diff --git a/src/mod/uti/atlantian.uti.json b/src/module/uti/atlantian.uti.json similarity index 100% rename from src/mod/uti/atlantian.uti.json rename to src/module/uti/atlantian.uti.json diff --git a/src/mod/uti/atlantiankata001.uti.json b/src/module/uti/atlantiankata001.uti.json similarity index 100% rename from src/mod/uti/atlantiankata001.uti.json rename to src/module/uti/atlantiankata001.uti.json diff --git a/src/mod/uti/atlantiankata002.uti.json b/src/module/uti/atlantiankata002.uti.json similarity index 100% rename from src/mod/uti/atlantiankata002.uti.json rename to src/module/uti/atlantiankata002.uti.json diff --git a/src/mod/uti/atlantiankatana.uti.json b/src/module/uti/atlantiankatana.uti.json similarity index 100% rename from src/mod/uti/atlantiankatana.uti.json rename to src/module/uti/atlantiankatana.uti.json diff --git a/src/mod/uti/atlantianstaff.uti.json b/src/module/uti/atlantianstaff.uti.json similarity index 100% rename from src/mod/uti/atlantianstaff.uti.json rename to src/module/uti/atlantianstaff.uti.json diff --git a/src/mod/uti/atlantisstaff.uti.json b/src/module/uti/atlantisstaff.uti.json similarity index 100% rename from src/mod/uti/atlantisstaff.uti.json rename to src/module/uti/atlantisstaff.uti.json diff --git a/src/mod/uti/atlclericarmor.uti.json b/src/module/uti/atlclericarmor.uti.json similarity index 100% rename from src/mod/uti/atlclericarmor.uti.json rename to src/module/uti/atlclericarmor.uti.json diff --git a/src/mod/uti/atlmace.uti.json b/src/module/uti/atlmace.uti.json similarity index 100% rename from src/mod/uti/atlmace.uti.json rename to src/module/uti/atlmace.uti.json diff --git a/src/mod/uti/atlportstone.uti.json b/src/module/uti/atlportstone.uti.json similarity index 100% rename from src/mod/uti/atlportstone.uti.json rename to src/module/uti/atlportstone.uti.json diff --git a/src/mod/uti/atlrobe.uti.json b/src/module/uti/atlrobe.uti.json similarity index 100% rename from src/mod/uti/atlrobe.uti.json rename to src/module/uti/atlrobe.uti.json diff --git a/src/mod/uti/atlrobe001.uti.json b/src/module/uti/atlrobe001.uti.json similarity index 100% rename from src/mod/uti/atlrobe001.uti.json rename to src/module/uti/atlrobe001.uti.json diff --git a/src/mod/uti/autofollow.uti.json b/src/module/uti/autofollow.uti.json similarity index 100% rename from src/mod/uti/autofollow.uti.json rename to src/module/uti/autofollow.uti.json diff --git a/src/mod/uti/aw1d20.uti.json b/src/module/uti/aw1d20.uti.json similarity index 100% rename from src/mod/uti/aw1d20.uti.json rename to src/module/uti/aw1d20.uti.json diff --git a/src/mod/uti/awadamantiumhit.uti.json b/src/module/uti/awadamantiumhit.uti.json similarity index 100% rename from src/mod/uti/awadamantiumhit.uti.json rename to src/module/uti/awadamantiumhit.uti.json diff --git a/src/mod/uti/awammyofvera.uti.json b/src/module/uti/awammyofvera.uti.json similarity index 100% rename from src/mod/uti/awammyofvera.uti.json rename to src/module/uti/awammyofvera.uti.json diff --git a/src/mod/uti/awamuletofthemin.uti.json b/src/module/uti/awamuletofthemin.uti.json similarity index 100% rename from src/mod/uti/awamuletofthemin.uti.json rename to src/module/uti/awamuletofthemin.uti.json diff --git a/src/mod/uti/awapprenticebrac.uti.json b/src/module/uti/awapprenticebrac.uti.json similarity index 100% rename from src/mod/uti/awapprenticebrac.uti.json rename to src/module/uti/awapprenticebrac.uti.json diff --git a/src/mod/uti/awapprenticerobe.uti.json b/src/module/uti/awapprenticerobe.uti.json similarity index 100% rename from src/mod/uti/awapprenticerobe.uti.json rename to src/module/uti/awapprenticerobe.uti.json diff --git a/src/mod/uti/awarmorofshiftin.uti.json b/src/module/uti/awarmorofshiftin.uti.json similarity index 100% rename from src/mod/uti/awarmorofshiftin.uti.json rename to src/module/uti/awarmorofshiftin.uti.json diff --git a/src/mod/uti/awarmorofthedivi.uti.json b/src/module/uti/awarmorofthedivi.uti.json similarity index 100% rename from src/mod/uti/awarmorofthedivi.uti.json rename to src/module/uti/awarmorofthedivi.uti.json diff --git a/src/mod/uti/awarmoroftheunde.uti.json b/src/module/uti/awarmoroftheunde.uti.json similarity index 100% rename from src/mod/uti/awarmoroftheunde.uti.json rename to src/module/uti/awarmoroftheunde.uti.json diff --git a/src/mod/uti/awarrowoffebrith.uti.json b/src/module/uti/awarrowoffebrith.uti.json similarity index 100% rename from src/mod/uti/awarrowoffebrith.uti.json rename to src/module/uti/awarrowoffebrith.uti.json diff --git a/src/mod/uti/awbeholderbite.uti.json b/src/module/uti/awbeholderbite.uti.json similarity index 100% rename from src/mod/uti/awbeholderbite.uti.json rename to src/module/uti/awbeholderbite.uti.json diff --git a/src/mod/uti/awbeholdercloak.uti.json b/src/module/uti/awbeholdercloak.uti.json similarity index 100% rename from src/mod/uti/awbeholdercloak.uti.json rename to src/module/uti/awbeholdercloak.uti.json diff --git a/src/mod/uti/awbeholdereye.uti.json b/src/module/uti/awbeholdereye.uti.json similarity index 100% rename from src/mod/uti/awbeholdereye.uti.json rename to src/module/uti/awbeholdereye.uti.json diff --git a/src/mod/uti/awbeholdereyebal.uti.json b/src/module/uti/awbeholdereyebal.uti.json similarity index 100% rename from src/mod/uti/awbeholdereyebal.uti.json rename to src/module/uti/awbeholdereyebal.uti.json diff --git a/src/mod/uti/awbeholdergas001.uti.json b/src/module/uti/awbeholdergas001.uti.json similarity index 100% rename from src/mod/uti/awbeholdergas001.uti.json rename to src/module/uti/awbeholdergas001.uti.json diff --git a/src/mod/uti/awbeholdergash.uti.json b/src/module/uti/awbeholdergash.uti.json similarity index 100% rename from src/mod/uti/awbeholdergash.uti.json rename to src/module/uti/awbeholdergash.uti.json diff --git a/src/mod/uti/awbeholderpotion.uti.json b/src/module/uti/awbeholderpotion.uti.json similarity index 100% rename from src/mod/uti/awbeholderpotion.uti.json rename to src/module/uti/awbeholderpotion.uti.json diff --git a/src/mod/uti/awbeholderskin.uti.json b/src/module/uti/awbeholderskin.uti.json similarity index 100% rename from src/mod/uti/awbeholderskin.uti.json rename to src/module/uti/awbeholderskin.uti.json diff --git a/src/mod/uti/awbeltoftrollsca.uti.json b/src/module/uti/awbeltoftrollsca.uti.json similarity index 100% rename from src/mod/uti/awbeltoftrollsca.uti.json rename to src/module/uti/awbeltoftrollsca.uti.json diff --git a/src/mod/uti/awblessedstone.uti.json b/src/module/uti/awblessedstone.uti.json similarity index 100% rename from src/mod/uti/awblessedstone.uti.json rename to src/module/uti/awblessedstone.uti.json diff --git a/src/mod/uti/awbootsofvera.uti.json b/src/module/uti/awbootsofvera.uti.json similarity index 100% rename from src/mod/uti/awbootsofvera.uti.json rename to src/module/uti/awbootsofvera.uti.json diff --git a/src/mod/uti/awcapturescroll.uti.json b/src/module/uti/awcapturescroll.uti.json similarity index 100% rename from src/mod/uti/awcapturescroll.uti.json rename to src/module/uti/awcapturescroll.uti.json diff --git a/src/mod/uti/awcelolaswhip.uti.json b/src/module/uti/awcelolaswhip.uti.json similarity index 100% rename from src/mod/uti/awcelolaswhip.uti.json rename to src/module/uti/awcelolaswhip.uti.json diff --git a/src/mod/uti/awdivineburst.uti.json b/src/module/uti/awdivineburst.uti.json similarity index 100% rename from src/mod/uti/awdivineburst.uti.json rename to src/module/uti/awdivineburst.uti.json diff --git a/src/mod/uti/awdolly.uti.json b/src/module/uti/awdolly.uti.json similarity index 100% rename from src/mod/uti/awdolly.uti.json rename to src/module/uti/awdolly.uti.json diff --git a/src/mod/uti/awdraineddarksto.uti.json b/src/module/uti/awdraineddarksto.uti.json similarity index 100% rename from src/mod/uti/awdraineddarksto.uti.json rename to src/module/uti/awdraineddarksto.uti.json diff --git a/src/mod/uti/awdridereye.uti.json b/src/module/uti/awdridereye.uti.json similarity index 100% rename from src/mod/uti/awdridereye.uti.json rename to src/module/uti/awdridereye.uti.json diff --git a/src/mod/uti/awdriderhelm.uti.json b/src/module/uti/awdriderhelm.uti.json similarity index 100% rename from src/mod/uti/awdriderhelm.uti.json rename to src/module/uti/awdriderhelm.uti.json diff --git a/src/mod/uti/awdriderhvyarmor.uti.json b/src/module/uti/awdriderhvyarmor.uti.json similarity index 100% rename from src/mod/uti/awdriderhvyarmor.uti.json rename to src/module/uti/awdriderhvyarmor.uti.json diff --git a/src/mod/uti/awdriderscythe.uti.json b/src/module/uti/awdriderscythe.uti.json similarity index 100% rename from src/mod/uti/awdriderscythe.uti.json rename to src/module/uti/awdriderscythe.uti.json diff --git a/src/mod/uti/awdrowarrow.uti.json b/src/module/uti/awdrowarrow.uti.json similarity index 100% rename from src/mod/uti/awdrowarrow.uti.json rename to src/module/uti/awdrowarrow.uti.json diff --git a/src/mod/uti/awdrowassassinar.uti.json b/src/module/uti/awdrowassassinar.uti.json similarity index 100% rename from src/mod/uti/awdrowassassinar.uti.json rename to src/module/uti/awdrowassassinar.uti.json diff --git a/src/mod/uti/awdrowboots.uti.json b/src/module/uti/awdrowboots.uti.json similarity index 100% rename from src/mod/uti/awdrowboots.uti.json rename to src/module/uti/awdrowboots.uti.json diff --git a/src/mod/uti/awdrowbow.uti.json b/src/module/uti/awdrowbow.uti.json similarity index 100% rename from src/mod/uti/awdrowbow.uti.json rename to src/module/uti/awdrowbow.uti.json diff --git a/src/mod/uti/awdrowcloak.uti.json b/src/module/uti/awdrowcloak.uti.json similarity index 100% rename from src/mod/uti/awdrowcloak.uti.json rename to src/module/uti/awdrowcloak.uti.json diff --git a/src/mod/uti/awdrowdagger.uti.json b/src/module/uti/awdrowdagger.uti.json similarity index 100% rename from src/mod/uti/awdrowdagger.uti.json rename to src/module/uti/awdrowdagger.uti.json diff --git a/src/mod/uti/awdrowhalbred.uti.json b/src/module/uti/awdrowhalbred.uti.json similarity index 100% rename from src/mod/uti/awdrowhalbred.uti.json rename to src/module/uti/awdrowhalbred.uti.json diff --git a/src/mod/uti/awdrowheavyarmor.uti.json b/src/module/uti/awdrowheavyarmor.uti.json similarity index 100% rename from src/mod/uti/awdrowheavyarmor.uti.json rename to src/module/uti/awdrowheavyarmor.uti.json diff --git a/src/mod/uti/awdrowlongsword.uti.json b/src/module/uti/awdrowlongsword.uti.json similarity index 100% rename from src/mod/uti/awdrowlongsword.uti.json rename to src/module/uti/awdrowlongsword.uti.json diff --git a/src/mod/uti/awdrowprops.uti.json b/src/module/uti/awdrowprops.uti.json similarity index 100% rename from src/mod/uti/awdrowprops.uti.json rename to src/module/uti/awdrowprops.uti.json diff --git a/src/mod/uti/awdrowrapier.uti.json b/src/module/uti/awdrowrapier.uti.json similarity index 100% rename from src/mod/uti/awdrowrapier.uti.json rename to src/module/uti/awdrowrapier.uti.json diff --git a/src/mod/uti/awdrowscim.uti.json b/src/module/uti/awdrowscim.uti.json similarity index 100% rename from src/mod/uti/awdrowscim.uti.json rename to src/module/uti/awdrowscim.uti.json diff --git a/src/mod/uti/awdrowshortsw001.uti.json b/src/module/uti/awdrowshortsw001.uti.json similarity index 100% rename from src/mod/uti/awdrowshortsw001.uti.json rename to src/module/uti/awdrowshortsw001.uti.json diff --git a/src/mod/uti/awdrowshortsword.uti.json b/src/module/uti/awdrowshortsword.uti.json similarity index 100% rename from src/mod/uti/awdrowshortsword.uti.json rename to src/module/uti/awdrowshortsword.uti.json diff --git a/src/mod/uti/awdrowstaff.uti.json b/src/module/uti/awdrowstaff.uti.json similarity index 100% rename from src/mod/uti/awdrowstaff.uti.json rename to src/module/uti/awdrowstaff.uti.json diff --git a/src/mod/uti/awdrowstaff001.uti.json b/src/module/uti/awdrowstaff001.uti.json similarity index 100% rename from src/mod/uti/awdrowstaff001.uti.json rename to src/module/uti/awdrowstaff001.uti.json diff --git a/src/mod/uti/awdrowtwin.uti.json b/src/module/uti/awdrowtwin.uti.json similarity index 100% rename from src/mod/uti/awdrowtwin.uti.json rename to src/module/uti/awdrowtwin.uti.json diff --git a/src/mod/uti/awdrowtwin001.uti.json b/src/module/uti/awdrowtwin001.uti.json similarity index 100% rename from src/mod/uti/awdrowtwin001.uti.json rename to src/module/uti/awdrowtwin001.uti.json diff --git a/src/mod/uti/awdrowwhoreoutfi.uti.json b/src/module/uti/awdrowwhoreoutfi.uti.json similarity index 100% rename from src/mod/uti/awdrowwhoreoutfi.uti.json rename to src/module/uti/awdrowwhoreoutfi.uti.json diff --git a/src/mod/uti/awdrowwizardring.uti.json b/src/module/uti/awdrowwizardring.uti.json similarity index 100% rename from src/mod/uti/awdrowwizardring.uti.json rename to src/module/uti/awdrowwizardring.uti.json diff --git a/src/mod/uti/awdrowwizardrobe.uti.json b/src/module/uti/awdrowwizardrobe.uti.json similarity index 100% rename from src/mod/uti/awdrowwizardrobe.uti.json rename to src/module/uti/awdrowwizardrobe.uti.json diff --git a/src/mod/uti/awdrudocssheild.uti.json b/src/module/uti/awdrudocssheild.uti.json similarity index 100% rename from src/mod/uti/awdrudocssheild.uti.json rename to src/module/uti/awdrudocssheild.uti.json diff --git a/src/mod/uti/awdruidbuff.uti.json b/src/module/uti/awdruidbuff.uti.json similarity index 100% rename from src/mod/uti/awdruidbuff.uti.json rename to src/module/uti/awdruidbuff.uti.json diff --git a/src/mod/uti/aweggsplat.uti.json b/src/module/uti/aweggsplat.uti.json similarity index 100% rename from src/mod/uti/aweggsplat.uti.json rename to src/module/uti/aweggsplat.uti.json diff --git a/src/mod/uti/awelecticlock.uti.json b/src/module/uti/awelecticlock.uti.json similarity index 100% rename from src/mod/uti/awelecticlock.uti.json rename to src/module/uti/awelecticlock.uti.json diff --git a/src/mod/uti/aweyeofthebehold.uti.json b/src/module/uti/aweyeofthebehold.uti.json similarity index 100% rename from src/mod/uti/aweyeofthebehold.uti.json rename to src/module/uti/aweyeofthebehold.uti.json diff --git a/src/mod/uti/awfamilereyeball.uti.json b/src/module/uti/awfamilereyeball.uti.json similarity index 100% rename from src/mod/uti/awfamilereyeball.uti.json rename to src/module/uti/awfamilereyeball.uti.json diff --git a/src/mod/uti/awfistsofvera.uti.json b/src/module/uti/awfistsofvera.uti.json similarity index 100% rename from src/mod/uti/awfistsofvera.uti.json rename to src/module/uti/awfistsofvera.uti.json diff --git a/src/mod/uti/awgreatswordunde.uti.json b/src/module/uti/awgreatswordunde.uti.json similarity index 100% rename from src/mod/uti/awgreatswordunde.uti.json rename to src/module/uti/awgreatswordunde.uti.json diff --git a/src/mod/uti/awhalfbarbarmor.uti.json b/src/module/uti/awhalfbarbarmor.uti.json similarity index 100% rename from src/mod/uti/awhalfbarbarmor.uti.json rename to src/module/uti/awhalfbarbarmor.uti.json diff --git a/src/mod/uti/awheavyarmor.uti.json b/src/module/uti/awheavyarmor.uti.json similarity index 100% rename from src/mod/uti/awheavyarmor.uti.json rename to src/module/uti/awheavyarmor.uti.json diff --git a/src/mod/uti/awhelmoftoli.uti.json b/src/module/uti/awhelmoftoli.uti.json similarity index 100% rename from src/mod/uti/awhelmoftoli.uti.json rename to src/module/uti/awhelmoftoli.uti.json diff --git a/src/mod/uti/awkeytocelolas.uti.json b/src/module/uti/awkeytocelolas.uti.json similarity index 100% rename from src/mod/uti/awkeytocelolas.uti.json rename to src/module/uti/awkeytocelolas.uti.json diff --git a/src/mod/uti/awmagicalhit.uti.json b/src/module/uti/awmagicalhit.uti.json similarity index 100% rename from src/mod/uti/awmagicalhit.uti.json rename to src/module/uti/awmagicalhit.uti.json diff --git a/src/mod/uti/awminofist.uti.json b/src/module/uti/awminofist.uti.json similarity index 100% rename from src/mod/uti/awminofist.uti.json rename to src/module/uti/awminofist.uti.json diff --git a/src/mod/uti/awminoskin.uti.json b/src/module/uti/awminoskin.uti.json similarity index 100% rename from src/mod/uti/awminoskin.uti.json rename to src/module/uti/awminoskin.uti.json diff --git a/src/mod/uti/awminoslam.uti.json b/src/module/uti/awminoslam.uti.json similarity index 100% rename from src/mod/uti/awminoslam.uti.json rename to src/module/uti/awminoslam.uti.json diff --git a/src/mod/uti/aworbofdarkness.uti.json b/src/module/uti/aworbofdarkness.uti.json similarity index 100% rename from src/mod/uti/aworbofdarkness.uti.json rename to src/module/uti/aworbofdarkness.uti.json diff --git a/src/mod/uti/awplaguedart.uti.json b/src/module/uti/awplaguedart.uti.json similarity index 100% rename from src/mod/uti/awplaguedart.uti.json rename to src/module/uti/awplaguedart.uti.json diff --git a/src/mod/uti/awquestitem.uti.json b/src/module/uti/awquestitem.uti.json similarity index 100% rename from src/mod/uti/awquestitem.uti.json rename to src/module/uti/awquestitem.uti.json diff --git a/src/mod/uti/awrangerbracer.uti.json b/src/module/uti/awrangerbracer.uti.json similarity index 100% rename from src/mod/uti/awrangerbracer.uti.json rename to src/module/uti/awrangerbracer.uti.json diff --git a/src/mod/uti/awregenpotion.uti.json b/src/module/uti/awregenpotion.uti.json similarity index 100% rename from src/mod/uti/awregenpotion.uti.json rename to src/module/uti/awregenpotion.uti.json diff --git a/src/mod/uti/awringofbone.uti.json b/src/module/uti/awringofbone.uti.json similarity index 100% rename from src/mod/uti/awringofbone.uti.json rename to src/module/uti/awringofbone.uti.json diff --git a/src/mod/uti/awringofveraplay.uti.json b/src/module/uti/awringofveraplay.uti.json similarity index 100% rename from src/mod/uti/awringofveraplay.uti.json rename to src/module/uti/awringofveraplay.uti.json diff --git a/src/mod/uti/awrune001.uti.json b/src/module/uti/awrune001.uti.json similarity index 100% rename from src/mod/uti/awrune001.uti.json rename to src/module/uti/awrune001.uti.json diff --git a/src/mod/uti/awrune002.uti.json b/src/module/uti/awrune002.uti.json similarity index 100% rename from src/mod/uti/awrune002.uti.json rename to src/module/uti/awrune002.uti.json diff --git a/src/mod/uti/awrune003.uti.json b/src/module/uti/awrune003.uti.json similarity index 100% rename from src/mod/uti/awrune003.uti.json rename to src/module/uti/awrune003.uti.json diff --git a/src/mod/uti/awrune004.uti.json b/src/module/uti/awrune004.uti.json similarity index 100% rename from src/mod/uti/awrune004.uti.json rename to src/module/uti/awrune004.uti.json diff --git a/src/mod/uti/awsheildofbone.uti.json b/src/module/uti/awsheildofbone.uti.json similarity index 100% rename from src/mod/uti/awsheildofbone.uti.json rename to src/module/uti/awsheildofbone.uti.json diff --git a/src/mod/uti/awshifterbastard.uti.json b/src/module/uti/awshifterbastard.uti.json similarity index 100% rename from src/mod/uti/awshifterbastard.uti.json rename to src/module/uti/awshifterbastard.uti.json diff --git a/src/mod/uti/awshifterdrider.uti.json b/src/module/uti/awshifterdrider.uti.json similarity index 100% rename from src/mod/uti/awshifterdrider.uti.json rename to src/module/uti/awshifterdrider.uti.json diff --git a/src/mod/uti/awshiftergeatswo.uti.json b/src/module/uti/awshiftergeatswo.uti.json similarity index 100% rename from src/mod/uti/awshiftergeatswo.uti.json rename to src/module/uti/awshiftergeatswo.uti.json diff --git a/src/mod/uti/awshifterlongswo.uti.json b/src/module/uti/awshifterlongswo.uti.json similarity index 100% rename from src/mod/uti/awshifterlongswo.uti.json rename to src/module/uti/awshifterlongswo.uti.json diff --git a/src/mod/uti/awshifterminot.uti.json b/src/module/uti/awshifterminot.uti.json similarity index 100% rename from src/mod/uti/awshifterminot.uti.json rename to src/module/uti/awshifterminot.uti.json diff --git a/src/mod/uti/awshiftershort.uti.json b/src/module/uti/awshiftershort.uti.json similarity index 100% rename from src/mod/uti/awshiftershort.uti.json rename to src/module/uti/awshiftershort.uti.json diff --git a/src/mod/uti/awshiftertwin.uti.json b/src/module/uti/awshiftertwin.uti.json similarity index 100% rename from src/mod/uti/awshiftertwin.uti.json rename to src/module/uti/awshiftertwin.uti.json diff --git a/src/mod/uti/awskeletonaxe.uti.json b/src/module/uti/awskeletonaxe.uti.json similarity index 100% rename from src/mod/uti/awskeletonaxe.uti.json rename to src/module/uti/awskeletonaxe.uti.json diff --git a/src/mod/uti/awskeletongreata.uti.json b/src/module/uti/awskeletongreata.uti.json similarity index 100% rename from src/mod/uti/awskeletongreata.uti.json rename to src/module/uti/awskeletongreata.uti.json diff --git a/src/mod/uti/awskeletonhelm.uti.json b/src/module/uti/awskeletonhelm.uti.json similarity index 100% rename from src/mod/uti/awskeletonhelm.uti.json rename to src/module/uti/awskeletonhelm.uti.json diff --git a/src/mod/uti/awspawnclaw.uti.json b/src/module/uti/awspawnclaw.uti.json similarity index 100% rename from src/mod/uti/awspawnclaw.uti.json rename to src/module/uti/awspawnclaw.uti.json diff --git a/src/mod/uti/awspiderbelt.uti.json b/src/module/uti/awspiderbelt.uti.json similarity index 100% rename from src/mod/uti/awspiderbelt.uti.json rename to src/module/uti/awspiderbelt.uti.json diff --git a/src/mod/uti/awspideregg.uti.json b/src/module/uti/awspideregg.uti.json similarity index 100% rename from src/mod/uti/awspideregg.uti.json rename to src/module/uti/awspideregg.uti.json diff --git a/src/mod/uti/awstaffofbone.uti.json b/src/module/uti/awstaffofbone.uti.json similarity index 100% rename from src/mod/uti/awstaffofbone.uti.json rename to src/module/uti/awstaffofbone.uti.json diff --git a/src/mod/uti/awtolislongsword.uti.json b/src/module/uti/awtolislongsword.uti.json similarity index 100% rename from src/mod/uti/awtolislongsword.uti.json rename to src/module/uti/awtolislongsword.uti.json diff --git a/src/mod/uti/awtolissheild.uti.json b/src/module/uti/awtolissheild.uti.json similarity index 100% rename from src/mod/uti/awtolissheild.uti.json rename to src/module/uti/awtolissheild.uti.json diff --git a/src/mod/uti/awtorncloak.uti.json b/src/module/uti/awtorncloak.uti.json similarity index 100% rename from src/mod/uti/awtorncloak.uti.json rename to src/module/uti/awtorncloak.uti.json diff --git a/src/mod/uti/awtrollbite.uti.json b/src/module/uti/awtrollbite.uti.json similarity index 100% rename from src/mod/uti/awtrollbite.uti.json rename to src/module/uti/awtrollbite.uti.json diff --git a/src/mod/uti/awtrollbiteacid.uti.json b/src/module/uti/awtrollbiteacid.uti.json similarity index 100% rename from src/mod/uti/awtrollbiteacid.uti.json rename to src/module/uti/awtrollbiteacid.uti.json diff --git a/src/mod/uti/awtrollbugger.uti.json b/src/module/uti/awtrollbugger.uti.json similarity index 100% rename from src/mod/uti/awtrollbugger.uti.json rename to src/module/uti/awtrollbugger.uti.json diff --git a/src/mod/uti/awtrollcraws.uti.json b/src/module/uti/awtrollcraws.uti.json similarity index 100% rename from src/mod/uti/awtrollcraws.uti.json rename to src/module/uti/awtrollcraws.uti.json diff --git a/src/mod/uti/awtrollgore.uti.json b/src/module/uti/awtrollgore.uti.json similarity index 100% rename from src/mod/uti/awtrollgore.uti.json rename to src/module/uti/awtrollgore.uti.json diff --git a/src/mod/uti/awtrollgoreacid.uti.json b/src/module/uti/awtrollgoreacid.uti.json similarity index 100% rename from src/mod/uti/awtrollgoreacid.uti.json rename to src/module/uti/awtrollgoreacid.uti.json diff --git a/src/mod/uti/awtrollkur.uti.json b/src/module/uti/awtrollkur.uti.json similarity index 100% rename from src/mod/uti/awtrollkur.uti.json rename to src/module/uti/awtrollkur.uti.json diff --git a/src/mod/uti/awtrollscales.uti.json b/src/module/uti/awtrollscales.uti.json similarity index 100% rename from src/mod/uti/awtrollscales.uti.json rename to src/module/uti/awtrollscales.uti.json diff --git a/src/mod/uti/awtrollskinsling.uti.json b/src/module/uti/awtrollskinsling.uti.json similarity index 100% rename from src/mod/uti/awtrollskinsling.uti.json rename to src/module/uti/awtrollskinsling.uti.json diff --git a/src/mod/uti/awtrollskinslnp.uti.json b/src/module/uti/awtrollskinslnp.uti.json similarity index 100% rename from src/mod/uti/awtrollskinslnp.uti.json rename to src/module/uti/awtrollskinslnp.uti.json diff --git a/src/mod/uti/awtrollslam.uti.json b/src/module/uti/awtrollslam.uti.json similarity index 100% rename from src/mod/uti/awtrollslam.uti.json rename to src/module/uti/awtrollslam.uti.json diff --git a/src/mod/uti/awtrollslam001.uti.json b/src/module/uti/awtrollslam001.uti.json similarity index 100% rename from src/mod/uti/awtrollslam001.uti.json rename to src/module/uti/awtrollslam001.uti.json diff --git a/src/mod/uti/awtrollsring.uti.json b/src/module/uti/awtrollsring.uti.json similarity index 100% rename from src/mod/uti/awtrollsring.uti.json rename to src/module/uti/awtrollsring.uti.json diff --git a/src/mod/uti/awundeadammy.uti.json b/src/module/uti/awundeadammy.uti.json similarity index 100% rename from src/mod/uti/awundeadammy.uti.json rename to src/module/uti/awundeadammy.uti.json diff --git a/src/mod/uti/awundeadblade.uti.json b/src/module/uti/awundeadblade.uti.json similarity index 100% rename from src/mod/uti/awundeadblade.uti.json rename to src/module/uti/awundeadblade.uti.json diff --git a/src/mod/uti/awundeaddagger.uti.json b/src/module/uti/awundeaddagger.uti.json similarity index 100% rename from src/mod/uti/awundeaddagger.uti.json rename to src/module/uti/awundeaddagger.uti.json diff --git a/src/mod/uti/awundeadkama.uti.json b/src/module/uti/awundeadkama.uti.json similarity index 100% rename from src/mod/uti/awundeadkama.uti.json rename to src/module/uti/awundeadkama.uti.json diff --git a/src/mod/uti/awundeadlong.uti.json b/src/module/uti/awundeadlong.uti.json similarity index 100% rename from src/mod/uti/awundeadlong.uti.json rename to src/module/uti/awundeadlong.uti.json diff --git a/src/mod/uti/awvenasrapier.uti.json b/src/module/uti/awvenasrapier.uti.json similarity index 100% rename from src/mod/uti/awvenasrapier.uti.json rename to src/module/uti/awvenasrapier.uti.json diff --git a/src/mod/uti/awveradragon.uti.json b/src/module/uti/awveradragon.uti.json similarity index 100% rename from src/mod/uti/awveradragon.uti.json rename to src/module/uti/awveradragon.uti.json diff --git a/src/mod/uti/awveradragonbite.uti.json b/src/module/uti/awveradragonbite.uti.json similarity index 100% rename from src/mod/uti/awveradragonbite.uti.json rename to src/module/uti/awveradragonbite.uti.json diff --git a/src/mod/uti/awveradragonclaw.uti.json b/src/module/uti/awveradragonclaw.uti.json similarity index 100% rename from src/mod/uti/awveradragonclaw.uti.json rename to src/module/uti/awveradragonclaw.uti.json diff --git a/src/mod/uti/awveraguardar001.uti.json b/src/module/uti/awveraguardar001.uti.json similarity index 100% rename from src/mod/uti/awveraguardar001.uti.json rename to src/module/uti/awveraguardar001.uti.json diff --git a/src/mod/uti/awveraguardarmon.uti.json b/src/module/uti/awveraguardarmon.uti.json similarity index 100% rename from src/mod/uti/awveraguardarmon.uti.json rename to src/module/uti/awveraguardarmon.uti.json diff --git a/src/mod/uti/awveraguardarmor.uti.json b/src/module/uti/awveraguardarmor.uti.json similarity index 100% rename from src/mod/uti/awveraguardarmor.uti.json rename to src/module/uti/awveraguardarmor.uti.json diff --git a/src/mod/uti/awveraguardaxe.uti.json b/src/module/uti/awveraguardaxe.uti.json similarity index 100% rename from src/mod/uti/awveraguardaxe.uti.json rename to src/module/uti/awveraguardaxe.uti.json diff --git a/src/mod/uti/awveraguardhelm.uti.json b/src/module/uti/awveraguardhelm.uti.json similarity index 100% rename from src/mod/uti/awveraguardhelm.uti.json rename to src/module/uti/awveraguardhelm.uti.json diff --git a/src/mod/uti/awveraguardsheil.uti.json b/src/module/uti/awveraguardsheil.uti.json similarity index 100% rename from src/mod/uti/awveraguardsheil.uti.json rename to src/module/uti/awveraguardsheil.uti.json diff --git a/src/mod/uti/awveraguardsword.uti.json b/src/module/uti/awveraguardsword.uti.json similarity index 100% rename from src/mod/uti/awveraguardsword.uti.json rename to src/module/uti/awveraguardsword.uti.json diff --git a/src/mod/uti/awveraring.uti.json b/src/module/uti/awveraring.uti.json similarity index 100% rename from src/mod/uti/awveraring.uti.json rename to src/module/uti/awveraring.uti.json diff --git a/src/mod/uti/awveraspawnbite.uti.json b/src/module/uti/awveraspawnbite.uti.json similarity index 100% rename from src/mod/uti/awveraspawnbite.uti.json rename to src/module/uti/awveraspawnbite.uti.json diff --git a/src/mod/uti/awveraspawnclaw.uti.json b/src/module/uti/awveraspawnclaw.uti.json similarity index 100% rename from src/mod/uti/awveraspawnclaw.uti.json rename to src/module/uti/awveraspawnclaw.uti.json diff --git a/src/mod/uti/awveraspawnhide.uti.json b/src/module/uti/awveraspawnhide.uti.json similarity index 100% rename from src/mod/uti/awveraspawnhide.uti.json rename to src/module/uti/awveraspawnhide.uti.json diff --git a/src/mod/uti/awwhorekey.uti.json b/src/module/uti/awwhorekey.uti.json similarity index 100% rename from src/mod/uti/awwhorekey.uti.json rename to src/module/uti/awwhorekey.uti.json diff --git a/src/mod/uti/awworkergloves.uti.json b/src/module/uti/awworkergloves.uti.json similarity index 100% rename from src/mod/uti/awworkergloves.uti.json rename to src/module/uti/awworkergloves.uti.json diff --git a/src/mod/uti/axeoftheancientg.uti.json b/src/module/uti/axeoftheancientg.uti.json similarity index 100% rename from src/mod/uti/axeoftheancientg.uti.json rename to src/module/uti/axeoftheancientg.uti.json diff --git a/src/mod/uti/banditaxe.uti.json b/src/module/uti/banditaxe.uti.json similarity index 100% rename from src/mod/uti/banditaxe.uti.json rename to src/module/uti/banditaxe.uti.json diff --git a/src/mod/uti/banditrapier.uti.json b/src/module/uti/banditrapier.uti.json similarity index 100% rename from src/mod/uti/banditrapier.uti.json rename to src/module/uti/banditrapier.uti.json diff --git a/src/mod/uti/banditring.uti.json b/src/module/uti/banditring.uti.json similarity index 100% rename from src/mod/uti/banditring.uti.json rename to src/module/uti/banditring.uti.json diff --git a/src/mod/uti/banditskin.uti.json b/src/module/uti/banditskin.uti.json similarity index 100% rename from src/mod/uti/banditskin.uti.json rename to src/module/uti/banditskin.uti.json diff --git a/src/mod/uti/banditskin001.uti.json b/src/module/uti/banditskin001.uti.json similarity index 100% rename from src/mod/uti/banditskin001.uti.json rename to src/module/uti/banditskin001.uti.json diff --git a/src/mod/uti/banditskin002.uti.json b/src/module/uti/banditskin002.uti.json similarity index 100% rename from src/mod/uti/banditskin002.uti.json rename to src/module/uti/banditskin002.uti.json diff --git a/src/mod/uti/banditskin003.uti.json b/src/module/uti/banditskin003.uti.json similarity index 100% rename from src/mod/uti/banditskin003.uti.json rename to src/module/uti/banditskin003.uti.json diff --git a/src/mod/uti/banditstaff.uti.json b/src/module/uti/banditstaff.uti.json similarity index 100% rename from src/mod/uti/banditstaff.uti.json rename to src/module/uti/banditstaff.uti.json diff --git a/src/mod/uti/banditstools.uti.json b/src/module/uti/banditstools.uti.json similarity index 100% rename from src/mod/uti/banditstools.uti.json rename to src/module/uti/banditstools.uti.json diff --git a/src/mod/uti/barbarianbelt.uti.json b/src/module/uti/barbarianbelt.uti.json similarity index 100% rename from src/mod/uti/barbarianbelt.uti.json rename to src/module/uti/barbarianbelt.uti.json diff --git a/src/mod/uti/bardsummon.uti.json b/src/module/uti/bardsummon.uti.json similarity index 100% rename from src/mod/uti/bardsummon.uti.json rename to src/module/uti/bardsummon.uti.json diff --git a/src/mod/uti/basicimmunes.uti.json b/src/module/uti/basicimmunes.uti.json similarity index 100% rename from src/mod/uti/basicimmunes.uti.json rename to src/module/uti/basicimmunes.uti.json diff --git a/src/mod/uti/basicimmunes001.uti.json b/src/module/uti/basicimmunes001.uti.json similarity index 100% rename from src/mod/uti/basicimmunes001.uti.json rename to src/module/uti/basicimmunes001.uti.json diff --git a/src/mod/uti/batsblood.uti.json b/src/module/uti/batsblood.uti.json similarity index 100% rename from src/mod/uti/batsblood.uti.json rename to src/module/uti/batsblood.uti.json diff --git a/src/mod/uti/battelmencloak.uti.json b/src/module/uti/battelmencloak.uti.json similarity index 100% rename from src/mod/uti/battelmencloak.uti.json rename to src/module/uti/battelmencloak.uti.json diff --git a/src/mod/uti/battlebotsword.uti.json b/src/module/uti/battlebotsword.uti.json similarity index 100% rename from src/mod/uti/battlebotsword.uti.json rename to src/module/uti/battlebotsword.uti.json diff --git a/src/mod/uti/battlegolemhi001.uti.json b/src/module/uti/battlegolemhi001.uti.json similarity index 100% rename from src/mod/uti/battlegolemhi001.uti.json rename to src/module/uti/battlegolemhi001.uti.json diff --git a/src/mod/uti/battlegolemhi002.uti.json b/src/module/uti/battlegolemhi002.uti.json similarity index 100% rename from src/mod/uti/battlegolemhi002.uti.json rename to src/module/uti/battlegolemhi002.uti.json diff --git a/src/mod/uti/battlegolemhide.uti.json b/src/module/uti/battlegolemhide.uti.json similarity index 100% rename from src/mod/uti/battlegolemhide.uti.json rename to src/module/uti/battlegolemhide.uti.json diff --git a/src/mod/uti/battlegolemsl001.uti.json b/src/module/uti/battlegolemsl001.uti.json similarity index 100% rename from src/mod/uti/battlegolemsl001.uti.json rename to src/module/uti/battlegolemsl001.uti.json diff --git a/src/mod/uti/battlegolemsl002.uti.json b/src/module/uti/battlegolemsl002.uti.json similarity index 100% rename from src/mod/uti/battlegolemsl002.uti.json rename to src/module/uti/battlegolemsl002.uti.json diff --git a/src/mod/uti/battlegolemslam.uti.json b/src/module/uti/battlegolemslam.uti.json similarity index 100% rename from src/mod/uti/battlegolemslam.uti.json rename to src/module/uti/battlegolemslam.uti.json diff --git a/src/mod/uti/beer.uti.json b/src/module/uti/beer.uti.json similarity index 100% rename from src/mod/uti/beer.uti.json rename to src/module/uti/beer.uti.json diff --git a/src/mod/uti/beingrobe.uti.json b/src/module/uti/beingrobe.uti.json similarity index 100% rename from src/mod/uti/beingrobe.uti.json rename to src/module/uti/beingrobe.uti.json diff --git a/src/mod/uti/beltofjagang.uti.json b/src/module/uti/beltofjagang.uti.json similarity index 100% rename from src/mod/uti/beltofjagang.uti.json rename to src/module/uti/beltofjagang.uti.json diff --git a/src/mod/uti/beltofspellcraft.uti.json b/src/module/uti/beltofspellcraft.uti.json similarity index 100% rename from src/mod/uti/beltofspellcraft.uti.json rename to src/module/uti/beltofspellcraft.uti.json diff --git a/src/mod/uti/beltofthecenobit.uti.json b/src/module/uti/beltofthecenobit.uti.json similarity index 100% rename from src/mod/uti/beltofthecenobit.uti.json rename to src/module/uti/beltofthecenobit.uti.json diff --git a/src/mod/uti/beltofthemasters.uti.json b/src/module/uti/beltofthemasters.uti.json similarity index 100% rename from src/mod/uti/beltofthemasters.uti.json rename to src/module/uti/beltofthemasters.uti.json diff --git a/src/mod/uti/bigspyammy.uti.json b/src/module/uti/bigspyammy.uti.json similarity index 100% rename from src/mod/uti/bigspyammy.uti.json rename to src/module/uti/bigspyammy.uti.json diff --git a/src/mod/uti/bikinispecattack.uti.json b/src/module/uti/bikinispecattack.uti.json similarity index 100% rename from src/mod/uti/bikinispecattack.uti.json rename to src/module/uti/bikinispecattack.uti.json diff --git a/src/mod/uti/birkenstocks.uti.json b/src/module/uti/birkenstocks.uti.json similarity index 100% rename from src/mod/uti/birkenstocks.uti.json rename to src/module/uti/birkenstocks.uti.json diff --git a/src/mod/uti/bite3d10plus5.uti.json b/src/module/uti/bite3d10plus5.uti.json similarity index 100% rename from src/mod/uti/bite3d10plus5.uti.json rename to src/module/uti/bite3d10plus5.uti.json diff --git a/src/mod/uti/bite8d12plus5.uti.json b/src/module/uti/bite8d12plus5.uti.json similarity index 100% rename from src/mod/uti/bite8d12plus5.uti.json rename to src/module/uti/bite8d12plus5.uti.json diff --git a/src/mod/uti/bite9d10plus5.uti.json b/src/module/uti/bite9d10plus5.uti.json similarity index 100% rename from src/mod/uti/bite9d10plus5.uti.json rename to src/module/uti/bite9d10plus5.uti.json diff --git a/src/mod/uti/blackflamearmor.uti.json b/src/module/uti/blackflamearmor.uti.json similarity index 100% rename from src/mod/uti/blackflamearmor.uti.json rename to src/module/uti/blackflamearmor.uti.json diff --git a/src/mod/uti/bladeofdivinewra.uti.json b/src/module/uti/bladeofdivinewra.uti.json similarity index 100% rename from src/mod/uti/bladeofdivinewra.uti.json rename to src/module/uti/bladeofdivinewra.uti.json diff --git a/src/mod/uti/bladeofdracula.uti.json b/src/module/uti/bladeofdracula.uti.json similarity index 100% rename from src/mod/uti/bladeofdracula.uti.json rename to src/module/uti/bladeofdracula.uti.json diff --git a/src/mod/uti/bladeofjustice.uti.json b/src/module/uti/bladeofjustice.uti.json similarity index 100% rename from src/mod/uti/bladeofjustice.uti.json rename to src/module/uti/bladeofjustice.uti.json diff --git a/src/mod/uti/bladeofmagicalen.uti.json b/src/module/uti/bladeofmagicalen.uti.json similarity index 100% rename from src/mod/uti/bladeofmagicalen.uti.json rename to src/module/uti/bladeofmagicalen.uti.json diff --git a/src/mod/uti/bladeslingerarmo.uti.json b/src/module/uti/bladeslingerarmo.uti.json similarity index 100% rename from src/mod/uti/bladeslingerarmo.uti.json rename to src/module/uti/bladeslingerarmo.uti.json diff --git a/src/mod/uti/bluebite.uti.json b/src/module/uti/bluebite.uti.json similarity index 100% rename from src/mod/uti/bluebite.uti.json rename to src/module/uti/bluebite.uti.json diff --git a/src/mod/uti/blueclaw.uti.json b/src/module/uti/blueclaw.uti.json similarity index 100% rename from src/mod/uti/blueclaw.uti.json rename to src/module/uti/blueclaw.uti.json diff --git a/src/mod/uti/bluerod.uti.json b/src/module/uti/bluerod.uti.json similarity index 100% rename from src/mod/uti/bluerod.uti.json rename to src/module/uti/bluerod.uti.json diff --git a/src/mod/uti/bluerod001.uti.json b/src/module/uti/bluerod001.uti.json similarity index 100% rename from src/mod/uti/bluerod001.uti.json rename to src/module/uti/bluerod001.uti.json diff --git a/src/mod/uti/bluerod002.uti.json b/src/module/uti/bluerod002.uti.json similarity index 100% rename from src/mod/uti/bluerod002.uti.json rename to src/module/uti/bluerod002.uti.json diff --git a/src/mod/uti/bmrobes.uti.json b/src/module/uti/bmrobes.uti.json similarity index 100% rename from src/mod/uti/bmrobes.uti.json rename to src/module/uti/bmrobes.uti.json diff --git a/src/mod/uti/bodaksysthe.uti.json b/src/module/uti/bodaksysthe.uti.json similarity index 100% rename from src/mod/uti/bodaksysthe.uti.json rename to src/module/uti/bodaksysthe.uti.json diff --git a/src/mod/uti/bodyguardblade.uti.json b/src/module/uti/bodyguardblade.uti.json similarity index 100% rename from src/mod/uti/bodyguardblade.uti.json rename to src/module/uti/bodyguardblade.uti.json diff --git a/src/mod/uti/boneclub.uti.json b/src/module/uti/boneclub.uti.json similarity index 100% rename from src/mod/uti/boneclub.uti.json rename to src/module/uti/boneclub.uti.json diff --git a/src/mod/uti/boogiearmor.uti.json b/src/module/uti/boogiearmor.uti.json similarity index 100% rename from src/mod/uti/boogiearmor.uti.json rename to src/module/uti/boogiearmor.uti.json diff --git a/src/mod/uti/boogieaxe.uti.json b/src/module/uti/boogieaxe.uti.json similarity index 100% rename from src/mod/uti/boogieaxe.uti.json rename to src/module/uti/boogieaxe.uti.json diff --git a/src/mod/uti/bookofloveandlus.uti.json b/src/module/uti/bookofloveandlus.uti.json similarity index 100% rename from src/mod/uti/bookofloveandlus.uti.json rename to src/module/uti/bookofloveandlus.uti.json diff --git a/src/mod/uti/bookofnoblehisto.uti.json b/src/module/uti/bookofnoblehisto.uti.json similarity index 100% rename from src/mod/uti/bookofnoblehisto.uti.json rename to src/module/uti/bookofnoblehisto.uti.json diff --git a/src/mod/uti/bookofoztele.uti.json b/src/module/uti/bookofoztele.uti.json similarity index 100% rename from src/mod/uti/bookofoztele.uti.json rename to src/module/uti/bookofoztele.uti.json diff --git a/src/mod/uti/bookofyoga.uti.json b/src/module/uti/bookofyoga.uti.json similarity index 100% rename from src/mod/uti/bookofyoga.uti.json rename to src/module/uti/bookofyoga.uti.json diff --git a/src/mod/uti/bootsofagility.uti.json b/src/module/uti/bootsofagility.uti.json similarity index 100% rename from src/mod/uti/bootsofagility.uti.json rename to src/module/uti/bootsofagility.uti.json diff --git a/src/mod/uti/bootsofreflex.uti.json b/src/module/uti/bootsofreflex.uti.json similarity index 100% rename from src/mod/uti/bootsofreflex.uti.json rename to src/module/uti/bootsofreflex.uti.json diff --git a/src/mod/uti/bootsofswift.uti.json b/src/module/uti/bootsofswift.uti.json similarity index 100% rename from src/mod/uti/bootsofswift.uti.json rename to src/module/uti/bootsofswift.uti.json diff --git a/src/mod/uti/bootsofwind.uti.json b/src/module/uti/bootsofwind.uti.json similarity index 100% rename from src/mod/uti/bootsofwind.uti.json rename to src/module/uti/bootsofwind.uti.json diff --git a/src/mod/uti/boradhammerbrace.uti.json b/src/module/uti/boradhammerbrace.uti.json similarity index 100% rename from src/mod/uti/boradhammerbrace.uti.json rename to src/module/uti/boradhammerbrace.uti.json diff --git a/src/mod/uti/boradhammerhelm.uti.json b/src/module/uti/boradhammerhelm.uti.json similarity index 100% rename from src/mod/uti/boradhammerhelm.uti.json rename to src/module/uti/boradhammerhelm.uti.json diff --git a/src/mod/uti/bowofbark.uti.json b/src/module/uti/bowofbark.uti.json similarity index 100% rename from src/mod/uti/bowofbark.uti.json rename to src/module/uti/bowofbark.uti.json diff --git a/src/mod/uti/bowoffebrith.uti.json b/src/module/uti/bowoffebrith.uti.json similarity index 100% rename from src/mod/uti/bowoffebrith.uti.json rename to src/module/uti/bowoffebrith.uti.json diff --git a/src/mod/uti/bowofgrit.uti.json b/src/module/uti/bowofgrit.uti.json similarity index 100% rename from src/mod/uti/bowofgrit.uti.json rename to src/module/uti/bowofgrit.uti.json diff --git a/src/mod/uti/bowoftheunderwor.uti.json b/src/module/uti/bowoftheunderwor.uti.json similarity index 100% rename from src/mod/uti/bowoftheunderwor.uti.json rename to src/module/uti/bowoftheunderwor.uti.json diff --git a/src/mod/uti/bracersofevil.uti.json b/src/module/uti/bracersofevil.uti.json similarity index 100% rename from src/mod/uti/bracersofevil.uti.json rename to src/module/uti/bracersofevil.uti.json diff --git a/src/mod/uti/brethguildkey.uti.json b/src/module/uti/brethguildkey.uti.json similarity index 100% rename from src/mod/uti/brethguildkey.uti.json rename to src/module/uti/brethguildkey.uti.json diff --git a/src/mod/uti/brewreward.uti.json b/src/module/uti/brewreward.uti.json similarity index 100% rename from src/mod/uti/brewreward.uti.json rename to src/module/uti/brewreward.uti.json diff --git a/src/mod/uti/brewreward2.uti.json b/src/module/uti/brewreward2.uti.json similarity index 100% rename from src/mod/uti/brewreward2.uti.json rename to src/module/uti/brewreward2.uti.json diff --git a/src/mod/uti/briggskey.uti.json b/src/module/uti/briggskey.uti.json similarity index 100% rename from src/mod/uti/briggskey.uti.json rename to src/module/uti/briggskey.uti.json diff --git a/src/mod/uti/broadhammerarmor.uti.json b/src/module/uti/broadhammerarmor.uti.json similarity index 100% rename from src/mod/uti/broadhammerarmor.uti.json rename to src/module/uti/broadhammerarmor.uti.json diff --git a/src/mod/uti/broadhammershiel.uti.json b/src/module/uti/broadhammershiel.uti.json similarity index 100% rename from src/mod/uti/broadhammershiel.uti.json rename to src/module/uti/broadhammershiel.uti.json diff --git a/src/mod/uti/broadtwinhammer.uti.json b/src/module/uti/broadtwinhammer.uti.json similarity index 100% rename from src/mod/uti/broadtwinhammer.uti.json rename to src/module/uti/broadtwinhammer.uti.json diff --git a/src/mod/uti/bronzedragonbloo.uti.json b/src/module/uti/bronzedragonbloo.uti.json similarity index 100% rename from src/mod/uti/bronzedragonbloo.uti.json rename to src/module/uti/bronzedragonbloo.uti.json diff --git a/src/mod/uti/bullpotion.uti.json b/src/module/uti/bullpotion.uti.json similarity index 100% rename from src/mod/uti/bullpotion.uti.json rename to src/module/uti/bullpotion.uti.json diff --git a/src/mod/uti/cainarmor.uti.json b/src/module/uti/cainarmor.uti.json similarity index 100% rename from src/mod/uti/cainarmor.uti.json rename to src/module/uti/cainarmor.uti.json diff --git a/src/mod/uti/cainbite001.uti.json b/src/module/uti/cainbite001.uti.json similarity index 100% rename from src/mod/uti/cainbite001.uti.json rename to src/module/uti/cainbite001.uti.json diff --git a/src/mod/uti/caingaurdarmor.uti.json b/src/module/uti/caingaurdarmor.uti.json similarity index 100% rename from src/mod/uti/caingaurdarmor.uti.json rename to src/module/uti/caingaurdarmor.uti.json diff --git a/src/mod/uti/cainguardrobes.uti.json b/src/module/uti/cainguardrobes.uti.json similarity index 100% rename from src/mod/uti/cainguardrobes.uti.json rename to src/module/uti/cainguardrobes.uti.json diff --git a/src/mod/uti/cainhammer.uti.json b/src/module/uti/cainhammer.uti.json similarity index 100% rename from src/mod/uti/cainhammer.uti.json rename to src/module/uti/cainhammer.uti.json diff --git a/src/mod/uti/cainhead.uti.json b/src/module/uti/cainhead.uti.json similarity index 100% rename from src/mod/uti/cainhead.uti.json rename to src/module/uti/cainhead.uti.json diff --git a/src/mod/uti/cainhelm.uti.json b/src/module/uti/cainhelm.uti.json similarity index 100% rename from src/mod/uti/cainhelm.uti.json rename to src/module/uti/cainhelm.uti.json diff --git a/src/mod/uti/cainhelm001.uti.json b/src/module/uti/cainhelm001.uti.json similarity index 100% rename from src/mod/uti/cainhelm001.uti.json rename to src/module/uti/cainhelm001.uti.json diff --git a/src/mod/uti/cainlongsword.uti.json b/src/module/uti/cainlongsword.uti.json similarity index 100% rename from src/mod/uti/cainlongsword.uti.json rename to src/module/uti/cainlongsword.uti.json diff --git a/src/mod/uti/cainskin.uti.json b/src/module/uti/cainskin.uti.json similarity index 100% rename from src/mod/uti/cainskin.uti.json rename to src/module/uti/cainskin.uti.json diff --git a/src/mod/uti/cainwaraxe.uti.json b/src/module/uti/cainwaraxe.uti.json similarity index 100% rename from src/mod/uti/cainwaraxe.uti.json rename to src/module/uti/cainwaraxe.uti.json diff --git a/src/mod/uti/carlyleskin.uti.json b/src/module/uti/carlyleskin.uti.json similarity index 100% rename from src/mod/uti/carlyleskin.uti.json rename to src/module/uti/carlyleskin.uti.json diff --git a/src/mod/uti/catsgrace.uti.json b/src/module/uti/catsgrace.uti.json similarity index 100% rename from src/mod/uti/catsgrace.uti.json rename to src/module/uti/catsgrace.uti.json diff --git a/src/mod/uti/cavemanarmor.uti.json b/src/module/uti/cavemanarmor.uti.json similarity index 100% rename from src/mod/uti/cavemanarmor.uti.json rename to src/module/uti/cavemanarmor.uti.json diff --git a/src/mod/uti/cavemanclub.uti.json b/src/module/uti/cavemanclub.uti.json similarity index 100% rename from src/mod/uti/cavemanclub.uti.json rename to src/module/uti/cavemanclub.uti.json diff --git a/src/mod/uti/cavemanclub001.uti.json b/src/module/uti/cavemanclub001.uti.json similarity index 100% rename from src/mod/uti/cavemanclub001.uti.json rename to src/module/uti/cavemanclub001.uti.json diff --git a/src/mod/uti/celolasrobe.uti.json b/src/module/uti/celolasrobe.uti.json similarity index 100% rename from src/mod/uti/celolasrobe.uti.json rename to src/module/uti/celolasrobe.uti.json diff --git a/src/mod/uti/celricmace.uti.json b/src/module/uti/celricmace.uti.json similarity index 100% rename from src/mod/uti/celricmace.uti.json rename to src/module/uti/celricmace.uti.json diff --git a/src/mod/uti/choirmonkrobes.uti.json b/src/module/uti/choirmonkrobes.uti.json similarity index 100% rename from src/mod/uti/choirmonkrobes.uti.json rename to src/module/uti/choirmonkrobes.uti.json diff --git a/src/mod/uti/clanleaderarmor.uti.json b/src/module/uti/clanleaderarmor.uti.json similarity index 100% rename from src/mod/uti/clanleaderarmor.uti.json rename to src/module/uti/clanleaderarmor.uti.json diff --git a/src/mod/uti/clanleaderscl001.uti.json b/src/module/uti/clanleaderscl001.uti.json similarity index 100% rename from src/mod/uti/clanleaderscl001.uti.json rename to src/module/uti/clanleaderscl001.uti.json diff --git a/src/mod/uti/clanleadersclub.uti.json b/src/module/uti/clanleadersclub.uti.json similarity index 100% rename from src/mod/uti/clanleadersclub.uti.json rename to src/module/uti/clanleadersclub.uti.json diff --git a/src/mod/uti/clanleadersear.uti.json b/src/module/uti/clanleadersear.uti.json similarity index 100% rename from src/mod/uti/clanleadersear.uti.json rename to src/module/uti/clanleadersear.uti.json diff --git a/src/mod/uti/clanleaderskin.uti.json b/src/module/uti/clanleaderskin.uti.json similarity index 100% rename from src/mod/uti/clanleaderskin.uti.json rename to src/module/uti/clanleaderskin.uti.json diff --git a/src/mod/uti/claw3d8plus5.uti.json b/src/module/uti/claw3d8plus5.uti.json similarity index 100% rename from src/mod/uti/claw3d8plus5.uti.json rename to src/module/uti/claw3d8plus5.uti.json diff --git a/src/mod/uti/claw5d8plus005.uti.json b/src/module/uti/claw5d8plus005.uti.json similarity index 100% rename from src/mod/uti/claw5d8plus005.uti.json rename to src/module/uti/claw5d8plus005.uti.json diff --git a/src/mod/uti/claw5d8plus006.uti.json b/src/module/uti/claw5d8plus006.uti.json similarity index 100% rename from src/mod/uti/claw5d8plus006.uti.json rename to src/module/uti/claw5d8plus006.uti.json diff --git a/src/mod/uti/claw5d8plus4.uti.json b/src/module/uti/claw5d8plus4.uti.json similarity index 100% rename from src/mod/uti/claw5d8plus4.uti.json rename to src/module/uti/claw5d8plus4.uti.json diff --git a/src/mod/uti/claw6d8plus5.uti.json b/src/module/uti/claw6d8plus5.uti.json similarity index 100% rename from src/mod/uti/claw6d8plus5.uti.json rename to src/module/uti/claw6d8plus5.uti.json diff --git a/src/mod/uti/claw9d8plus5.uti.json b/src/module/uti/claw9d8plus5.uti.json similarity index 100% rename from src/mod/uti/claw9d8plus5.uti.json rename to src/module/uti/claw9d8plus5.uti.json diff --git a/src/mod/uti/cleanserrobes.uti.json b/src/module/uti/cleanserrobes.uti.json similarity index 100% rename from src/mod/uti/cleanserrobes.uti.json rename to src/module/uti/cleanserrobes.uti.json diff --git a/src/mod/uti/clericstaff.uti.json b/src/module/uti/clericstaff.uti.json similarity index 100% rename from src/mod/uti/clericstaff.uti.json rename to src/module/uti/clericstaff.uti.json diff --git a/src/mod/uti/cloak007.uti.json b/src/module/uti/cloak007.uti.json similarity index 100% rename from src/mod/uti/cloak007.uti.json rename to src/module/uti/cloak007.uti.json diff --git a/src/mod/uti/cloak6.uti.json b/src/module/uti/cloak6.uti.json similarity index 100% rename from src/mod/uti/cloak6.uti.json rename to src/module/uti/cloak6.uti.json diff --git a/src/mod/uti/cloakoflife001.uti.json b/src/module/uti/cloakoflife001.uti.json similarity index 100% rename from src/mod/uti/cloakoflife001.uti.json rename to src/module/uti/cloakoflife001.uti.json diff --git a/src/mod/uti/cloakofthehills.uti.json b/src/module/uti/cloakofthehills.uti.json similarity index 100% rename from src/mod/uti/cloakofthehills.uti.json rename to src/module/uti/cloakofthehills.uti.json diff --git a/src/mod/uti/cloakoftheshadow.uti.json b/src/module/uti/cloakoftheshadow.uti.json similarity index 100% rename from src/mod/uti/cloakoftheshadow.uti.json rename to src/module/uti/cloakoftheshadow.uti.json diff --git a/src/mod/uti/cloakpotion.uti.json b/src/module/uti/cloakpotion.uti.json similarity index 100% rename from src/mod/uti/cloakpotion.uti.json rename to src/module/uti/cloakpotion.uti.json diff --git a/src/mod/uti/closetmonsterbit.uti.json b/src/module/uti/closetmonsterbit.uti.json similarity index 100% rename from src/mod/uti/closetmonsterbit.uti.json rename to src/module/uti/closetmonsterbit.uti.json diff --git a/src/mod/uti/closetmonstercla.uti.json b/src/module/uti/closetmonstercla.uti.json similarity index 100% rename from src/mod/uti/closetmonstercla.uti.json rename to src/module/uti/closetmonstercla.uti.json diff --git a/src/mod/uti/closetmonsterski.uti.json b/src/module/uti/closetmonsterski.uti.json similarity index 100% rename from src/mod/uti/closetmonsterski.uti.json rename to src/module/uti/closetmonsterski.uti.json diff --git a/src/mod/uti/coldironblade.uti.json b/src/module/uti/coldironblade.uti.json similarity index 100% rename from src/mod/uti/coldironblade.uti.json rename to src/module/uti/coldironblade.uti.json diff --git a/src/mod/uti/copperdragonbloo.uti.json b/src/module/uti/copperdragonbloo.uti.json similarity index 100% rename from src/mod/uti/copperdragonbloo.uti.json rename to src/module/uti/copperdragonbloo.uti.json diff --git a/src/mod/uti/crackaaxenpc.uti.json b/src/module/uti/crackaaxenpc.uti.json similarity index 100% rename from src/mod/uti/crackaaxenpc.uti.json rename to src/module/uti/crackaaxenpc.uti.json diff --git a/src/mod/uti/crawlybite.uti.json b/src/module/uti/crawlybite.uti.json similarity index 100% rename from src/mod/uti/crawlybite.uti.json rename to src/module/uti/crawlybite.uti.json diff --git a/src/mod/uti/crawlyclaw.uti.json b/src/module/uti/crawlyclaw.uti.json similarity index 100% rename from src/mod/uti/crawlyclaw.uti.json rename to src/module/uti/crawlyclaw.uti.json diff --git a/src/mod/uti/crawlyskin.uti.json b/src/module/uti/crawlyskin.uti.json similarity index 100% rename from src/mod/uti/crawlyskin.uti.json rename to src/module/uti/crawlyskin.uti.json diff --git a/src/mod/uti/creepybite.uti.json b/src/module/uti/creepybite.uti.json similarity index 100% rename from src/mod/uti/creepybite.uti.json rename to src/module/uti/creepybite.uti.json diff --git a/src/mod/uti/creepyclaw.uti.json b/src/module/uti/creepyclaw.uti.json similarity index 100% rename from src/mod/uti/creepyclaw.uti.json rename to src/module/uti/creepyclaw.uti.json diff --git a/src/mod/uti/crownofbrotherho.uti.json b/src/module/uti/crownofbrotherho.uti.json similarity index 100% rename from src/mod/uti/crownofbrotherho.uti.json rename to src/module/uti/crownofbrotherho.uti.json diff --git a/src/mod/uti/cs_invul_toggle.uti.json b/src/module/uti/cs_invul_toggle.uti.json similarity index 100% rename from src/mod/uti/cs_invul_toggle.uti.json rename to src/module/uti/cs_invul_toggle.uti.json diff --git a/src/mod/uti/cs_takegold.uti.json b/src/module/uti/cs_takegold.uti.json similarity index 100% rename from src/mod/uti/cs_takegold.uti.json rename to src/module/uti/cs_takegold.uti.json diff --git a/src/mod/uti/cult_leader_skin.uti.json b/src/module/uti/cult_leader_skin.uti.json similarity index 100% rename from src/mod/uti/cult_leader_skin.uti.json rename to src/module/uti/cult_leader_skin.uti.json diff --git a/src/mod/uti/curemod.uti.json b/src/module/uti/curemod.uti.json similarity index 100% rename from src/mod/uti/curemod.uti.json rename to src/module/uti/curemod.uti.json diff --git a/src/mod/uti/curemod10.uti.json b/src/module/uti/curemod10.uti.json similarity index 100% rename from src/mod/uti/curemod10.uti.json rename to src/module/uti/curemod10.uti.json diff --git a/src/mod/uti/cus_armoroffa001.uti.json b/src/module/uti/cus_armoroffa001.uti.json similarity index 100% rename from src/mod/uti/cus_armoroffa001.uti.json rename to src/module/uti/cus_armoroffa001.uti.json diff --git a/src/mod/uti/cust_bl_dw_armor.uti.json b/src/module/uti/cust_bl_dw_armor.uti.json similarity index 100% rename from src/mod/uti/cust_bl_dw_armor.uti.json rename to src/module/uti/cust_bl_dw_armor.uti.json diff --git a/src/mod/uti/cust_dw_great_sw.uti.json b/src/module/uti/cust_dw_great_sw.uti.json similarity index 100% rename from src/mod/uti/cust_dw_great_sw.uti.json rename to src/module/uti/cust_dw_great_sw.uti.json diff --git a/src/mod/uti/cust_dw_hammer2.uti.json b/src/module/uti/cust_dw_hammer2.uti.json similarity index 100% rename from src/mod/uti/cust_dw_hammer2.uti.json rename to src/module/uti/cust_dw_hammer2.uti.json diff --git a/src/mod/uti/cust_gr_dw_armor.uti.json b/src/module/uti/cust_gr_dw_armor.uti.json similarity index 100% rename from src/mod/uti/cust_gr_dw_armor.uti.json rename to src/module/uti/cust_gr_dw_armor.uti.json diff --git a/src/mod/uti/damreductionskin.uti.json b/src/module/uti/damreductionskin.uti.json similarity index 100% rename from src/mod/uti/damreductionskin.uti.json rename to src/module/uti/damreductionskin.uti.json diff --git a/src/mod/uti/dantarrow.uti.json b/src/module/uti/dantarrow.uti.json similarity index 100% rename from src/mod/uti/dantarrow.uti.json rename to src/module/uti/dantarrow.uti.json diff --git a/src/mod/uti/dantgreatsword.uti.json b/src/module/uti/dantgreatsword.uti.json similarity index 100% rename from src/mod/uti/dantgreatsword.uti.json rename to src/module/uti/dantgreatsword.uti.json diff --git a/src/mod/uti/danthalbred.uti.json b/src/module/uti/danthalbred.uti.json similarity index 100% rename from src/mod/uti/danthalbred.uti.json rename to src/module/uti/danthalbred.uti.json diff --git a/src/mod/uti/dantlongbow.uti.json b/src/module/uti/dantlongbow.uti.json similarity index 100% rename from src/mod/uti/dantlongbow.uti.json rename to src/module/uti/dantlongbow.uti.json diff --git a/src/mod/uti/dantmorningstar.uti.json b/src/module/uti/dantmorningstar.uti.json similarity index 100% rename from src/mod/uti/dantmorningstar.uti.json rename to src/module/uti/dantmorningstar.uti.json diff --git a/src/mod/uti/dantrapier.uti.json b/src/module/uti/dantrapier.uti.json similarity index 100% rename from src/mod/uti/dantrapier.uti.json rename to src/module/uti/dantrapier.uti.json diff --git a/src/mod/uti/dargknightarmor.uti.json b/src/module/uti/dargknightarmor.uti.json similarity index 100% rename from src/mod/uti/dargknightarmor.uti.json rename to src/module/uti/dargknightarmor.uti.json diff --git a/src/mod/uti/darknessesbane.uti.json b/src/module/uti/darknessesbane.uti.json similarity index 100% rename from src/mod/uti/darknessesbane.uti.json rename to src/module/uti/darknessesbane.uti.json diff --git a/src/mod/uti/darkqueenrobe.uti.json b/src/module/uti/darkqueenrobe.uti.json similarity index 100% rename from src/mod/uti/darkqueenrobe.uti.json rename to src/module/uti/darkqueenrobe.uti.json diff --git a/src/mod/uti/darthsarmor.uti.json b/src/module/uti/darthsarmor.uti.json similarity index 100% rename from src/mod/uti/darthsarmor.uti.json rename to src/module/uti/darthsarmor.uti.json diff --git a/src/mod/uti/darthseye.uti.json b/src/module/uti/darthseye.uti.json similarity index 100% rename from src/mod/uti/darthseye.uti.json rename to src/module/uti/darthseye.uti.json diff --git a/src/mod/uti/darthshelmet.uti.json b/src/module/uti/darthshelmet.uti.json similarity index 100% rename from src/mod/uti/darthshelmet.uti.json rename to src/module/uti/darthshelmet.uti.json diff --git a/src/mod/uti/darthshield.uti.json b/src/module/uti/darthshield.uti.json similarity index 100% rename from src/mod/uti/darthshield.uti.json rename to src/module/uti/darthshield.uti.json diff --git a/src/mod/uti/darthssaber.uti.json b/src/module/uti/darthssaber.uti.json similarity index 100% rename from src/mod/uti/darthssaber.uti.json rename to src/module/uti/darthssaber.uti.json diff --git a/src/mod/uti/darthsskin.uti.json b/src/module/uti/darthsskin.uti.json similarity index 100% rename from src/mod/uti/darthsskin.uti.json rename to src/module/uti/darthsskin.uti.json diff --git a/src/mod/uti/deamonsummonarmo.uti.json b/src/module/uti/deamonsummonarmo.uti.json similarity index 100% rename from src/mod/uti/deamonsummonarmo.uti.json rename to src/module/uti/deamonsummonarmo.uti.json diff --git a/src/mod/uti/defenderkama.uti.json b/src/module/uti/defenderkama.uti.json similarity index 100% rename from src/mod/uti/defenderkama.uti.json rename to src/module/uti/defenderkama.uti.json diff --git a/src/mod/uti/desertarmor.uti.json b/src/module/uti/desertarmor.uti.json similarity index 100% rename from src/mod/uti/desertarmor.uti.json rename to src/module/uti/desertarmor.uti.json diff --git a/src/mod/uti/desertaxe.uti.json b/src/module/uti/desertaxe.uti.json similarity index 100% rename from src/mod/uti/desertaxe.uti.json rename to src/module/uti/desertaxe.uti.json diff --git a/src/mod/uti/desertaxe001.uti.json b/src/module/uti/desertaxe001.uti.json similarity index 100% rename from src/mod/uti/desertaxe001.uti.json rename to src/module/uti/desertaxe001.uti.json diff --git a/src/mod/uti/desertdart.uti.json b/src/module/uti/desertdart.uti.json similarity index 100% rename from src/mod/uti/desertdart.uti.json rename to src/module/uti/desertdart.uti.json diff --git a/src/mod/uti/desertkukri.uti.json b/src/module/uti/desertkukri.uti.json similarity index 100% rename from src/mod/uti/desertkukri.uti.json rename to src/module/uti/desertkukri.uti.json diff --git a/src/mod/uti/desertrobe.uti.json b/src/module/uti/desertrobe.uti.json similarity index 100% rename from src/mod/uti/desertrobe.uti.json rename to src/module/uti/desertrobe.uti.json diff --git a/src/mod/uti/dickysshield.uti.json b/src/module/uti/dickysshield.uti.json similarity index 100% rename from src/mod/uti/dickysshield.uti.json rename to src/module/uti/dickysshield.uti.json diff --git a/src/mod/uti/dinosaurbite.uti.json b/src/module/uti/dinosaurbite.uti.json similarity index 100% rename from src/mod/uti/dinosaurbite.uti.json rename to src/module/uti/dinosaurbite.uti.json diff --git a/src/mod/uti/dinosaurclaw.uti.json b/src/module/uti/dinosaurclaw.uti.json similarity index 100% rename from src/mod/uti/dinosaurclaw.uti.json rename to src/module/uti/dinosaurclaw.uti.json diff --git a/src/mod/uti/dinosaurskin.uti.json b/src/module/uti/dinosaurskin.uti.json similarity index 100% rename from src/mod/uti/dinosaurskin.uti.json rename to src/module/uti/dinosaurskin.uti.json diff --git a/src/mod/uti/dinosaurslam.uti.json b/src/module/uti/dinosaurslam.uti.json similarity index 100% rename from src/mod/uti/dinosaurslam.uti.json rename to src/module/uti/dinosaurslam.uti.json diff --git a/src/mod/uti/direpenguinbite.uti.json b/src/module/uti/direpenguinbite.uti.json similarity index 100% rename from src/mod/uti/direpenguinbite.uti.json rename to src/module/uti/direpenguinbite.uti.json diff --git a/src/mod/uti/direpenguinclaw.uti.json b/src/module/uti/direpenguinclaw.uti.json similarity index 100% rename from src/mod/uti/direpenguinclaw.uti.json rename to src/module/uti/direpenguinclaw.uti.json diff --git a/src/mod/uti/direpenguinskin.uti.json b/src/module/uti/direpenguinskin.uti.json similarity index 100% rename from src/mod/uti/direpenguinskin.uti.json rename to src/module/uti/direpenguinskin.uti.json diff --git a/src/mod/uti/dirtharrows.uti.json b/src/module/uti/dirtharrows.uti.json similarity index 100% rename from src/mod/uti/dirtharrows.uti.json rename to src/module/uti/dirtharrows.uti.json diff --git a/src/mod/uti/dirthbow.uti.json b/src/module/uti/dirthbow.uti.json similarity index 100% rename from src/mod/uti/dirthbow.uti.json rename to src/module/uti/dirthbow.uti.json diff --git a/src/mod/uti/dirthrrapier.uti.json b/src/module/uti/dirthrrapier.uti.json similarity index 100% rename from src/mod/uti/dirthrrapier.uti.json rename to src/module/uti/dirthrrapier.uti.json diff --git a/src/mod/uti/dirthstaff.uti.json b/src/module/uti/dirthstaff.uti.json similarity index 100% rename from src/mod/uti/dirthstaff.uti.json rename to src/module/uti/dirthstaff.uti.json diff --git a/src/mod/uti/disarmedclaw.uti.json b/src/module/uti/disarmedclaw.uti.json similarity index 100% rename from src/mod/uti/disarmedclaw.uti.json rename to src/module/uti/disarmedclaw.uti.json diff --git a/src/mod/uti/divineammy.uti.json b/src/module/uti/divineammy.uti.json similarity index 100% rename from src/mod/uti/divineammy.uti.json rename to src/module/uti/divineammy.uti.json diff --git a/src/mod/uti/divinestrengthst.uti.json b/src/module/uti/divinestrengthst.uti.json similarity index 100% rename from src/mod/uti/divinestrengthst.uti.json rename to src/module/uti/divinestrengthst.uti.json diff --git a/src/mod/uti/dmrobes.uti.json b/src/module/uti/dmrobes.uti.json similarity index 100% rename from src/mod/uti/dmrobes.uti.json rename to src/module/uti/dmrobes.uti.json diff --git a/src/mod/uti/dmshelper.uti.json b/src/module/uti/dmshelper.uti.json similarity index 100% rename from src/mod/uti/dmshelper.uti.json rename to src/module/uti/dmshelper.uti.json diff --git a/src/mod/uti/doctorskey.uti.json b/src/module/uti/doctorskey.uti.json similarity index 100% rename from src/mod/uti/doctorskey.uti.json rename to src/module/uti/doctorskey.uti.json diff --git a/src/mod/uti/draculaclaw.uti.json b/src/module/uti/draculaclaw.uti.json similarity index 100% rename from src/mod/uti/draculaclaw.uti.json rename to src/module/uti/draculaclaw.uti.json diff --git a/src/mod/uti/draculasfang.uti.json b/src/module/uti/draculasfang.uti.json similarity index 100% rename from src/mod/uti/draculasfang.uti.json rename to src/module/uti/draculasfang.uti.json diff --git a/src/mod/uti/draculaslam.uti.json b/src/module/uti/draculaslam.uti.json similarity index 100% rename from src/mod/uti/draculaslam.uti.json rename to src/module/uti/draculaslam.uti.json diff --git a/src/mod/uti/draculasskin.uti.json b/src/module/uti/draculasskin.uti.json similarity index 100% rename from src/mod/uti/draculasskin.uti.json rename to src/module/uti/draculasskin.uti.json diff --git a/src/mod/uti/dragenergy.uti.json b/src/module/uti/dragenergy.uti.json similarity index 100% rename from src/mod/uti/dragenergy.uti.json rename to src/module/uti/dragenergy.uti.json diff --git a/src/mod/uti/dragknightscythe.uti.json b/src/module/uti/dragknightscythe.uti.json similarity index 100% rename from src/mod/uti/dragknightscythe.uti.json rename to src/module/uti/dragknightscythe.uti.json diff --git a/src/mod/uti/dragonclaws.uti.json b/src/module/uti/dragonclaws.uti.json similarity index 100% rename from src/mod/uti/dragonclaws.uti.json rename to src/module/uti/dragonclaws.uti.json diff --git a/src/mod/uti/dragoncultbla001.uti.json b/src/module/uti/dragoncultbla001.uti.json similarity index 100% rename from src/mod/uti/dragoncultbla001.uti.json rename to src/module/uti/dragoncultbla001.uti.json diff --git a/src/mod/uti/dragoncultbla002.uti.json b/src/module/uti/dragoncultbla002.uti.json similarity index 100% rename from src/mod/uti/dragoncultbla002.uti.json rename to src/module/uti/dragoncultbla002.uti.json diff --git a/src/mod/uti/dragoncultblade.uti.json b/src/module/uti/dragoncultblade.uti.json similarity index 100% rename from src/mod/uti/dragoncultblade.uti.json rename to src/module/uti/dragoncultblade.uti.json diff --git a/src/mod/uti/dragoncultgaunts.uti.json b/src/module/uti/dragoncultgaunts.uti.json similarity index 100% rename from src/mod/uti/dragoncultgaunts.uti.json rename to src/module/uti/dragoncultgaunts.uti.json diff --git a/src/mod/uti/dragoncultham001.uti.json b/src/module/uti/dragoncultham001.uti.json similarity index 100% rename from src/mod/uti/dragoncultham001.uti.json rename to src/module/uti/dragoncultham001.uti.json diff --git a/src/mod/uti/dragonculthammer.uti.json b/src/module/uti/dragonculthammer.uti.json similarity index 100% rename from src/mod/uti/dragonculthammer.uti.json rename to src/module/uti/dragonculthammer.uti.json diff --git a/src/mod/uti/dragoncultrobe.uti.json b/src/module/uti/dragoncultrobe.uti.json similarity index 100% rename from src/mod/uti/dragoncultrobe.uti.json rename to src/module/uti/dragoncultrobe.uti.json diff --git a/src/mod/uti/dragoncultscy001.uti.json b/src/module/uti/dragoncultscy001.uti.json similarity index 100% rename from src/mod/uti/dragoncultscy001.uti.json rename to src/module/uti/dragoncultscy001.uti.json diff --git a/src/mod/uti/dragoncultscythe.uti.json b/src/module/uti/dragoncultscythe.uti.json similarity index 100% rename from src/mod/uti/dragoncultscythe.uti.json rename to src/module/uti/dragoncultscythe.uti.json diff --git a/src/mod/uti/dragoncultskin.uti.json b/src/module/uti/dragoncultskin.uti.json similarity index 100% rename from src/mod/uti/dragoncultskin.uti.json rename to src/module/uti/dragoncultskin.uti.json diff --git a/src/mod/uti/dragoncultstaff.uti.json b/src/module/uti/dragoncultstaff.uti.json similarity index 100% rename from src/mod/uti/dragoncultstaff.uti.json rename to src/module/uti/dragoncultstaff.uti.json diff --git a/src/mod/uti/dragoncultweapon.uti.json b/src/module/uti/dragoncultweapon.uti.json similarity index 100% rename from src/mod/uti/dragoncultweapon.uti.json rename to src/module/uti/dragoncultweapon.uti.json diff --git a/src/mod/uti/dragondbleaxe.uti.json b/src/module/uti/dragondbleaxe.uti.json similarity index 100% rename from src/mod/uti/dragondbleaxe.uti.json rename to src/module/uti/dragondbleaxe.uti.json diff --git a/src/mod/uti/dragongem.uti.json b/src/module/uti/dragongem.uti.json similarity index 100% rename from src/mod/uti/dragongem.uti.json rename to src/module/uti/dragongem.uti.json diff --git a/src/mod/uti/dragonmonkstaff.uti.json b/src/module/uti/dragonmonkstaff.uti.json similarity index 100% rename from src/mod/uti/dragonmonkstaff.uti.json rename to src/module/uti/dragonmonkstaff.uti.json diff --git a/src/mod/uti/dragonskin.uti.json b/src/module/uti/dragonskin.uti.json similarity index 100% rename from src/mod/uti/dragonskin.uti.json rename to src/module/uti/dragonskin.uti.json diff --git a/src/mod/uti/dragonskinlvl003.uti.json b/src/module/uti/dragonskinlvl003.uti.json similarity index 100% rename from src/mod/uti/dragonskinlvl003.uti.json rename to src/module/uti/dragonskinlvl003.uti.json diff --git a/src/mod/uti/dragonskinlvl2.uti.json b/src/module/uti/dragonskinlvl2.uti.json similarity index 100% rename from src/mod/uti/dragonskinlvl2.uti.json rename to src/module/uti/dragonskinlvl2.uti.json diff --git a/src/mod/uti/dragonslayeraxe.uti.json b/src/module/uti/dragonslayeraxe.uti.json similarity index 100% rename from src/mod/uti/dragonslayeraxe.uti.json rename to src/module/uti/dragonslayeraxe.uti.json diff --git a/src/mod/uti/dreamcatcher.uti.json b/src/module/uti/dreamcatcher.uti.json similarity index 100% rename from src/mod/uti/dreamcatcher.uti.json rename to src/module/uti/dreamcatcher.uti.json diff --git a/src/mod/uti/dreamweaverfeath.uti.json b/src/module/uti/dreamweaverfeath.uti.json similarity index 100% rename from src/mod/uti/dreamweaverfeath.uti.json rename to src/module/uti/dreamweaverfeath.uti.json diff --git a/src/mod/uti/droidclaw.uti.json b/src/module/uti/droidclaw.uti.json similarity index 100% rename from src/mod/uti/droidclaw.uti.json rename to src/module/uti/droidclaw.uti.json diff --git a/src/mod/uti/droidgore.uti.json b/src/module/uti/droidgore.uti.json similarity index 100% rename from src/mod/uti/droidgore.uti.json rename to src/module/uti/droidgore.uti.json diff --git a/src/mod/uti/droidskin.uti.json b/src/module/uti/droidskin.uti.json similarity index 100% rename from src/mod/uti/droidskin.uti.json rename to src/module/uti/droidskin.uti.json diff --git a/src/mod/uti/droidslam.uti.json b/src/module/uti/droidslam.uti.json similarity index 100% rename from src/mod/uti/droidslam.uti.json rename to src/module/uti/droidslam.uti.json diff --git a/src/mod/uti/drowblade.uti.json b/src/module/uti/drowblade.uti.json similarity index 100% rename from src/mod/uti/drowblade.uti.json rename to src/module/uti/drowblade.uti.json diff --git a/src/mod/uti/drowclericarmor.uti.json b/src/module/uti/drowclericarmor.uti.json similarity index 100% rename from src/mod/uti/drowclericarmor.uti.json rename to src/module/uti/drowclericarmor.uti.json diff --git a/src/mod/uti/drowmace.uti.json b/src/module/uti/drowmace.uti.json similarity index 100% rename from src/mod/uti/drowmace.uti.json rename to src/module/uti/drowmace.uti.json diff --git a/src/mod/uti/drowmace001.uti.json b/src/module/uti/drowmace001.uti.json similarity index 100% rename from src/mod/uti/drowmace001.uti.json rename to src/module/uti/drowmace001.uti.json diff --git a/src/mod/uti/drownoble.uti.json b/src/module/uti/drownoble.uti.json similarity index 100% rename from src/mod/uti/drownoble.uti.json rename to src/module/uti/drownoble.uti.json diff --git a/src/mod/uti/drowstar.uti.json b/src/module/uti/drowstar.uti.json similarity index 100% rename from src/mod/uti/drowstar.uti.json rename to src/module/uti/drowstar.uti.json diff --git a/src/mod/uti/drowstar001.uti.json b/src/module/uti/drowstar001.uti.json similarity index 100% rename from src/mod/uti/drowstar001.uti.json rename to src/module/uti/drowstar001.uti.json diff --git a/src/mod/uti/drudocsaxe.uti.json b/src/module/uti/drudocsaxe.uti.json similarity index 100% rename from src/mod/uti/drudocsaxe.uti.json rename to src/module/uti/drudocsaxe.uti.json diff --git a/src/mod/uti/dwarfgaurdarmor.uti.json b/src/module/uti/dwarfgaurdarmor.uti.json similarity index 100% rename from src/mod/uti/dwarfgaurdarmor.uti.json rename to src/module/uti/dwarfgaurdarmor.uti.json diff --git a/src/mod/uti/dwarfgaurdhelm.uti.json b/src/module/uti/dwarfgaurdhelm.uti.json similarity index 100% rename from src/mod/uti/dwarfgaurdhelm.uti.json rename to src/module/uti/dwarfgaurdhelm.uti.json diff --git a/src/mod/uti/dwarfhammer.uti.json b/src/module/uti/dwarfhammer.uti.json similarity index 100% rename from src/mod/uti/dwarfhammer.uti.json rename to src/module/uti/dwarfhammer.uti.json diff --git a/src/mod/uti/dwarfhighwizardr.uti.json b/src/module/uti/dwarfhighwizardr.uti.json similarity index 100% rename from src/mod/uti/dwarfhighwizardr.uti.json rename to src/module/uti/dwarfhighwizardr.uti.json diff --git a/src/mod/uti/dwarfport003.uti.json b/src/module/uti/dwarfport003.uti.json similarity index 100% rename from src/mod/uti/dwarfport003.uti.json rename to src/module/uti/dwarfport003.uti.json diff --git a/src/mod/uti/dwarfquarterstaf.uti.json b/src/module/uti/dwarfquarterstaf.uti.json similarity index 100% rename from src/mod/uti/dwarfquarterstaf.uti.json rename to src/module/uti/dwarfquarterstaf.uti.json diff --git a/src/mod/uti/dwarvenbracers.uti.json b/src/module/uti/dwarvenbracers.uti.json similarity index 100% rename from src/mod/uti/dwarvenbracers.uti.json rename to src/module/uti/dwarvenbracers.uti.json diff --git a/src/mod/uti/dwarvenclericarm.uti.json b/src/module/uti/dwarvenclericarm.uti.json similarity index 100% rename from src/mod/uti/dwarvenclericarm.uti.json rename to src/module/uti/dwarvenclericarm.uti.json diff --git a/src/mod/uti/dwarvendungeonke.uti.json b/src/module/uti/dwarvendungeonke.uti.json similarity index 100% rename from src/mod/uti/dwarvendungeonke.uti.json rename to src/module/uti/dwarvendungeonke.uti.json diff --git a/src/mod/uti/dwarvenhelm.uti.json b/src/module/uti/dwarvenhelm.uti.json similarity index 100% rename from src/mod/uti/dwarvenhelm.uti.json rename to src/module/uti/dwarvenhelm.uti.json diff --git a/src/mod/uti/elevenarmor.uti.json b/src/module/uti/elevenarmor.uti.json similarity index 100% rename from src/mod/uti/elevenarmor.uti.json rename to src/module/uti/elevenarmor.uti.json diff --git a/src/mod/uti/elevenarmor001.uti.json b/src/module/uti/elevenarmor001.uti.json similarity index 100% rename from src/mod/uti/elevenarmor001.uti.json rename to src/module/uti/elevenarmor001.uti.json diff --git a/src/mod/uti/elevenaxe.uti.json b/src/module/uti/elevenaxe.uti.json similarity index 100% rename from src/mod/uti/elevenaxe.uti.json rename to src/module/uti/elevenaxe.uti.json diff --git a/src/mod/uti/elevenblade.uti.json b/src/module/uti/elevenblade.uti.json similarity index 100% rename from src/mod/uti/elevenblade.uti.json rename to src/module/uti/elevenblade.uti.json diff --git a/src/mod/uti/elevenmageboots.uti.json b/src/module/uti/elevenmageboots.uti.json similarity index 100% rename from src/mod/uti/elevenmageboots.uti.json rename to src/module/uti/elevenmageboots.uti.json diff --git a/src/mod/uti/elevenrobe.uti.json b/src/module/uti/elevenrobe.uti.json similarity index 100% rename from src/mod/uti/elevenrobe.uti.json rename to src/module/uti/elevenrobe.uti.json diff --git a/src/mod/uti/elevenrobe001.uti.json b/src/module/uti/elevenrobe001.uti.json similarity index 100% rename from src/mod/uti/elevenrobe001.uti.json rename to src/module/uti/elevenrobe001.uti.json diff --git a/src/mod/uti/elevenshield.uti.json b/src/module/uti/elevenshield.uti.json similarity index 100% rename from src/mod/uti/elevenshield.uti.json rename to src/module/uti/elevenshield.uti.json diff --git a/src/mod/uti/elevenstaff.uti.json b/src/module/uti/elevenstaff.uti.json similarity index 100% rename from src/mod/uti/elevenstaff.uti.json rename to src/module/uti/elevenstaff.uti.json diff --git a/src/mod/uti/elvendarbear.uti.json b/src/module/uti/elvendarbear.uti.json similarity index 100% rename from src/mod/uti/elvendarbear.uti.json rename to src/module/uti/elvendarbear.uti.json diff --git a/src/mod/uti/elvendarbear001.uti.json b/src/module/uti/elvendarbear001.uti.json similarity index 100% rename from src/mod/uti/elvendarbear001.uti.json rename to src/module/uti/elvendarbear001.uti.json diff --git a/src/mod/uti/elvendarbear002.uti.json b/src/module/uti/elvendarbear002.uti.json similarity index 100% rename from src/mod/uti/elvendarbear002.uti.json rename to src/module/uti/elvendarbear002.uti.json diff --git a/src/mod/uti/elvendarbearh001.uti.json b/src/module/uti/elvendarbearh001.uti.json similarity index 100% rename from src/mod/uti/elvendarbearh001.uti.json rename to src/module/uti/elvendarbearh001.uti.json diff --git a/src/mod/uti/elvendarbearh002.uti.json b/src/module/uti/elvendarbearh002.uti.json similarity index 100% rename from src/mod/uti/elvendarbearh002.uti.json rename to src/module/uti/elvendarbearh002.uti.json diff --git a/src/mod/uti/elvendarbearh003.uti.json b/src/module/uti/elvendarbearh003.uti.json similarity index 100% rename from src/mod/uti/elvendarbearh003.uti.json rename to src/module/uti/elvendarbearh003.uti.json diff --git a/src/mod/uti/elvendarbearhide.uti.json b/src/module/uti/elvendarbearhide.uti.json similarity index 100% rename from src/mod/uti/elvendarbearhide.uti.json rename to src/module/uti/elvendarbearhide.uti.json diff --git a/src/mod/uti/elvendarbow.uti.json b/src/module/uti/elvendarbow.uti.json similarity index 100% rename from src/mod/uti/elvendarbow.uti.json rename to src/module/uti/elvendarbow.uti.json diff --git a/src/mod/uti/emotewand.uti.json b/src/module/uti/emotewand.uti.json similarity index 100% rename from src/mod/uti/emotewand.uti.json rename to src/module/uti/emotewand.uti.json diff --git a/src/mod/uti/enchantedscroll.uti.json b/src/module/uti/enchantedscroll.uti.json similarity index 100% rename from src/mod/uti/enchantedscroll.uti.json rename to src/module/uti/enchantedscroll.uti.json diff --git a/src/mod/uti/engineertools20.uti.json b/src/module/uti/engineertools20.uti.json similarity index 100% rename from src/mod/uti/engineertools20.uti.json rename to src/module/uti/engineertools20.uti.json diff --git a/src/mod/uti/essenceofmagical.uti.json b/src/module/uti/essenceofmagical.uti.json similarity index 100% rename from src/mod/uti/essenceofmagical.uti.json rename to src/module/uti/essenceofmagical.uti.json diff --git a/src/mod/uti/essenceofthedivi.uti.json b/src/module/uti/essenceofthedivi.uti.json similarity index 100% rename from src/mod/uti/essenceofthedivi.uti.json rename to src/module/uti/essenceofthedivi.uti.json diff --git a/src/mod/uti/essenceofthelowe.uti.json b/src/module/uti/essenceofthelowe.uti.json similarity index 100% rename from src/mod/uti/essenceofthelowe.uti.json rename to src/module/uti/essenceofthelowe.uti.json diff --git a/src/mod/uti/essenceofthepure.uti.json b/src/module/uti/essenceofthepure.uti.json similarity index 100% rename from src/mod/uti/essenceofthepure.uti.json rename to src/module/uti/essenceofthepure.uti.json diff --git a/src/mod/uti/essenceofthestor.uti.json b/src/module/uti/essenceofthestor.uti.json similarity index 100% rename from src/mod/uti/essenceofthestor.uti.json rename to src/module/uti/essenceofthestor.uti.json diff --git a/src/mod/uti/evilorb.uti.json b/src/module/uti/evilorb.uti.json similarity index 100% rename from src/mod/uti/evilorb.uti.json rename to src/module/uti/evilorb.uti.json diff --git a/src/mod/uti/evilsymbol.uti.json b/src/module/uti/evilsymbol.uti.json similarity index 100% rename from src/mod/uti/evilsymbol.uti.json rename to src/module/uti/evilsymbol.uti.json diff --git a/src/mod/uti/fallencleric.uti.json b/src/module/uti/fallencleric.uti.json similarity index 100% rename from src/mod/uti/fallencleric.uti.json rename to src/module/uti/fallencleric.uti.json diff --git a/src/mod/uti/fallenpallysword.uti.json b/src/module/uti/fallenpallysword.uti.json similarity index 100% rename from src/mod/uti/fallenpallysword.uti.json rename to src/module/uti/fallenpallysword.uti.json diff --git a/src/mod/uti/feetofthedead.uti.json b/src/module/uti/feetofthedead.uti.json similarity index 100% rename from src/mod/uti/feetofthedead.uti.json rename to src/module/uti/feetofthedead.uti.json diff --git a/src/mod/uti/femaledruidwarpi.uti.json b/src/module/uti/femaledruidwarpi.uti.json similarity index 100% rename from src/mod/uti/femaledruidwarpi.uti.json rename to src/module/uti/femaledruidwarpi.uti.json diff --git a/src/mod/uti/fireaxe.uti.json b/src/module/uti/fireaxe.uti.json similarity index 100% rename from src/mod/uti/fireaxe.uti.json rename to src/module/uti/fireaxe.uti.json diff --git a/src/mod/uti/firebombnpc.uti.json b/src/module/uti/firebombnpc.uti.json similarity index 100% rename from src/mod/uti/firebombnpc.uti.json rename to src/module/uti/firebombnpc.uti.json diff --git a/src/mod/uti/firebombnpc001.uti.json b/src/module/uti/firebombnpc001.uti.json similarity index 100% rename from src/mod/uti/firebombnpc001.uti.json rename to src/module/uti/firebombnpc001.uti.json diff --git a/src/mod/uti/fireclub.uti.json b/src/module/uti/fireclub.uti.json similarity index 100% rename from src/mod/uti/fireclub.uti.json rename to src/module/uti/fireclub.uti.json diff --git a/src/mod/uti/firedart.uti.json b/src/module/uti/firedart.uti.json similarity index 100% rename from src/mod/uti/firedart.uti.json rename to src/module/uti/firedart.uti.json diff --git a/src/mod/uti/fistskey.uti.json b/src/module/uti/fistskey.uti.json similarity index 100% rename from src/mod/uti/fistskey.uti.json rename to src/module/uti/fistskey.uti.json diff --git a/src/mod/uti/fistsoffear.uti.json b/src/module/uti/fistsoffear.uti.json similarity index 100% rename from src/mod/uti/fistsoffear.uti.json rename to src/module/uti/fistsoffear.uti.json diff --git a/src/mod/uti/flametakerslam.uti.json b/src/module/uti/flametakerslam.uti.json similarity index 100% rename from src/mod/uti/flametakerslam.uti.json rename to src/module/uti/flametakerslam.uti.json diff --git a/src/mod/uti/floatingbow.uti.json b/src/module/uti/floatingbow.uti.json similarity index 100% rename from src/mod/uti/floatingbow.uti.json rename to src/module/uti/floatingbow.uti.json diff --git a/src/mod/uti/followersguild.uti.json b/src/module/uti/followersguild.uti.json similarity index 100% rename from src/mod/uti/followersguild.uti.json rename to src/module/uti/followersguild.uti.json diff --git a/src/mod/uti/foreverbow.uti.json b/src/module/uti/foreverbow.uti.json similarity index 100% rename from src/mod/uti/foreverbow.uti.json rename to src/module/uti/foreverbow.uti.json diff --git a/src/mod/uti/formianarmor.uti.json b/src/module/uti/formianarmor.uti.json similarity index 100% rename from src/mod/uti/formianarmor.uti.json rename to src/module/uti/formianarmor.uti.json diff --git a/src/mod/uti/formianarrow.uti.json b/src/module/uti/formianarrow.uti.json similarity index 100% rename from src/mod/uti/formianarrow.uti.json rename to src/module/uti/formianarrow.uti.json diff --git a/src/mod/uti/formianaxe.uti.json b/src/module/uti/formianaxe.uti.json similarity index 100% rename from src/mod/uti/formianaxe.uti.json rename to src/module/uti/formianaxe.uti.json diff --git a/src/mod/uti/formiangoldarmor.uti.json b/src/module/uti/formiangoldarmor.uti.json similarity index 100% rename from src/mod/uti/formiangoldarmor.uti.json rename to src/module/uti/formiangoldarmor.uti.json diff --git a/src/mod/uti/formiankama.uti.json b/src/module/uti/formiankama.uti.json similarity index 100% rename from src/mod/uti/formiankama.uti.json rename to src/module/uti/formiankama.uti.json diff --git a/src/mod/uti/formianmace.uti.json b/src/module/uti/formianmace.uti.json similarity index 100% rename from src/mod/uti/formianmace.uti.json rename to src/module/uti/formianmace.uti.json diff --git a/src/mod/uti/formianshortbow.uti.json b/src/module/uti/formianshortbow.uti.json similarity index 100% rename from src/mod/uti/formianshortbow.uti.json rename to src/module/uti/formianshortbow.uti.json diff --git a/src/mod/uti/frostwolfbite.uti.json b/src/module/uti/frostwolfbite.uti.json similarity index 100% rename from src/mod/uti/frostwolfbite.uti.json rename to src/module/uti/frostwolfbite.uti.json diff --git a/src/mod/uti/frostwolfclaw.uti.json b/src/module/uti/frostwolfclaw.uti.json similarity index 100% rename from src/mod/uti/frostwolfclaw.uti.json rename to src/module/uti/frostwolfclaw.uti.json diff --git a/src/mod/uti/frostwolfskin.uti.json b/src/module/uti/frostwolfskin.uti.json similarity index 100% rename from src/mod/uti/frostwolfskin.uti.json rename to src/module/uti/frostwolfskin.uti.json diff --git a/src/mod/uti/frothickey.uti.json b/src/module/uti/frothickey.uti.json similarity index 100% rename from src/mod/uti/frothickey.uti.json rename to src/module/uti/frothickey.uti.json diff --git a/src/mod/uti/fullplate5.uti.json b/src/module/uti/fullplate5.uti.json similarity index 100% rename from src/mod/uti/fullplate5.uti.json rename to src/module/uti/fullplate5.uti.json diff --git a/src/mod/uti/gauntletsbornoff.uti.json b/src/module/uti/gauntletsbornoff.uti.json similarity index 100% rename from src/mod/uti/gauntletsbornoff.uti.json rename to src/module/uti/gauntletsbornoff.uti.json diff --git a/src/mod/uti/gladiatorbalde.uti.json b/src/module/uti/gladiatorbalde.uti.json similarity index 100% rename from src/mod/uti/gladiatorbalde.uti.json rename to src/module/uti/gladiatorbalde.uti.json diff --git a/src/mod/uti/glovesoflegends.uti.json b/src/module/uti/glovesoflegends.uti.json similarity index 100% rename from src/mod/uti/glovesoflegends.uti.json rename to src/module/uti/glovesoflegends.uti.json diff --git a/src/mod/uti/glovesofthedead.uti.json b/src/module/uti/glovesofthedead.uti.json similarity index 100% rename from src/mod/uti/glovesofthedead.uti.json rename to src/module/uti/glovesofthedead.uti.json diff --git a/src/mod/uti/gnollskin.uti.json b/src/module/uti/gnollskin.uti.json similarity index 100% rename from src/mod/uti/gnollskin.uti.json rename to src/module/uti/gnollskin.uti.json diff --git a/src/mod/uti/gnomearmor.uti.json b/src/module/uti/gnomearmor.uti.json similarity index 100% rename from src/mod/uti/gnomearmor.uti.json rename to src/module/uti/gnomearmor.uti.json diff --git a/src/mod/uti/gnomemight001.uti.json b/src/module/uti/gnomemight001.uti.json similarity index 100% rename from src/mod/uti/gnomemight001.uti.json rename to src/module/uti/gnomemight001.uti.json diff --git a/src/mod/uti/gold100.uti.json b/src/module/uti/gold100.uti.json similarity index 100% rename from src/mod/uti/gold100.uti.json rename to src/module/uti/gold100.uti.json diff --git a/src/mod/uti/gold200.uti.json b/src/module/uti/gold200.uti.json similarity index 100% rename from src/mod/uti/gold200.uti.json rename to src/module/uti/gold200.uti.json diff --git a/src/mod/uti/gold2000k.uti.json b/src/module/uti/gold2000k.uti.json similarity index 100% rename from src/mod/uti/gold2000k.uti.json rename to src/module/uti/gold2000k.uti.json diff --git a/src/mod/uti/gold200k.uti.json b/src/module/uti/gold200k.uti.json similarity index 100% rename from src/mod/uti/gold200k.uti.json rename to src/module/uti/gold200k.uti.json diff --git a/src/mod/uti/gold25k.uti.json b/src/module/uti/gold25k.uti.json similarity index 100% rename from src/mod/uti/gold25k.uti.json rename to src/module/uti/gold25k.uti.json diff --git a/src/mod/uti/gold5000.uti.json b/src/module/uti/gold5000.uti.json similarity index 100% rename from src/mod/uti/gold5000.uti.json rename to src/module/uti/gold5000.uti.json diff --git a/src/mod/uti/goldenrapier.uti.json b/src/module/uti/goldenrapier.uti.json similarity index 100% rename from src/mod/uti/goldenrapier.uti.json rename to src/module/uti/goldenrapier.uti.json diff --git a/src/mod/uti/goldkama.uti.json b/src/module/uti/goldkama.uti.json similarity index 100% rename from src/mod/uti/goldkama.uti.json rename to src/module/uti/goldkama.uti.json diff --git a/src/mod/uti/goodorb.uti.json b/src/module/uti/goodorb.uti.json similarity index 100% rename from src/mod/uti/goodorb.uti.json rename to src/module/uti/goodorb.uti.json diff --git a/src/mod/uti/goodsymbol.uti.json b/src/module/uti/goodsymbol.uti.json similarity index 100% rename from src/mod/uti/goodsymbol.uti.json rename to src/module/uti/goodsymbol.uti.json diff --git a/src/mod/uti/grailofundead.uti.json b/src/module/uti/grailofundead.uti.json similarity index 100% rename from src/mod/uti/grailofundead.uti.json rename to src/module/uti/grailofundead.uti.json diff --git a/src/mod/uti/granola.uti.json b/src/module/uti/granola.uti.json similarity index 100% rename from src/mod/uti/granola.uti.json rename to src/module/uti/granola.uti.json diff --git a/src/mod/uti/granolaarmor.uti.json b/src/module/uti/granolaarmor.uti.json similarity index 100% rename from src/mod/uti/granolaarmor.uti.json rename to src/module/uti/granolaarmor.uti.json diff --git a/src/mod/uti/granolasickle.uti.json b/src/module/uti/granolasickle.uti.json similarity index 100% rename from src/mod/uti/granolasickle.uti.json rename to src/module/uti/granolasickle.uti.json diff --git a/src/mod/uti/granolastick.uti.json b/src/module/uti/granolastick.uti.json similarity index 100% rename from src/mod/uti/granolastick.uti.json rename to src/module/uti/granolastick.uti.json diff --git a/src/mod/uti/granolawhip.uti.json b/src/module/uti/granolawhip.uti.json similarity index 100% rename from src/mod/uti/granolawhip.uti.json rename to src/module/uti/granolawhip.uti.json diff --git a/src/mod/uti/greataxeoftheold.uti.json b/src/module/uti/greataxeoftheold.uti.json similarity index 100% rename from src/mod/uti/greataxeoftheold.uti.json rename to src/module/uti/greataxeoftheold.uti.json diff --git a/src/mod/uti/greatoakarmor.uti.json b/src/module/uti/greatoakarmor.uti.json similarity index 100% rename from src/mod/uti/greatoakarmor.uti.json rename to src/module/uti/greatoakarmor.uti.json diff --git a/src/mod/uti/greendragonblood.uti.json b/src/module/uti/greendragonblood.uti.json similarity index 100% rename from src/mod/uti/greendragonblood.uti.json rename to src/module/uti/greendragonblood.uti.json diff --git a/src/mod/uti/grendelbelt.uti.json b/src/module/uti/grendelbelt.uti.json similarity index 100% rename from src/mod/uti/grendelbelt.uti.json rename to src/module/uti/grendelbelt.uti.json diff --git a/src/mod/uti/grendelsletter.uti.json b/src/module/uti/grendelsletter.uti.json similarity index 100% rename from src/mod/uti/grendelsletter.uti.json rename to src/module/uti/grendelsletter.uti.json diff --git a/src/mod/uti/guardianamulet.uti.json b/src/module/uti/guardianamulet.uti.json similarity index 100% rename from src/mod/uti/guardianamulet.uti.json rename to src/module/uti/guardianamulet.uti.json diff --git a/src/mod/uti/guardianarmor.uti.json b/src/module/uti/guardianarmor.uti.json similarity index 100% rename from src/mod/uti/guardianarmor.uti.json rename to src/module/uti/guardianarmor.uti.json diff --git a/src/mod/uti/guardianhelm.uti.json b/src/module/uti/guardianhelm.uti.json similarity index 100% rename from src/mod/uti/guardianhelm.uti.json rename to src/module/uti/guardianhelm.uti.json diff --git a/src/mod/uti/guardmoinkgaunts.uti.json b/src/module/uti/guardmoinkgaunts.uti.json similarity index 100% rename from src/mod/uti/guardmoinkgaunts.uti.json rename to src/module/uti/guardmoinkgaunts.uti.json diff --git a/src/mod/uti/guardmonkrobes.uti.json b/src/module/uti/guardmonkrobes.uti.json similarity index 100% rename from src/mod/uti/guardmonkrobes.uti.json rename to src/module/uti/guardmonkrobes.uti.json diff --git a/src/mod/uti/hammerofsentross.uti.json b/src/module/uti/hammerofsentross.uti.json similarity index 100% rename from src/mod/uti/hammerofsentross.uti.json rename to src/module/uti/hammerofsentross.uti.json diff --git a/src/mod/uti/handsoftime002.uti.json b/src/module/uti/handsoftime002.uti.json similarity index 100% rename from src/mod/uti/handsoftime002.uti.json rename to src/module/uti/handsoftime002.uti.json diff --git a/src/mod/uti/handsoftime003.uti.json b/src/module/uti/handsoftime003.uti.json similarity index 100% rename from src/mod/uti/handsoftime003.uti.json rename to src/module/uti/handsoftime003.uti.json diff --git a/src/mod/uti/handsoftime1.uti.json b/src/module/uti/handsoftime1.uti.json similarity index 100% rename from src/mod/uti/handsoftime1.uti.json rename to src/module/uti/handsoftime1.uti.json diff --git a/src/mod/uti/hardyboots.uti.json b/src/module/uti/hardyboots.uti.json similarity index 100% rename from src/mod/uti/hardyboots.uti.json rename to src/module/uti/hardyboots.uti.json diff --git a/src/mod/uti/hastepotion.uti.json b/src/module/uti/hastepotion.uti.json similarity index 100% rename from src/mod/uti/hastepotion.uti.json rename to src/module/uti/hastepotion.uti.json diff --git a/src/mod/uti/hastepotion1.uti.json b/src/module/uti/hastepotion1.uti.json similarity index 100% rename from src/mod/uti/hastepotion1.uti.json rename to src/module/uti/hastepotion1.uti.json diff --git a/src/mod/uti/headoffrothic.uti.json b/src/module/uti/headoffrothic.uti.json similarity index 100% rename from src/mod/uti/headoffrothic.uti.json rename to src/module/uti/headoffrothic.uti.json diff --git a/src/mod/uti/heal1.uti.json b/src/module/uti/heal1.uti.json similarity index 100% rename from src/mod/uti/heal1.uti.json rename to src/module/uti/heal1.uti.json diff --git a/src/mod/uti/heal10.uti.json b/src/module/uti/heal10.uti.json similarity index 100% rename from src/mod/uti/heal10.uti.json rename to src/module/uti/heal10.uti.json diff --git a/src/mod/uti/healstack10.uti.json b/src/module/uti/healstack10.uti.json similarity index 100% rename from src/mod/uti/healstack10.uti.json rename to src/module/uti/healstack10.uti.json diff --git a/src/mod/uti/heavingarmor.uti.json b/src/module/uti/heavingarmor.uti.json similarity index 100% rename from src/mod/uti/heavingarmor.uti.json rename to src/module/uti/heavingarmor.uti.json diff --git a/src/mod/uti/heavingarrows.uti.json b/src/module/uti/heavingarrows.uti.json similarity index 100% rename from src/mod/uti/heavingarrows.uti.json rename to src/module/uti/heavingarrows.uti.json diff --git a/src/mod/uti/heavingarrows001.uti.json b/src/module/uti/heavingarrows001.uti.json similarity index 100% rename from src/mod/uti/heavingarrows001.uti.json rename to src/module/uti/heavingarrows001.uti.json diff --git a/src/mod/uti/heavingbow.uti.json b/src/module/uti/heavingbow.uti.json similarity index 100% rename from src/mod/uti/heavingbow.uti.json rename to src/module/uti/heavingbow.uti.json diff --git a/src/mod/uti/helmofbrilliance.uti.json b/src/module/uti/helmofbrilliance.uti.json similarity index 100% rename from src/mod/uti/helmofbrilliance.uti.json rename to src/module/uti/helmofbrilliance.uti.json diff --git a/src/mod/uti/hideofvera.uti.json b/src/module/uti/hideofvera.uti.json similarity index 100% rename from src/mod/uti/hideofvera.uti.json rename to src/module/uti/hideofvera.uti.json diff --git a/src/mod/uti/hillsideiceberry.uti.json b/src/module/uti/hillsideiceberry.uti.json similarity index 100% rename from src/mod/uti/hillsideiceberry.uti.json rename to src/module/uti/hillsideiceberry.uti.json diff --git a/src/mod/uti/hillsidespecters.uti.json b/src/module/uti/hillsidespecters.uti.json similarity index 100% rename from src/mod/uti/hillsidespecters.uti.json rename to src/module/uti/hillsidespecters.uti.json diff --git a/src/mod/uti/hillsidestingerh.uti.json b/src/module/uti/hillsidestingerh.uti.json similarity index 100% rename from src/mod/uti/hillsidestingerh.uti.json rename to src/module/uti/hillsidestingerh.uti.json diff --git a/src/mod/uti/hillsiflameberry.uti.json b/src/module/uti/hillsiflameberry.uti.json similarity index 100% rename from src/mod/uti/hillsiflameberry.uti.json rename to src/module/uti/hillsiflameberry.uti.json diff --git a/src/mod/uti/historykey.uti.json b/src/module/uti/historykey.uti.json similarity index 100% rename from src/mod/uti/historykey.uti.json rename to src/module/uti/historykey.uti.json diff --git a/src/mod/uti/holoarmor.uti.json b/src/module/uti/holoarmor.uti.json similarity index 100% rename from src/mod/uti/holoarmor.uti.json rename to src/module/uti/holoarmor.uti.json diff --git a/src/mod/uti/holohelmet.uti.json b/src/module/uti/holohelmet.uti.json similarity index 100% rename from src/mod/uti/holohelmet.uti.json rename to src/module/uti/holohelmet.uti.json diff --git a/src/mod/uti/holomace.uti.json b/src/module/uti/holomace.uti.json similarity index 100% rename from src/mod/uti/holomace.uti.json rename to src/module/uti/holomace.uti.json diff --git a/src/mod/uti/holoshield.uti.json b/src/module/uti/holoshield.uti.json similarity index 100% rename from src/mod/uti/holoshield.uti.json rename to src/module/uti/holoshield.uti.json diff --git a/src/mod/uti/holyserum.uti.json b/src/module/uti/holyserum.uti.json similarity index 100% rename from src/mod/uti/holyserum.uti.json rename to src/module/uti/holyserum.uti.json diff --git a/src/mod/uti/holystrike.uti.json b/src/module/uti/holystrike.uti.json similarity index 100% rename from src/mod/uti/holystrike.uti.json rename to src/module/uti/holystrike.uti.json diff --git a/src/mod/uti/horrorkey.uti.json b/src/module/uti/horrorkey.uti.json similarity index 100% rename from src/mod/uti/horrorkey.uti.json rename to src/module/uti/horrorkey.uti.json diff --git a/src/mod/uti/icyblade.uti.json b/src/module/uti/icyblade.uti.json similarity index 100% rename from src/mod/uti/icyblade.uti.json rename to src/module/uti/icyblade.uti.json diff --git a/src/mod/uti/impclaws.uti.json b/src/module/uti/impclaws.uti.json similarity index 100% rename from src/mod/uti/impclaws.uti.json rename to src/module/uti/impclaws.uti.json diff --git a/src/mod/uti/imporovedfirearr.uti.json b/src/module/uti/imporovedfirearr.uti.json similarity index 100% rename from src/mod/uti/imporovedfirearr.uti.json rename to src/module/uti/imporovedfirearr.uti.json diff --git a/src/mod/uti/imporovedsonic.uti.json b/src/module/uti/imporovedsonic.uti.json similarity index 100% rename from src/mod/uti/imporovedsonic.uti.json rename to src/module/uti/imporovedsonic.uti.json diff --git a/src/mod/uti/impskin.uti.json b/src/module/uti/impskin.uti.json similarity index 100% rename from src/mod/uti/impskin.uti.json rename to src/module/uti/impskin.uti.json diff --git a/src/mod/uti/infernokey.uti.json b/src/module/uti/infernokey.uti.json similarity index 100% rename from src/mod/uti/infernokey.uti.json rename to src/module/uti/infernokey.uti.json diff --git a/src/mod/uti/infernorobe.uti.json b/src/module/uti/infernorobe.uti.json similarity index 100% rename from src/mod/uti/infernorobe.uti.json rename to src/module/uti/infernorobe.uti.json diff --git a/src/mod/uti/infernorobe001.uti.json b/src/module/uti/infernorobe001.uti.json similarity index 100% rename from src/mod/uti/infernorobe001.uti.json rename to src/module/uti/infernorobe001.uti.json diff --git a/src/mod/uti/infernostaff.uti.json b/src/module/uti/infernostaff.uti.json similarity index 100% rename from src/mod/uti/infernostaff.uti.json rename to src/module/uti/infernostaff.uti.json diff --git a/src/mod/uti/infusionrobe.uti.json b/src/module/uti/infusionrobe.uti.json similarity index 100% rename from src/mod/uti/infusionrobe.uti.json rename to src/module/uti/infusionrobe.uti.json diff --git a/src/mod/uti/insightrobes.uti.json b/src/module/uti/insightrobes.uti.json similarity index 100% rename from src/mod/uti/insightrobes.uti.json rename to src/module/uti/insightrobes.uti.json diff --git a/src/mod/uti/iron_slash.uti.json b/src/module/uti/iron_slash.uti.json similarity index 100% rename from src/mod/uti/iron_slash.uti.json rename to src/module/uti/iron_slash.uti.json diff --git a/src/mod/uti/iron_slash2.uti.json b/src/module/uti/iron_slash2.uti.json similarity index 100% rename from src/mod/uti/iron_slash2.uti.json rename to src/module/uti/iron_slash2.uti.json diff --git a/src/mod/uti/ironbite.uti.json b/src/module/uti/ironbite.uti.json similarity index 100% rename from src/mod/uti/ironbite.uti.json rename to src/module/uti/ironbite.uti.json diff --git a/src/mod/uti/ironclawarmor.uti.json b/src/module/uti/ironclawarmor.uti.json similarity index 100% rename from src/mod/uti/ironclawarmor.uti.json rename to src/module/uti/ironclawarmor.uti.json diff --git a/src/mod/uti/ironclawarmor2.uti.json b/src/module/uti/ironclawarmor2.uti.json similarity index 100% rename from src/mod/uti/ironclawarmor2.uti.json rename to src/module/uti/ironclawarmor2.uti.json diff --git a/src/mod/uti/ironclawaxe.uti.json b/src/module/uti/ironclawaxe.uti.json similarity index 100% rename from src/mod/uti/ironclawaxe.uti.json rename to src/module/uti/ironclawaxe.uti.json diff --git a/src/mod/uti/ironclawbastard.uti.json b/src/module/uti/ironclawbastard.uti.json similarity index 100% rename from src/mod/uti/ironclawbastard.uti.json rename to src/module/uti/ironclawbastard.uti.json diff --git a/src/mod/uti/ironclawgreat001.uti.json b/src/module/uti/ironclawgreat001.uti.json similarity index 100% rename from src/mod/uti/ironclawgreat001.uti.json rename to src/module/uti/ironclawgreat001.uti.json diff --git a/src/mod/uti/ironclawgreataxe.uti.json b/src/module/uti/ironclawgreataxe.uti.json similarity index 100% rename from src/mod/uti/ironclawgreataxe.uti.json rename to src/module/uti/ironclawgreataxe.uti.json diff --git a/src/mod/uti/ironclawgreatswo.uti.json b/src/module/uti/ironclawgreatswo.uti.json similarity index 100% rename from src/mod/uti/ironclawgreatswo.uti.json rename to src/module/uti/ironclawgreatswo.uti.json diff --git a/src/mod/uti/ironclawham.uti.json b/src/module/uti/ironclawham.uti.json similarity index 100% rename from src/mod/uti/ironclawham.uti.json rename to src/module/uti/ironclawham.uti.json diff --git a/src/mod/uti/ironclawhelm.uti.json b/src/module/uti/ironclawhelm.uti.json similarity index 100% rename from src/mod/uti/ironclawhelm.uti.json rename to src/module/uti/ironclawhelm.uti.json diff --git a/src/mod/uti/ironclawjailkey.uti.json b/src/module/uti/ironclawjailkey.uti.json similarity index 100% rename from src/mod/uti/ironclawjailkey.uti.json rename to src/module/uti/ironclawjailkey.uti.json diff --git a/src/mod/uti/ironclawrobe.uti.json b/src/module/uti/ironclawrobe.uti.json similarity index 100% rename from src/mod/uti/ironclawrobe.uti.json rename to src/module/uti/ironclawrobe.uti.json diff --git a/src/mod/uti/ironclaws.uti.json b/src/module/uti/ironclaws.uti.json similarity index 100% rename from src/mod/uti/ironclaws.uti.json rename to src/module/uti/ironclaws.uti.json diff --git a/src/mod/uti/ironclaws001.uti.json b/src/module/uti/ironclaws001.uti.json similarity index 100% rename from src/mod/uti/ironclaws001.uti.json rename to src/module/uti/ironclaws001.uti.json diff --git a/src/mod/uti/ironclaws2.uti.json b/src/module/uti/ironclaws2.uti.json similarity index 100% rename from src/mod/uti/ironclaws2.uti.json rename to src/module/uti/ironclaws2.uti.json diff --git a/src/mod/uti/ironclawsword.uti.json b/src/module/uti/ironclawsword.uti.json similarity index 100% rename from src/mod/uti/ironclawsword.uti.json rename to src/module/uti/ironclawsword.uti.json diff --git a/src/mod/uti/ironclawthrowing.uti.json b/src/module/uti/ironclawthrowing.uti.json similarity index 100% rename from src/mod/uti/ironclawthrowing.uti.json rename to src/module/uti/ironclawthrowing.uti.json diff --git a/src/mod/uti/ironenergy.uti.json b/src/module/uti/ironenergy.uti.json similarity index 100% rename from src/mod/uti/ironenergy.uti.json rename to src/module/uti/ironenergy.uti.json diff --git a/src/mod/uti/irongoblindagger.uti.json b/src/module/uti/irongoblindagger.uti.json similarity index 100% rename from src/mod/uti/irongoblindagger.uti.json rename to src/module/uti/irongoblindagger.uti.json diff --git a/src/mod/uti/ironkatana.uti.json b/src/module/uti/ironkatana.uti.json similarity index 100% rename from src/mod/uti/ironkatana.uti.json rename to src/module/uti/ironkatana.uti.json diff --git a/src/mod/uti/ironminotaurswor.uti.json b/src/module/uti/ironminotaurswor.uti.json similarity index 100% rename from src/mod/uti/ironminotaurswor.uti.json rename to src/module/uti/ironminotaurswor.uti.json diff --git a/src/mod/uti/ironore.uti.json b/src/module/uti/ironore.uti.json similarity index 100% rename from src/mod/uti/ironore.uti.json rename to src/module/uti/ironore.uti.json diff --git a/src/mod/uti/ironskin.uti.json b/src/module/uti/ironskin.uti.json similarity index 100% rename from src/mod/uti/ironskin.uti.json rename to src/module/uti/ironskin.uti.json diff --git a/src/mod/uti/ironskin001.uti.json b/src/module/uti/ironskin001.uti.json similarity index 100% rename from src/mod/uti/ironskin001.uti.json rename to src/module/uti/ironskin001.uti.json diff --git a/src/mod/uti/ironskin002.uti.json b/src/module/uti/ironskin002.uti.json similarity index 100% rename from src/mod/uti/ironskin002.uti.json rename to src/module/uti/ironskin002.uti.json diff --git a/src/mod/uti/ironskin003.uti.json b/src/module/uti/ironskin003.uti.json similarity index 100% rename from src/mod/uti/ironskin003.uti.json rename to src/module/uti/ironskin003.uti.json diff --git a/src/mod/uti/ironskin004.uti.json b/src/module/uti/ironskin004.uti.json similarity index 100% rename from src/mod/uti/ironskin004.uti.json rename to src/module/uti/ironskin004.uti.json diff --git a/src/mod/uti/ironskin005.uti.json b/src/module/uti/ironskin005.uti.json similarity index 100% rename from src/mod/uti/ironskin005.uti.json rename to src/module/uti/ironskin005.uti.json diff --git a/src/mod/uti/ironskin006.uti.json b/src/module/uti/ironskin006.uti.json similarity index 100% rename from src/mod/uti/ironskin006.uti.json rename to src/module/uti/ironskin006.uti.json diff --git a/src/mod/uti/ironstaff.uti.json b/src/module/uti/ironstaff.uti.json similarity index 100% rename from src/mod/uti/ironstaff.uti.json rename to src/module/uti/ironstaff.uti.json diff --git a/src/mod/uti/isaacsbane.uti.json b/src/module/uti/isaacsbane.uti.json similarity index 100% rename from src/mod/uti/isaacsbane.uti.json rename to src/module/uti/isaacsbane.uti.json diff --git a/src/mod/uti/isisbolt.uti.json b/src/module/uti/isisbolt.uti.json similarity index 100% rename from src/mod/uti/isisbolt.uti.json rename to src/module/uti/isisbolt.uti.json diff --git a/src/mod/uti/isiscrossbow.uti.json b/src/module/uti/isiscrossbow.uti.json similarity index 100% rename from src/mod/uti/isiscrossbow.uti.json rename to src/module/uti/isiscrossbow.uti.json diff --git a/src/mod/uti/issacgaunts.uti.json b/src/module/uti/issacgaunts.uti.json similarity index 100% rename from src/mod/uti/issacgaunts.uti.json rename to src/module/uti/issacgaunts.uti.json diff --git a/src/mod/uti/issackey.uti.json b/src/module/uti/issackey.uti.json similarity index 100% rename from src/mod/uti/issackey.uti.json rename to src/module/uti/issackey.uti.json diff --git a/src/mod/uti/issacrobe.uti.json b/src/module/uti/issacrobe.uti.json similarity index 100% rename from src/mod/uti/issacrobe.uti.json rename to src/module/uti/issacrobe.uti.json diff --git a/src/mod/uti/issacrobe01.uti.json b/src/module/uti/issacrobe01.uti.json similarity index 100% rename from src/mod/uti/issacrobe01.uti.json rename to src/module/uti/issacrobe01.uti.json diff --git a/src/mod/uti/issacstaff.uti.json b/src/module/uti/issacstaff.uti.json similarity index 100% rename from src/mod/uti/issacstaff.uti.json rename to src/module/uti/issacstaff.uti.json diff --git a/src/mod/uti/it_cregelcslm001.uti.json b/src/module/uti/it_cregelcslm001.uti.json similarity index 100% rename from src/mod/uti/it_cregelcslm001.uti.json rename to src/module/uti/it_cregelcslm001.uti.json diff --git a/src/mod/uti/it_crewpb021.uti.json b/src/module/uti/it_crewpb021.uti.json similarity index 100% rename from src/mod/uti/it_crewpb021.uti.json rename to src/module/uti/it_crewpb021.uti.json diff --git a/src/mod/uti/it_crewpsp003.uti.json b/src/module/uti/it_crewpsp003.uti.json similarity index 100% rename from src/mod/uti/it_crewpsp003.uti.json rename to src/module/uti/it_crewpsp003.uti.json diff --git a/src/mod/uti/it_gold003.uti.json b/src/module/uti/it_gold003.uti.json similarity index 100% rename from src/mod/uti/it_gold003.uti.json rename to src/module/uti/it_gold003.uti.json diff --git a/src/mod/uti/it_mthnmisc018.uti.json b/src/module/uti/it_mthnmisc018.uti.json similarity index 100% rename from src/mod/uti/it_mthnmisc018.uti.json rename to src/module/uti/it_mthnmisc018.uti.json diff --git a/src/mod/uti/it_novel009.uti.json b/src/module/uti/it_novel009.uti.json similarity index 100% rename from src/mod/uti/it_novel009.uti.json rename to src/module/uti/it_novel009.uti.json diff --git a/src/mod/uti/item.uti.json b/src/module/uti/item.uti.json similarity index 100% rename from src/mod/uti/item.uti.json rename to src/module/uti/item.uti.json diff --git a/src/mod/uti/item001.uti.json b/src/module/uti/item001.uti.json similarity index 100% rename from src/mod/uti/item001.uti.json rename to src/module/uti/item001.uti.json diff --git a/src/mod/uti/item002.uti.json b/src/module/uti/item002.uti.json similarity index 100% rename from src/mod/uti/item002.uti.json rename to src/module/uti/item002.uti.json diff --git a/src/mod/uti/item003.uti.json b/src/module/uti/item003.uti.json similarity index 100% rename from src/mod/uti/item003.uti.json rename to src/module/uti/item003.uti.json diff --git a/src/mod/uti/item004.uti.json b/src/module/uti/item004.uti.json similarity index 100% rename from src/mod/uti/item004.uti.json rename to src/module/uti/item004.uti.json diff --git a/src/mod/uti/item005.uti.json b/src/module/uti/item005.uti.json similarity index 100% rename from src/mod/uti/item005.uti.json rename to src/module/uti/item005.uti.json diff --git a/src/mod/uti/item006.uti.json b/src/module/uti/item006.uti.json similarity index 100% rename from src/mod/uti/item006.uti.json rename to src/module/uti/item006.uti.json diff --git a/src/mod/uti/item007.uti.json b/src/module/uti/item007.uti.json similarity index 100% rename from src/mod/uti/item007.uti.json rename to src/module/uti/item007.uti.json diff --git a/src/mod/uti/item010.uti.json b/src/module/uti/item010.uti.json similarity index 100% rename from src/mod/uti/item010.uti.json rename to src/module/uti/item010.uti.json diff --git a/src/mod/uti/item011.uti.json b/src/module/uti/item011.uti.json similarity index 100% rename from src/mod/uti/item011.uti.json rename to src/module/uti/item011.uti.json diff --git a/src/mod/uti/item012.uti.json b/src/module/uti/item012.uti.json similarity index 100% rename from src/mod/uti/item012.uti.json rename to src/module/uti/item012.uti.json diff --git a/src/mod/uti/item013.uti.json b/src/module/uti/item013.uti.json similarity index 100% rename from src/mod/uti/item013.uti.json rename to src/module/uti/item013.uti.json diff --git a/src/mod/uti/item017.uti.json b/src/module/uti/item017.uti.json similarity index 100% rename from src/mod/uti/item017.uti.json rename to src/module/uti/item017.uti.json diff --git a/src/mod/uti/item020.uti.json b/src/module/uti/item020.uti.json similarity index 100% rename from src/mod/uti/item020.uti.json rename to src/module/uti/item020.uti.json diff --git a/src/mod/uti/jagangbosskey.uti.json b/src/module/uti/jagangbosskey.uti.json similarity index 100% rename from src/mod/uti/jagangbosskey.uti.json rename to src/module/uti/jagangbosskey.uti.json diff --git a/src/mod/uti/jagangkey1.uti.json b/src/module/uti/jagangkey1.uti.json similarity index 100% rename from src/mod/uti/jagangkey1.uti.json rename to src/module/uti/jagangkey1.uti.json diff --git a/src/mod/uti/jagangrobenpc.uti.json b/src/module/uti/jagangrobenpc.uti.json similarity index 100% rename from src/mod/uti/jagangrobenpc.uti.json rename to src/module/uti/jagangrobenpc.uti.json diff --git a/src/mod/uti/jagangsanctumkey.uti.json b/src/module/uti/jagangsanctumkey.uti.json similarity index 100% rename from src/mod/uti/jagangsanctumkey.uti.json rename to src/module/uti/jagangsanctumkey.uti.json diff --git a/src/mod/uti/jailorsword.uti.json b/src/module/uti/jailorsword.uti.json similarity index 100% rename from src/mod/uti/jailorsword.uti.json rename to src/module/uti/jailorsword.uti.json diff --git a/src/mod/uti/jerkinsamulet.uti.json b/src/module/uti/jerkinsamulet.uti.json similarity index 100% rename from src/mod/uti/jerkinsamulet.uti.json rename to src/module/uti/jerkinsamulet.uti.json diff --git a/src/mod/uti/jewlerytool.uti.json b/src/module/uti/jewlerytool.uti.json similarity index 100% rename from src/mod/uti/jewlerytool.uti.json rename to src/module/uti/jewlerytool.uti.json diff --git a/src/mod/uti/jezarmor.uti.json b/src/module/uti/jezarmor.uti.json similarity index 100% rename from src/mod/uti/jezarmor.uti.json rename to src/module/uti/jezarmor.uti.json diff --git a/src/mod/uti/jimmyssword.uti.json b/src/module/uti/jimmyssword.uti.json similarity index 100% rename from src/mod/uti/jimmyssword.uti.json rename to src/module/uti/jimmyssword.uti.json diff --git a/src/mod/uti/katarmor.uti.json b/src/module/uti/katarmor.uti.json similarity index 100% rename from src/mod/uti/katarmor.uti.json rename to src/module/uti/katarmor.uti.json diff --git a/src/mod/uti/keyofcheating.uti.json b/src/module/uti/keyofcheating.uti.json similarity index 100% rename from src/mod/uti/keyofcheating.uti.json rename to src/module/uti/keyofcheating.uti.json diff --git a/src/mod/uti/kobolddagger.uti.json b/src/module/uti/kobolddagger.uti.json similarity index 100% rename from src/mod/uti/kobolddagger.uti.json rename to src/module/uti/kobolddagger.uti.json diff --git a/src/mod/uti/koboldianscimita.uti.json b/src/module/uti/koboldianscimita.uti.json similarity index 100% rename from src/mod/uti/koboldianscimita.uti.json rename to src/module/uti/koboldianscimita.uti.json diff --git a/src/mod/uti/koboldsword.uti.json b/src/module/uti/koboldsword.uti.json similarity index 100% rename from src/mod/uti/koboldsword.uti.json rename to src/module/uti/koboldsword.uti.json diff --git a/src/mod/uti/kotshelper001.uti.json b/src/module/uti/kotshelper001.uti.json similarity index 100% rename from src/mod/uti/kotshelper001.uti.json rename to src/module/uti/kotshelper001.uti.json diff --git a/src/mod/uti/leathercloak.uti.json b/src/module/uti/leathercloak.uti.json similarity index 100% rename from src/mod/uti/leathercloak.uti.json rename to src/module/uti/leathercloak.uti.json diff --git a/src/mod/uti/leathersoftheund.uti.json b/src/module/uti/leathersoftheund.uti.json similarity index 100% rename from src/mod/uti/leathersoftheund.uti.json rename to src/module/uti/leathersoftheund.uti.json diff --git a/src/mod/uti/legendbracers01.uti.json b/src/module/uti/legendbracers01.uti.json similarity index 100% rename from src/mod/uti/legendbracers01.uti.json rename to src/module/uti/legendbracers01.uti.json diff --git a/src/mod/uti/legionarrows.uti.json b/src/module/uti/legionarrows.uti.json similarity index 100% rename from src/mod/uti/legionarrows.uti.json rename to src/module/uti/legionarrows.uti.json diff --git a/src/mod/uti/legionassrobe.uti.json b/src/module/uti/legionassrobe.uti.json similarity index 100% rename from src/mod/uti/legionassrobe.uti.json rename to src/module/uti/legionassrobe.uti.json diff --git a/src/mod/uti/legionbow.uti.json b/src/module/uti/legionbow.uti.json similarity index 100% rename from src/mod/uti/legionbow.uti.json rename to src/module/uti/legionbow.uti.json diff --git a/src/mod/uti/legiondagger.uti.json b/src/module/uti/legiondagger.uti.json similarity index 100% rename from src/mod/uti/legiondagger.uti.json rename to src/module/uti/legiondagger.uti.json diff --git a/src/mod/uti/legiongrail002.uti.json b/src/module/uti/legiongrail002.uti.json similarity index 100% rename from src/mod/uti/legiongrail002.uti.json rename to src/module/uti/legiongrail002.uti.json diff --git a/src/mod/uti/legiongrail003.uti.json b/src/module/uti/legiongrail003.uti.json similarity index 100% rename from src/mod/uti/legiongrail003.uti.json rename to src/module/uti/legiongrail003.uti.json diff --git a/src/mod/uti/legiongrail004.uti.json b/src/module/uti/legiongrail004.uti.json similarity index 100% rename from src/mod/uti/legiongrail004.uti.json rename to src/module/uti/legiongrail004.uti.json diff --git a/src/mod/uti/legiongrail1.uti.json b/src/module/uti/legiongrail1.uti.json similarity index 100% rename from src/mod/uti/legiongrail1.uti.json rename to src/module/uti/legiongrail1.uti.json diff --git a/src/mod/uti/legionkingrob2.uti.json b/src/module/uti/legionkingrob2.uti.json similarity index 100% rename from src/mod/uti/legionkingrob2.uti.json rename to src/module/uti/legionkingrob2.uti.json diff --git a/src/mod/uti/legionkingrobe.uti.json b/src/module/uti/legionkingrobe.uti.json similarity index 100% rename from src/mod/uti/legionkingrobe.uti.json rename to src/module/uti/legionkingrobe.uti.json diff --git a/src/mod/uti/legionkingtunic.uti.json b/src/module/uti/legionkingtunic.uti.json similarity index 100% rename from src/mod/uti/legionkingtunic.uti.json rename to src/module/uti/legionkingtunic.uti.json diff --git a/src/mod/uti/legionkukri.uti.json b/src/module/uti/legionkukri.uti.json similarity index 100% rename from src/mod/uti/legionkukri.uti.json rename to src/module/uti/legionkukri.uti.json diff --git a/src/mod/uti/legionroguehelm.uti.json b/src/module/uti/legionroguehelm.uti.json similarity index 100% rename from src/mod/uti/legionroguehelm.uti.json rename to src/module/uti/legionroguehelm.uti.json diff --git a/src/mod/uti/legionscimitar.uti.json b/src/module/uti/legionscimitar.uti.json similarity index 100% rename from src/mod/uti/legionscimitar.uti.json rename to src/module/uti/legionscimitar.uti.json diff --git a/src/mod/uti/legionskin.uti.json b/src/module/uti/legionskin.uti.json similarity index 100% rename from src/mod/uti/legionskin.uti.json rename to src/module/uti/legionskin.uti.json diff --git a/src/mod/uti/lesserveraring.uti.json b/src/module/uti/lesserveraring.uti.json similarity index 100% rename from src/mod/uti/lesserveraring.uti.json rename to src/module/uti/lesserveraring.uti.json diff --git a/src/mod/uti/librariansletter.uti.json b/src/module/uti/librariansletter.uti.json similarity index 100% rename from src/mod/uti/librariansletter.uti.json rename to src/module/uti/librariansletter.uti.json diff --git a/src/mod/uti/librarycard.uti.json b/src/module/uti/librarycard.uti.json similarity index 100% rename from src/mod/uti/librarycard.uti.json rename to src/module/uti/librarycard.uti.json diff --git a/src/mod/uti/librarystaff.uti.json b/src/module/uti/librarystaff.uti.json similarity index 100% rename from src/mod/uti/librarystaff.uti.json rename to src/module/uti/librarystaff.uti.json diff --git a/src/mod/uti/lichsstaff.uti.json b/src/module/uti/lichsstaff.uti.json similarity index 100% rename from src/mod/uti/lichsstaff.uti.json rename to src/module/uti/lichsstaff.uti.json diff --git a/src/mod/uti/lightingcrossbow.uti.json b/src/module/uti/lightingcrossbow.uti.json similarity index 100% rename from src/mod/uti/lightingcrossbow.uti.json rename to src/module/uti/lightingcrossbow.uti.json diff --git a/src/mod/uti/lightingdart.uti.json b/src/module/uti/lightingdart.uti.json similarity index 100% rename from src/mod/uti/lightingdart.uti.json rename to src/module/uti/lightingdart.uti.json diff --git a/src/mod/uti/lightpack.uti.json b/src/module/uti/lightpack.uti.json similarity index 100% rename from src/mod/uti/lightpack.uti.json rename to src/module/uti/lightpack.uti.json diff --git a/src/mod/uti/lithiumbastard.uti.json b/src/module/uti/lithiumbastard.uti.json similarity index 100% rename from src/mod/uti/lithiumbastard.uti.json rename to src/module/uti/lithiumbastard.uti.json diff --git a/src/mod/uti/lithiumheavy.uti.json b/src/module/uti/lithiumheavy.uti.json similarity index 100% rename from src/mod/uti/lithiumheavy.uti.json rename to src/module/uti/lithiumheavy.uti.json diff --git a/src/mod/uti/lithiumlight.uti.json b/src/module/uti/lithiumlight.uti.json similarity index 100% rename from src/mod/uti/lithiumlight.uti.json rename to src/module/uti/lithiumlight.uti.json diff --git a/src/mod/uti/lithiumlong.uti.json b/src/module/uti/lithiumlong.uti.json similarity index 100% rename from src/mod/uti/lithiumlong.uti.json rename to src/module/uti/lithiumlong.uti.json diff --git a/src/mod/uti/lucephcptmace.uti.json b/src/module/uti/lucephcptmace.uti.json similarity index 100% rename from src/mod/uti/lucephcptmace.uti.json rename to src/module/uti/lucephcptmace.uti.json diff --git a/src/mod/uti/lustyblade.uti.json b/src/module/uti/lustyblade.uti.json similarity index 100% rename from src/mod/uti/lustyblade.uti.json rename to src/module/uti/lustyblade.uti.json diff --git a/src/mod/uti/madwizardrobe.uti.json b/src/module/uti/madwizardrobe.uti.json similarity index 100% rename from src/mod/uti/madwizardrobe.uti.json rename to src/module/uti/madwizardrobe.uti.json diff --git a/src/mod/uti/magicaldefenseri.uti.json b/src/module/uti/magicaldefenseri.uti.json similarity index 100% rename from src/mod/uti/magicaldefenseri.uti.json rename to src/module/uti/magicaldefenseri.uti.json diff --git a/src/mod/uti/magicalstone20.uti.json b/src/module/uti/magicalstone20.uti.json similarity index 100% rename from src/mod/uti/magicalstone20.uti.json rename to src/module/uti/magicalstone20.uti.json diff --git a/src/mod/uti/magicrune.uti.json b/src/module/uti/magicrune.uti.json similarity index 100% rename from src/mod/uti/magicrune.uti.json rename to src/module/uti/magicrune.uti.json diff --git a/src/mod/uti/magicyellowpowde.uti.json b/src/module/uti/magicyellowpowde.uti.json similarity index 100% rename from src/mod/uti/magicyellowpowde.uti.json rename to src/module/uti/magicyellowpowde.uti.json diff --git a/src/mod/uti/masterassassintu.uti.json b/src/module/uti/masterassassintu.uti.json similarity index 100% rename from src/mod/uti/masterassassintu.uti.json rename to src/module/uti/masterassassintu.uti.json diff --git a/src/mod/uti/masterworkarmor.uti.json b/src/module/uti/masterworkarmor.uti.json similarity index 100% rename from src/mod/uti/masterworkarmor.uti.json rename to src/module/uti/masterworkarmor.uti.json diff --git a/src/mod/uti/masterworkhelm.uti.json b/src/module/uti/masterworkhelm.uti.json similarity index 100% rename from src/mod/uti/masterworkhelm.uti.json rename to src/module/uti/masterworkhelm.uti.json diff --git a/src/mod/uti/mayorsletter.uti.json b/src/module/uti/mayorsletter.uti.json similarity index 100% rename from src/mod/uti/mayorsletter.uti.json rename to src/module/uti/mayorsletter.uti.json diff --git a/src/mod/uti/mc_garmant.uti.json b/src/module/uti/mc_garmant.uti.json similarity index 100% rename from src/mod/uti/mc_garmant.uti.json rename to src/module/uti/mc_garmant.uti.json diff --git a/src/mod/uti/mcloth004.uti.json b/src/module/uti/mcloth004.uti.json similarity index 100% rename from src/mod/uti/mcloth004.uti.json rename to src/module/uti/mcloth004.uti.json diff --git a/src/mod/uti/mercshield.uti.json b/src/module/uti/mercshield.uti.json similarity index 100% rename from src/mod/uti/mercshield.uti.json rename to src/module/uti/mercshield.uti.json diff --git a/src/mod/uti/mindflayerammy.uti.json b/src/module/uti/mindflayerammy.uti.json similarity index 100% rename from src/mod/uti/mindflayerammy.uti.json rename to src/module/uti/mindflayerammy.uti.json diff --git a/src/mod/uti/mindport.uti.json b/src/module/uti/mindport.uti.json similarity index 100% rename from src/mod/uti/mindport.uti.json rename to src/module/uti/mindport.uti.json diff --git a/src/mod/uti/minimonkgauntlet.uti.json b/src/module/uti/minimonkgauntlet.uti.json similarity index 100% rename from src/mod/uti/minimonkgauntlet.uti.json rename to src/module/uti/minimonkgauntlet.uti.json diff --git a/src/mod/uti/minimonkrobes.uti.json b/src/module/uti/minimonkrobes.uti.json similarity index 100% rename from src/mod/uti/minimonkrobes.uti.json rename to src/module/uti/minimonkrobes.uti.json diff --git a/src/mod/uti/minotaurscythe.uti.json b/src/module/uti/minotaurscythe.uti.json similarity index 100% rename from src/mod/uti/minotaurscythe.uti.json rename to src/module/uti/minotaurscythe.uti.json diff --git a/src/mod/uti/mmgauntlets001.uti.json b/src/module/uti/mmgauntlets001.uti.json similarity index 100% rename from src/mod/uti/mmgauntlets001.uti.json rename to src/module/uti/mmgauntlets001.uti.json diff --git a/src/mod/uti/mmrobes.uti.json b/src/module/uti/mmrobes.uti.json similarity index 100% rename from src/mod/uti/mmrobes.uti.json rename to src/module/uti/mmrobes.uti.json diff --git a/src/mod/uti/monkkey.uti.json b/src/module/uti/monkkey.uti.json similarity index 100% rename from src/mod/uti/monkkey.uti.json rename to src/module/uti/monkkey.uti.json diff --git a/src/mod/uti/monkosaurusskin.uti.json b/src/module/uti/monkosaurusskin.uti.json similarity index 100% rename from src/mod/uti/monkosaurusskin.uti.json rename to src/module/uti/monkosaurusskin.uti.json diff --git a/src/mod/uti/monkskin002.uti.json b/src/module/uti/monkskin002.uti.json similarity index 100% rename from src/mod/uti/monkskin002.uti.json rename to src/module/uti/monkskin002.uti.json diff --git a/src/mod/uti/monxiegauntlets.uti.json b/src/module/uti/monxiegauntlets.uti.json similarity index 100% rename from src/mod/uti/monxiegauntlets.uti.json rename to src/module/uti/monxiegauntlets.uti.json diff --git a/src/mod/uti/msaurusbite.uti.json b/src/module/uti/msaurusbite.uti.json similarity index 100% rename from src/mod/uti/msaurusbite.uti.json rename to src/module/uti/msaurusbite.uti.json diff --git a/src/mod/uti/msaurusclaw.uti.json b/src/module/uti/msaurusclaw.uti.json similarity index 100% rename from src/mod/uti/msaurusclaw.uti.json rename to src/module/uti/msaurusclaw.uti.json diff --git a/src/mod/uti/msaurusskin.uti.json b/src/module/uti/msaurusskin.uti.json similarity index 100% rename from src/mod/uti/msaurusskin.uti.json rename to src/module/uti/msaurusskin.uti.json diff --git a/src/mod/uti/mysticalcloak.uti.json b/src/module/uti/mysticalcloak.uti.json similarity index 100% rename from src/mod/uti/mysticalcloak.uti.json rename to src/module/uti/mysticalcloak.uti.json diff --git a/src/mod/uti/mysticbow.uti.json b/src/module/uti/mysticbow.uti.json similarity index 100% rename from src/mod/uti/mysticbow.uti.json rename to src/module/uti/mysticbow.uti.json diff --git a/src/mod/uti/mysticbracer.uti.json b/src/module/uti/mysticbracer.uti.json similarity index 100% rename from src/mod/uti/mysticbracer.uti.json rename to src/module/uti/mysticbracer.uti.json diff --git a/src/mod/uti/mysticdagger.uti.json b/src/module/uti/mysticdagger.uti.json similarity index 100% rename from src/mod/uti/mysticdagger.uti.json rename to src/module/uti/mysticdagger.uti.json diff --git a/src/mod/uti/mystichelm.uti.json b/src/module/uti/mystichelm.uti.json similarity index 100% rename from src/mod/uti/mystichelm.uti.json rename to src/module/uti/mystichelm.uti.json diff --git a/src/mod/uti/mysticrobe.uti.json b/src/module/uti/mysticrobe.uti.json similarity index 100% rename from src/mod/uti/mysticrobe.uti.json rename to src/module/uti/mysticrobe.uti.json diff --git a/src/mod/uti/naturesarmor.uti.json b/src/module/uti/naturesarmor.uti.json similarity index 100% rename from src/mod/uti/naturesarmor.uti.json rename to src/module/uti/naturesarmor.uti.json diff --git a/src/mod/uti/naturescloak.uti.json b/src/module/uti/naturescloak.uti.json similarity index 100% rename from src/mod/uti/naturescloak.uti.json rename to src/module/uti/naturescloak.uti.json diff --git a/src/mod/uti/naturesfootsteps.uti.json b/src/module/uti/naturesfootsteps.uti.json similarity index 100% rename from src/mod/uti/naturesfootsteps.uti.json rename to src/module/uti/naturesfootsteps.uti.json diff --git a/src/mod/uti/nealyskin.uti.json b/src/module/uti/nealyskin.uti.json similarity index 100% rename from src/mod/uti/nealyskin.uti.json rename to src/module/uti/nealyskin.uti.json diff --git a/src/mod/uti/newcainbite.uti.json b/src/module/uti/newcainbite.uti.json similarity index 100% rename from src/mod/uti/newcainbite.uti.json rename to src/module/uti/newcainbite.uti.json diff --git a/src/mod/uti/newcainclaws.uti.json b/src/module/uti/newcainclaws.uti.json similarity index 100% rename from src/mod/uti/newcainclaws.uti.json rename to src/module/uti/newcainclaws.uti.json diff --git a/src/mod/uti/newcainskin.uti.json b/src/module/uti/newcainskin.uti.json similarity index 100% rename from src/mod/uti/newcainskin.uti.json rename to src/module/uti/newcainskin.uti.json diff --git a/src/mod/uti/newsanataclaws.uti.json b/src/module/uti/newsanataclaws.uti.json similarity index 100% rename from src/mod/uti/newsanataclaws.uti.json rename to src/module/uti/newsanataclaws.uti.json diff --git a/src/mod/uti/npcbelt.uti.json b/src/module/uti/npcbelt.uti.json similarity index 100% rename from src/mod/uti/npcbelt.uti.json rename to src/module/uti/npcbelt.uti.json diff --git a/src/mod/uti/npcbelt001.uti.json b/src/module/uti/npcbelt001.uti.json similarity index 100% rename from src/mod/uti/npcbelt001.uti.json rename to src/module/uti/npcbelt001.uti.json diff --git a/src/mod/uti/npcbelt002.uti.json b/src/module/uti/npcbelt002.uti.json similarity index 100% rename from src/mod/uti/npcbelt002.uti.json rename to src/module/uti/npcbelt002.uti.json diff --git a/src/mod/uti/npcbelt003.uti.json b/src/module/uti/npcbelt003.uti.json similarity index 100% rename from src/mod/uti/npcbelt003.uti.json rename to src/module/uti/npcbelt003.uti.json diff --git a/src/mod/uti/npccritimmunerin.uti.json b/src/module/uti/npccritimmunerin.uti.json similarity index 100% rename from src/mod/uti/npccritimmunerin.uti.json rename to src/module/uti/npccritimmunerin.uti.json diff --git a/src/mod/uti/npcorcarmor.uti.json b/src/module/uti/npcorcarmor.uti.json similarity index 100% rename from src/mod/uti/npcorcarmor.uti.json rename to src/module/uti/npcorcarmor.uti.json diff --git a/src/mod/uti/npcorcarmor001.uti.json b/src/module/uti/npcorcarmor001.uti.json similarity index 100% rename from src/mod/uti/npcorcarmor001.uti.json rename to src/module/uti/npcorcarmor001.uti.json diff --git a/src/mod/uti/npcringimmunitie.uti.json b/src/module/uti/npcringimmunitie.uti.json similarity index 100% rename from src/mod/uti/npcringimmunitie.uti.json rename to src/module/uti/npcringimmunitie.uti.json diff --git a/src/mod/uti/nymphclaw.uti.json b/src/module/uti/nymphclaw.uti.json similarity index 100% rename from src/mod/uti/nymphclaw.uti.json rename to src/module/uti/nymphclaw.uti.json diff --git a/src/mod/uti/ogreaxe.uti.json b/src/module/uti/ogreaxe.uti.json similarity index 100% rename from src/mod/uti/ogreaxe.uti.json rename to src/module/uti/ogreaxe.uti.json diff --git a/src/mod/uti/oldarmor.uti.json b/src/module/uti/oldarmor.uti.json similarity index 100% rename from src/mod/uti/oldarmor.uti.json rename to src/module/uti/oldarmor.uti.json diff --git a/src/mod/uti/oldbastardsword.uti.json b/src/module/uti/oldbastardsword.uti.json similarity index 100% rename from src/mod/uti/oldbastardsword.uti.json rename to src/module/uti/oldbastardsword.uti.json diff --git a/src/mod/uti/oldbroom20.uti.json b/src/module/uti/oldbroom20.uti.json similarity index 100% rename from src/mod/uti/oldbroom20.uti.json rename to src/module/uti/oldbroom20.uti.json diff --git a/src/mod/uti/oldholycloak.uti.json b/src/module/uti/oldholycloak.uti.json similarity index 100% rename from src/mod/uti/oldholycloak.uti.json rename to src/module/uti/oldholycloak.uti.json diff --git a/src/mod/uti/oldnecklace.uti.json b/src/module/uti/oldnecklace.uti.json similarity index 100% rename from src/mod/uti/oldnecklace.uti.json rename to src/module/uti/oldnecklace.uti.json diff --git a/src/mod/uti/oldpickaxe20.uti.json b/src/module/uti/oldpickaxe20.uti.json similarity index 100% rename from src/mod/uti/oldpickaxe20.uti.json rename to src/module/uti/oldpickaxe20.uti.json diff --git a/src/mod/uti/oldpiercedshield.uti.json b/src/module/uti/oldpiercedshield.uti.json similarity index 100% rename from src/mod/uti/oldpiercedshield.uti.json rename to src/module/uti/oldpiercedshield.uti.json diff --git a/src/mod/uti/oldshield.uti.json b/src/module/uti/oldshield.uti.json similarity index 100% rename from src/mod/uti/oldshield.uti.json rename to src/module/uti/oldshield.uti.json diff --git a/src/mod/uti/oldshovel.uti.json b/src/module/uti/oldshovel.uti.json similarity index 100% rename from src/mod/uti/oldshovel.uti.json rename to src/module/uti/oldshovel.uti.json diff --git a/src/mod/uti/oldsword.uti.json b/src/module/uti/oldsword.uti.json similarity index 100% rename from src/mod/uti/oldsword.uti.json rename to src/module/uti/oldsword.uti.json diff --git a/src/mod/uti/oldtatteredbelt.uti.json b/src/module/uti/oldtatteredbelt.uti.json similarity index 100% rename from src/mod/uti/oldtatteredbelt.uti.json rename to src/module/uti/oldtatteredbelt.uti.json diff --git a/src/mod/uti/oldweatheredrobe.uti.json b/src/module/uti/oldweatheredrobe.uti.json similarity index 100% rename from src/mod/uti/oldweatheredrobe.uti.json rename to src/module/uti/oldweatheredrobe.uti.json diff --git a/src/mod/uti/oldwizardrobe20.uti.json b/src/module/uti/oldwizardrobe20.uti.json similarity index 100% rename from src/mod/uti/oldwizardrobe20.uti.json rename to src/module/uti/oldwizardrobe20.uti.json diff --git a/src/mod/uti/oldworldkey.uti.json b/src/module/uti/oldworldkey.uti.json similarity index 100% rename from src/mod/uti/oldworldkey.uti.json rename to src/module/uti/oldworldkey.uti.json diff --git a/src/mod/uti/orcbattlehorn.uti.json b/src/module/uti/orcbattlehorn.uti.json similarity index 100% rename from src/mod/uti/orcbattlehorn.uti.json rename to src/module/uti/orcbattlehorn.uti.json diff --git a/src/mod/uti/orcbattleplans.uti.json b/src/module/uti/orcbattleplans.uti.json similarity index 100% rename from src/mod/uti/orcbattleplans.uti.json rename to src/module/uti/orcbattleplans.uti.json diff --git a/src/mod/uti/orcinvaderarm001.uti.json b/src/module/uti/orcinvaderarm001.uti.json similarity index 100% rename from src/mod/uti/orcinvaderarm001.uti.json rename to src/module/uti/orcinvaderarm001.uti.json diff --git a/src/mod/uti/orcinvaderarmor.uti.json b/src/module/uti/orcinvaderarmor.uti.json similarity index 100% rename from src/mod/uti/orcinvaderarmor.uti.json rename to src/module/uti/orcinvaderarmor.uti.json diff --git a/src/mod/uti/orcishdoubleaxe.uti.json b/src/module/uti/orcishdoubleaxe.uti.json similarity index 100% rename from src/mod/uti/orcishdoubleaxe.uti.json rename to src/module/uti/orcishdoubleaxe.uti.json diff --git a/src/mod/uti/orcishflail.uti.json b/src/module/uti/orcishflail.uti.json similarity index 100% rename from src/mod/uti/orcishflail.uti.json rename to src/module/uti/orcishflail.uti.json diff --git a/src/mod/uti/orcishgreataxe.uti.json b/src/module/uti/orcishgreataxe.uti.json similarity index 100% rename from src/mod/uti/orcishgreataxe.uti.json rename to src/module/uti/orcishgreataxe.uti.json diff --git a/src/mod/uti/orckey.uti.json b/src/module/uti/orckey.uti.json similarity index 100% rename from src/mod/uti/orckey.uti.json rename to src/module/uti/orckey.uti.json diff --git a/src/mod/uti/orcleaderskin.uti.json b/src/module/uti/orcleaderskin.uti.json similarity index 100% rename from src/mod/uti/orcleaderskin.uti.json rename to src/module/uti/orcleaderskin.uti.json diff --git a/src/mod/uti/orcmasterskin.uti.json b/src/module/uti/orcmasterskin.uti.json similarity index 100% rename from src/mod/uti/orcmasterskin.uti.json rename to src/module/uti/orcmasterskin.uti.json diff --git a/src/mod/uti/orcplans.uti.json b/src/module/uti/orcplans.uti.json similarity index 100% rename from src/mod/uti/orcplans.uti.json rename to src/module/uti/orcplans.uti.json diff --git a/src/mod/uti/orcraiderclaw.uti.json b/src/module/uti/orcraiderclaw.uti.json similarity index 100% rename from src/mod/uti/orcraiderclaw.uti.json rename to src/module/uti/orcraiderclaw.uti.json diff --git a/src/mod/uti/osdguildkey.uti.json b/src/module/uti/osdguildkey.uti.json similarity index 100% rename from src/mod/uti/osdguildkey.uti.json rename to src/module/uti/osdguildkey.uti.json diff --git a/src/mod/uti/ozbookofknowl001.uti.json b/src/module/uti/ozbookofknowl001.uti.json similarity index 100% rename from src/mod/uti/ozbookofknowl001.uti.json rename to src/module/uti/ozbookofknowl001.uti.json diff --git a/src/mod/uti/ozbookofknowledg.uti.json b/src/module/uti/ozbookofknowledg.uti.json similarity index 100% rename from src/mod/uti/ozbookofknowledg.uti.json rename to src/module/uti/ozbookofknowledg.uti.json diff --git a/src/mod/uti/ozclaw.uti.json b/src/module/uti/ozclaw.uti.json similarity index 100% rename from src/mod/uti/ozclaw.uti.json rename to src/module/uti/ozclaw.uti.json diff --git a/src/mod/uti/ozeastkey.uti.json b/src/module/uti/ozeastkey.uti.json similarity index 100% rename from src/mod/uti/ozeastkey.uti.json rename to src/module/uti/ozeastkey.uti.json diff --git a/src/mod/uti/ozeastkey001.uti.json b/src/module/uti/ozeastkey001.uti.json similarity index 100% rename from src/mod/uti/ozeastkey001.uti.json rename to src/module/uti/ozeastkey001.uti.json diff --git a/src/mod/uti/ozjailkey.uti.json b/src/module/uti/ozjailkey.uti.json similarity index 100% rename from src/mod/uti/ozjailkey.uti.json rename to src/module/uti/ozjailkey.uti.json diff --git a/src/mod/uti/ozknight.uti.json b/src/module/uti/ozknight.uti.json similarity index 100% rename from src/mod/uti/ozknight.uti.json rename to src/module/uti/ozknight.uti.json diff --git a/src/mod/uti/oznoblestaff.uti.json b/src/module/uti/oznoblestaff.uti.json similarity index 100% rename from src/mod/uti/oznoblestaff.uti.json rename to src/module/uti/oznoblestaff.uti.json diff --git a/src/mod/uti/oznoblestaff001.uti.json b/src/module/uti/oznoblestaff001.uti.json similarity index 100% rename from src/mod/uti/oznoblestaff001.uti.json rename to src/module/uti/oznoblestaff001.uti.json diff --git a/src/mod/uti/ozskin.uti.json b/src/module/uti/ozskin.uti.json similarity index 100% rename from src/mod/uti/ozskin.uti.json rename to src/module/uti/ozskin.uti.json diff --git a/src/mod/uti/ozskin001.uti.json b/src/module/uti/ozskin001.uti.json similarity index 100% rename from src/mod/uti/ozskin001.uti.json rename to src/module/uti/ozskin001.uti.json diff --git a/src/mod/uti/ozskin002.uti.json b/src/module/uti/ozskin002.uti.json similarity index 100% rename from src/mod/uti/ozskin002.uti.json rename to src/module/uti/ozskin002.uti.json diff --git a/src/mod/uti/ozskin004.uti.json b/src/module/uti/ozskin004.uti.json similarity index 100% rename from src/mod/uti/ozskin004.uti.json rename to src/module/uti/ozskin004.uti.json diff --git a/src/mod/uti/painting20.uti.json b/src/module/uti/painting20.uti.json similarity index 100% rename from src/mod/uti/painting20.uti.json rename to src/module/uti/painting20.uti.json diff --git a/src/mod/uti/pawnboots.uti.json b/src/module/uti/pawnboots.uti.json similarity index 100% rename from src/mod/uti/pawnboots.uti.json rename to src/module/uti/pawnboots.uti.json diff --git a/src/mod/uti/pawnstick.uti.json b/src/module/uti/pawnstick.uti.json similarity index 100% rename from src/mod/uti/pawnstick.uti.json rename to src/module/uti/pawnstick.uti.json diff --git a/src/mod/uti/phantomsmoke.uti.json b/src/module/uti/phantomsmoke.uti.json similarity index 100% rename from src/mod/uti/phantomsmoke.uti.json rename to src/module/uti/phantomsmoke.uti.json diff --git a/src/mod/uti/phwarmor.uti.json b/src/module/uti/phwarmor.uti.json similarity index 100% rename from src/mod/uti/phwarmor.uti.json rename to src/module/uti/phwarmor.uti.json diff --git a/src/mod/uti/phwclaw.uti.json b/src/module/uti/phwclaw.uti.json similarity index 100% rename from src/mod/uti/phwclaw.uti.json rename to src/module/uti/phwclaw.uti.json diff --git a/src/mod/uti/phwhelmet.uti.json b/src/module/uti/phwhelmet.uti.json similarity index 100% rename from src/mod/uti/phwhelmet.uti.json rename to src/module/uti/phwhelmet.uti.json diff --git a/src/mod/uti/phwskin.uti.json b/src/module/uti/phwskin.uti.json similarity index 100% rename from src/mod/uti/phwskin.uti.json rename to src/module/uti/phwskin.uti.json diff --git a/src/mod/uti/phwsthing.uti.json b/src/module/uti/phwsthing.uti.json similarity index 100% rename from src/mod/uti/phwsthing.uti.json rename to src/module/uti/phwsthing.uti.json diff --git a/src/mod/uti/planarsheild.uti.json b/src/module/uti/planarsheild.uti.json similarity index 100% rename from src/mod/uti/planarsheild.uti.json rename to src/module/uti/planarsheild.uti.json diff --git a/src/mod/uti/polarbearbite.uti.json b/src/module/uti/polarbearbite.uti.json similarity index 100% rename from src/mod/uti/polarbearbite.uti.json rename to src/module/uti/polarbearbite.uti.json diff --git a/src/mod/uti/polarbearbite001.uti.json b/src/module/uti/polarbearbite001.uti.json similarity index 100% rename from src/mod/uti/polarbearbite001.uti.json rename to src/module/uti/polarbearbite001.uti.json diff --git a/src/mod/uti/polarbearclaw.uti.json b/src/module/uti/polarbearclaw.uti.json similarity index 100% rename from src/mod/uti/polarbearclaw.uti.json rename to src/module/uti/polarbearclaw.uti.json diff --git a/src/mod/uti/polarbearclaw001.uti.json b/src/module/uti/polarbearclaw001.uti.json similarity index 100% rename from src/mod/uti/polarbearclaw001.uti.json rename to src/module/uti/polarbearclaw001.uti.json diff --git a/src/mod/uti/polarbearclaw002.uti.json b/src/module/uti/polarbearclaw002.uti.json similarity index 100% rename from src/mod/uti/polarbearclaw002.uti.json rename to src/module/uti/polarbearclaw002.uti.json diff --git a/src/mod/uti/polarbearpelt.uti.json b/src/module/uti/polarbearpelt.uti.json similarity index 100% rename from src/mod/uti/polarbearpelt.uti.json rename to src/module/uti/polarbearpelt.uti.json diff --git a/src/mod/uti/polarbearskin.uti.json b/src/module/uti/polarbearskin.uti.json similarity index 100% rename from src/mod/uti/polarbearskin.uti.json rename to src/module/uti/polarbearskin.uti.json diff --git a/src/mod/uti/polarbearskin001.uti.json b/src/module/uti/polarbearskin001.uti.json similarity index 100% rename from src/mod/uti/polarbearskin001.uti.json rename to src/module/uti/polarbearskin001.uti.json diff --git a/src/mod/uti/polarbearskin002.uti.json b/src/module/uti/polarbearskin002.uti.json similarity index 100% rename from src/mod/uti/polarbearskin002.uti.json rename to src/module/uti/polarbearskin002.uti.json diff --git a/src/mod/uti/portalkey.uti.json b/src/module/uti/portalkey.uti.json similarity index 100% rename from src/mod/uti/portalkey.uti.json rename to src/module/uti/portalkey.uti.json diff --git a/src/mod/uti/potioncalrity.uti.json b/src/module/uti/potioncalrity.uti.json similarity index 100% rename from src/mod/uti/potioncalrity.uti.json rename to src/module/uti/potioncalrity.uti.json diff --git a/src/mod/uti/potioncritical.uti.json b/src/module/uti/potioncritical.uti.json similarity index 100% rename from src/mod/uti/potioncritical.uti.json rename to src/module/uti/potioncritical.uti.json diff --git a/src/mod/uti/potioncritical10.uti.json b/src/module/uti/potioncritical10.uti.json similarity index 100% rename from src/mod/uti/potioncritical10.uti.json rename to src/module/uti/potioncritical10.uti.json diff --git a/src/mod/uti/potioneagle.uti.json b/src/module/uti/potioneagle.uti.json similarity index 100% rename from src/mod/uti/potioneagle.uti.json rename to src/module/uti/potioneagle.uti.json diff --git a/src/mod/uti/potionendurance.uti.json b/src/module/uti/potionendurance.uti.json similarity index 100% rename from src/mod/uti/potionendurance.uti.json rename to src/module/uti/potionendurance.uti.json diff --git a/src/mod/uti/potionfox.uti.json b/src/module/uti/potionfox.uti.json similarity index 100% rename from src/mod/uti/potionfox.uti.json rename to src/module/uti/potionfox.uti.json diff --git a/src/mod/uti/potionguts.uti.json b/src/module/uti/potionguts.uti.json similarity index 100% rename from src/mod/uti/potionguts.uti.json rename to src/module/uti/potionguts.uti.json diff --git a/src/mod/uti/potionlore.uti.json b/src/module/uti/potionlore.uti.json similarity index 100% rename from src/mod/uti/potionlore.uti.json rename to src/module/uti/potionlore.uti.json diff --git a/src/mod/uti/potionofaid.uti.json b/src/module/uti/potionofaid.uti.json similarity index 100% rename from src/mod/uti/potionofaid.uti.json rename to src/module/uti/potionofaid.uti.json diff --git a/src/mod/uti/potionofbless.uti.json b/src/module/uti/potionofbless.uti.json similarity index 100% rename from src/mod/uti/potionofbless.uti.json rename to src/module/uti/potionofbless.uti.json diff --git a/src/mod/uti/potionofwake.uti.json b/src/module/uti/potionofwake.uti.json similarity index 100% rename from src/mod/uti/potionofwake.uti.json rename to src/module/uti/potionofwake.uti.json diff --git a/src/mod/uti/potionwisdom.uti.json b/src/module/uti/potionwisdom.uti.json similarity index 100% rename from src/mod/uti/potionwisdom.uti.json rename to src/module/uti/potionwisdom.uti.json diff --git a/src/mod/uti/prehistoricbite.uti.json b/src/module/uti/prehistoricbite.uti.json similarity index 100% rename from src/mod/uti/prehistoricbite.uti.json rename to src/module/uti/prehistoricbite.uti.json diff --git a/src/mod/uti/prehistoricclaw.uti.json b/src/module/uti/prehistoricclaw.uti.json similarity index 100% rename from src/mod/uti/prehistoricclaw.uti.json rename to src/module/uti/prehistoricclaw.uti.json diff --git a/src/mod/uti/prehistoricskin.uti.json b/src/module/uti/prehistoricskin.uti.json similarity index 100% rename from src/mod/uti/prehistoricskin.uti.json rename to src/module/uti/prehistoricskin.uti.json diff --git a/src/mod/uti/purifiedhands.uti.json b/src/module/uti/purifiedhands.uti.json similarity index 100% rename from src/mod/uti/purifiedhands.uti.json rename to src/module/uti/purifiedhands.uti.json diff --git a/src/mod/uti/pvpevilhelm.uti.json b/src/module/uti/pvpevilhelm.uti.json similarity index 100% rename from src/mod/uti/pvpevilhelm.uti.json rename to src/module/uti/pvpevilhelm.uti.json diff --git a/src/mod/uti/pvpgoodhelm.uti.json b/src/module/uti/pvpgoodhelm.uti.json similarity index 100% rename from src/mod/uti/pvpgoodhelm.uti.json rename to src/module/uti/pvpgoodhelm.uti.json diff --git a/src/mod/uti/pvptoken.uti.json b/src/module/uti/pvptoken.uti.json similarity index 100% rename from src/mod/uti/pvptoken.uti.json rename to src/module/uti/pvptoken.uti.json diff --git a/src/mod/uti/raiderorcflail.uti.json b/src/module/uti/raiderorcflail.uti.json similarity index 100% rename from src/mod/uti/raiderorcflail.uti.json rename to src/module/uti/raiderorcflail.uti.json diff --git a/src/mod/uti/rapieroftheoldwo.uti.json b/src/module/uti/rapieroftheoldwo.uti.json similarity index 100% rename from src/mod/uti/rapieroftheoldwo.uti.json rename to src/module/uti/rapieroftheoldwo.uti.json diff --git a/src/mod/uti/rapscallionscloa.uti.json b/src/module/uti/rapscallionscloa.uti.json similarity index 100% rename from src/mod/uti/rapscallionscloa.uti.json rename to src/module/uti/rapscallionscloa.uti.json diff --git a/src/mod/uti/reaperbite.uti.json b/src/module/uti/reaperbite.uti.json similarity index 100% rename from src/mod/uti/reaperbite.uti.json rename to src/module/uti/reaperbite.uti.json diff --git a/src/mod/uti/reaperkey.uti.json b/src/module/uti/reaperkey.uti.json similarity index 100% rename from src/mod/uti/reaperkey.uti.json rename to src/module/uti/reaperkey.uti.json diff --git a/src/mod/uti/rebhead.uti.json b/src/module/uti/rebhead.uti.json similarity index 100% rename from src/mod/uti/rebhead.uti.json rename to src/module/uti/rebhead.uti.json diff --git a/src/mod/uti/reddragonblood.uti.json b/src/module/uti/reddragonblood.uti.json similarity index 100% rename from src/mod/uti/reddragonblood.uti.json rename to src/module/uti/reddragonblood.uti.json diff --git a/src/mod/uti/reinforcedarmor.uti.json b/src/module/uti/reinforcedarmor.uti.json similarity index 100% rename from src/mod/uti/reinforcedarmor.uti.json rename to src/module/uti/reinforcedarmor.uti.json diff --git a/src/mod/uti/reinforcedarmorl.uti.json b/src/module/uti/reinforcedarmorl.uti.json similarity index 100% rename from src/mod/uti/reinforcedarmorl.uti.json rename to src/module/uti/reinforcedarmorl.uti.json diff --git a/src/mod/uti/reinforcedarmorm.uti.json b/src/module/uti/reinforcedarmorm.uti.json similarity index 100% rename from src/mod/uti/reinforcedarmorm.uti.json rename to src/module/uti/reinforcedarmorm.uti.json diff --git a/src/mod/uti/reinforcedbelt.uti.json b/src/module/uti/reinforcedbelt.uti.json similarity index 100% rename from src/mod/uti/reinforcedbelt.uti.json rename to src/module/uti/reinforcedbelt.uti.json diff --git a/src/mod/uti/reinforcedboots.uti.json b/src/module/uti/reinforcedboots.uti.json similarity index 100% rename from src/mod/uti/reinforcedboots.uti.json rename to src/module/uti/reinforcedboots.uti.json diff --git a/src/mod/uti/reinforcedbracer.uti.json b/src/module/uti/reinforcedbracer.uti.json similarity index 100% rename from src/mod/uti/reinforcedbracer.uti.json rename to src/module/uti/reinforcedbracer.uti.json diff --git a/src/mod/uti/reinforcedcloak.uti.json b/src/module/uti/reinforcedcloak.uti.json similarity index 100% rename from src/mod/uti/reinforcedcloak.uti.json rename to src/module/uti/reinforcedcloak.uti.json diff --git a/src/mod/uti/reinforcedgloves.uti.json b/src/module/uti/reinforcedgloves.uti.json similarity index 100% rename from src/mod/uti/reinforcedgloves.uti.json rename to src/module/uti/reinforcedgloves.uti.json diff --git a/src/mod/uti/reinforcedhelm.uti.json b/src/module/uti/reinforcedhelm.uti.json similarity index 100% rename from src/mod/uti/reinforcedhelm.uti.json rename to src/module/uti/reinforcedhelm.uti.json diff --git a/src/mod/uti/reinforcedlarges.uti.json b/src/module/uti/reinforcedlarges.uti.json similarity index 100% rename from src/mod/uti/reinforcedlarges.uti.json rename to src/module/uti/reinforcedlarges.uti.json diff --git a/src/mod/uti/reinforcedrobe.uti.json b/src/module/uti/reinforcedrobe.uti.json similarity index 100% rename from src/mod/uti/reinforcedrobe.uti.json rename to src/module/uti/reinforcedrobe.uti.json diff --git a/src/mod/uti/reinforcedtowers.uti.json b/src/module/uti/reinforcedtowers.uti.json similarity index 100% rename from src/mod/uti/reinforcedtowers.uti.json rename to src/module/uti/reinforcedtowers.uti.json diff --git a/src/mod/uti/resistring.uti.json b/src/module/uti/resistring.uti.json similarity index 100% rename from src/mod/uti/resistring.uti.json rename to src/module/uti/resistring.uti.json diff --git a/src/mod/uti/resrod.uti.json b/src/module/uti/resrod.uti.json similarity index 100% rename from src/mod/uti/resrod.uti.json rename to src/module/uti/resrod.uti.json diff --git a/src/mod/uti/riftrobe.uti.json b/src/module/uti/riftrobe.uti.json similarity index 100% rename from src/mod/uti/riftrobe.uti.json rename to src/module/uti/riftrobe.uti.json diff --git a/src/mod/uti/ringoffearles001.uti.json b/src/module/uti/ringoffearles001.uti.json similarity index 100% rename from src/mod/uti/ringoffearles001.uti.json rename to src/module/uti/ringoffearles001.uti.json diff --git a/src/mod/uti/ringoffearless.uti.json b/src/module/uti/ringoffearless.uti.json similarity index 100% rename from src/mod/uti/ringoffearless.uti.json rename to src/module/uti/ringoffearless.uti.json diff --git a/src/mod/uti/ringoflight.uti.json b/src/module/uti/ringoflight.uti.json similarity index 100% rename from src/mod/uti/ringoflight.uti.json rename to src/module/uti/ringoflight.uti.json diff --git a/src/mod/uti/ringofterror.uti.json b/src/module/uti/ringofterror.uti.json similarity index 100% rename from src/mod/uti/ringofterror.uti.json rename to src/module/uti/ringofterror.uti.json diff --git a/src/mod/uti/ringoftheforest.uti.json b/src/module/uti/ringoftheforest.uti.json similarity index 100% rename from src/mod/uti/ringoftheforest.uti.json rename to src/module/uti/ringoftheforest.uti.json diff --git a/src/mod/uti/ringofthehealer.uti.json b/src/module/uti/ringofthehealer.uti.json similarity index 100% rename from src/mod/uti/ringofthehealer.uti.json rename to src/module/uti/ringofthehealer.uti.json diff --git a/src/mod/uti/ringofthemystic.uti.json b/src/module/uti/ringofthemystic.uti.json similarity index 100% rename from src/mod/uti/ringofthemystic.uti.json rename to src/module/uti/ringofthemystic.uti.json diff --git a/src/mod/uti/ringofthereaper.uti.json b/src/module/uti/ringofthereaper.uti.json similarity index 100% rename from src/mod/uti/ringofthereaper.uti.json rename to src/module/uti/ringofthereaper.uti.json diff --git a/src/mod/uti/risenclub.uti.json b/src/module/uti/risenclub.uti.json similarity index 100% rename from src/mod/uti/risenclub.uti.json rename to src/module/uti/risenclub.uti.json diff --git a/src/mod/uti/robeoflegends.uti.json b/src/module/uti/robeoflegends.uti.json similarity index 100% rename from src/mod/uti/robeoflegends.uti.json rename to src/module/uti/robeoflegends.uti.json diff --git a/src/mod/uti/robesofthehighwi.uti.json b/src/module/uti/robesofthehighwi.uti.json similarity index 100% rename from src/mod/uti/robesofthehighwi.uti.json rename to src/module/uti/robesofthehighwi.uti.json diff --git a/src/mod/uti/robesofthelowerr.uti.json b/src/module/uti/robesofthelowerr.uti.json similarity index 100% rename from src/mod/uti/robesofthelowerr.uti.json rename to src/module/uti/robesofthelowerr.uti.json diff --git a/src/mod/uti/robesoftheperfor.uti.json b/src/module/uti/robesoftheperfor.uti.json similarity index 100% rename from src/mod/uti/robesoftheperfor.uti.json rename to src/module/uti/robesoftheperfor.uti.json diff --git a/src/mod/uti/robesofthepurifi.uti.json b/src/module/uti/robesofthepurifi.uti.json similarity index 100% rename from src/mod/uti/robesofthepurifi.uti.json rename to src/module/uti/robesofthepurifi.uti.json diff --git a/src/mod/uti/roguesarmor.uti.json b/src/module/uti/roguesarmor.uti.json similarity index 100% rename from src/mod/uti/roguesarmor.uti.json rename to src/module/uti/roguesarmor.uti.json diff --git a/src/mod/uti/romancekey.uti.json b/src/module/uti/romancekey.uti.json similarity index 100% rename from src/mod/uti/romancekey.uti.json rename to src/module/uti/romancekey.uti.json diff --git a/src/mod/uti/ruinsreaperclaw.uti.json b/src/module/uti/ruinsreaperclaw.uti.json similarity index 100% rename from src/mod/uti/ruinsreaperclaw.uti.json rename to src/module/uti/ruinsreaperclaw.uti.json diff --git a/src/mod/uti/ruinsreaperprops.uti.json b/src/module/uti/ruinsreaperprops.uti.json similarity index 100% rename from src/mod/uti/ruinsreaperprops.uti.json rename to src/module/uti/ruinsreaperprops.uti.json diff --git a/src/mod/uti/sandsoftime.uti.json b/src/module/uti/sandsoftime.uti.json similarity index 100% rename from src/mod/uti/sandsoftime.uti.json rename to src/module/uti/sandsoftime.uti.json diff --git a/src/mod/uti/santakey.uti.json b/src/module/uti/santakey.uti.json similarity index 100% rename from src/mod/uti/santakey.uti.json rename to src/module/uti/santakey.uti.json diff --git a/src/mod/uti/santarobe.uti.json b/src/module/uti/santarobe.uti.json similarity index 100% rename from src/mod/uti/santarobe.uti.json rename to src/module/uti/santarobe.uti.json diff --git a/src/mod/uti/santastaff.uti.json b/src/module/uti/santastaff.uti.json similarity index 100% rename from src/mod/uti/santastaff.uti.json rename to src/module/uti/santastaff.uti.json diff --git a/src/mod/uti/santastaff001.uti.json b/src/module/uti/santastaff001.uti.json similarity index 100% rename from src/mod/uti/santastaff001.uti.json rename to src/module/uti/santastaff001.uti.json diff --git a/src/mod/uti/santastaff002.uti.json b/src/module/uti/santastaff002.uti.json similarity index 100% rename from src/mod/uti/santastaff002.uti.json rename to src/module/uti/santastaff002.uti.json diff --git a/src/mod/uti/scifikey.uti.json b/src/module/uti/scifikey.uti.json similarity index 100% rename from src/mod/uti/scifikey.uti.json rename to src/module/uti/scifikey.uti.json diff --git a/src/mod/uti/scrollofevil.uti.json b/src/module/uti/scrollofevil.uti.json similarity index 100% rename from src/mod/uti/scrollofevil.uti.json rename to src/module/uti/scrollofevil.uti.json diff --git a/src/mod/uti/scrollofevil001.uti.json b/src/module/uti/scrollofevil001.uti.json similarity index 100% rename from src/mod/uti/scrollofevil001.uti.json rename to src/module/uti/scrollofevil001.uti.json diff --git a/src/mod/uti/scrollofknow.uti.json b/src/module/uti/scrollofknow.uti.json similarity index 100% rename from src/mod/uti/scrollofknow.uti.json rename to src/module/uti/scrollofknow.uti.json diff --git a/src/mod/uti/scrolloftruth.uti.json b/src/module/uti/scrolloftruth.uti.json similarity index 100% rename from src/mod/uti/scrolloftruth.uti.json rename to src/module/uti/scrolloftruth.uti.json diff --git a/src/mod/uti/sdefenderrobes.uti.json b/src/module/uti/sdefenderrobes.uti.json similarity index 100% rename from src/mod/uti/sdefenderrobes.uti.json rename to src/module/uti/sdefenderrobes.uti.json diff --git a/src/mod/uti/seacptarmor.uti.json b/src/module/uti/seacptarmor.uti.json similarity index 100% rename from src/mod/uti/seacptarmor.uti.json rename to src/module/uti/seacptarmor.uti.json diff --git a/src/mod/uti/senatekey.uti.json b/src/module/uti/senatekey.uti.json similarity index 100% rename from src/mod/uti/senatekey.uti.json rename to src/module/uti/senatekey.uti.json diff --git a/src/mod/uti/sentrossiclaw.uti.json b/src/module/uti/sentrossiclaw.uti.json similarity index 100% rename from src/mod/uti/sentrossiclaw.uti.json rename to src/module/uti/sentrossiclaw.uti.json diff --git a/src/mod/uti/serfkey.uti.json b/src/module/uti/serfkey.uti.json similarity index 100% rename from src/mod/uti/serfkey.uti.json rename to src/module/uti/serfkey.uti.json diff --git a/src/mod/uti/sexyfreakkey.uti.json b/src/module/uti/sexyfreakkey.uti.json similarity index 100% rename from src/mod/uti/sexyfreakkey.uti.json rename to src/module/uti/sexyfreakkey.uti.json diff --git a/src/mod/uti/shadowcommon.uti.json b/src/module/uti/shadowcommon.uti.json similarity index 100% rename from src/mod/uti/shadowcommon.uti.json rename to src/module/uti/shadowcommon.uti.json diff --git a/src/mod/uti/shadowskin.uti.json b/src/module/uti/shadowskin.uti.json similarity index 100% rename from src/mod/uti/shadowskin.uti.json rename to src/module/uti/shadowskin.uti.json diff --git a/src/mod/uti/shadowskin001.uti.json b/src/module/uti/shadowskin001.uti.json similarity index 100% rename from src/mod/uti/shadowskin001.uti.json rename to src/module/uti/shadowskin001.uti.json diff --git a/src/mod/uti/shatteredsword20.uti.json b/src/module/uti/shatteredsword20.uti.json similarity index 100% rename from src/mod/uti/shatteredsword20.uti.json rename to src/module/uti/shatteredsword20.uti.json diff --git a/src/mod/uti/shieldofthewarri.uti.json b/src/module/uti/shieldofthewarri.uti.json similarity index 100% rename from src/mod/uti/shieldofthewarri.uti.json rename to src/module/uti/shieldofthewarri.uti.json diff --git a/src/mod/uti/shifter.uti.json b/src/module/uti/shifter.uti.json similarity index 100% rename from src/mod/uti/shifter.uti.json rename to src/module/uti/shifter.uti.json diff --git a/src/mod/uti/shifter001.uti.json b/src/module/uti/shifter001.uti.json similarity index 100% rename from src/mod/uti/shifter001.uti.json rename to src/module/uti/shifter001.uti.json diff --git a/src/mod/uti/shifter002.uti.json b/src/module/uti/shifter002.uti.json similarity index 100% rename from src/mod/uti/shifter002.uti.json rename to src/module/uti/shifter002.uti.json diff --git a/src/mod/uti/shifter003.uti.json b/src/module/uti/shifter003.uti.json similarity index 100% rename from src/mod/uti/shifter003.uti.json rename to src/module/uti/shifter003.uti.json diff --git a/src/mod/uti/shifter004.uti.json b/src/module/uti/shifter004.uti.json similarity index 100% rename from src/mod/uti/shifter004.uti.json rename to src/module/uti/shifter004.uti.json diff --git a/src/mod/uti/shiftercrossbow.uti.json b/src/module/uti/shiftercrossbow.uti.json similarity index 100% rename from src/mod/uti/shiftercrossbow.uti.json rename to src/module/uti/shiftercrossbow.uti.json diff --git a/src/mod/uti/shifterlongbow.uti.json b/src/module/uti/shifterlongbow.uti.json similarity index 100% rename from src/mod/uti/shifterlongbow.uti.json rename to src/module/uti/shifterlongbow.uti.json diff --git a/src/mod/uti/shiftermorningst.uti.json b/src/module/uti/shiftermorningst.uti.json similarity index 100% rename from src/mod/uti/shiftermorningst.uti.json rename to src/module/uti/shiftermorningst.uti.json diff --git a/src/mod/uti/shifterquarterst.uti.json b/src/module/uti/shifterquarterst.uti.json similarity index 100% rename from src/mod/uti/shifterquarterst.uti.json rename to src/module/uti/shifterquarterst.uti.json diff --git a/src/mod/uti/shifterscythe.uti.json b/src/module/uti/shifterscythe.uti.json similarity index 100% rename from src/mod/uti/shifterscythe.uti.json rename to src/module/uti/shifterscythe.uti.json diff --git a/src/mod/uti/shiftershortbow.uti.json b/src/module/uti/shiftershortbow.uti.json similarity index 100% rename from src/mod/uti/shiftershortbow.uti.json rename to src/module/uti/shiftershortbow.uti.json diff --git a/src/mod/uti/shogunblade.uti.json b/src/module/uti/shogunblade.uti.json similarity index 100% rename from src/mod/uti/shogunblade.uti.json rename to src/module/uti/shogunblade.uti.json diff --git a/src/mod/uti/shoguncloak.uti.json b/src/module/uti/shoguncloak.uti.json similarity index 100% rename from src/mod/uti/shoguncloak.uti.json rename to src/module/uti/shoguncloak.uti.json diff --git a/src/mod/uti/shogunsanctum.uti.json b/src/module/uti/shogunsanctum.uti.json similarity index 100% rename from src/mod/uti/shogunsanctum.uti.json rename to src/module/uti/shogunsanctum.uti.json diff --git a/src/mod/uti/shokey.uti.json b/src/module/uti/shokey.uti.json similarity index 100% rename from src/mod/uti/shokey.uti.json rename to src/module/uti/shokey.uti.json diff --git a/src/mod/uti/shokey2.uti.json b/src/module/uti/shokey2.uti.json similarity index 100% rename from src/mod/uti/shokey2.uti.json rename to src/module/uti/shokey2.uti.json diff --git a/src/mod/uti/shokey3.uti.json b/src/module/uti/shokey3.uti.json similarity index 100% rename from src/mod/uti/shokey3.uti.json rename to src/module/uti/shokey3.uti.json diff --git a/src/mod/uti/shokey4.uti.json b/src/module/uti/shokey4.uti.json similarity index 100% rename from src/mod/uti/shokey4.uti.json rename to src/module/uti/shokey4.uti.json diff --git a/src/mod/uti/sisterofthedarkr.uti.json b/src/module/uti/sisterofthedarkr.uti.json similarity index 100% rename from src/mod/uti/sisterofthedarkr.uti.json rename to src/module/uti/sisterofthedarkr.uti.json diff --git a/src/mod/uti/sludgeaxe.uti.json b/src/module/uti/sludgeaxe.uti.json similarity index 100% rename from src/mod/uti/sludgeaxe.uti.json rename to src/module/uti/sludgeaxe.uti.json diff --git a/src/mod/uti/smgauntlets001.uti.json b/src/module/uti/smgauntlets001.uti.json similarity index 100% rename from src/mod/uti/smgauntlets001.uti.json rename to src/module/uti/smgauntlets001.uti.json diff --git a/src/mod/uti/smitevilstar.uti.json b/src/module/uti/smitevilstar.uti.json similarity index 100% rename from src/mod/uti/smitevilstar.uti.json rename to src/module/uti/smitevilstar.uti.json diff --git a/src/mod/uti/smmrobes.uti.json b/src/module/uti/smmrobes.uti.json similarity index 100% rename from src/mod/uti/smmrobes.uti.json rename to src/module/uti/smmrobes.uti.json diff --git a/src/mod/uti/smrobes.uti.json b/src/module/uti/smrobes.uti.json similarity index 100% rename from src/mod/uti/smrobes.uti.json rename to src/module/uti/smrobes.uti.json diff --git a/src/mod/uti/snowlingslam.uti.json b/src/module/uti/snowlingslam.uti.json similarity index 100% rename from src/mod/uti/snowlingslam.uti.json rename to src/module/uti/snowlingslam.uti.json diff --git a/src/mod/uti/snowrobe.uti.json b/src/module/uti/snowrobe.uti.json similarity index 100% rename from src/mod/uti/snowrobe.uti.json rename to src/module/uti/snowrobe.uti.json diff --git a/src/mod/uti/snowrobe001.uti.json b/src/module/uti/snowrobe001.uti.json similarity index 100% rename from src/mod/uti/snowrobe001.uti.json rename to src/module/uti/snowrobe001.uti.json diff --git a/src/mod/uti/snowrobe002.uti.json b/src/module/uti/snowrobe002.uti.json similarity index 100% rename from src/mod/uti/snowrobe002.uti.json rename to src/module/uti/snowrobe002.uti.json diff --git a/src/mod/uti/snowstaff.uti.json b/src/module/uti/snowstaff.uti.json similarity index 100% rename from src/mod/uti/snowstaff.uti.json rename to src/module/uti/snowstaff.uti.json diff --git a/src/mod/uti/sorcerertwinrobe.uti.json b/src/module/uti/sorcerertwinrobe.uti.json similarity index 100% rename from src/mod/uti/sorcerertwinrobe.uti.json rename to src/module/uti/sorcerertwinrobe.uti.json diff --git a/src/mod/uti/sorcerertwinstaf.uti.json b/src/module/uti/sorcerertwinstaf.uti.json similarity index 100% rename from src/mod/uti/sorcerertwinstaf.uti.json rename to src/module/uti/sorcerertwinstaf.uti.json diff --git a/src/mod/uti/sorcstaffofpower.uti.json b/src/module/uti/sorcstaffofpower.uti.json similarity index 100% rename from src/mod/uti/sorcstaffofpower.uti.json rename to src/module/uti/sorcstaffofpower.uti.json diff --git a/src/mod/uti/soulstone.uti.json b/src/module/uti/soulstone.uti.json similarity index 100% rename from src/mod/uti/soulstone.uti.json rename to src/module/uti/soulstone.uti.json diff --git a/src/mod/uti/soultaker002.uti.json b/src/module/uti/soultaker002.uti.json similarity index 100% rename from src/mod/uti/soultaker002.uti.json rename to src/module/uti/soultaker002.uti.json diff --git a/src/mod/uti/spearofthelad.uti.json b/src/module/uti/spearofthelad.uti.json similarity index 100% rename from src/mod/uti/spearofthelad.uti.json rename to src/module/uti/spearofthelad.uti.json diff --git a/src/mod/uti/spearofthelad001.uti.json b/src/module/uti/spearofthelad001.uti.json similarity index 100% rename from src/mod/uti/spearofthelad001.uti.json rename to src/module/uti/spearofthelad001.uti.json diff --git a/src/mod/uti/spirtfist.uti.json b/src/module/uti/spirtfist.uti.json similarity index 100% rename from src/mod/uti/spirtfist.uti.json rename to src/module/uti/spirtfist.uti.json diff --git a/src/mod/uti/ssgauntlets.uti.json b/src/module/uti/ssgauntlets.uti.json similarity index 100% rename from src/mod/uti/ssgauntlets.uti.json rename to src/module/uti/ssgauntlets.uti.json diff --git a/src/mod/uti/ssoutfit.uti.json b/src/module/uti/ssoutfit.uti.json similarity index 100% rename from src/mod/uti/ssoutfit.uti.json rename to src/module/uti/ssoutfit.uti.json diff --git a/src/mod/uti/staffmaster.uti.json b/src/module/uti/staffmaster.uti.json similarity index 100% rename from src/mod/uti/staffmaster.uti.json rename to src/module/uti/staffmaster.uti.json diff --git a/src/mod/uti/staffofchoice.uti.json b/src/module/uti/staffofchoice.uti.json similarity index 100% rename from src/mod/uti/staffofchoice.uti.json rename to src/module/uti/staffofchoice.uti.json diff --git a/src/mod/uti/staffofcommand.uti.json b/src/module/uti/staffofcommand.uti.json similarity index 100% rename from src/mod/uti/staffofcommand.uti.json rename to src/module/uti/staffofcommand.uti.json diff --git a/src/mod/uti/staffofdefense.uti.json b/src/module/uti/staffofdefense.uti.json similarity index 100% rename from src/mod/uti/staffofdefense.uti.json rename to src/module/uti/staffofdefense.uti.json diff --git a/src/mod/uti/staffofpain.uti.json b/src/module/uti/staffofpain.uti.json similarity index 100% rename from src/mod/uti/staffofpain.uti.json rename to src/module/uti/staffofpain.uti.json diff --git a/src/mod/uti/staffofthedark.uti.json b/src/module/uti/staffofthedark.uti.json similarity index 100% rename from src/mod/uti/staffofthedark.uti.json rename to src/module/uti/staffofthedark.uti.json diff --git a/src/mod/uti/staffofvera.uti.json b/src/module/uti/staffofvera.uti.json similarity index 100% rename from src/mod/uti/staffofvera.uti.json rename to src/module/uti/staffofvera.uti.json diff --git a/src/mod/uti/starofvengance.uti.json b/src/module/uti/starofvengance.uti.json similarity index 100% rename from src/mod/uti/starofvengance.uti.json rename to src/module/uti/starofvengance.uti.json diff --git a/src/mod/uti/starsofholyness.uti.json b/src/module/uti/starsofholyness.uti.json similarity index 100% rename from src/mod/uti/starsofholyness.uti.json rename to src/module/uti/starsofholyness.uti.json diff --git a/src/mod/uti/stealkatana.uti.json b/src/module/uti/stealkatana.uti.json similarity index 100% rename from src/mod/uti/stealkatana.uti.json rename to src/module/uti/stealkatana.uti.json diff --git a/src/mod/uti/steallongsword.uti.json b/src/module/uti/steallongsword.uti.json similarity index 100% rename from src/mod/uti/steallongsword.uti.json rename to src/module/uti/steallongsword.uti.json diff --git a/src/mod/uti/stinger.uti.json b/src/module/uti/stinger.uti.json similarity index 100% rename from src/mod/uti/stinger.uti.json rename to src/module/uti/stinger.uti.json diff --git a/src/mod/uti/stinger_hide001.uti.json b/src/module/uti/stinger_hide001.uti.json similarity index 100% rename from src/mod/uti/stinger_hide001.uti.json rename to src/module/uti/stinger_hide001.uti.json diff --git a/src/mod/uti/stinger_tail001.uti.json b/src/module/uti/stinger_tail001.uti.json similarity index 100% rename from src/mod/uti/stinger_tail001.uti.json rename to src/module/uti/stinger_tail001.uti.json diff --git a/src/mod/uti/stinger_tail002.uti.json b/src/module/uti/stinger_tail002.uti.json similarity index 100% rename from src/mod/uti/stinger_tail002.uti.json rename to src/module/uti/stinger_tail002.uti.json diff --git a/src/mod/uti/stingerclaw.uti.json b/src/module/uti/stingerclaw.uti.json similarity index 100% rename from src/mod/uti/stingerclaw.uti.json rename to src/module/uti/stingerclaw.uti.json diff --git a/src/mod/uti/stingerheavyplat.uti.json b/src/module/uti/stingerheavyplat.uti.json similarity index 100% rename from src/mod/uti/stingerheavyplat.uti.json rename to src/module/uti/stingerheavyplat.uti.json diff --git a/src/mod/uti/stingerplate.uti.json b/src/module/uti/stingerplate.uti.json similarity index 100% rename from src/mod/uti/stingerplate.uti.json rename to src/module/uti/stingerplate.uti.json diff --git a/src/mod/uti/stingerscales.uti.json b/src/module/uti/stingerscales.uti.json similarity index 100% rename from src/mod/uti/stingerscales.uti.json rename to src/module/uti/stingerscales.uti.json diff --git a/src/mod/uti/stingerstaff.uti.json b/src/module/uti/stingerstaff.uti.json similarity index 100% rename from src/mod/uti/stingerstaff.uti.json rename to src/module/uti/stingerstaff.uti.json diff --git a/src/mod/uti/stolenloot.uti.json b/src/module/uti/stolenloot.uti.json similarity index 100% rename from src/mod/uti/stolenloot.uti.json rename to src/module/uti/stolenloot.uti.json diff --git a/src/mod/uti/stoneofreturn.uti.json b/src/module/uti/stoneofreturn.uti.json similarity index 100% rename from src/mod/uti/stoneofreturn.uti.json rename to src/module/uti/stoneofreturn.uti.json diff --git a/src/mod/uti/strappingarmor.uti.json b/src/module/uti/strappingarmor.uti.json similarity index 100% rename from src/mod/uti/strappingarmor.uti.json rename to src/module/uti/strappingarmor.uti.json diff --git a/src/mod/uti/strappingspear.uti.json b/src/module/uti/strappingspear.uti.json similarity index 100% rename from src/mod/uti/strappingspear.uti.json rename to src/module/uti/strappingspear.uti.json diff --git a/src/mod/uti/sturdycrossbow.uti.json b/src/module/uti/sturdycrossbow.uti.json similarity index 100% rename from src/mod/uti/sturdycrossbow.uti.json rename to src/module/uti/sturdycrossbow.uti.json diff --git a/src/mod/uti/subzeroarrows.uti.json b/src/module/uti/subzeroarrows.uti.json similarity index 100% rename from src/mod/uti/subzeroarrows.uti.json rename to src/module/uti/subzeroarrows.uti.json diff --git a/src/mod/uti/subzeroaxe.uti.json b/src/module/uti/subzeroaxe.uti.json similarity index 100% rename from src/mod/uti/subzeroaxe.uti.json rename to src/module/uti/subzeroaxe.uti.json diff --git a/src/mod/uti/subzerobow.uti.json b/src/module/uti/subzerobow.uti.json similarity index 100% rename from src/mod/uti/subzerobow.uti.json rename to src/module/uti/subzerobow.uti.json diff --git a/src/mod/uti/subzerokingclaw.uti.json b/src/module/uti/subzerokingclaw.uti.json similarity index 100% rename from src/mod/uti/subzerokingclaw.uti.json rename to src/module/uti/subzerokingclaw.uti.json diff --git a/src/mod/uti/subzerokinggore.uti.json b/src/module/uti/subzerokinggore.uti.json similarity index 100% rename from src/mod/uti/subzerokinggore.uti.json rename to src/module/uti/subzerokinggore.uti.json diff --git a/src/mod/uti/subzerokingskin.uti.json b/src/module/uti/subzerokingskin.uti.json similarity index 100% rename from src/mod/uti/subzerokingskin.uti.json rename to src/module/uti/subzerokingskin.uti.json diff --git a/src/mod/uti/subzeromageskin.uti.json b/src/module/uti/subzeromageskin.uti.json similarity index 100% rename from src/mod/uti/subzeromageskin.uti.json rename to src/module/uti/subzeromageskin.uti.json diff --git a/src/mod/uti/subzerostaff.uti.json b/src/module/uti/subzerostaff.uti.json similarity index 100% rename from src/mod/uti/subzerostaff.uti.json rename to src/module/uti/subzerostaff.uti.json diff --git a/src/mod/uti/subzerowarriorsk.uti.json b/src/module/uti/subzerowarriorsk.uti.json similarity index 100% rename from src/mod/uti/subzerowarriorsk.uti.json rename to src/module/uti/subzerowarriorsk.uti.json diff --git a/src/mod/uti/suitofthearchane.uti.json b/src/module/uti/suitofthearchane.uti.json similarity index 100% rename from src/mod/uti/suitofthearchane.uti.json rename to src/module/uti/suitofthearchane.uti.json diff --git a/src/mod/uti/summonarmor.uti.json b/src/module/uti/summonarmor.uti.json similarity index 100% rename from src/mod/uti/summonarmor.uti.json rename to src/module/uti/summonarmor.uti.json diff --git a/src/mod/uti/summonarmor001.uti.json b/src/module/uti/summonarmor001.uti.json similarity index 100% rename from src/mod/uti/summonarmor001.uti.json rename to src/module/uti/summonarmor001.uti.json diff --git a/src/mod/uti/summonarmor004.uti.json b/src/module/uti/summonarmor004.uti.json similarity index 100% rename from src/mod/uti/summonarmor004.uti.json rename to src/module/uti/summonarmor004.uti.json diff --git a/src/mod/uti/summongreatsword.uti.json b/src/module/uti/summongreatsword.uti.json similarity index 100% rename from src/mod/uti/summongreatsword.uti.json rename to src/module/uti/summongreatsword.uti.json diff --git a/src/mod/uti/summonshield.uti.json b/src/module/uti/summonshield.uti.json similarity index 100% rename from src/mod/uti/summonshield.uti.json rename to src/module/uti/summonshield.uti.json diff --git a/src/mod/uti/swordofthelowerr.uti.json b/src/module/uti/swordofthelowerr.uti.json similarity index 100% rename from src/mod/uti/swordofthelowerr.uti.json rename to src/module/uti/swordofthelowerr.uti.json diff --git a/src/mod/uti/swrobes.uti.json b/src/module/uti/swrobes.uti.json similarity index 100% rename from src/mod/uti/swrobes.uti.json rename to src/module/uti/swrobes.uti.json diff --git a/src/mod/uti/tabddkey.uti.json b/src/module/uti/tabddkey.uti.json similarity index 100% rename from src/mod/uti/tabddkey.uti.json rename to src/module/uti/tabddkey.uti.json diff --git a/src/mod/uti/tabdrow.uti.json b/src/module/uti/tabdrow.uti.json similarity index 100% rename from src/mod/uti/tabdrow.uti.json rename to src/module/uti/tabdrow.uti.json diff --git a/src/mod/uti/tabdrowkey2.uti.json b/src/module/uti/tabdrowkey2.uti.json similarity index 100% rename from src/mod/uti/tabdrowkey2.uti.json rename to src/module/uti/tabdrowkey2.uti.json diff --git a/src/mod/uti/tabdrowo2.uti.json b/src/module/uti/tabdrowo2.uti.json similarity index 100% rename from src/mod/uti/tabdrowo2.uti.json rename to src/module/uti/tabdrowo2.uti.json diff --git a/src/mod/uti/tagnerkukri.uti.json b/src/module/uti/tagnerkukri.uti.json similarity index 100% rename from src/mod/uti/tagnerkukri.uti.json rename to src/module/uti/tagnerkukri.uti.json diff --git a/src/mod/uti/test002.uti.json b/src/module/uti/test002.uti.json similarity index 100% rename from src/mod/uti/test002.uti.json rename to src/module/uti/test002.uti.json diff --git a/src/mod/uti/theshifter.uti.json b/src/module/uti/theshifter.uti.json similarity index 100% rename from src/mod/uti/theshifter.uti.json rename to src/module/uti/theshifter.uti.json diff --git a/src/mod/uti/theshifterbroken.uti.json b/src/module/uti/theshifterbroken.uti.json similarity index 100% rename from src/mod/uti/theshifterbroken.uti.json rename to src/module/uti/theshifterbroken.uti.json diff --git a/src/mod/uti/thorn.uti.json b/src/module/uti/thorn.uti.json similarity index 100% rename from src/mod/uti/thorn.uti.json rename to src/module/uti/thorn.uti.json diff --git a/src/mod/uti/thunderlordar001.uti.json b/src/module/uti/thunderlordar001.uti.json similarity index 100% rename from src/mod/uti/thunderlordar001.uti.json rename to src/module/uti/thunderlordar001.uti.json diff --git a/src/mod/uti/thunderlordstaff.uti.json b/src/module/uti/thunderlordstaff.uti.json similarity index 100% rename from src/mod/uti/thunderlordstaff.uti.json rename to src/module/uti/thunderlordstaff.uti.json diff --git a/src/mod/uti/thundermounti001.uti.json b/src/module/uti/thundermounti001.uti.json similarity index 100% rename from src/mod/uti/thundermounti001.uti.json rename to src/module/uti/thundermounti001.uti.json diff --git a/src/mod/uti/titaniumshield.uti.json b/src/module/uti/titaniumshield.uti.json similarity index 100% rename from src/mod/uti/titaniumshield.uti.json rename to src/module/uti/titaniumshield.uti.json diff --git a/src/mod/uti/titaniumsword.uti.json b/src/module/uti/titaniumsword.uti.json similarity index 100% rename from src/mod/uti/titaniumsword.uti.json rename to src/module/uti/titaniumsword.uti.json diff --git a/src/mod/uti/tmarcherarmor.uti.json b/src/module/uti/tmarcherarmor.uti.json similarity index 100% rename from src/mod/uti/tmarcherarmor.uti.json rename to src/module/uti/tmarcherarmor.uti.json diff --git a/src/mod/uti/tmbattleplans.uti.json b/src/module/uti/tmbattleplans.uti.json similarity index 100% rename from src/mod/uti/tmbattleplans.uti.json rename to src/module/uti/tmbattleplans.uti.json diff --git a/src/mod/uti/tmgaurdarmor.uti.json b/src/module/uti/tmgaurdarmor.uti.json similarity index 100% rename from src/mod/uti/tmgaurdarmor.uti.json rename to src/module/uti/tmgaurdarmor.uti.json diff --git a/src/mod/uti/tmgaurdarmor001.uti.json b/src/module/uti/tmgaurdarmor001.uti.json similarity index 100% rename from src/mod/uti/tmgaurdarmor001.uti.json rename to src/module/uti/tmgaurdarmor001.uti.json diff --git a/src/mod/uti/tmgaurdhelmit.uti.json b/src/module/uti/tmgaurdhelmit.uti.json similarity index 100% rename from src/mod/uti/tmgaurdhelmit.uti.json rename to src/module/uti/tmgaurdhelmit.uti.json diff --git a/src/mod/uti/tmhalberd.uti.json b/src/module/uti/tmhalberd.uti.json similarity index 100% rename from src/mod/uti/tmhalberd.uti.json rename to src/module/uti/tmhalberd.uti.json diff --git a/src/mod/uti/tmjailor001.uti.json b/src/module/uti/tmjailor001.uti.json similarity index 100% rename from src/mod/uti/tmjailor001.uti.json rename to src/module/uti/tmjailor001.uti.json diff --git a/src/mod/uti/tmjailor002.uti.json b/src/module/uti/tmjailor002.uti.json similarity index 100% rename from src/mod/uti/tmjailor002.uti.json rename to src/module/uti/tmjailor002.uti.json diff --git a/src/mod/uti/tmjailorcloak.uti.json b/src/module/uti/tmjailorcloak.uti.json similarity index 100% rename from src/mod/uti/tmjailorcloak.uti.json rename to src/module/uti/tmjailorcloak.uti.json diff --git a/src/mod/uti/tmjailorshield.uti.json b/src/module/uti/tmjailorshield.uti.json similarity index 100% rename from src/mod/uti/tmjailorshield.uti.json rename to src/module/uti/tmjailorshield.uti.json diff --git a/src/mod/uti/tmkingarmor.uti.json b/src/module/uti/tmkingarmor.uti.json similarity index 100% rename from src/mod/uti/tmkingarmor.uti.json rename to src/module/uti/tmkingarmor.uti.json diff --git a/src/mod/uti/tmkingshield.uti.json b/src/module/uti/tmkingshield.uti.json similarity index 100% rename from src/mod/uti/tmkingshield.uti.json rename to src/module/uti/tmkingshield.uti.json diff --git a/src/mod/uti/tmlordguardhelm.uti.json b/src/module/uti/tmlordguardhelm.uti.json similarity index 100% rename from src/mod/uti/tmlordguardhelm.uti.json rename to src/module/uti/tmlordguardhelm.uti.json diff --git a/src/mod/uti/tmspearmenarmor.uti.json b/src/module/uti/tmspearmenarmor.uti.json similarity index 100% rename from src/mod/uti/tmspearmenarmor.uti.json rename to src/module/uti/tmspearmenarmor.uti.json diff --git a/src/mod/uti/tmspearmenhelm.uti.json b/src/module/uti/tmspearmenhelm.uti.json similarity index 100% rename from src/mod/uti/tmspearmenhelm.uti.json rename to src/module/uti/tmspearmenhelm.uti.json diff --git a/src/mod/uti/trinitybook.uti.json b/src/module/uti/trinitybook.uti.json similarity index 100% rename from src/mod/uti/trinitybook.uti.json rename to src/module/uti/trinitybook.uti.json diff --git a/src/mod/uti/trinitychampi002.uti.json b/src/module/uti/trinitychampi002.uti.json similarity index 100% rename from src/mod/uti/trinitychampi002.uti.json rename to src/module/uti/trinitychampi002.uti.json diff --git a/src/mod/uti/trinitychampswor.uti.json b/src/module/uti/trinitychampswor.uti.json similarity index 100% rename from src/mod/uti/trinitychampswor.uti.json rename to src/module/uti/trinitychampswor.uti.json diff --git a/src/mod/uti/trollboots.uti.json b/src/module/uti/trollboots.uti.json similarity index 100% rename from src/mod/uti/trollboots.uti.json rename to src/module/uti/trollboots.uti.json diff --git a/src/mod/uti/trooperammo.uti.json b/src/module/uti/trooperammo.uti.json similarity index 100% rename from src/mod/uti/trooperammo.uti.json rename to src/module/uti/trooperammo.uti.json diff --git a/src/mod/uti/trooperarmor.uti.json b/src/module/uti/trooperarmor.uti.json similarity index 100% rename from src/mod/uti/trooperarmor.uti.json rename to src/module/uti/trooperarmor.uti.json diff --git a/src/mod/uti/troopergun.uti.json b/src/module/uti/troopergun.uti.json similarity index 100% rename from src/mod/uti/troopergun.uti.json rename to src/module/uti/troopergun.uti.json diff --git a/src/mod/uti/trooperhelmet.uti.json b/src/module/uti/trooperhelmet.uti.json similarity index 100% rename from src/mod/uti/trooperhelmet.uti.json rename to src/module/uti/trooperhelmet.uti.json diff --git a/src/mod/uti/trophyofchamp001.uti.json b/src/module/uti/trophyofchamp001.uti.json similarity index 100% rename from src/mod/uti/trophyofchamp001.uti.json rename to src/module/uti/trophyofchamp001.uti.json diff --git a/src/mod/uti/trophyofinsight.uti.json b/src/module/uti/trophyofinsight.uti.json similarity index 100% rename from src/mod/uti/trophyofinsight.uti.json rename to src/module/uti/trophyofinsight.uti.json diff --git a/src/mod/uti/tumblearmor.uti.json b/src/module/uti/tumblearmor.uti.json similarity index 100% rename from src/mod/uti/tumblearmor.uti.json rename to src/module/uti/tumblearmor.uti.json diff --git a/src/mod/uti/tumbleboots.uti.json b/src/module/uti/tumbleboots.uti.json similarity index 100% rename from src/mod/uti/tumbleboots.uti.json rename to src/module/uti/tumbleboots.uti.json diff --git a/src/mod/uti/tumblewhip.uti.json b/src/module/uti/tumblewhip.uti.json similarity index 100% rename from src/mod/uti/tumblewhip.uti.json rename to src/module/uti/tumblewhip.uti.json diff --git a/src/mod/uti/udkey.uti.json b/src/module/uti/udkey.uti.json similarity index 100% rename from src/mod/uti/udkey.uti.json rename to src/module/uti/udkey.uti.json diff --git a/src/mod/uti/undeadskins.uti.json b/src/module/uti/undeadskins.uti.json similarity index 100% rename from src/mod/uti/undeadskins.uti.json rename to src/module/uti/undeadskins.uti.json diff --git a/src/mod/uti/unenshelmet.uti.json b/src/module/uti/unenshelmet.uti.json similarity index 100% rename from src/mod/uti/unenshelmet.uti.json rename to src/module/uti/unenshelmet.uti.json diff --git a/src/mod/uti/unicornblood.uti.json b/src/module/uti/unicornblood.uti.json similarity index 100% rename from src/mod/uti/unicornblood.uti.json rename to src/module/uti/unicornblood.uti.json diff --git a/src/mod/uti/vampirerobenpc.uti.json b/src/module/uti/vampirerobenpc.uti.json similarity index 100% rename from src/mod/uti/vampirerobenpc.uti.json rename to src/module/uti/vampirerobenpc.uti.json diff --git a/src/mod/uti/vassiskin001.uti.json b/src/module/uti/vassiskin001.uti.json similarity index 100% rename from src/mod/uti/vassiskin001.uti.json rename to src/module/uti/vassiskin001.uti.json diff --git a/src/mod/uti/vibroblade.uti.json b/src/module/uti/vibroblade.uti.json similarity index 100% rename from src/mod/uti/vibroblade.uti.json rename to src/module/uti/vibroblade.uti.json diff --git a/src/mod/uti/vmgauntlets.uti.json b/src/module/uti/vmgauntlets.uti.json similarity index 100% rename from src/mod/uti/vmgauntlets.uti.json rename to src/module/uti/vmgauntlets.uti.json diff --git a/src/mod/uti/vmrobes.uti.json b/src/module/uti/vmrobes.uti.json similarity index 100% rename from src/mod/uti/vmrobes.uti.json rename to src/module/uti/vmrobes.uti.json diff --git a/src/mod/uti/wdarkqueenrapier.uti.json b/src/module/uti/wdarkqueenrapier.uti.json similarity index 100% rename from src/mod/uti/wdarkqueenrapier.uti.json rename to src/module/uti/wdarkqueenrapier.uti.json diff --git a/src/mod/uti/whitedragonblood.uti.json b/src/module/uti/whitedragonblood.uti.json similarity index 100% rename from src/mod/uti/whitedragonblood.uti.json rename to src/module/uti/whitedragonblood.uti.json diff --git a/src/mod/uti/wildmagekey.uti.json b/src/module/uti/wildmagekey.uti.json similarity index 100% rename from src/mod/uti/wildmagekey.uti.json rename to src/module/uti/wildmagekey.uti.json diff --git a/src/mod/uti/wildmagekey2.uti.json b/src/module/uti/wildmagekey2.uti.json similarity index 100% rename from src/mod/uti/wildmagekey2.uti.json rename to src/module/uti/wildmagekey2.uti.json diff --git a/src/mod/uti/wizstaffofpower.uti.json b/src/module/uti/wizstaffofpower.uti.json similarity index 100% rename from src/mod/uti/wizstaffofpower.uti.json rename to src/module/uti/wizstaffofpower.uti.json diff --git a/src/mod/uti/wizzymonkrobe.uti.json b/src/module/uti/wizzymonkrobe.uti.json similarity index 100% rename from src/mod/uti/wizzymonkrobe.uti.json rename to src/module/uti/wizzymonkrobe.uti.json diff --git a/src/mod/uti/wnguildkey.uti.json b/src/module/uti/wnguildkey.uti.json similarity index 100% rename from src/mod/uti/wnguildkey.uti.json rename to src/module/uti/wnguildkey.uti.json diff --git a/src/mod/uti/worthlessrod.uti.json b/src/module/uti/worthlessrod.uti.json similarity index 100% rename from src/mod/uti/worthlessrod.uti.json rename to src/module/uti/worthlessrod.uti.json diff --git a/src/mod/uti/wswbs002.uti.json b/src/module/uti/wswbs002.uti.json similarity index 100% rename from src/mod/uti/wswbs002.uti.json rename to src/module/uti/wswbs002.uti.json diff --git a/src/mod/uti/xx_atlport.uti.json b/src/module/uti/xx_atlport.uti.json similarity index 100% rename from src/mod/uti/xx_atlport.uti.json rename to src/module/uti/xx_atlport.uti.json diff --git a/src/mod/uti/xx_dragonport.uti.json b/src/module/uti/xx_dragonport.uti.json similarity index 100% rename from src/mod/uti/xx_dragonport.uti.json rename to src/module/uti/xx_dragonport.uti.json diff --git a/src/mod/uti/xx_dwarfport.uti.json b/src/module/uti/xx_dwarfport.uti.json similarity index 100% rename from src/mod/uti/xx_dwarfport.uti.json rename to src/module/uti/xx_dwarfport.uti.json diff --git a/src/mod/uti/xx_manyport.uti.json b/src/module/uti/xx_manyport.uti.json similarity index 100% rename from src/mod/uti/xx_manyport.uti.json rename to src/module/uti/xx_manyport.uti.json diff --git a/src/mod/uti/xx_nordicport.uti.json b/src/module/uti/xx_nordicport.uti.json similarity index 100% rename from src/mod/uti/xx_nordicport.uti.json rename to src/module/uti/xx_nordicport.uti.json diff --git a/src/mod/uti/xx_reward10k.uti.json b/src/module/uti/xx_reward10k.uti.json similarity index 100% rename from src/mod/uti/xx_reward10k.uti.json rename to src/module/uti/xx_reward10k.uti.json diff --git a/src/mod/uti/xx_reward2k.uti.json b/src/module/uti/xx_reward2k.uti.json similarity index 100% rename from src/mod/uti/xx_reward2k.uti.json rename to src/module/uti/xx_reward2k.uti.json diff --git a/src/mod/uti/xx_tempcain.uti.json b/src/module/uti/xx_tempcain.uti.json similarity index 100% rename from src/mod/uti/xx_tempcain.uti.json rename to src/module/uti/xx_tempcain.uti.json diff --git a/src/mod/uti/xx_testreward.uti.json b/src/module/uti/xx_testreward.uti.json similarity index 100% rename from src/mod/uti/xx_testreward.uti.json rename to src/module/uti/xx_testreward.uti.json diff --git a/src/mod/uti/xx_trinport.uti.json b/src/module/uti/xx_trinport.uti.json similarity index 100% rename from src/mod/uti/xx_trinport.uti.json rename to src/module/uti/xx_trinport.uti.json diff --git a/src/mod/utm/brewmaster.utm.json b/src/module/utm/brewmaster.utm.json similarity index 100% rename from src/mod/utm/brewmaster.utm.json rename to src/module/utm/brewmaster.utm.json diff --git a/src/mod/utm/dmstore2.utm.json b/src/module/utm/dmstore2.utm.json similarity index 100% rename from src/mod/utm/dmstore2.utm.json rename to src/module/utm/dmstore2.utm.json diff --git a/src/mod/utm/dmstore3.utm.json b/src/module/utm/dmstore3.utm.json similarity index 100% rename from src/mod/utm/dmstore3.utm.json rename to src/module/utm/dmstore3.utm.json diff --git a/src/mod/utm/dmstore4.utm.json b/src/module/utm/dmstore4.utm.json similarity index 100% rename from src/mod/utm/dmstore4.utm.json rename to src/module/utm/dmstore4.utm.json diff --git a/src/mod/utm/elfmherchant.utm.json b/src/module/utm/elfmherchant.utm.json similarity index 100% rename from src/mod/utm/elfmherchant.utm.json rename to src/module/utm/elfmherchant.utm.json diff --git a/src/mod/utm/legionbar.utm.json b/src/module/utm/legionbar.utm.json similarity index 100% rename from src/mod/utm/legionbar.utm.json rename to src/module/utm/legionbar.utm.json diff --git a/src/mod/utm/malnip.utm.json b/src/module/utm/malnip.utm.json similarity index 100% rename from src/mod/utm/malnip.utm.json rename to src/module/utm/malnip.utm.json diff --git a/src/mod/utm/maxstore.utm.json b/src/module/utm/maxstore.utm.json similarity index 100% rename from src/mod/utm/maxstore.utm.json rename to src/module/utm/maxstore.utm.json diff --git a/src/mod/utm/tabhill.utm.json b/src/module/utm/tabhill.utm.json similarity index 100% rename from src/mod/utm/tabhill.utm.json rename to src/module/utm/tabhill.utm.json diff --git a/src/mod/utm/trapstore.utm.json b/src/module/utm/trapstore.utm.json similarity index 100% rename from src/mod/utm/trapstore.utm.json rename to src/module/utm/trapstore.utm.json diff --git a/src/mod/utp/alchapprtus001.utp.json b/src/module/utp/alchapprtus001.utp.json similarity index 100% rename from src/mod/utp/alchapprtus001.utp.json rename to src/module/utp/alchapprtus001.utp.json diff --git a/src/mod/utp/anvil001.utp.json b/src/module/utp/anvil001.utp.json similarity index 100% rename from src/mod/utp/anvil001.utp.json rename to src/module/utp/anvil001.utp.json diff --git a/src/mod/utp/arrowcorpse001.utp.json b/src/module/utp/arrowcorpse001.utp.json similarity index 100% rename from src/mod/utp/arrowcorpse001.utp.json rename to src/module/utp/arrowcorpse001.utp.json diff --git a/src/mod/utp/awptth.utp.json b/src/module/utp/awptth.utp.json similarity index 100% rename from src/mod/utp/awptth.utp.json rename to src/module/utp/awptth.utp.json diff --git a/src/mod/utp/awverachamberthi.utp.json b/src/module/utp/awverachamberthi.utp.json similarity index 100% rename from src/mod/utp/awverachamberthi.utp.json rename to src/module/utp/awverachamberthi.utp.json diff --git a/src/mod/utp/ballistabrk001.utp.json b/src/module/utp/ballistabrk001.utp.json similarity index 100% rename from src/mod/utp/ballistabrk001.utp.json rename to src/module/utp/ballistabrk001.utp.json diff --git a/src/mod/utp/bearskinrug002.utp.json b/src/module/utp/bearskinrug002.utp.json similarity index 100% rename from src/mod/utp/bearskinrug002.utp.json rename to src/module/utp/bearskinrug002.utp.json diff --git a/src/mod/utp/bedrolls001.utp.json b/src/module/utp/bedrolls001.utp.json similarity index 100% rename from src/mod/utp/bedrolls001.utp.json rename to src/module/utp/bedrolls001.utp.json diff --git a/src/mod/utp/bloodstain001.utp.json b/src/module/utp/bloodstain001.utp.json similarity index 100% rename from src/mod/utp/bloodstain001.utp.json rename to src/module/utp/bloodstain001.utp.json diff --git a/src/mod/utp/bluepillar.utp.json b/src/module/utp/bluepillar.utp.json similarity index 100% rename from src/mod/utp/bluepillar.utp.json rename to src/module/utp/bluepillar.utp.json diff --git a/src/mod/utp/bookcase004.utp.json b/src/module/utp/bookcase004.utp.json similarity index 100% rename from src/mod/utp/bookcase004.utp.json rename to src/module/utp/bookcase004.utp.json diff --git a/src/mod/utp/brazier001.utp.json b/src/module/utp/brazier001.utp.json similarity index 100% rename from src/mod/utp/brazier001.utp.json rename to src/module/utp/brazier001.utp.json diff --git a/src/mod/utp/brazier002.utp.json b/src/module/utp/brazier002.utp.json similarity index 100% rename from src/mod/utp/brazier002.utp.json rename to src/module/utp/brazier002.utp.json diff --git a/src/mod/utp/bread.utp.json b/src/module/utp/bread.utp.json similarity index 100% rename from src/mod/utp/bread.utp.json rename to src/module/utp/bread.utp.json diff --git a/src/mod/utp/bttrrambrk001.utp.json b/src/module/utp/bttrrambrk001.utp.json similarity index 100% rename from src/mod/utp/bttrrambrk001.utp.json rename to src/module/utp/bttrrambrk001.utp.json diff --git a/src/mod/utp/bubbleball.utp.json b/src/module/utp/bubbleball.utp.json similarity index 100% rename from src/mod/utp/bubbleball.utp.json rename to src/module/utp/bubbleball.utp.json diff --git a/src/mod/utp/cainportal.utp.json b/src/module/utp/cainportal.utp.json similarity index 100% rename from src/mod/utp/cainportal.utp.json rename to src/module/utp/cainportal.utp.json diff --git a/src/mod/utp/calimanwalk.utp.json b/src/module/utp/calimanwalk.utp.json similarity index 100% rename from src/mod/utp/calimanwalk.utp.json rename to src/module/utp/calimanwalk.utp.json diff --git a/src/mod/utp/calimanwalk001.utp.json b/src/module/utp/calimanwalk001.utp.json similarity index 100% rename from src/mod/utp/calimanwalk001.utp.json rename to src/module/utp/calimanwalk001.utp.json diff --git a/src/mod/utp/campfr001.utp.json b/src/module/utp/campfr001.utp.json similarity index 100% rename from src/mod/utp/campfr001.utp.json rename to src/module/utp/campfr001.utp.json diff --git a/src/mod/utp/campfrwpot001.utp.json b/src/module/utp/campfrwpot001.utp.json similarity index 100% rename from src/mod/utp/campfrwpot001.utp.json rename to src/module/utp/campfrwpot001.utp.json diff --git a/src/mod/utp/campfrwspit001.utp.json b/src/module/utp/campfrwspit001.utp.json similarity index 100% rename from src/mod/utp/campfrwspit001.utp.json rename to src/module/utp/campfrwspit001.utp.json diff --git a/src/mod/utp/candelabra001.utp.json b/src/module/utp/candelabra001.utp.json similarity index 100% rename from src/mod/utp/candelabra001.utp.json rename to src/module/utp/candelabra001.utp.json diff --git a/src/mod/utp/catplt001.utp.json b/src/module/utp/catplt001.utp.json similarity index 100% rename from src/mod/utp/catplt001.utp.json rename to src/module/utp/catplt001.utp.json diff --git a/src/mod/utp/catpltbrk001.utp.json b/src/module/utp/catpltbrk001.utp.json similarity index 100% rename from src/mod/utp/catpltbrk001.utp.json rename to src/module/utp/catpltbrk001.utp.json diff --git a/src/mod/utp/cauldron001.utp.json b/src/module/utp/cauldron001.utp.json similarity index 100% rename from src/mod/utp/cauldron001.utp.json rename to src/module/utp/cauldron001.utp.json diff --git a/src/mod/utp/chair001.utp.json b/src/module/utp/chair001.utp.json similarity index 100% rename from src/mod/utp/chair001.utp.json rename to src/module/utp/chair001.utp.json diff --git a/src/mod/utp/chest002.utp.json b/src/module/utp/chest002.utp.json similarity index 100% rename from src/mod/utp/chest002.utp.json rename to src/module/utp/chest002.utp.json diff --git a/src/mod/utp/chest010.utp.json b/src/module/utp/chest010.utp.json similarity index 100% rename from src/mod/utp/chest010.utp.json rename to src/module/utp/chest010.utp.json diff --git a/src/mod/utp/chest1.utp.json b/src/module/utp/chest1.utp.json similarity index 100% rename from src/mod/utp/chest1.utp.json rename to src/module/utp/chest1.utp.json diff --git a/src/mod/utp/closetmonsterpor.utp.json b/src/module/utp/closetmonsterpor.utp.json similarity index 100% rename from src/mod/utp/closetmonsterpor.utp.json rename to src/module/utp/closetmonsterpor.utp.json diff --git a/src/mod/utp/cmbtdummy001.utp.json b/src/module/utp/cmbtdummy001.utp.json similarity index 100% rename from src/mod/utp/cmbtdummy001.utp.json rename to src/module/utp/cmbtdummy001.utp.json diff --git a/src/mod/utp/cushions.utp.json b/src/module/utp/cushions.utp.json similarity index 100% rename from src/mod/utp/cushions.utp.json rename to src/module/utp/cushions.utp.json diff --git a/src/mod/utp/drowlight.utp.json b/src/module/utp/drowlight.utp.json similarity index 100% rename from src/mod/utp/drowlight.utp.json rename to src/module/utp/drowlight.utp.json diff --git a/src/mod/utp/dustplume001.utp.json b/src/module/utp/dustplume001.utp.json similarity index 100% rename from src/mod/utp/dustplume001.utp.json rename to src/module/utp/dustplume001.utp.json diff --git a/src/mod/utp/dustplume002.utp.json b/src/module/utp/dustplume002.utp.json similarity index 100% rename from src/mod/utp/dustplume002.utp.json rename to src/module/utp/dustplume002.utp.json diff --git a/src/mod/utp/dustplume003.utp.json b/src/module/utp/dustplume003.utp.json similarity index 100% rename from src/mod/utp/dustplume003.utp.json rename to src/module/utp/dustplume003.utp.json diff --git a/src/mod/utp/emptywagon001.utp.json b/src/module/utp/emptywagon001.utp.json similarity index 100% rename from src/mod/utp/emptywagon001.utp.json rename to src/module/utp/emptywagon001.utp.json diff --git a/src/mod/utp/ffx_bar_blue.utp.json b/src/module/utp/ffx_bar_blue.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_blue.utp.json rename to src/module/utp/ffx_bar_blue.utp.json diff --git a/src/mod/utp/ffx_bar_green.utp.json b/src/module/utp/ffx_bar_green.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_green.utp.json rename to src/module/utp/ffx_bar_green.utp.json diff --git a/src/mod/utp/ffx_bar_orange.utp.json b/src/module/utp/ffx_bar_orange.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_orange.utp.json rename to src/module/utp/ffx_bar_orange.utp.json diff --git a/src/mod/utp/ffx_bar_purple.utp.json b/src/module/utp/ffx_bar_purple.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_purple.utp.json rename to src/module/utp/ffx_bar_purple.utp.json diff --git a/src/mod/utp/ffx_bar_red.utp.json b/src/module/utp/ffx_bar_red.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_red.utp.json rename to src/module/utp/ffx_bar_red.utp.json diff --git a/src/mod/utp/ffx_bar_white.utp.json b/src/module/utp/ffx_bar_white.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_white.utp.json rename to src/module/utp/ffx_bar_white.utp.json diff --git a/src/mod/utp/ffx_bar_yellow.utp.json b/src/module/utp/ffx_bar_yellow.utp.json similarity index 100% rename from src/mod/utp/ffx_bar_yellow.utp.json rename to src/module/utp/ffx_bar_yellow.utp.json diff --git a/src/mod/utp/flamelarge001.utp.json b/src/module/utp/flamelarge001.utp.json similarity index 100% rename from src/mod/utp/flamelarge001.utp.json rename to src/module/utp/flamelarge001.utp.json diff --git a/src/mod/utp/flamelarge002.utp.json b/src/module/utp/flamelarge002.utp.json similarity index 100% rename from src/mod/utp/flamelarge002.utp.json rename to src/module/utp/flamelarge002.utp.json diff --git a/src/mod/utp/flamemedium001.utp.json b/src/module/utp/flamemedium001.utp.json similarity index 100% rename from src/mod/utp/flamemedium001.utp.json rename to src/module/utp/flamemedium001.utp.json diff --git a/src/mod/utp/flamesmall001.utp.json b/src/module/utp/flamesmall001.utp.json similarity index 100% rename from src/mod/utp/flamesmall001.utp.json rename to src/module/utp/flamesmall001.utp.json diff --git a/src/mod/utp/glowingpillar.utp.json b/src/module/utp/glowingpillar.utp.json similarity index 100% rename from src/mod/utp/glowingpillar.utp.json rename to src/module/utp/glowingpillar.utp.json diff --git a/src/mod/utp/gnomcntrptn001.utp.json b/src/module/utp/gnomcntrptn001.utp.json similarity index 100% rename from src/mod/utp/gnomcntrptn001.utp.json rename to src/module/utp/gnomcntrptn001.utp.json diff --git a/src/mod/utp/golempartsbon001.utp.json b/src/module/utp/golempartsbon001.utp.json similarity index 100% rename from src/mod/utp/golempartsbon001.utp.json rename to src/module/utp/golempartsbon001.utp.json diff --git a/src/mod/utp/golempartsiro001.utp.json b/src/module/utp/golempartsiro001.utp.json similarity index 100% rename from src/mod/utp/golempartsiro001.utp.json rename to src/module/utp/golempartsiro001.utp.json diff --git a/src/mod/utp/golempartssto001.utp.json b/src/module/utp/golempartssto001.utp.json similarity index 100% rename from src/mod/utp/golempartssto001.utp.json rename to src/module/utp/golempartssto001.utp.json diff --git a/src/mod/utp/gong001.utp.json b/src/module/utp/gong001.utp.json similarity index 100% rename from src/mod/utp/gong001.utp.json rename to src/module/utp/gong001.utp.json diff --git a/src/mod/utp/haybundle001.utp.json b/src/module/utp/haybundle001.utp.json similarity index 100% rename from src/mod/utp/haybundle001.utp.json rename to src/module/utp/haybundle001.utp.json diff --git a/src/mod/utp/humancage001.utp.json b/src/module/utp/humancage001.utp.json similarity index 100% rename from src/mod/utp/humancage001.utp.json rename to src/module/utp/humancage001.utp.json diff --git a/src/mod/utp/icefloe001.utp.json b/src/module/utp/icefloe001.utp.json similarity index 100% rename from src/mod/utp/icefloe001.utp.json rename to src/module/utp/icefloe001.utp.json diff --git a/src/mod/utp/impledcrpse003.utp.json b/src/module/utp/impledcrpse003.utp.json similarity index 100% rename from src/mod/utp/impledcrpse003.utp.json rename to src/module/utp/impledcrpse003.utp.json diff --git a/src/mod/utp/jacksoutfitters.utp.json b/src/module/utp/jacksoutfitters.utp.json similarity index 100% rename from src/mod/utp/jacksoutfitters.utp.json rename to src/module/utp/jacksoutfitters.utp.json diff --git a/src/mod/utp/ladder.utp.json b/src/module/utp/ladder.utp.json similarity index 100% rename from src/mod/utp/ladder.utp.json rename to src/module/utp/ladder.utp.json diff --git a/src/mod/utp/lamppost001.utp.json b/src/module/utp/lamppost001.utp.json similarity index 100% rename from src/mod/utp/lamppost001.utp.json rename to src/module/utp/lamppost001.utp.json diff --git a/src/mod/utp/monitor.utp.json b/src/module/utp/monitor.utp.json similarity index 100% rename from src/mod/utp/monitor.utp.json rename to src/module/utp/monitor.utp.json diff --git a/src/mod/utp/nightmareportal.utp.json b/src/module/utp/nightmareportal.utp.json similarity index 100% rename from src/mod/utp/nightmareportal.utp.json rename to src/module/utp/nightmareportal.utp.json diff --git a/src/mod/utp/overgrownrui001.utp.json b/src/module/utp/overgrownrui001.utp.json similarity index 100% rename from src/mod/utp/overgrownrui001.utp.json rename to src/module/utp/overgrownrui001.utp.json diff --git a/src/mod/utp/ozglyph01.utp.json b/src/module/utp/ozglyph01.utp.json similarity index 100% rename from src/mod/utp/ozglyph01.utp.json rename to src/module/utp/ozglyph01.utp.json diff --git a/src/mod/utp/ozglyph02.utp.json b/src/module/utp/ozglyph02.utp.json similarity index 100% rename from src/mod/utp/ozglyph02.utp.json rename to src/module/utp/ozglyph02.utp.json diff --git a/src/mod/utp/ozglyph03.utp.json b/src/module/utp/ozglyph03.utp.json similarity index 100% rename from src/mod/utp/ozglyph03.utp.json rename to src/module/utp/ozglyph03.utp.json diff --git a/src/mod/utp/ozglyph04.utp.json b/src/module/utp/ozglyph04.utp.json similarity index 100% rename from src/mod/utp/ozglyph04.utp.json rename to src/module/utp/ozglyph04.utp.json diff --git a/src/mod/utp/ozglyph05.utp.json b/src/module/utp/ozglyph05.utp.json similarity index 100% rename from src/mod/utp/ozglyph05.utp.json rename to src/module/utp/ozglyph05.utp.json diff --git a/src/mod/utp/ozglyph06.utp.json b/src/module/utp/ozglyph06.utp.json similarity index 100% rename from src/mod/utp/ozglyph06.utp.json rename to src/module/utp/ozglyph06.utp.json diff --git a/src/mod/utp/pedestal001.utp.json b/src/module/utp/pedestal001.utp.json similarity index 100% rename from src/mod/utp/pedestal001.utp.json rename to src/module/utp/pedestal001.utp.json diff --git a/src/mod/utp/pillar002.utp.json b/src/module/utp/pillar002.utp.json similarity index 100% rename from src/mod/utp/pillar002.utp.json rename to src/module/utp/pillar002.utp.json diff --git a/src/mod/utp/plc_bunkbed001.utp.json b/src/module/utp/plc_bunkbed001.utp.json similarity index 100% rename from src/mod/utp/plc_bunkbed001.utp.json rename to src/module/utp/plc_bunkbed001.utp.json diff --git a/src/mod/utp/plc_cball001.utp.json b/src/module/utp/plc_cball001.utp.json similarity index 100% rename from src/mod/utp/plc_cball001.utp.json rename to src/module/utp/plc_cball001.utp.json diff --git a/src/mod/utp/plc_chairmind001.utp.json b/src/module/utp/plc_chairmind001.utp.json similarity index 100% rename from src/mod/utp/plc_chairmind001.utp.json rename to src/module/utp/plc_chairmind001.utp.json diff --git a/src/mod/utp/plc_hole_b001.utp.json b/src/module/utp/plc_hole_b001.utp.json similarity index 100% rename from src/mod/utp/plc_hole_b001.utp.json rename to src/module/utp/plc_hole_b001.utp.json diff --git a/src/mod/utp/plc_phylact001.utp.json b/src/module/utp/plc_phylact001.utp.json similarity index 100% rename from src/mod/utp/plc_phylact001.utp.json rename to src/module/utp/plc_phylact001.utp.json diff --git a/src/mod/utp/plc_ppsheets001.utp.json b/src/module/utp/plc_ppsheets001.utp.json similarity index 100% rename from src/mod/utp/plc_ppsheets001.utp.json rename to src/module/utp/plc_ppsheets001.utp.json diff --git a/src/mod/utp/plc_psheets001.utp.json b/src/module/utp/plc_psheets001.utp.json similarity index 100% rename from src/mod/utp/plc_psheets001.utp.json rename to src/module/utp/plc_psheets001.utp.json diff --git a/src/mod/utp/plc_scircle001.utp.json b/src/module/utp/plc_scircle001.utp.json similarity index 100% rename from src/mod/utp/plc_scircle001.utp.json rename to src/module/utp/plc_scircle001.utp.json diff --git a/src/mod/utp/plc_stube001.utp.json b/src/module/utp/plc_stube001.utp.json similarity index 100% rename from src/mod/utp/plc_stube001.utp.json rename to src/module/utp/plc_stube001.utp.json diff --git a/src/mod/utp/plc_tablemind001.utp.json b/src/module/utp/plc_tablemind001.utp.json similarity index 100% rename from src/mod/utp/plc_tablemind001.utp.json rename to src/module/utp/plc_tablemind001.utp.json diff --git a/src/mod/utp/plc_tent_r001.utp.json b/src/module/utp/plc_tent_r001.utp.json similarity index 100% rename from src/mod/utp/plc_tent_r001.utp.json rename to src/module/utp/plc_tent_r001.utp.json diff --git a/src/mod/utp/portal001.utp.json b/src/module/utp/portal001.utp.json similarity index 100% rename from src/mod/utp/portal001.utp.json rename to src/module/utp/portal001.utp.json diff --git a/src/mod/utp/portaltovera.utp.json b/src/module/utp/portaltovera.utp.json similarity index 100% rename from src/mod/utp/portaltovera.utp.json rename to src/module/utp/portaltovera.utp.json diff --git a/src/mod/utp/portaltovera001.utp.json b/src/module/utp/portaltovera001.utp.json similarity index 100% rename from src/mod/utp/portaltovera001.utp.json rename to src/module/utp/portaltovera001.utp.json diff --git a/src/mod/utp/pvpexit.utp.json b/src/module/utp/pvpexit.utp.json similarity index 100% rename from src/mod/utp/pvpexit.utp.json rename to src/module/utp/pvpexit.utp.json diff --git a/src/mod/utp/reaperportal.utp.json b/src/module/utp/reaperportal.utp.json similarity index 100% rename from src/mod/utp/reaperportal.utp.json rename to src/module/utp/reaperportal.utp.json diff --git a/src/mod/utp/redpillar.utp.json b/src/module/utp/redpillar.utp.json similarity index 100% rename from src/mod/utp/redpillar.utp.json rename to src/module/utp/redpillar.utp.json diff --git a/src/mod/utp/regen_chest005.utp.json b/src/module/utp/regen_chest005.utp.json similarity index 100% rename from src/mod/utp/regen_chest005.utp.json rename to src/module/utp/regen_chest005.utp.json diff --git a/src/mod/utp/regen_chest006.utp.json b/src/module/utp/regen_chest006.utp.json similarity index 100% rename from src/mod/utp/regen_chest006.utp.json rename to src/module/utp/regen_chest006.utp.json diff --git a/src/mod/utp/regen_chest007.utp.json b/src/module/utp/regen_chest007.utp.json similarity index 100% rename from src/mod/utp/regen_chest007.utp.json rename to src/module/utp/regen_chest007.utp.json diff --git a/src/mod/utp/regen_chest008.utp.json b/src/module/utp/regen_chest008.utp.json similarity index 100% rename from src/mod/utp/regen_chest008.utp.json rename to src/module/utp/regen_chest008.utp.json diff --git a/src/mod/utp/regen_chest009.utp.json b/src/module/utp/regen_chest009.utp.json similarity index 100% rename from src/mod/utp/regen_chest009.utp.json rename to src/module/utp/regen_chest009.utp.json diff --git a/src/mod/utp/returntohillside.utp.json b/src/module/utp/returntohillside.utp.json similarity index 100% rename from src/mod/utp/returntohillside.utp.json rename to src/module/utp/returntohillside.utp.json diff --git a/src/mod/utp/rodwonder001.utp.json b/src/module/utp/rodwonder001.utp.json similarity index 100% rename from src/mod/utp/rodwonder001.utp.json rename to src/module/utp/rodwonder001.utp.json diff --git a/src/mod/utp/rodwonder002.utp.json b/src/module/utp/rodwonder002.utp.json similarity index 100% rename from src/mod/utp/rodwonder002.utp.json rename to src/module/utp/rodwonder002.utp.json diff --git a/src/mod/utp/rodwonder003.utp.json b/src/module/utp/rodwonder003.utp.json similarity index 100% rename from src/mod/utp/rodwonder003.utp.json rename to src/module/utp/rodwonder003.utp.json diff --git a/src/mod/utp/rodwonder004.utp.json b/src/module/utp/rodwonder004.utp.json similarity index 100% rename from src/mod/utp/rodwonder004.utp.json rename to src/module/utp/rodwonder004.utp.json diff --git a/src/mod/utp/rodwonder005.utp.json b/src/module/utp/rodwonder005.utp.json similarity index 100% rename from src/mod/utp/rodwonder005.utp.json rename to src/module/utp/rodwonder005.utp.json diff --git a/src/mod/utp/rodwonder006.utp.json b/src/module/utp/rodwonder006.utp.json similarity index 100% rename from src/mod/utp/rodwonder006.utp.json rename to src/module/utp/rodwonder006.utp.json diff --git a/src/mod/utp/rodwonder067.utp.json b/src/module/utp/rodwonder067.utp.json similarity index 100% rename from src/mod/utp/rodwonder067.utp.json rename to src/module/utp/rodwonder067.utp.json diff --git a/src/mod/utp/rodwonder068.utp.json b/src/module/utp/rodwonder068.utp.json similarity index 100% rename from src/mod/utp/rodwonder068.utp.json rename to src/module/utp/rodwonder068.utp.json diff --git a/src/mod/utp/rodwonder069.utp.json b/src/module/utp/rodwonder069.utp.json similarity index 100% rename from src/mod/utp/rodwonder069.utp.json rename to src/module/utp/rodwonder069.utp.json diff --git a/src/mod/utp/rodwonder070.utp.json b/src/module/utp/rodwonder070.utp.json similarity index 100% rename from src/mod/utp/rodwonder070.utp.json rename to src/module/utp/rodwonder070.utp.json diff --git a/src/mod/utp/ruglarge001.utp.json b/src/module/utp/ruglarge001.utp.json similarity index 100% rename from src/mod/utp/ruglarge001.utp.json rename to src/module/utp/ruglarge001.utp.json diff --git a/src/mod/utp/rugoriental003.utp.json b/src/module/utp/rugoriental003.utp.json similarity index 100% rename from src/mod/utp/rugoriental003.utp.json rename to src/module/utp/rugoriental003.utp.json diff --git a/src/mod/utp/snowdrift001.utp.json b/src/module/utp/snowdrift001.utp.json similarity index 100% rename from src/mod/utp/snowdrift001.utp.json rename to src/module/utp/snowdrift001.utp.json diff --git a/src/mod/utp/solcyan001.utp.json b/src/module/utp/solcyan001.utp.json similarity index 100% rename from src/mod/utp/solcyan001.utp.json rename to src/module/utp/solcyan001.utp.json diff --git a/src/mod/utp/solred001.utp.json b/src/module/utp/solred001.utp.json similarity index 100% rename from src/mod/utp/solred001.utp.json rename to src/module/utp/solred001.utp.json diff --git a/src/mod/utp/spearcorpse001.utp.json b/src/module/utp/spearcorpse001.utp.json similarity index 100% rename from src/mod/utp/spearcorpse001.utp.json rename to src/module/utp/spearcorpse001.utp.json diff --git a/src/mod/utp/stocks001.utp.json b/src/module/utp/stocks001.utp.json similarity index 100% rename from src/mod/utp/stocks001.utp.json rename to src/module/utp/stocks001.utp.json diff --git a/src/mod/utp/tabdrag_port.utp.json b/src/module/utp/tabdrag_port.utp.json similarity index 100% rename from src/mod/utp/tabdrag_port.utp.json rename to src/module/utp/tabdrag_port.utp.json diff --git a/src/mod/utp/table001.utp.json b/src/module/utp/table001.utp.json similarity index 100% rename from src/mod/utp/table001.utp.json rename to src/module/utp/table001.utp.json diff --git a/src/mod/utp/tabozbook1.utp.json b/src/module/utp/tabozbook1.utp.json similarity index 100% rename from src/mod/utp/tabozbook1.utp.json rename to src/module/utp/tabozbook1.utp.json diff --git a/src/mod/utp/tabozbook2.utp.json b/src/module/utp/tabozbook2.utp.json similarity index 100% rename from src/mod/utp/tabozbook2.utp.json rename to src/module/utp/tabozbook2.utp.json diff --git a/src/mod/utp/tabozbook3.utp.json b/src/module/utp/tabozbook3.utp.json similarity index 100% rename from src/mod/utp/tabozbook3.utp.json rename to src/module/utp/tabozbook3.utp.json diff --git a/src/mod/utp/tabozbook4.utp.json b/src/module/utp/tabozbook4.utp.json similarity index 100% rename from src/mod/utp/tabozbook4.utp.json rename to src/module/utp/tabozbook4.utp.json diff --git a/src/mod/utp/throneevil001.utp.json b/src/module/utp/throneevil001.utp.json similarity index 100% rename from src/mod/utp/throneevil001.utp.json rename to src/module/utp/throneevil001.utp.json diff --git a/src/mod/utp/tree001.utp.json b/src/module/utp/tree001.utp.json similarity index 100% rename from src/mod/utp/tree001.utp.json rename to src/module/utp/tree001.utp.json diff --git a/src/mod/utp/waterdrip001.utp.json b/src/module/utp/waterdrip001.utp.json similarity index 100% rename from src/mod/utp/waterdrip001.utp.json rename to src/module/utp/waterdrip001.utp.json diff --git a/src/mod/utp/whitepillar.utp.json b/src/module/utp/whitepillar.utp.json similarity index 100% rename from src/mod/utp/whitepillar.utp.json rename to src/module/utp/whitepillar.utp.json diff --git a/src/mod/utp/yellowpillar.utp.json b/src/module/utp/yellowpillar.utp.json similarity index 100% rename from src/mod/utp/yellowpillar.utp.json rename to src/module/utp/yellowpillar.utp.json diff --git a/src/mod/uts/ghosts001.uts.json b/src/module/uts/ghosts001.uts.json similarity index 100% rename from src/mod/uts/ghosts001.uts.json rename to src/module/uts/ghosts001.uts.json diff --git a/src/mod/utt/battlefield.utt.json b/src/module/utt/battlefield.utt.json similarity index 100% rename from src/mod/utt/battlefield.utt.json rename to src/module/utt/battlefield.utt.json diff --git a/src/mod/utt/biggins_to_many.utt.json b/src/module/utt/biggins_to_many.utt.json similarity index 100% rename from src/mod/utt/biggins_to_many.utt.json rename to src/module/utt/biggins_to_many.utt.json diff --git a/src/mod/utt/chanting_monk.utt.json b/src/module/utt/chanting_monk.utt.json similarity index 100% rename from src/mod/utt/chanting_monk.utt.json rename to src/module/utt/chanting_monk.utt.json diff --git a/src/mod/utt/check_pvp_items.utt.json b/src/module/utt/check_pvp_items.utt.json similarity index 100% rename from src/mod/utt/check_pvp_items.utt.json rename to src/module/utt/check_pvp_items.utt.json diff --git a/src/mod/utt/cloakwall.utt.json b/src/module/utt/cloakwall.utt.json similarity index 100% rename from src/mod/utt/cloakwall.utt.json rename to src/module/utt/cloakwall.utt.json diff --git a/src/mod/utt/dirth_t1_up_01.utt.json b/src/module/utt/dirth_t1_up_01.utt.json similarity index 100% rename from src/mod/utt/dirth_t1_up_01.utt.json rename to src/module/utt/dirth_t1_up_01.utt.json diff --git a/src/mod/utt/dirthtrigger.utt.json b/src/module/utt/dirthtrigger.utt.json similarity index 100% rename from src/mod/utt/dirthtrigger.utt.json rename to src/module/utt/dirthtrigger.utt.json diff --git a/src/mod/utt/enter_fe_desert.utt.json b/src/module/utt/enter_fe_desert.utt.json similarity index 100% rename from src/mod/utt/enter_fe_desert.utt.json rename to src/module/utt/enter_fe_desert.utt.json diff --git a/src/mod/utt/enter_legiontab.utt.json b/src/module/utt/enter_legiontab.utt.json similarity index 100% rename from src/mod/utt/enter_legiontab.utt.json rename to src/module/utt/enter_legiontab.utt.json diff --git a/src/mod/utt/enter_sl_realm.utt.json b/src/module/utt/enter_sl_realm.utt.json similarity index 100% rename from src/mod/utt/enter_sl_realm.utt.json rename to src/module/utt/enter_sl_realm.utt.json diff --git a/src/mod/utt/enter_tm_base.utt.json b/src/module/utt/enter_tm_base.utt.json similarity index 100% rename from src/mod/utt/enter_tm_base.utt.json rename to src/module/utt/enter_tm_base.utt.json diff --git a/src/mod/utt/enter_trin_grave.utt.json b/src/module/utt/enter_trin_grave.utt.json similarity index 100% rename from src/mod/utt/enter_trin_grave.utt.json rename to src/module/utt/enter_trin_grave.utt.json diff --git a/src/mod/utt/gotojail.utt.json b/src/module/utt/gotojail.utt.json similarity index 100% rename from src/mod/utt/gotojail.utt.json rename to src/module/utt/gotojail.utt.json diff --git a/src/mod/utt/megacoldtrap.utt.json b/src/module/utt/megacoldtrap.utt.json similarity index 100% rename from src/mod/utt/megacoldtrap.utt.json rename to src/module/utt/megacoldtrap.utt.json diff --git a/src/mod/utt/megaelectrictrap.utt.json b/src/module/utt/megaelectrictrap.utt.json similarity index 100% rename from src/mod/utt/megaelectrictrap.utt.json rename to src/module/utt/megaelectrictrap.utt.json diff --git a/src/mod/utt/megafiretrap.utt.json b/src/module/utt/megafiretrap.utt.json similarity index 100% rename from src/mod/utt/megafiretrap.utt.json rename to src/module/utt/megafiretrap.utt.json diff --git a/src/mod/utt/newgeneric001.utt.json b/src/module/utt/newgeneric001.utt.json similarity index 100% rename from src/mod/utt/newgeneric001.utt.json rename to src/module/utt/newgeneric001.utt.json diff --git a/src/mod/utt/newgeneric002.utt.json b/src/module/utt/newgeneric002.utt.json similarity index 100% rename from src/mod/utt/newgeneric002.utt.json rename to src/module/utt/newgeneric002.utt.json diff --git a/src/mod/utt/ozport.utt.json b/src/module/utt/ozport.utt.json similarity index 100% rename from src/mod/utt/ozport.utt.json rename to src/module/utt/ozport.utt.json diff --git a/src/mod/utt/please_to_north.utt.json b/src/module/utt/please_to_north.utt.json similarity index 100% rename from src/mod/utt/please_to_north.utt.json rename to src/module/utt/please_to_north.utt.json diff --git a/src/mod/utt/please_to_shogun.utt.json b/src/module/utt/please_to_shogun.utt.json similarity index 100% rename from src/mod/utt/please_to_shogun.utt.json rename to src/module/utt/please_to_shogun.utt.json diff --git a/src/mod/utt/please_to_tm.utt.json b/src/module/utt/please_to_tm.utt.json similarity index 100% rename from src/mod/utt/please_to_tm.utt.json rename to src/module/utt/please_to_tm.utt.json diff --git a/src/mod/utt/please_to_westro.utt.json b/src/module/utt/please_to_westro.utt.json similarity index 100% rename from src/mod/utt/please_to_westro.utt.json rename to src/module/utt/please_to_westro.utt.json diff --git a/src/mod/utt/tab_on_mod_enter.utt.json b/src/module/utt/tab_on_mod_enter.utt.json similarity index 100% rename from src/mod/utt/tab_on_mod_enter.utt.json rename to src/module/utt/tab_on_mod_enter.utt.json diff --git a/src/mod/utt/take_drow_noble.utt.json b/src/module/utt/take_drow_noble.utt.json similarity index 100% rename from src/mod/utt/take_drow_noble.utt.json rename to src/module/utt/take_drow_noble.utt.json diff --git a/src/mod/utt/updates.utt.json b/src/module/utt/updates.utt.json similarity index 100% rename from src/mod/utt/updates.utt.json rename to src/module/utt/updates.utt.json diff --git a/src/mod/utt/westfrom_grave.utt.json b/src/module/utt/westfrom_grave.utt.json similarity index 100% rename from src/mod/utt/westfrom_grave.utt.json rename to src/module/utt/westfrom_grave.utt.json diff --git a/src/mod/utw/fb1_intensity.utw.json b/src/module/utw/fb1_intensity.utw.json similarity index 100% rename from src/mod/utw/fb1_intensity.utw.json rename to src/module/utw/fb1_intensity.utw.json diff --git a/src/mod/utw/ffx_bouncer.utw.json b/src/module/utw/ffx_bouncer.utw.json similarity index 100% rename from src/mod/utw/ffx_bouncer.utw.json rename to src/module/utw/ffx_bouncer.utw.json diff --git a/src/mod/utw/oz_glyph_002.utw.json b/src/module/utw/oz_glyph_002.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_002.utw.json rename to src/module/utw/oz_glyph_002.utw.json diff --git a/src/mod/utw/oz_glyph_003.utw.json b/src/module/utw/oz_glyph_003.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_003.utw.json rename to src/module/utw/oz_glyph_003.utw.json diff --git a/src/mod/utw/oz_glyph_004.utw.json b/src/module/utw/oz_glyph_004.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_004.utw.json rename to src/module/utw/oz_glyph_004.utw.json diff --git a/src/mod/utw/oz_glyph_005.utw.json b/src/module/utw/oz_glyph_005.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_005.utw.json rename to src/module/utw/oz_glyph_005.utw.json diff --git a/src/mod/utw/oz_glyph_006.utw.json b/src/module/utw/oz_glyph_006.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_006.utw.json rename to src/module/utw/oz_glyph_006.utw.json diff --git a/src/mod/utw/oz_glyph_01.utw.json b/src/module/utw/oz_glyph_01.utw.json similarity index 100% rename from src/mod/utw/oz_glyph_01.utw.json rename to src/module/utw/oz_glyph_01.utw.json diff --git a/src/mod/utw/wp_11_tab.utw.json b/src/module/utw/wp_11_tab.utw.json similarity index 100% rename from src/mod/utw/wp_11_tab.utw.json rename to src/module/utw/wp_11_tab.utw.json diff --git a/src/mod/utw/wp_atl_port_02.utw.json b/src/module/utw/wp_atl_port_02.utw.json similarity index 100% rename from src/mod/utw/wp_atl_port_02.utw.json rename to src/module/utw/wp_atl_port_02.utw.json diff --git a/src/mod/utw/wp_backtobarrack.utw.json b/src/module/utw/wp_backtobarrack.utw.json similarity index 100% rename from src/mod/utw/wp_backtobarrack.utw.json rename to src/module/utw/wp_backtobarrack.utw.json diff --git a/src/mod/utw/wp_blackbear_01.utw.json b/src/module/utw/wp_blackbear_01.utw.json similarity index 100% rename from src/mod/utw/wp_blackbear_01.utw.json rename to src/module/utw/wp_blackbear_01.utw.json diff --git a/src/mod/utw/wp_cain_002.utw.json b/src/module/utw/wp_cain_002.utw.json similarity index 100% rename from src/mod/utw/wp_cain_002.utw.json rename to src/module/utw/wp_cain_002.utw.json diff --git a/src/mod/utw/wp_cain_003.utw.json b/src/module/utw/wp_cain_003.utw.json similarity index 100% rename from src/mod/utw/wp_cain_003.utw.json rename to src/module/utw/wp_cain_003.utw.json diff --git a/src/mod/utw/wp_cain_004.utw.json b/src/module/utw/wp_cain_004.utw.json similarity index 100% rename from src/mod/utw/wp_cain_004.utw.json rename to src/module/utw/wp_cain_004.utw.json diff --git a/src/mod/utw/wp_cain_005.utw.json b/src/module/utw/wp_cain_005.utw.json similarity index 100% rename from src/mod/utw/wp_cain_005.utw.json rename to src/module/utw/wp_cain_005.utw.json diff --git a/src/mod/utw/wp_cain_006.utw.json b/src/module/utw/wp_cain_006.utw.json similarity index 100% rename from src/mod/utw/wp_cain_006.utw.json rename to src/module/utw/wp_cain_006.utw.json diff --git a/src/mod/utw/wp_cain_007.utw.json b/src/module/utw/wp_cain_007.utw.json similarity index 100% rename from src/mod/utw/wp_cain_007.utw.json rename to src/module/utw/wp_cain_007.utw.json diff --git a/src/mod/utw/wp_cain_008.utw.json b/src/module/utw/wp_cain_008.utw.json similarity index 100% rename from src/mod/utw/wp_cain_008.utw.json rename to src/module/utw/wp_cain_008.utw.json diff --git a/src/mod/utw/wp_cain_009.utw.json b/src/module/utw/wp_cain_009.utw.json similarity index 100% rename from src/mod/utw/wp_cain_009.utw.json rename to src/module/utw/wp_cain_009.utw.json diff --git a/src/mod/utw/wp_cain_01.utw.json b/src/module/utw/wp_cain_01.utw.json similarity index 100% rename from src/mod/utw/wp_cain_01.utw.json rename to src/module/utw/wp_cain_01.utw.json diff --git a/src/mod/utw/wp_cain_010.utw.json b/src/module/utw/wp_cain_010.utw.json similarity index 100% rename from src/mod/utw/wp_cain_010.utw.json rename to src/module/utw/wp_cain_010.utw.json diff --git a/src/mod/utw/wp_cain_portal.utw.json b/src/module/utw/wp_cain_portal.utw.json similarity index 100% rename from src/mod/utw/wp_cain_portal.utw.json rename to src/module/utw/wp_cain_portal.utw.json diff --git a/src/mod/utw/wp_caindeath.utw.json b/src/module/utw/wp_caindeath.utw.json similarity index 100% rename from src/mod/utw/wp_caindeath.utw.json rename to src/module/utw/wp_caindeath.utw.json diff --git a/src/mod/utw/wp_cbrune_003.utw.json b/src/module/utw/wp_cbrune_003.utw.json similarity index 100% rename from src/mod/utw/wp_cbrune_003.utw.json rename to src/module/utw/wp_cbrune_003.utw.json diff --git a/src/mod/utw/wp_cbrune_004.utw.json b/src/module/utw/wp_cbrune_004.utw.json similarity index 100% rename from src/mod/utw/wp_cbrune_004.utw.json rename to src/module/utw/wp_cbrune_004.utw.json diff --git a/src/mod/utw/wp_cbrune_005.utw.json b/src/module/utw/wp_cbrune_005.utw.json similarity index 100% rename from src/mod/utw/wp_cbrune_005.utw.json rename to src/module/utw/wp_cbrune_005.utw.json diff --git a/src/mod/utw/wp_cbrune_02.utw.json b/src/module/utw/wp_cbrune_02.utw.json similarity index 100% rename from src/mod/utw/wp_cbrune_02.utw.json rename to src/module/utw/wp_cbrune_02.utw.json diff --git a/src/mod/utw/wp_chmonk_002.utw.json b/src/module/utw/wp_chmonk_002.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_002.utw.json rename to src/module/utw/wp_chmonk_002.utw.json diff --git a/src/mod/utw/wp_chmonk_003.utw.json b/src/module/utw/wp_chmonk_003.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_003.utw.json rename to src/module/utw/wp_chmonk_003.utw.json diff --git a/src/mod/utw/wp_chmonk_004.utw.json b/src/module/utw/wp_chmonk_004.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_004.utw.json rename to src/module/utw/wp_chmonk_004.utw.json diff --git a/src/mod/utw/wp_chmonk_005.utw.json b/src/module/utw/wp_chmonk_005.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_005.utw.json rename to src/module/utw/wp_chmonk_005.utw.json diff --git a/src/mod/utw/wp_chmonk_006.utw.json b/src/module/utw/wp_chmonk_006.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_006.utw.json rename to src/module/utw/wp_chmonk_006.utw.json diff --git a/src/mod/utw/wp_chmonk_01.utw.json b/src/module/utw/wp_chmonk_01.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_01.utw.json rename to src/module/utw/wp_chmonk_01.utw.json diff --git a/src/mod/utw/wp_chmonk_07.utw.json b/src/module/utw/wp_chmonk_07.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_07.utw.json rename to src/module/utw/wp_chmonk_07.utw.json diff --git a/src/mod/utw/wp_chmonk_08.utw.json b/src/module/utw/wp_chmonk_08.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_08.utw.json rename to src/module/utw/wp_chmonk_08.utw.json diff --git a/src/mod/utw/wp_chmonk_09.utw.json b/src/module/utw/wp_chmonk_09.utw.json similarity index 100% rename from src/mod/utw/wp_chmonk_09.utw.json rename to src/module/utw/wp_chmonk_09.utw.json diff --git a/src/mod/utw/wp_cloak_002.utw.json b/src/module/utw/wp_cloak_002.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_002.utw.json rename to src/module/utw/wp_cloak_002.utw.json diff --git a/src/mod/utw/wp_cloak_003.utw.json b/src/module/utw/wp_cloak_003.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_003.utw.json rename to src/module/utw/wp_cloak_003.utw.json diff --git a/src/mod/utw/wp_cloak_004.utw.json b/src/module/utw/wp_cloak_004.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_004.utw.json rename to src/module/utw/wp_cloak_004.utw.json diff --git a/src/mod/utw/wp_cloak_005.utw.json b/src/module/utw/wp_cloak_005.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_005.utw.json rename to src/module/utw/wp_cloak_005.utw.json diff --git a/src/mod/utw/wp_cloak_006.utw.json b/src/module/utw/wp_cloak_006.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_006.utw.json rename to src/module/utw/wp_cloak_006.utw.json diff --git a/src/mod/utw/wp_cloak_007.utw.json b/src/module/utw/wp_cloak_007.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_007.utw.json rename to src/module/utw/wp_cloak_007.utw.json diff --git a/src/mod/utw/wp_cloak_008.utw.json b/src/module/utw/wp_cloak_008.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_008.utw.json rename to src/module/utw/wp_cloak_008.utw.json diff --git a/src/mod/utw/wp_cloak_009.utw.json b/src/module/utw/wp_cloak_009.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_009.utw.json rename to src/module/utw/wp_cloak_009.utw.json diff --git a/src/mod/utw/wp_cloak_01.utw.json b/src/module/utw/wp_cloak_01.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_01.utw.json rename to src/module/utw/wp_cloak_01.utw.json diff --git a/src/mod/utw/wp_cloak_010.utw.json b/src/module/utw/wp_cloak_010.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_010.utw.json rename to src/module/utw/wp_cloak_010.utw.json diff --git a/src/mod/utw/wp_cloak_potion.utw.json b/src/module/utw/wp_cloak_potion.utw.json similarity index 100% rename from src/mod/utw/wp_cloak_potion.utw.json rename to src/module/utw/wp_cloak_potion.utw.json diff --git a/src/mod/utw/wp_cushions.utw.json b/src/module/utw/wp_cushions.utw.json similarity index 100% rename from src/mod/utw/wp_cushions.utw.json rename to src/module/utw/wp_cushions.utw.json diff --git a/src/mod/utw/wp_dcleric_002.utw.json b/src/module/utw/wp_dcleric_002.utw.json similarity index 100% rename from src/mod/utw/wp_dcleric_002.utw.json rename to src/module/utw/wp_dcleric_002.utw.json diff --git a/src/mod/utw/wp_dcleric_003.utw.json b/src/module/utw/wp_dcleric_003.utw.json similarity index 100% rename from src/mod/utw/wp_dcleric_003.utw.json rename to src/module/utw/wp_dcleric_003.utw.json diff --git a/src/mod/utw/wp_dcleric_01.utw.json b/src/module/utw/wp_dcleric_01.utw.json similarity index 100% rename from src/mod/utw/wp_dcleric_01.utw.json rename to src/module/utw/wp_dcleric_01.utw.json diff --git a/src/mod/utw/wp_dirth_t1_leve.utw.json b/src/module/utw/wp_dirth_t1_leve.utw.json similarity index 100% rename from src/mod/utw/wp_dirth_t1_leve.utw.json rename to src/module/utw/wp_dirth_t1_leve.utw.json diff --git a/src/mod/utw/wp_dirthbarraks1.utw.json b/src/module/utw/wp_dirthbarraks1.utw.json similarity index 100% rename from src/mod/utw/wp_dirthbarraks1.utw.json rename to src/module/utw/wp_dirthbarraks1.utw.json diff --git a/src/mod/utw/wp_dirthprin_002.utw.json b/src/module/utw/wp_dirthprin_002.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_002.utw.json rename to src/module/utw/wp_dirthprin_002.utw.json diff --git a/src/mod/utw/wp_dirthprin_003.utw.json b/src/module/utw/wp_dirthprin_003.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_003.utw.json rename to src/module/utw/wp_dirthprin_003.utw.json diff --git a/src/mod/utw/wp_dirthprin_004.utw.json b/src/module/utw/wp_dirthprin_004.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_004.utw.json rename to src/module/utw/wp_dirthprin_004.utw.json diff --git a/src/mod/utw/wp_dirthprin_005.utw.json b/src/module/utw/wp_dirthprin_005.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_005.utw.json rename to src/module/utw/wp_dirthprin_005.utw.json diff --git a/src/mod/utw/wp_dirthprin_006.utw.json b/src/module/utw/wp_dirthprin_006.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_006.utw.json rename to src/module/utw/wp_dirthprin_006.utw.json diff --git a/src/mod/utw/wp_dirthprin_01.utw.json b/src/module/utw/wp_dirthprin_01.utw.json similarity index 100% rename from src/mod/utw/wp_dirthprin_01.utw.json rename to src/module/utw/wp_dirthprin_01.utw.json diff --git a/src/mod/utw/wp_drow_light.utw.json b/src/module/utw/wp_drow_light.utw.json similarity index 100% rename from src/mod/utw/wp_drow_light.utw.json rename to src/module/utw/wp_drow_light.utw.json diff --git a/src/mod/utw/wp_drowguard_002.utw.json b/src/module/utw/wp_drowguard_002.utw.json similarity index 100% rename from src/mod/utw/wp_drowguard_002.utw.json rename to src/module/utw/wp_drowguard_002.utw.json diff --git a/src/mod/utw/wp_drowguard_003.utw.json b/src/module/utw/wp_drowguard_003.utw.json similarity index 100% rename from src/mod/utw/wp_drowguard_003.utw.json rename to src/module/utw/wp_drowguard_003.utw.json diff --git a/src/mod/utw/wp_drowguard_01.utw.json b/src/module/utw/wp_drowguard_01.utw.json similarity index 100% rename from src/mod/utw/wp_drowguard_01.utw.json rename to src/module/utw/wp_drowguard_01.utw.json diff --git a/src/mod/utw/wp_elfguy_002.utw.json b/src/module/utw/wp_elfguy_002.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_002.utw.json rename to src/module/utw/wp_elfguy_002.utw.json diff --git a/src/mod/utw/wp_elfguy_003.utw.json b/src/module/utw/wp_elfguy_003.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_003.utw.json rename to src/module/utw/wp_elfguy_003.utw.json diff --git a/src/mod/utw/wp_elfguy_004.utw.json b/src/module/utw/wp_elfguy_004.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_004.utw.json rename to src/module/utw/wp_elfguy_004.utw.json diff --git a/src/mod/utw/wp_elfguy_005.utw.json b/src/module/utw/wp_elfguy_005.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_005.utw.json rename to src/module/utw/wp_elfguy_005.utw.json diff --git a/src/mod/utw/wp_elfguy_006.utw.json b/src/module/utw/wp_elfguy_006.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_006.utw.json rename to src/module/utw/wp_elfguy_006.utw.json diff --git a/src/mod/utw/wp_elfguy_01.utw.json b/src/module/utw/wp_elfguy_01.utw.json similarity index 100% rename from src/mod/utw/wp_elfguy_01.utw.json rename to src/module/utw/wp_elfguy_01.utw.json diff --git a/src/mod/utw/wp_enter_atl_tab.utw.json b/src/module/utw/wp_enter_atl_tab.utw.json similarity index 100% rename from src/mod/utw/wp_enter_atl_tab.utw.json rename to src/module/utw/wp_enter_atl_tab.utw.json diff --git a/src/mod/utw/wp_enter_cain_ta.utw.json b/src/module/utw/wp_enter_cain_ta.utw.json similarity index 100% rename from src/mod/utw/wp_enter_cain_ta.utw.json rename to src/module/utw/wp_enter_cain_ta.utw.json diff --git a/src/mod/utw/wp_enter_fe_dese.utw.json b/src/module/utw/wp_enter_fe_dese.utw.json similarity index 100% rename from src/mod/utw/wp_enter_fe_dese.utw.json rename to src/module/utw/wp_enter_fe_dese.utw.json diff --git a/src/mod/utw/wp_enter_grave_y.utw.json b/src/module/utw/wp_enter_grave_y.utw.json similarity index 100% rename from src/mod/utw/wp_enter_grave_y.utw.json rename to src/module/utw/wp_enter_grave_y.utw.json diff --git a/src/mod/utw/wp_enter_lith.utw.json b/src/module/utw/wp_enter_lith.utw.json similarity index 100% rename from src/mod/utw/wp_enter_lith.utw.json rename to src/module/utw/wp_enter_lith.utw.json diff --git a/src/mod/utw/wp_falcon_01.utw.json b/src/module/utw/wp_falcon_01.utw.json similarity index 100% rename from src/mod/utw/wp_falcon_01.utw.json rename to src/module/utw/wp_falcon_01.utw.json diff --git a/src/mod/utw/wp_from_cha_to_b.utw.json b/src/module/utw/wp_from_cha_to_b.utw.json similarity index 100% rename from src/mod/utw/wp_from_cha_to_b.utw.json rename to src/module/utw/wp_from_cha_to_b.utw.json diff --git a/src/mod/utw/wp_insight_002.utw.json b/src/module/utw/wp_insight_002.utw.json similarity index 100% rename from src/mod/utw/wp_insight_002.utw.json rename to src/module/utw/wp_insight_002.utw.json diff --git a/src/mod/utw/wp_insight_003.utw.json b/src/module/utw/wp_insight_003.utw.json similarity index 100% rename from src/mod/utw/wp_insight_003.utw.json rename to src/module/utw/wp_insight_003.utw.json diff --git a/src/mod/utw/wp_insight_004.utw.json b/src/module/utw/wp_insight_004.utw.json similarity index 100% rename from src/mod/utw/wp_insight_004.utw.json rename to src/module/utw/wp_insight_004.utw.json diff --git a/src/mod/utw/wp_insight_005.utw.json b/src/module/utw/wp_insight_005.utw.json similarity index 100% rename from src/mod/utw/wp_insight_005.utw.json rename to src/module/utw/wp_insight_005.utw.json diff --git a/src/mod/utw/wp_insight_01.utw.json b/src/module/utw/wp_insight_01.utw.json similarity index 100% rename from src/mod/utw/wp_insight_01.utw.json rename to src/module/utw/wp_insight_01.utw.json diff --git a/src/mod/utw/wp_isleofrepent.utw.json b/src/module/utw/wp_isleofrepent.utw.json similarity index 100% rename from src/mod/utw/wp_isleofrepent.utw.json rename to src/module/utw/wp_isleofrepent.utw.json diff --git a/src/mod/utw/wp_leave_lith.utw.json b/src/module/utw/wp_leave_lith.utw.json similarity index 100% rename from src/mod/utw/wp_leave_lith.utw.json rename to src/module/utw/wp_leave_lith.utw.json diff --git a/src/mod/utw/wp_leave_temple.utw.json b/src/module/utw/wp_leave_temple.utw.json similarity index 100% rename from src/mod/utw/wp_leave_temple.utw.json rename to src/module/utw/wp_leave_temple.utw.json diff --git a/src/mod/utw/wp_lith_002.utw.json b/src/module/utw/wp_lith_002.utw.json similarity index 100% rename from src/mod/utw/wp_lith_002.utw.json rename to src/module/utw/wp_lith_002.utw.json diff --git a/src/mod/utw/wp_lith_003.utw.json b/src/module/utw/wp_lith_003.utw.json similarity index 100% rename from src/mod/utw/wp_lith_003.utw.json rename to src/module/utw/wp_lith_003.utw.json diff --git a/src/mod/utw/wp_lith_004.utw.json b/src/module/utw/wp_lith_004.utw.json similarity index 100% rename from src/mod/utw/wp_lith_004.utw.json rename to src/module/utw/wp_lith_004.utw.json diff --git a/src/mod/utw/wp_lith_005.utw.json b/src/module/utw/wp_lith_005.utw.json similarity index 100% rename from src/mod/utw/wp_lith_005.utw.json rename to src/module/utw/wp_lith_005.utw.json diff --git a/src/mod/utw/wp_lith_01.utw.json b/src/module/utw/wp_lith_01.utw.json similarity index 100% rename from src/mod/utw/wp_lith_01.utw.json rename to src/module/utw/wp_lith_01.utw.json diff --git a/src/mod/utw/wp_new_port.utw.json b/src/module/utw/wp_new_port.utw.json similarity index 100% rename from src/mod/utw/wp_new_port.utw.json rename to src/module/utw/wp_new_port.utw.json diff --git a/src/mod/utw/wp_nmonk_002.utw.json b/src/module/utw/wp_nmonk_002.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_002.utw.json rename to src/module/utw/wp_nmonk_002.utw.json diff --git a/src/mod/utw/wp_nmonk_003.utw.json b/src/module/utw/wp_nmonk_003.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_003.utw.json rename to src/module/utw/wp_nmonk_003.utw.json diff --git a/src/mod/utw/wp_nmonk_004.utw.json b/src/module/utw/wp_nmonk_004.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_004.utw.json rename to src/module/utw/wp_nmonk_004.utw.json diff --git a/src/mod/utw/wp_nmonk_005.utw.json b/src/module/utw/wp_nmonk_005.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_005.utw.json rename to src/module/utw/wp_nmonk_005.utw.json diff --git a/src/mod/utw/wp_nmonk_006.utw.json b/src/module/utw/wp_nmonk_006.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_006.utw.json rename to src/module/utw/wp_nmonk_006.utw.json diff --git a/src/mod/utw/wp_nmonk_007.utw.json b/src/module/utw/wp_nmonk_007.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_007.utw.json rename to src/module/utw/wp_nmonk_007.utw.json diff --git a/src/mod/utw/wp_nmonk_008.utw.json b/src/module/utw/wp_nmonk_008.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_008.utw.json rename to src/module/utw/wp_nmonk_008.utw.json diff --git a/src/mod/utw/wp_nmonk_009.utw.json b/src/module/utw/wp_nmonk_009.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_009.utw.json rename to src/module/utw/wp_nmonk_009.utw.json diff --git a/src/mod/utw/wp_nmonk_01.utw.json b/src/module/utw/wp_nmonk_01.utw.json similarity index 100% rename from src/mod/utw/wp_nmonk_01.utw.json rename to src/module/utw/wp_nmonk_01.utw.json diff --git a/src/mod/utw/wp_please_to_nor.utw.json b/src/module/utw/wp_please_to_nor.utw.json similarity index 100% rename from src/mod/utw/wp_please_to_nor.utw.json rename to src/module/utw/wp_please_to_nor.utw.json diff --git a/src/mod/utw/wp_please_to_sho.utw.json b/src/module/utw/wp_please_to_sho.utw.json similarity index 100% rename from src/mod/utw/wp_please_to_sho.utw.json rename to src/module/utw/wp_please_to_sho.utw.json diff --git a/src/mod/utw/wp_please_to_tm.utw.json b/src/module/utw/wp_please_to_tm.utw.json similarity index 100% rename from src/mod/utw/wp_please_to_tm.utw.json rename to src/module/utw/wp_please_to_tm.utw.json diff --git a/src/mod/utw/wp_please_to_wes.utw.json b/src/module/utw/wp_please_to_wes.utw.json similarity index 100% rename from src/mod/utw/wp_please_to_wes.utw.json rename to src/module/utw/wp_please_to_wes.utw.json diff --git a/src/mod/utw/wp_raven_002.utw.json b/src/module/utw/wp_raven_002.utw.json similarity index 100% rename from src/mod/utw/wp_raven_002.utw.json rename to src/module/utw/wp_raven_002.utw.json diff --git a/src/mod/utw/wp_raven_003.utw.json b/src/module/utw/wp_raven_003.utw.json similarity index 100% rename from src/mod/utw/wp_raven_003.utw.json rename to src/module/utw/wp_raven_003.utw.json diff --git a/src/mod/utw/wp_raven_01.utw.json b/src/module/utw/wp_raven_01.utw.json similarity index 100% rename from src/mod/utw/wp_raven_01.utw.json rename to src/module/utw/wp_raven_01.utw.json diff --git a/src/mod/utw/wp_reb.utw.json b/src/module/utw/wp_reb.utw.json similarity index 100% rename from src/mod/utw/wp_reb.utw.json rename to src/module/utw/wp_reb.utw.json diff --git a/src/mod/utw/wp_reb_boot.utw.json b/src/module/utw/wp_reb_boot.utw.json similarity index 100% rename from src/mod/utw/wp_reb_boot.utw.json rename to src/module/utw/wp_reb_boot.utw.json diff --git a/src/mod/utw/wp_reb_reborn.utw.json b/src/module/utw/wp_reb_reborn.utw.json similarity index 100% rename from src/mod/utw/wp_reb_reborn.utw.json rename to src/module/utw/wp_reb_reborn.utw.json diff --git a/src/mod/utw/wp_reb_trials.utw.json b/src/module/utw/wp_reb_trials.utw.json similarity index 100% rename from src/mod/utw/wp_reb_trials.utw.json rename to src/module/utw/wp_reb_trials.utw.json diff --git a/src/mod/utw/wp_reb_trust.utw.json b/src/module/utw/wp_reb_trust.utw.json similarity index 100% rename from src/mod/utw/wp_reb_trust.utw.json rename to src/module/utw/wp_reb_trust.utw.json diff --git a/src/mod/utw/wp_rebl_01.utw.json b/src/module/utw/wp_rebl_01.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_01.utw.json rename to src/module/utw/wp_rebl_01.utw.json diff --git a/src/mod/utw/wp_rebl_017.utw.json b/src/module/utw/wp_rebl_017.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_017.utw.json rename to src/module/utw/wp_rebl_017.utw.json diff --git a/src/mod/utw/wp_rebl_018.utw.json b/src/module/utw/wp_rebl_018.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_018.utw.json rename to src/module/utw/wp_rebl_018.utw.json diff --git a/src/mod/utw/wp_rebl_019.utw.json b/src/module/utw/wp_rebl_019.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_019.utw.json rename to src/module/utw/wp_rebl_019.utw.json diff --git a/src/mod/utw/wp_rebl_020.utw.json b/src/module/utw/wp_rebl_020.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_020.utw.json rename to src/module/utw/wp_rebl_020.utw.json diff --git a/src/mod/utw/wp_rebl_021.utw.json b/src/module/utw/wp_rebl_021.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_021.utw.json rename to src/module/utw/wp_rebl_021.utw.json diff --git a/src/mod/utw/wp_rebl_022.utw.json b/src/module/utw/wp_rebl_022.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_022.utw.json rename to src/module/utw/wp_rebl_022.utw.json diff --git a/src/mod/utw/wp_rebl_023.utw.json b/src/module/utw/wp_rebl_023.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_023.utw.json rename to src/module/utw/wp_rebl_023.utw.json diff --git a/src/mod/utw/wp_rebl_024.utw.json b/src/module/utw/wp_rebl_024.utw.json similarity index 100% rename from src/mod/utw/wp_rebl_024.utw.json rename to src/module/utw/wp_rebl_024.utw.json diff --git a/src/mod/utw/wp_repent_pally.utw.json b/src/module/utw/wp_repent_pally.utw.json similarity index 100% rename from src/mod/utw/wp_repent_pally.utw.json rename to src/module/utw/wp_repent_pally.utw.json diff --git a/src/mod/utw/wp_repent_pally2.utw.json b/src/module/utw/wp_repent_pally2.utw.json similarity index 100% rename from src/mod/utw/wp_repent_pally2.utw.json rename to src/module/utw/wp_repent_pally2.utw.json diff --git a/src/mod/utw/wp_rod_002.utw.json b/src/module/utw/wp_rod_002.utw.json similarity index 100% rename from src/mod/utw/wp_rod_002.utw.json rename to src/module/utw/wp_rod_002.utw.json diff --git a/src/mod/utw/wp_rod_003.utw.json b/src/module/utw/wp_rod_003.utw.json similarity index 100% rename from src/mod/utw/wp_rod_003.utw.json rename to src/module/utw/wp_rod_003.utw.json diff --git a/src/mod/utw/wp_rod_004.utw.json b/src/module/utw/wp_rod_004.utw.json similarity index 100% rename from src/mod/utw/wp_rod_004.utw.json rename to src/module/utw/wp_rod_004.utw.json diff --git a/src/mod/utw/wp_rod_005.utw.json b/src/module/utw/wp_rod_005.utw.json similarity index 100% rename from src/mod/utw/wp_rod_005.utw.json rename to src/module/utw/wp_rod_005.utw.json diff --git a/src/mod/utw/wp_rod_01.utw.json b/src/module/utw/wp_rod_01.utw.json similarity index 100% rename from src/mod/utw/wp_rod_01.utw.json rename to src/module/utw/wp_rod_01.utw.json diff --git a/src/mod/utw/wp_rpally_002.utw.json b/src/module/utw/wp_rpally_002.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_002.utw.json rename to src/module/utw/wp_rpally_002.utw.json diff --git a/src/mod/utw/wp_rpally_003.utw.json b/src/module/utw/wp_rpally_003.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_003.utw.json rename to src/module/utw/wp_rpally_003.utw.json diff --git a/src/mod/utw/wp_rpally_004.utw.json b/src/module/utw/wp_rpally_004.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_004.utw.json rename to src/module/utw/wp_rpally_004.utw.json diff --git a/src/mod/utw/wp_rpally_005.utw.json b/src/module/utw/wp_rpally_005.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_005.utw.json rename to src/module/utw/wp_rpally_005.utw.json diff --git a/src/mod/utw/wp_rpally_006.utw.json b/src/module/utw/wp_rpally_006.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_006.utw.json rename to src/module/utw/wp_rpally_006.utw.json diff --git a/src/mod/utw/wp_rpally_01.utw.json b/src/module/utw/wp_rpally_01.utw.json similarity index 100% rename from src/mod/utw/wp_rpally_01.utw.json rename to src/module/utw/wp_rpally_01.utw.json diff --git a/src/mod/utw/wp_shofinal_002.utw.json b/src/module/utw/wp_shofinal_002.utw.json similarity index 100% rename from src/mod/utw/wp_shofinal_002.utw.json rename to src/module/utw/wp_shofinal_002.utw.json diff --git a/src/mod/utw/wp_shofinal_003.utw.json b/src/module/utw/wp_shofinal_003.utw.json similarity index 100% rename from src/mod/utw/wp_shofinal_003.utw.json rename to src/module/utw/wp_shofinal_003.utw.json diff --git a/src/mod/utw/wp_shofinal_01.utw.json b/src/module/utw/wp_shofinal_01.utw.json similarity index 100% rename from src/mod/utw/wp_shofinal_01.utw.json rename to src/module/utw/wp_shofinal_01.utw.json diff --git a/src/mod/utw/wp_shogun_pre.utw.json b/src/module/utw/wp_shogun_pre.utw.json similarity index 100% rename from src/mod/utw/wp_shogun_pre.utw.json rename to src/module/utw/wp_shogun_pre.utw.json diff --git a/src/mod/utw/wp_shoguncoward.utw.json b/src/module/utw/wp_shoguncoward.utw.json similarity index 100% rename from src/mod/utw/wp_shoguncoward.utw.json rename to src/module/utw/wp_shoguncoward.utw.json diff --git a/src/mod/utw/wp_snowtab.utw.json b/src/module/utw/wp_snowtab.utw.json similarity index 100% rename from src/mod/utw/wp_snowtab.utw.json rename to src/module/utw/wp_snowtab.utw.json diff --git a/src/mod/utw/wp_snowtab001.utw.json b/src/module/utw/wp_snowtab001.utw.json similarity index 100% rename from src/mod/utw/wp_snowtab001.utw.json rename to src/module/utw/wp_snowtab001.utw.json diff --git a/src/mod/utw/wp_source_500.utw.json b/src/module/utw/wp_source_500.utw.json similarity index 100% rename from src/mod/utw/wp_source_500.utw.json rename to src/module/utw/wp_source_500.utw.json diff --git a/src/mod/utw/wp_source_501.utw.json b/src/module/utw/wp_source_501.utw.json similarity index 100% rename from src/mod/utw/wp_source_501.utw.json rename to src/module/utw/wp_source_501.utw.json diff --git a/src/mod/utw/wp_source_502.utw.json b/src/module/utw/wp_source_502.utw.json similarity index 100% rename from src/mod/utw/wp_source_502.utw.json rename to src/module/utw/wp_source_502.utw.json diff --git a/src/mod/utw/wp_source_503.utw.json b/src/module/utw/wp_source_503.utw.json similarity index 100% rename from src/mod/utw/wp_source_503.utw.json rename to src/module/utw/wp_source_503.utw.json diff --git a/src/mod/utw/wp_tab_backup.utw.json b/src/module/utw/wp_tab_backup.utw.json similarity index 100% rename from src/mod/utw/wp_tab_backup.utw.json rename to src/module/utw/wp_tab_backup.utw.json diff --git a/src/mod/utw/wp_tab_drag_port.utw.json b/src/module/utw/wp_tab_drag_port.utw.json similarity index 100% rename from src/mod/utw/wp_tab_drag_port.utw.json rename to src/module/utw/wp_tab_drag_port.utw.json diff --git a/src/mod/utw/wp_tab_fe.utw.json b/src/module/utw/wp_tab_fe.utw.json similarity index 100% rename from src/mod/utw/wp_tab_fe.utw.json rename to src/module/utw/wp_tab_fe.utw.json diff --git a/src/mod/utw/wp_tab_from_bigg.utw.json b/src/module/utw/wp_tab_from_bigg.utw.json similarity index 100% rename from src/mod/utw/wp_tab_from_bigg.utw.json rename to src/module/utw/wp_tab_from_bigg.utw.json diff --git a/src/mod/utw/wp_tab_legion.utw.json b/src/module/utw/wp_tab_legion.utw.json similarity index 100% rename from src/mod/utw/wp_tab_legion.utw.json rename to src/module/utw/wp_tab_legion.utw.json diff --git a/src/mod/utw/wp_tab_legion_01.utw.json b/src/module/utw/wp_tab_legion_01.utw.json similarity index 100% rename from src/mod/utw/wp_tab_legion_01.utw.json rename to src/module/utw/wp_tab_legion_01.utw.json diff --git a/src/mod/utw/wp_tabbehold1.utw.json b/src/module/utw/wp_tabbehold1.utw.json similarity index 100% rename from src/mod/utw/wp_tabbehold1.utw.json rename to src/module/utw/wp_tabbehold1.utw.json diff --git a/src/mod/utw/wp_tabbo_orc1.utw.json b/src/module/utw/wp_tabbo_orc1.utw.json similarity index 100% rename from src/mod/utw/wp_tabbo_orc1.utw.json rename to src/module/utw/wp_tabbo_orc1.utw.json diff --git a/src/mod/utw/wp_tablith.utw.json b/src/module/utw/wp_tablith.utw.json similarity index 100% rename from src/mod/utw/wp_tablith.utw.json rename to src/module/utw/wp_tablith.utw.json diff --git a/src/mod/utw/wp_tablith001.utw.json b/src/module/utw/wp_tablith001.utw.json similarity index 100% rename from src/mod/utw/wp_tablith001.utw.json rename to src/module/utw/wp_tablith001.utw.json diff --git a/src/mod/utw/wp_tabmind_002.utw.json b/src/module/utw/wp_tabmind_002.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_002.utw.json rename to src/module/utw/wp_tabmind_002.utw.json diff --git a/src/mod/utw/wp_tabmind_003.utw.json b/src/module/utw/wp_tabmind_003.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_003.utw.json rename to src/module/utw/wp_tabmind_003.utw.json diff --git a/src/mod/utw/wp_tabmind_004.utw.json b/src/module/utw/wp_tabmind_004.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_004.utw.json rename to src/module/utw/wp_tabmind_004.utw.json diff --git a/src/mod/utw/wp_tabmind_005.utw.json b/src/module/utw/wp_tabmind_005.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_005.utw.json rename to src/module/utw/wp_tabmind_005.utw.json diff --git a/src/mod/utw/wp_tabmind_006.utw.json b/src/module/utw/wp_tabmind_006.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_006.utw.json rename to src/module/utw/wp_tabmind_006.utw.json diff --git a/src/mod/utw/wp_tabmind_007.utw.json b/src/module/utw/wp_tabmind_007.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_007.utw.json rename to src/module/utw/wp_tabmind_007.utw.json diff --git a/src/mod/utw/wp_tabmind_008.utw.json b/src/module/utw/wp_tabmind_008.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_008.utw.json rename to src/module/utw/wp_tabmind_008.utw.json diff --git a/src/mod/utw/wp_tabmind_01.utw.json b/src/module/utw/wp_tabmind_01.utw.json similarity index 100% rename from src/mod/utw/wp_tabmind_01.utw.json rename to src/module/utw/wp_tabmind_01.utw.json diff --git a/src/mod/utw/wp_temp_cain.utw.json b/src/module/utw/wp_temp_cain.utw.json similarity index 100% rename from src/mod/utw/wp_temp_cain.utw.json rename to src/module/utw/wp_temp_cain.utw.json diff --git a/src/mod/utw/wp_tm_base.utw.json b/src/module/utw/wp_tm_base.utw.json similarity index 100% rename from src/mod/utw/wp_tm_base.utw.json rename to src/module/utw/wp_tm_base.utw.json diff --git a/src/mod/utw/wp_west_frm_grav.utw.json b/src/module/utw/wp_west_frm_grav.utw.json similarity index 100% rename from src/mod/utw/wp_west_frm_grav.utw.json rename to src/module/utw/wp_west_frm_grav.utw.json diff --git a/src/mod/utw/wp_wolf_002.utw.json b/src/module/utw/wp_wolf_002.utw.json similarity index 100% rename from src/mod/utw/wp_wolf_002.utw.json rename to src/module/utw/wp_wolf_002.utw.json diff --git a/src/mod/utw/wp_wolf_003.utw.json b/src/module/utw/wp_wolf_003.utw.json similarity index 100% rename from src/mod/utw/wp_wolf_003.utw.json rename to src/module/utw/wp_wolf_003.utw.json diff --git a/src/mod/utw/wp_wolf_01.utw.json b/src/module/utw/wp_wolf_01.utw.json similarity index 100% rename from src/mod/utw/wp_wolf_01.utw.json rename to src/module/utw/wp_wolf_01.utw.json diff --git a/src/prc8/include/nw_inc_nui.nss b/src/prc8/include/nw_inc_nui.nss deleted file mode 100644 index 96fc3da..0000000 --- a/src/prc8/include/nw_inc_nui.nss +++ /dev/null @@ -1,1193 +0,0 @@ -const int NUI_DIRECTION_HORIZONTAL = 0; -const int NUI_DIRECTION_VERTICAL = 1; - -const int NUI_MOUSE_BUTTON_LEFT = 0; -const int NUI_MOUSE_BUTTON_MIDDLE = 1; -const int NUI_MOUSE_BUTTON_RIGHT = 2; - -const int NUI_SCROLLBARS_NONE = 0; -const int NUI_SCROLLBARS_X = 1; -const int NUI_SCROLLBARS_Y = 2; -const int NUI_SCROLLBARS_BOTH = 3; -const int NUI_SCROLLBARS_AUTO = 4; - -const int NUI_ASPECT_FIT = 0; -const int NUI_ASPECT_FILL = 1; -const int NUI_ASPECT_FIT100 = 2; -const int NUI_ASPECT_EXACT = 3; -const int NUI_ASPECT_EXACTSCALED = 4; -const int NUI_ASPECT_STRETCH = 5; - -const int NUI_HALIGN_CENTER = 0; -const int NUI_HALIGN_LEFT = 1; -const int NUI_HALIGN_RIGHT = 2; - -const int NUI_VALIGN_MIDDLE = 0; -const int NUI_VALIGN_TOP = 1; -const int NUI_VALIGN_BOTTOM = 2; - -// ----------------------- -// Style - -const float NUI_STYLE_PRIMARY_WIDTH = 150.0; -const float NUI_STYLE_PRIMARY_HEIGHT = 50.0; - -const float NUI_STYLE_SECONDARY_WIDTH = 150.0; -const float NUI_STYLE_SECONDARY_HEIGHT = 35.0; - -const float NUI_STYLE_TERTIARY_WIDTH = 100.0; -const float NUI_STYLE_TERTIARY_HEIGHT = 30.0; - -const float NUI_STYLE_ROW_HEIGHT = 25.0; - -// ----------------------- -// Window - -// Special cases: -// * 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. -); - -// ----------------------- -// Values - -// Create a dynamic bind. Unlike static values, these can change at runtime: -// NuiBind("mybindlabel"); -// NuiSetBind(.., "mybindlabel", JsonString("hi")); -// To create static values, just use the json types directly: -// JsonString("hi"); -json // Bind -NuiBind( - string sId -); - -// 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 -); - -// 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 -); - -// ----------------------- -// 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[] -); - -// 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[] -); - -// 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 -); - -// 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). -); - -json // Element -NuiHeight( - json jElem, // Element - float fHeight // Float: Height in pixels (strength=required). -); - -json // Element -NuiAspect( - json jElem, // Element - float fAspect // Float: Ratio of x/y. -); - -// Set a margin on the widget. The margin is the spacing outside of the widget. -json // Element -NuiMargin( - json jElem, // Element - float fMargin // Float -); - -// Set padding on the widget. The margin is the spacing inside of the widget. -json // Element -NuiPadding( - json jElem, // Element - float fPadding // Float -); - -// Disabled elements are non-interactive and greyed out. -json // Element -NuiEnabled( - json jElem, // Element - json jEnabler // Bind:Bool -); - -// Invisible elements do not render at all, but still take up layout space. -json // Element -NuiVisible( - json jElem, // Element - json jVisible // Bind:Bool -); - -// Tooltips show on mouse hover. -json // Element -NuiTooltip( - json jElem, // Element - json jTooltip // Bind:String -); - -// Tooltips for disabled elements show on mouse hover. -json // Element -NuiDisabledTooltip( - json jElem, // Element - json jTooltip // Bind:String -); - -// Encouraged elements have a breathing animated glow inside of it. -json // Element -NuiEncouraged( - json jElem, // Element - json jEncouraged // Bind:Bool -); - -// ----------------------- -// Props & Style - -json // Vec2 -NuiVec(float x, float y); - -json // Rect -NuiRect(float x, float y, float w, float h); - -json // Color -NuiColor(int r, int g, int b, int a = 255); - -// Style the foreground color of the widget. 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 -); - -// ----------------------- -// Widgets - -// 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(); - -// 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_* -); - -// 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_* -); - -// A clickable button with text as the label. -// Sends "click" events on click. -json // Element -NuiButton( - json jLabel // Bind:String -); - -// A clickable button with an image as the label. -// Sends "click" events on click. -json // Element -NuiButtonImage( - json jResRef // Bind:ResRef -); - -// 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 -); - -// A checkbox with a label to the right of it. -json // Element -NuiCheck( - json jLabel, // Bind:String - json jBool // Bind:Bool -); - -// 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_* -); - -// Optionally render only subregion of jImage. -// 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 -); - -// A combobox/dropdown. -json // Element -NuiCombo( - json jElements, // Bind:ComboEntry[] - json jSelected // Bind:Int (index into jElements) -); - -json // ComboEntry -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 -); - -// A integer/discrete slider. -json // Element -NuiSlider( - json jValue, // Bind:Int - json jMin, // Bind:Int - json jMax, // Bind:Int - json jStepSize // Bind:Int -); - -// A progress bar. Progress is always from 0.0 to 1.0. -json // Element -NuiProgress( - json jValue // Bind:Float (0.0->1.0) -); - -// 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 -); - -// Creates a list view of elements. -// jTemplate needs to be an array of NuiListTemplateCell instances. -// All binds referenced in jTemplate should be arrays of rRowCount size; -// 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. -); - -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 -); - -// A simple color picker, with no border or spacing. -json // Element -NuiColorPicker( - json jColor // Bind:Color -); - -// 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 -); - -// 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 -); - -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[] -); - -// Renders a chart. -// Currently, min and max values are determined automatically and -// cannot be influenced. -json // Element -NuiChart( - json jSlots // NuiChartSlot[] -); - -// ----------------------- -// Draw Lists - -// Draw lists are raw painting primitives on top of widgets. -// They are anchored to the widget x/y coordinates, and are always -// painted in order of definition, without culling. You cannot bind -// the draw_list itself, but most parameters on individual draw_list -// entries can be bound. - -const int NUI_DRAW_LIST_ITEM_TYPE_POLYLINE = 0; -const int NUI_DRAW_LIST_ITEM_TYPE_CURVE = 1; -const int NUI_DRAW_LIST_ITEM_TYPE_CIRCLE = 2; -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; - -// 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" -// a widget. - -const int NUI_DRAW_LIST_ITEM_ORDER_BEFORE = -1; -const int NUI_DRAW_LIST_ITEM_ORDER_AFTER = 1; - -// Always render draw list item (default). -const int NUI_DRAW_LIST_ITEM_RENDER_ALWAYS = 0; -// Only render when NOT hovering. -const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_OFF = 1; -// Only render when mouse is hovering. -const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_HOVER = 2; -// Only render while LMB is held down. -const int NUI_DRAW_LIST_ITEM_RENDER_MOUSE_LEFT = 3; -// Only render while RMB is held down. -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_* -); - -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_* -); - -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_* -); - -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_* -); - -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_* -); - -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_* -); - -json // DrawListItemImage -NuiDrawListImageRegion( - json jDrawListImage, // DrawListItemImage - json jRegion // Bind:NuiRect -); - -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_* -); - -json // Element -NuiDrawList( - json jElem, // Element - json jScissor, // Bind:Bool Constrain painted elements to widget bounds. - json jList // DrawListItem[] -); - -// ----------------------- -// Implementation - -json -NuiWindow( - json jRoot, - json jTitle, - json jGeometry, - json jResizable, - json jCollapsed, - json jClosable, - json jTransparent, - json jBorder, - json jAcceptsInput -) -{ - 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); - return ret; -} - -json -NuiElement( - string sType, - json jLabel, - json jValue -) -{ - json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonString(sType)); - ret = JsonObjectSet(ret, "label", jLabel); - ret = JsonObjectSet(ret, "value", jValue); - return ret; -} - -json -NuiBind( - string sId -) -{ - return JsonObjectSet(JsonObject(), "bind", JsonString(sId)); -} - -json -NuiId( - json jElem, - string sId -) -{ - return JsonObjectSet(jElem, "id", JsonString(sId)); -} - -json -NuiStrRef( - int nStrRef -) -{ - json ret = JsonObject(); - ret = JsonObjectSet(ret, "strref", JsonInt(nStrRef)); - return ret; -} - -json -NuiCol( - json jList -) -{ - return JsonObjectSet(NuiElement("col", JsonNull(), JsonNull()), "children", jList); -} - -json -NuiRow( - json jList -) -{ - return JsonObjectSet(NuiElement("row", JsonNull(), JsonNull()), "children", jList); -} - -json -NuiGroup( - json jChild, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_AUTO -) -{ - 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)); - return ret; -} - -json -NuiWidth(json jElem, float fWidth) -{ - return JsonObjectSet(jElem, "width", JsonFloat(fWidth)); -} - -json -NuiHeight(json jElem, float fHeight) -{ - return JsonObjectSet(jElem, "height", JsonFloat(fHeight)); -} - -json -NuiAspect(json jElem, float fAspect) -{ - return JsonObjectSet(jElem, "aspect", JsonFloat(fAspect)); -} - -json -NuiMargin( - json jElem, - float fMargin -) -{ - return JsonObjectSet(jElem, "margin", JsonFloat(fMargin)); -} - -json -NuiPadding( - json jElem, - float fPadding -) -{ - return JsonObjectSet(jElem, "padding", JsonFloat(fPadding)); -} - -json -NuiEnabled( - json jElem, - json jEnabler -) -{ - return JsonObjectSet(jElem, "enabled", jEnabler); -} - -json -NuiVisible( - json jElem, - json jVisible -) -{ - return JsonObjectSet(jElem, "visible", jVisible); -} - -json -NuiTooltip( - json jElem, - json jTooltip -) -{ - return JsonObjectSet(jElem, "tooltip", jTooltip); -} - -json -NuiDisabledTooltip( - json jElem, - json jTooltip -) -{ - return JsonObjectSet(jElem, "disabled_tooltip", jTooltip); -} - -json -NuiEncouraged( - json jElem, - json jEncouraged -) -{ - return JsonObjectSet(jElem, "encouraged", jEncouraged); -} - -json -NuiVec(float x, float y) -{ - json ret = JsonObject(); - ret = JsonObjectSet(ret, "x", JsonFloat(x)); - ret = JsonObjectSet(ret, "y", JsonFloat(y)); - return ret; -} - -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)); - return ret; -} - -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)); - return ret; -} - -json -NuiStyleForegroundColor( - json jElem, - json jColor -) -{ - return JsonObjectSet(jElem, "foreground_color", jColor); -} - -json -NuiSpacer() -{ - return NuiElement("spacer", JsonNull(), JsonNull()); -} - -json -NuiLabel( - json jValue, - json jHAlign, - json jVAlign -) -{ - json ret = NuiElement("label", JsonNull(), jValue); - ret = JsonObjectSet(ret, "text_halign", jHAlign); - ret = JsonObjectSet(ret, "text_valign", jVAlign); - return ret; -} - -json -NuiText( - json jValue, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_AUTO -) -{ - json ret = NuiElement("text", JsonNull(), jValue); - ret = JsonObjectSet(ret, "border", JsonBool(bBorder)); - ret = JsonObjectSet(ret, "scrollbars", JsonInt(nScroll)); - return ret; -} - -json -NuiButton( - json jLabel -) -{ - return NuiElement("button", jLabel, JsonNull()); -} - -json -NuiButtonImage( - json jResRef -) -{ - return NuiElement("button_image", jResRef, JsonNull()); -} - -json -NuiButtonSelect( - json jLabel, - json jValue -) -{ - return NuiElement("button_select", jLabel, jValue); -} - -json -NuiCheck( - json jLabel, - json jBool -) -{ - return NuiElement("check", jLabel, jBool); -} - -json -NuiImage( - json jResRef, - json jAspect, - json jHAlign, - json jVAlign -) -{ - json img = NuiElement("image", JsonNull(), jResRef); - img = JsonObjectSet(img, "image_aspect", jAspect); - img = JsonObjectSet(img, "image_halign", jHAlign); - img = JsonObjectSet(img, "image_valign", jVAlign); - return img; -} - -json -NuiImageRegion( - json jImage, - json jRegion -) -{ - return JsonObjectSet(jImage, "image_region", jRegion); -} - -json -NuiCombo( - json jElements, - json jSelected -) -{ - return JsonObjectSet(NuiElement("combo", JsonNull(), jSelected), "elements", jElements); -} - -json -NuiComboEntry( - string sLabel, - int nValue -) -{ - return JsonArrayInsert(JsonArrayInsert(JsonArray(), JsonString(sLabel)), JsonInt(nValue)); -} - -json -NuiSliderFloat( - json jValue, - json jMin, - json jMax, - json jStepSize -) -{ - json ret = NuiElement("sliderf", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); - return ret; -} - -json -NuiSlider( - json jValue, - json jMin, - json jMax, - json jStepSize -) -{ - json ret = NuiElement("slider", JsonNull(), jValue); - ret = JsonObjectSet(ret, "min", jMin); - ret = JsonObjectSet(ret, "max", jMax); - ret = JsonObjectSet(ret, "step", jStepSize); - return ret; -} - -json -NuiProgress( - json jValue -) -{ - return NuiElement("progress", JsonNull(), jValue); -} - -json -NuiTextEdit( - json jPlaceholder, - json jValue, - int nMaxLength, - int bMultiline, - int bWordWrap = TRUE -) -{ - json ret = NuiElement("textedit", jPlaceholder, jValue); - ret = JsonObjectSet(ret, "max", JsonInt(nMaxLength)); - ret = JsonObjectSet(ret, "multiline", JsonBool(bMultiline)); - ret = JsonObjectSet(ret, "wordwrap", JsonBool(bWordWrap)); - return ret; -} - -json -NuiList( - json jTemplate, - json jRowCount, - float fRowHeight = NUI_STYLE_ROW_HEIGHT, - int bBorder = TRUE, - int nScroll = NUI_SCROLLBARS_Y -) -{ - 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)); - return ret; -} - -json -NuiListTemplateCell( - json jElem, - float fWidth, - int bVariable -) -{ - json ret = JsonArray(); - ret = JsonArrayInsert(ret, jElem); - ret = JsonArrayInsert(ret, JsonFloat(fWidth)); - ret = JsonArrayInsert(ret, JsonBool(bVariable)); - return ret; -} - -json -NuiColorPicker( - json jColor -) -{ - json ret = NuiElement("color_picker", JsonNull(), jColor); - return ret; -} - -json -NuiOptions( - int nDirection, - json jElements, - json jValue -) -{ - json ret = NuiElement("options", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); - return ret; -} - -json -NuiToggles( - int nDirection, - json jElements, - json jValue -) -{ - json ret = NuiElement("tabbar", JsonNull(), jValue); - ret = JsonObjectSet(ret, "direction", JsonInt(nDirection)); - ret = JsonObjectSet(ret, "elements", jElements); - return ret; -} - -json -NuiChartSlot( - int nType, - json jLegend, - json jColor, - json jData -) -{ - json ret = JsonObject(); - ret = JsonObjectSet(ret, "type", JsonInt(nType)); - ret = JsonObjectSet(ret, "legend", jLegend); - ret = JsonObjectSet(ret, "color", jColor); - ret = JsonObjectSet(ret, "data", jData); - return ret; -} - -json -NuiChart( - json jSlots -) -{ - json ret = NuiElement("chart", JsonNull(), jSlots); - return ret; -} - -json -NuiDrawListItem( - int nType, - json jEnabled, - json jColor, - json jFill, - json jLineThickness, - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS -) -{ - 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)); - return ret; -} - -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 -) -{ - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_POLYLINE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "points", jPoints); - return ret; -} - -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 -) -{ - 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); - return ret; -} - -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 -) -{ - json ret = NuiDrawListItem(NUI_DRAW_LIST_ITEM_TYPE_CIRCLE, jEnabled, jColor, jFill, jLineThickness, nOrder, nRender); - ret = JsonObjectSet(ret, "rect", jRect); - return ret; -} - -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 -) -{ - 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); - return ret; -} - -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 -) -{ - 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); - return ret; -} - -json -NuiDrawListImage( - json jEnabled, - json jResRef, - json jRect, - json jAspect, - json jHAlign, - json jVAlign, - int nOrder = NUI_DRAW_LIST_ITEM_ORDER_AFTER, - int nRender = NUI_DRAW_LIST_ITEM_RENDER_ALWAYS -) -{ - 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); - return ret; -} - -json -NuiDrawListImageRegion( - json jDrawListImage, - json jRegion -) -{ - return JsonObjectSet(jDrawListImage, "image_region", jRegion); -} - -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 -) -{ - 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); - return ret; -} - -json -NuiDrawList( - json jElem, - json jScissor, - json jList -) -{ - json ret = JsonObjectSet(jElem, "draw_list", jList); - ret = JsonObjectSet(ret, "draw_list_scissor", jScissor); - return ret; -} - -// json -// NuiCanvas( -// json jList -// ) -// { -// json ret = NuiElement("canvas", JsonNull(), jList); -// return ret; -// } - diff --git a/src/prc8/scripts/nw_s1_aurablnda.nss b/src/prc8/scripts/nw_s1_aurablnda.nss deleted file mode 100644 index 0babfaa..0000000 --- a/src/prc8/scripts/nw_s1_aurablnda.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Blinding On Enter -//:: NW_S1_AuraBlndA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura of the creature the player - must make a will save or be blinded because of the - sheer ugliness or beauty of the creature. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD/3); - - effect eBlind = EffectBlindness(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVis = EffectVisualEffect(VFX_IMP_BLIND_DEAF_M); - effect eLink = EffectLinkEffects(eBlind, eDur); - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - //Entering object must make a will save or be blinded for the duration. - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_AURA_BLINDING)); - if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC)) - { - //Apply the blind effect and the VFX impact - DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_auracoldc.nss b/src/prc8/scripts/nw_s1_auracoldc.nss deleted file mode 100644 index 49cd95e..0000000 --- a/src/prc8/scripts/nw_s1_auracoldc.nss +++ /dev/null @@ -1,62 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Frost on Heartbeat -//:: NW_S1_AuraColdC.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Prolonged exposure to the aura of the creature - causes frost damage to all within the aura. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nFrost = 1 + (nHD/3); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - - effect eDam; - effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); - - //Get the first target in the aura of cold - oTarget = GetFirstInPersistentObject(); - - while (GetIsObjectValid(oTarget)) - { -/* if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) - { - oTarget = GetNextInPersistentObject(OBJECT_SELF); - continue; - } */ - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_AURA_COLD)); - //Roll damage based on the creatures HD - nDamage = d4(nFrost); - //Make a Fortitude save for half - if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_COLD)) - { - nDamage = nDamage / 2; - } - //Set the damage effect - eDam = EffectDamage(nDamage, DAMAGE_TYPE_COLD); - //Apply the VFX constant and damage effect - ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - //Get the next target in the aura of cold - oTarget = GetNextInPersistentObject(); - } -} diff --git a/src/prc8/scripts/nw_s1_auraelecc.nss b/src/prc8/scripts/nw_s1_auraelecc.nss deleted file mode 100644 index 06994f4..0000000 --- a/src/prc8/scripts/nw_s1_auraelecc.nss +++ /dev/null @@ -1,58 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Electricity on Heartbeat -//:: NW_S1_AuraElecC.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Prolonged exposure to the aura of the creature - causes electrical damage to all within the aura. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - int nHD = GetHitDice(oNPC); - int nZap = 1 + (nHD / 3); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 + nCHAMod + (nHD/2); - int nDamage; - - effect eDam; - effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); - - //Get first target in spell area - object oTarget = GetFirstInPersistentObject(); - while (GetIsObjectValid(oTarget)) - { -/* if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) - { - oTarget = GetNextInPersistentObject(OBJECT_SELF); - continue; - } */ - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - nDamage = d4(nZap); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_AURA_ELECTRICITY)); - //Make a saving throw check - if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_ELECTRICITY)) - { - nDamage = nDamage / 2; - } - eDam = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); - //Apply the VFX impact and effects - DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); - DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - //Get next target in spell area - oTarget = GetNextInPersistentObject(); - } -} diff --git a/src/prc8/scripts/nw_s1_aurafirec.nss b/src/prc8/scripts/nw_s1_aurafirec.nss deleted file mode 100644 index a6b9638..0000000 --- a/src/prc8/scripts/nw_s1_aurafirec.nss +++ /dev/null @@ -1,59 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Fire on Heartbeat -//:: NW_S1_AuraFireC.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Prolonged exposure to the aura of the creature - causes fire damage to all within the aura. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetFirstInPersistentObject(); //:: Get first target in spell area - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nBurn = 1 + (nHD/3); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - int nDamSave; - - effect eDam; - effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); - - while(GetIsObjectValid(oTarget)) - { -/* if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) - { - oTarget = GetNextInPersistentObject(OBJECT_SELF); - continue; - } */ - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELLABILITY_AURA_FIRE)); - //Roll damage - nDamage = d4(nBurn); - //Make a saving throw check - if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_FIRE)) - { - nDamage = nDamage / 2; - } - //Set the damage effect - eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); - } - //Get next target in spell area - oTarget = GetNextInPersistentObject(); - } -} diff --git a/src/prc8/scripts/nw_s1_auramenca.nss b/src/prc8/scripts/nw_s1_auramenca.nss deleted file mode 100644 index e786aaa..0000000 --- a/src/prc8/scripts/nw_s1_auramenca.nss +++ /dev/null @@ -1,46 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Menace On Enter -//:: NW_S1_AuraMencA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura all those that fail - a will save are stricken with Doom. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - int nDuration = 1 + (GetHitDice(oNPC)/3); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (GetHitDice(oNPC)/2); - int nLevel = GetCasterLevel(OBJECT_SELF); - int nMetaMagic = PRCGetMetaMagicFeat(); - - effect eVis = EffectVisualEffect(VFX_IMP_DOOM); - effect eLink = CreateDoomEffectsLink(); - - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_AURA_MENACE)); - //Spell Resistance and Saving throw - if (!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC)) - { - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink , oTarget, TurnsToSeconds(nDuration)); - } - } -} diff --git a/src/prc8/scripts/nw_s1_auraprota.nss b/src/prc8/scripts/nw_s1_auraprota.nss deleted file mode 100644 index 548f284..0000000 --- a/src/prc8/scripts/nw_s1_auraprota.nss +++ /dev/null @@ -1,35 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Protection: On Enter -//:: NW_S1_AuraProtA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Acts as a double strength Magic Circle against - evil and a Minor Globe for those friends in - the area. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On:Jan 8, 2002, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -void main() -{ - //Declare major variables - effect eProt = CreateProtectionFromAlignmentLink(ALIGNMENT_EVIL); - effect eGlobe = EffectSpellLevelAbsorption(3, 0); - effect eDur = EffectVisualEffect(VFX_DUR_GLOBE_MINOR); - - effect eLink = EffectLinkEffects(eProt, eGlobe); - eLink = EffectLinkEffects(eLink, eDur); - - object oTarget = GetEnteringObject(); - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - //Faction Check - if(GetIsFriend(oTarget, GetAreaOfEffectCreator())) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_aurastuna.nss b/src/prc8/scripts/nw_s1_aurastuna.nss deleted file mode 100644 index 03d0aae..0000000 --- a/src/prc8/scripts/nw_s1_aurastuna.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura Stunning On Enter -//:: NW_S1_AuraStunA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura of the creature the player - must make a will save or be stunned. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDuration = GetHitDice(oNPC); - int nDC = 10 + nCHAMod + (nDuration/2); - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - effect eVis = EffectVisualEffect(VFX_IMP_STUN); - effect eVis2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eDeath = EffectStunned(); - effect eLink = EffectLinkEffects(eVis2, eDeath); - - nDuration = GetScaledDuration(nDuration, oTarget); - - if(!GetIsFriend(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_AURA_STUN)); - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_auraunata.nss b/src/prc8/scripts/nw_s1_auraunata.nss deleted file mode 100644 index a597062..0000000 --- a/src/prc8/scripts/nw_s1_auraunata.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of the Unnatural On Enter -//:: NW_S1_AuraMencA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura all animals are struck with - fear. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - effect eVis = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eFear = EffectFrightened(); - effect eLink = EffectLinkEffects(eVis, eFear); - object oTarget = GetEnteringObject(); - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - int nDuration = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nRacial = GetRacialType(oTarget); - int nDC = 10 + nCHAMod + (GetHitDice(oNPC)/2); - - if(GetIsEnemy(oTarget)) - { - nDuration = (nDuration / 3) + 1; - //Make a saving throw check - if(nRacial == RACIAL_TYPE_ANIMAL) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELLABILITY_AURA_UNNATURAL)); - //if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR)) //:: This ability only affects animals & they don't get a save. - //{ - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); - //} - } - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_aurauneaa.nss b/src/prc8/scripts/nw_s1_aurauneaa.nss deleted file mode 100644 index 6f4a75b..0000000 --- a/src/prc8/scripts/nw_s1_aurauneaa.nss +++ /dev/null @@ -1,46 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura Unearthly Visage On Enter -//:: NW_S1_AuraUnEaA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura of the creature the player - must make a will save or be killed because of the - sheer ugliness or beauty of the creature. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - effect eDeath = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - if(GetIsEnemy(oTarget, oNPC)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_AURA_UNEARTHLY_VISAGE)); - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget); - //ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltacid.nss b/src/prc8/scripts/nw_s1_bltacid.nss deleted file mode 100644 index ef53a16..0000000 --- a/src/prc8/scripts/nw_s1_bltacid.nss +++ /dev/null @@ -1,66 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Acid -//:: NW_S1_BltAcid -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nCount = nHD/2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); - effect eBolt; - - //ankheg - if(GetAppearanceType(oNPC) == APPEARANCE_TYPE_BEETLE_SLICER) - { - nDamage = d4(4); - } - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_ACID)); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_ACID); - - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Set damage effect - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_ACID); - if(nDamage > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltcharm.nss b/src/prc8/scripts/nw_s1_bltcharm.nss deleted file mode 100644 index df11d65..0000000 --- a/src/prc8/scripts/nw_s1_bltcharm.nss +++ /dev/null @@ -1,47 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Charm -//:: NW_S1_BltCharm -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" -#include "NW_I0_SPELLS" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - nCount = GetScaledDuration(nCount, oTarget); - - effect eVis = EffectVisualEffect(VFX_IMP_CHARM); - effect eBolt = EffectCharmed(); - eBolt = GetScaledEffect(eBolt, oTarget); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_CHARM)); - //Make a saving throw check - if (!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_bltchrdr.nss b/src/prc8/scripts/nw_s1_bltchrdr.nss deleted file mode 100644 index e734580..0000000 --- a/src/prc8/scripts/nw_s1_bltchrdr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Charisma Drain -//:: NW_S1_BltChrDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Fortitude save is - needed to avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD / 3; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_BOLT_ABILITY_DRAIN_CHARISMA)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_CHARISMA, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget, RoundsToSeconds(nHD)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltcold.nss b/src/prc8/scripts/nw_s1_bltcold.nss deleted file mode 100644 index 657f0fe..0000000 --- a/src/prc8/scripts/nw_s1_bltcold.nss +++ /dev/null @@ -1,60 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Cold -//:: NW_S1_BltCold -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD/2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_COLD)); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_COLD); - - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Set damage effect - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_COLD); - if(nDamage > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltcondr.nss b/src/prc8/scripts/nw_s1_bltcondr.nss deleted file mode 100644 index 9d85f04..0000000 --- a/src/prc8/scripts/nw_s1_bltcondr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Constitution Drain -//:: NW_S1_BltConDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Fort save is - needed to avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD /3); - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_ABILITY_DRAIN_CONSTITUTION)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_CONSTITUTION, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget, RoundsToSeconds(nHD)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltconf.nss b/src/prc8/scripts/nw_s1_bltconf.nss deleted file mode 100644 index 5bed7dc..0000000 --- a/src/prc8/scripts/nw_s1_bltconf.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Confuse -//:: NW_S1_BltConf -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" -#include "NW_I0_SPELLS" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - nCount = GetScaledDuration(nCount, oTarget); - - effect eVis2 = EffectVisualEffect(VFX_IMP_CONFUSION_S); - effect eVis = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eBolt = EffectConfused(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - eLink = EffectLinkEffects(eLink, eVis); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_CONFUSE)); - //Make a saving throw check - if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_bltdaze.nss b/src/prc8/scripts/nw_s1_bltdaze.nss deleted file mode 100644 index 68d15c7..0000000 --- a/src/prc8/scripts/nw_s1_bltdaze.nss +++ /dev/null @@ -1,47 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Daze -//:: NW_S1_BltDaze -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" -#include "NW_I0_SPELLS" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - nCount = GetScaledDuration(nCount, oTarget); - - effect eVis = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eBolt = EffectDazed(); - eBolt = GetScaledEffect(eBolt, oTarget); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - eLink = EffectLinkEffects(eLink, eVis); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_DAZE)); - //Make a saving throw check - if (!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - } -} diff --git a/src/prc8/scripts/nw_s1_bltdeath.nss b/src/prc8/scripts/nw_s1_bltdeath.nss deleted file mode 100644 index e2cbcd7..0000000 --- a/src/prc8/scripts/nw_s1_bltdeath.nss +++ /dev/null @@ -1,47 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Death -//:: NW_S1_BltDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - effect eBolt = EffectDeath(); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_DEATH)); - //Make a saving throw check - if(TouchAttackRanged(oTarget)) - { - if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_DEATH)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - //ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} - diff --git a/src/prc8/scripts/nw_s1_bltdexdr.nss b/src/prc8/scripts/nw_s1_bltdexdr.nss deleted file mode 100644 index 4ef34d8..0000000 --- a/src/prc8/scripts/nw_s1_bltdexdr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Dexterity Drain -//:: NW_S1_BltDexDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Fort save is - needed to avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_ABILITY_DRAIN_DEXTERITY)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_DEXTERITY, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget, RoundsToSeconds(nHD)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltdisese.nss b/src/prc8/scripts/nw_s1_bltdisese.nss deleted file mode 100644 index 6513a06..0000000 --- a/src/prc8/scripts/nw_s1_bltdisese.nss +++ /dev/null @@ -1,73 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Disease -//:: NW_S1_BltDisease -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to infect - the target with a disease. The disease used - is chosen based upon the racial type of the - caster. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nRacial = MyPRCGetRacialType(oNPC); - int nDisease; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_DISEASE)); - - //Here we use the racial type of the attacker to select an - //appropriate disease. - switch (nRacial) - { - case RACIAL_TYPE_VERMIN: - nDisease = DISEASE_VERMIN_MADNESS; - break; - case RACIAL_TYPE_UNDEAD: - nDisease = DISEASE_FILTH_FEVER; - break; - case RACIAL_TYPE_OUTSIDER: - if(GetTag(oNPC) == "NW_SLAADRED") - { - nDisease = DISEASE_RED_SLAAD_EGGS; - } - else - { - nDisease = DISEASE_DEMON_FEVER; - } - break; - case RACIAL_TYPE_MAGICAL_BEAST: - nDisease = DISEASE_SOLDIER_SHAKES; - break; - case RACIAL_TYPE_ABERRATION: - nDisease = DISEASE_BLINDING_SICKNESS; - break; - default: - nDisease = DISEASE_SOLDIER_SHAKES; - break; - } - //Assign effect and chosen disease - effect eBolt = EffectDisease(nDisease); - //Make the ranged touch attack. - if (TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltdomn.nss b/src/prc8/scripts/nw_s1_bltdomn.nss deleted file mode 100644 index 5027b45..0000000 --- a/src/prc8/scripts/nw_s1_bltdomn.nss +++ /dev/null @@ -1,53 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Dominated -//:: NW_S1_BltDomn -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - nCount = GetScaledDuration(nCount, oTarget); - - effect eVis = EffectVisualEffect(VFX_IMP_DOMINATE_S); - effect eBolt = EffectDominated(); - eBolt = GetScaledEffect(eBolt, oTarget); - effect eVis2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED); - eBolt = GetScaledEffect(eBolt, oTarget); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - eLink = EffectLinkEffects(eLink, eVis2); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_DOMINATE)); - - //Make a saving throw check - if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltfire.nss b/src/prc8/scripts/nw_s1_bltfire.nss deleted file mode 100644 index 4f7a423..0000000 --- a/src/prc8/scripts/nw_s1_bltfire.nss +++ /dev/null @@ -1,58 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Fire -//:: NW_S1_BoltFire -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD/2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_FIRE)); - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_FIRE); - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Set damage effect - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - if(nDamage > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltintdr.nss b/src/prc8/scripts/nw_s1_bltintdr.nss deleted file mode 100644 index f3ffbad..0000000 --- a/src/prc8/scripts/nw_s1_bltintdr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Intelligence Drain -//:: NW_S1_BltIntDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_ABILITY_DRAIN_INTELLIGENCE)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_INTELLIGENCE, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget, RoundsToSeconds(nHD)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltknckd.nss b/src/prc8/scripts/nw_s1_bltknckd.nss deleted file mode 100644 index 6816964..0000000 --- a/src/prc8/scripts/nw_s1_bltknckd.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Knockdown -//:: NW_S1_BltKnckD -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD/2; - if (nCount == 0) { nCount = 1; } - - effect eVis = EffectVisualEffect(VFX_IMP_SONIC); - effect eBolt = EffectKnockdown(); - effect eDam = EffectDamage(d6(), DAMAGE_TYPE_BLUDGEONING); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_KNOCKDOWN)); - - //Make a saving throw check - if (!/*Reflex Save*/ PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBolt, oTarget, RoundsToSeconds(3)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltlightn.nss b/src/prc8/scripts/nw_s1_bltlightn.nss deleted file mode 100644 index 024eafb..0000000 --- a/src/prc8/scripts/nw_s1_bltlightn.nss +++ /dev/null @@ -1,59 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Lightning -//:: NW_S1_BltLightn -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Does 1d6 per level to a single target. Reflex - save for half -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Aug 10, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD/2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, OBJECT_SELF,BODY_NODE_HAND); - effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_BOLT_LIGHTNING)); - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,SAVING_THROW_TYPE_ELECTRICITY); - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Set damage effect - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); - if(nDamage > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLightning, oTarget, 1.7); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltlvldr.nss b/src/prc8/scripts/nw_s1_bltlvldr.nss deleted file mode 100644 index e3f14ca..0000000 --- a/src/prc8/scripts/nw_s1_bltlvldr.nss +++ /dev/null @@ -1,49 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Level Drain -//:: NW_S1_BltLvlDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = nHD/5; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt = EffectNegativeLevel(1); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_LEVEL_DRAIN)); - - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - //eBolt = LEVEL DRAIN EFFECT - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltparal.nss b/src/prc8/scripts/nw_s1_bltparal.nss deleted file mode 100644 index e4a6b59..0000000 --- a/src/prc8/scripts/nw_s1_bltparal.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Paralyze -//:: NW_S1_BltParal -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - nCount = GetScaledDuration(nCount, oTarget); - - effect eVis = EffectVisualEffect(VFX_DUR_PARALYZED); - effect eBolt = EffectParalyze(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - eLink = EffectLinkEffects(eLink, eVis); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_PARALYZE)); - //Make a saving throw check - if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - } -} diff --git a/src/prc8/scripts/nw_s1_bltpoison.nss b/src/prc8/scripts/nw_s1_bltpoison.nss deleted file mode 100644 index 8a34aca..0000000 --- a/src/prc8/scripts/nw_s1_bltpoison.nss +++ /dev/null @@ -1,123 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Poison -//:: NW_S1_BltPoison.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Must make a ranged touch attack. If successful - the target is struck down with poison that - scales with level. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 22, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nRacial = MyPRCGetRacialType(OBJECT_SELF); - int nPoison; - - effect ePoison; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_POISON)); - - //Determine the poison type based on the Racial Type and HD - switch (nRacial) - { - case RACIAL_TYPE_OUTSIDER: - if (nHD <= 9) - { - nPoison = POISON_QUASIT_VENOM; - } - else if (nHD > 9 && nHD < 13) - { - nPoison = POISON_BEBILITH_VENOM; - } - else if (nHD >= 13) - { - nPoison = POISON_PIT_FIEND_ICHOR; - } - break; - case RACIAL_TYPE_VERMIN: - if (nHD < 3) - { - nPoison = POISON_TINY_SPIDER_VENOM; - } - else if (nHD <= 3 && nHD < 6) - { - nPoison = POISON_SMALL_SPIDER_VENOM; - } - else if (nHD <= 6 && nHD < 9) - { - nPoison = POISON_MEDIUM_SPIDER_VENOM; - } - else if (nHD <= 9 && nHD < 12) - { - nPoison = POISON_LARGE_SPIDER_VENOM; - } - else if (nHD <= 12 && nHD < 15) - { - nPoison = POISON_HUGE_SPIDER_VENOM; - } - else if (nHD <= 15 && nHD < 18) - { - nPoison = POISON_GARGANTUAN_SPIDER_VENOM; - } - else if (nHD >= 18) - { - nPoison = POISON_COLOSSAL_SPIDER_VENOM; - } - break; - default: - if (nHD < 3) - { - nPoison = POISON_NIGHTSHADE; - } - else if (nHD <= 3 && nHD < 6) - { - nPoison = POISON_BLADE_BANE; - } - else if (nHD <= 6 && nHD < 9) - { - nPoison = POISON_BLOODROOT; - } - else if (nHD <= 9 && nHD < 12) - { - nPoison = POISON_LARGE_SPIDER_VENOM; - } - else if (nHD <= 12 && nHD < 15) - { - nPoison = POISON_LICH_DUST; - } - else if (nHD <= 15 && nHD < 18) - { - nPoison = POISON_DARK_REAVER_POWDER; - } - else if (nHD >= 18 ) - { - nPoison = POISON_BLACK_LOTUS_EXTRACT; - } - - break; - } - //Make a ranged touch attack - if (TouchAttackRanged (oTarget)) - { - ePoison = EffectPoison(nPoison); - //Apply effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoison, oTarget); - } -} - diff --git a/src/prc8/scripts/nw_s1_bltshards.nss b/src/prc8/scripts/nw_s1_bltshards.nss deleted file mode 100644 index 1b96e2b..0000000 --- a/src/prc8/scripts/nw_s1_bltshards.nss +++ /dev/null @@ -1,58 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Shards -//:: NW_S1_BltShard -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_BOLT_SHARDS)); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC); - - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Set damage effect - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_PIERCING, DAMAGE_POWER_PLUS_ONE); - if(nDamage > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_bltslow.nss b/src/prc8/scripts/nw_s1_bltslow.nss deleted file mode 100644 index bf4813a..0000000 --- a/src/prc8/scripts/nw_s1_bltslow.nss +++ /dev/null @@ -1,47 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Slow -//:: NW_S1_BltSlow -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex save is - needed to or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: June 18 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - - effect eVis = EffectVisualEffect(VFX_IMP_SLOW); - effect eBolt = EffectSlow(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_SLOW)); - //Make a saving throw check - if (!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltstrdr.nss b/src/prc8/scripts/nw_s1_bltstrdr.nss deleted file mode 100644 index dd03161..0000000 --- a/src/prc8/scripts/nw_s1_bltstrdr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Strength Drain -//:: NW_S1_BltStrDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Fort save is - needed to avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_BOLT_ABILITY_DRAIN_STRENGTH)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_STRENGTH, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget, RoundsToSeconds(nHD)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_bltstun.nss b/src/prc8/scripts/nw_s1_bltstun.nss deleted file mode 100644 index 1d77008..0000000 --- a/src/prc8/scripts/nw_s1_bltstun.nss +++ /dev/null @@ -1,50 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Stun -//:: NW_S1_BltStun -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Reflex or Will save is - needed to halve damage or avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD + 1) / 2; - if (nCount == 0) { nCount = 1; } - nCount = GetScaledDuration(nCount, oTarget); - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_STUN); - effect eBolt = EffectStunned(); - eBolt = GetScaledEffect(eBolt, oTarget); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBolt, eDur); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_STUN)); - //Make a saving throw check - if (!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_bltweb.nss b/src/prc8/scripts/nw_s1_bltweb.nss deleted file mode 100644 index 9ed210a..0000000 --- a/src/prc8/scripts/nw_s1_bltweb.nss +++ /dev/null @@ -1,44 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Web -//:: NW_S1_BltWeb -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Glues a single target to the ground with - sticky strands of webbing. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 28, 2002 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nCount = 1 + (nHD /2); - if (nCount == 0) { nCount = 1; } - - effect eVis = EffectVisualEffect(VFX_DUR_WEB); - effect eStick = EffectEntangle(); - effect eLink = EffectLinkEffects(eVis, eStick); - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_WEB)); - //Make a saving throw check - if (!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC) && TouchAttackRanged(oTarget)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount)); - } -} diff --git a/src/prc8/scripts/nw_s1_bltwisdr.nss b/src/prc8/scripts/nw_s1_bltwisdr.nss deleted file mode 100644 index 49643c0..0000000 --- a/src/prc8/scripts/nw_s1_bltwisdr.nss +++ /dev/null @@ -1,48 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolt: Wisdom Drain -//:: NW_S1_BltWisDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature must make a ranged touch attack to hit - the intended target. Fort save is - needed to avoid effect. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nCount = (nHD /3); - if (nCount == 0) { nCount = 1; } - int nDamage = d6(nCount); - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eBolt; - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_BOLT_ABILITY_DRAIN_WISDOM)); - //Make a saving throw check - if (!/*Fort Save*/ PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE) && TouchAttackRanged(oTarget)) - { - eBolt = EffectAbilityDecrease(ABILITY_WISDOM, nCount); - eBolt = SupernaturalEffect(eBolt); - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_coneacid.nss b/src/prc8/scripts/nw_s1_coneacid.nss deleted file mode 100644 index 97d9393..0000000 --- a/src/prc8/scripts/nw_s1_coneacid.nss +++ /dev/null @@ -1,76 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Cone: Acid -//:: NW_S1_ConeAcid -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A cone of damage eminated from the monster. Does - a set amount of damage based upon the creatures HD - and can be halved with a Reflex Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - int nLoop = nHD / 3; - - float fDelay; - - if(nLoop == 0) - { - nLoop = 1; - } - - //Calculate the damage - for (nLoop; nLoop > 0; nLoop--) - { - nDamage = nDamage + d6(2); - } - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eCone; - effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_CONE_ACID)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_ACID); - //Set damage effect - eCone = EffectDamage(nDamage, DAMAGE_TYPE_ACID); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - - diff --git a/src/prc8/scripts/nw_s1_conecold.nss b/src/prc8/scripts/nw_s1_conecold.nss deleted file mode 100644 index 50f2a0c..0000000 --- a/src/prc8/scripts/nw_s1_conecold.nss +++ /dev/null @@ -1,76 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Cone: Cold -//:: NW_S1_ConeCold -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A cone of damage eminated from the monster. Does - a set amount of damage based upon the creatures HD - and can be halved with a Reflex Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - int nLoop = nHD / 3; - - float fDelay; - - if(nLoop == 0) - { - nLoop = 1; - } - - //Calculate the damage - for (nLoop; nLoop > 0; nLoop--) - { - nDamage = nDamage + d6(2); - } - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eCone; - effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_CONE_COLD)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_COLD); - //Set damage effect - eCone = EffectDamage(nDamage, DAMAGE_TYPE_COLD); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - } -} - - diff --git a/src/prc8/scripts/nw_s1_conedisea.nss b/src/prc8/scripts/nw_s1_conedisea.nss deleted file mode 100644 index a1eb9b1..0000000 --- a/src/prc8/scripts/nw_s1_conedisea.nss +++ /dev/null @@ -1,99 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Cone: Disease -//:: NW_S1_ConeDisea -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creature spits out a cone of disease that cannot - be avoided unless a Reflex save is made. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 22, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nRacial = MyPRCGetRacialType(oNPC); - int nDisease; - - location lTargetLocation = PRCGetSpellTargetLocation(); - - float fDelay; - - effect eCone = EffectDisease(nDisease); - effect eVis = EffectVisualEffect(VFX_IMP_DISEASE_S); - - - //Determine the disease type based on the Racial Type and HD - switch (nRacial) - { - case RACIAL_TYPE_OUTSIDER: - nDisease = DISEASE_DEMON_FEVER; - break; - case RACIAL_TYPE_VERMIN: - nDisease = DISEASE_VERMIN_MADNESS; - break; - case RACIAL_TYPE_UNDEAD: - if(nHD <= 3) - { - nDisease = DISEASE_ZOMBIE_CREEP; - } - else if (nHD > 3 && nHD <= 10) - { - nDisease = DISEASE_GHOUL_ROT; - } - else if(nHD > 10) - { - nDisease = DISEASE_MUMMY_ROT; - } - default: - if(nHD <= 3) - { - nDisease = DISEASE_MINDFIRE; - } - else if (nHD > 3 && nHD <= 10) - { - nDisease = DISEASE_RED_ACHE; - } - else if(nHD > 10) - { - nDisease = DISEASE_SHAKES; - } - - - break; - } - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != OBJECT_SELF) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_CONE_DISEASE)); - //Get the delay time - fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - - } -} - - - diff --git a/src/prc8/scripts/nw_s1_coneelec.nss b/src/prc8/scripts/nw_s1_coneelec.nss deleted file mode 100644 index 0dba225..0000000 --- a/src/prc8/scripts/nw_s1_coneelec.nss +++ /dev/null @@ -1,78 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Cone: Lightning -//:: NW_S1_ConeElec -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A cone of damage eminates from the monster. Does - a set amount of damage based upon the creatures HD - and can be halved with a Reflex Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - int nLoop = nHD / 3; - - float fDelay; - - if(nLoop == 0) - { - nLoop = 1; - } - - //Calculate the damage - for (nLoop; nLoop > 0; nLoop--) - { - nDamage = nDamage + d6(2); - } - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oNPC, BODY_NODE_HAND); - effect eCone; - effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_CONE_LIGHTNING)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_ELECTRICITY); - //Set damage effect - eCone = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget,0.5)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - } -} - - diff --git a/src/prc8/scripts/nw_s1_conesonic.nss b/src/prc8/scripts/nw_s1_conesonic.nss deleted file mode 100644 index 1ba25bf..0000000 --- a/src/prc8/scripts/nw_s1_conesonic.nss +++ /dev/null @@ -1,75 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Cone: Sonic -//:: NW_S1_ConeSonic -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A cone of damage eminated from the monster. Does - a set amount of damage based upon the creatures HD - and can be halved with a Reflex Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - int nLoop = nHD / 3; - - float fDelay; - - if(nLoop == 0) - { - nLoop = 1; - } - - //Calculate the damage - for (nLoop; nLoop > 0; nLoop--) - { - nDamage = nDamage + d6(2); - } - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eCone; - effect eVis = EffectVisualEffect(VFX_IMP_SONIC); - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != OBJECT_SELF) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_CONE_SONIC)); - //Determine effect delay - fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC,DAMAGE_TYPE_SONIC); - //Set damage effect - eCone = EffectDamage(nDamage, DAMAGE_TYPE_SONIC); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_dragfear.nss b/src/prc8/scripts/nw_s1_dragfear.nss deleted file mode 100644 index 0b5e882..0000000 --- a/src/prc8/scripts/nw_s1_dragfear.nss +++ /dev/null @@ -1,119 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Dragon Breath Fear -//:: NW_S1_DragFear -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Calculates the proper DC Save for the - breath weapon based on the HD of the dragon. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" -void main() -{ - //if (WildMagicOverride()) { return; } - //Declare major variables - int nAge = GetHitDice(OBJECT_SELF); - int nCount; - int nDC; - float fDelay; - object oTarget; - effect eBreath = EffectFrightened(); - effect eFear = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eBreath, eDur); - eLink = EffectLinkEffects(eLink, eFear); - - //Determine the duration and save DC - if (nAge <= 6) //Wyrmling - { - nDC = 13; - nCount = 1; - } - else if (nAge >= 7 && nAge <= 9) //Very Young - { - nDC = 15; - nCount = 2; - } - else if (nAge >= 10 && nAge <= 12) //Young - { - nDC = 17; - nCount = 3; - } - else if (nAge >= 13 && nAge <= 15) //Juvenile - { - nDC = 19; - nCount = 4; - } - else if (nAge >= 16 && nAge <= 18) //Young Adult - { - nDC = 21; - nCount = 5; - } - else if (nAge >= 19 && nAge <= 21) //Adult - { - nDC = 24; - nCount = 6; - } - else if (nAge >= 22 && nAge <= 24) //Mature Adult - { - nDC = 27; - nCount = 7; - } - else if (nAge >= 25 && nAge <= 27) //Old - { - nDC = 28; - nCount = 8; - } - else if (nAge >= 28 && nAge <= 30) //Very Old - { - nDC = 30; - nCount = 9; - } - else if (nAge >= 31 && nAge <= 33) //Ancient - { - nDC = 32; - nCount = 10; - } - else if (nAge >= 34 && nAge <= 37) //Wyrm - { - nDC = 34; - nCount = 11; - } - else if (nAge > 37) //Great Wyrm - { - nDC = 37; - nCount = 12; - } - PlayDragonBattleCry(); - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 14.0, PRCGetSpellTargetLocation(), TRUE); - //Get first target in spell area - while(GetIsObjectValid(oTarget)) - { - if(oTarget != OBJECT_SELF && !GetIsReactionTypeFriendly(oTarget)) - { - nCount = GetScaledDuration(nCount, oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_DRAGON_BREATH_FEAR)); - //Determine the effect delay time - fDelay = GetDistanceBetween(oTarget, OBJECT_SELF)/20; - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR, OBJECT_SELF, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCount))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 14.0, PRCGetSpellTargetLocation(), TRUE); - } -} - - diff --git a/src/prc8/scripts/nw_s1_dragfeara.nss b/src/prc8/scripts/nw_s1_dragfeara.nss deleted file mode 100644 index 2bb5009..0000000 --- a/src/prc8/scripts/nw_s1_dragfeara.nss +++ /dev/null @@ -1,45 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Fear On Enter -//:: NW_S1_DragFearA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Upon entering the aura of the creature the player - must make a will save or be struck with fear because - of the creatures presence. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" -void main() -{ - //Declare major variables - object oTarget = GetEnteringObject(); - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); - effect eDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eDur2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eFear = EffectFrightened(); - effect eLink = EffectLinkEffects(eFear, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - int nHD = GetHitDice(GetAreaOfEffectCreator()); - int nDC = 10 + GetHitDice(GetAreaOfEffectCreator())/3; - int nDuration = GetScaledDuration(nHD, oTarget); - if(GetIsEnemy(oTarget, GetAreaOfEffectCreator())) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(GetAreaOfEffectCreator(), SPELLABILITY_AURA_FEAR)); - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } -} diff --git a/src/prc8/scripts/nw_s1_feroc3.nss b/src/prc8/scripts/nw_s1_feroc3.nss deleted file mode 100644 index 58a44cb..0000000 --- a/src/prc8/scripts/nw_s1_feroc3.nss +++ /dev/null @@ -1,41 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Ferocity 3 -//:: NW_S1_Feroc3 -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - The Dex and Str of the target increases -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Aug 13, 2001 -//::////////////////////////////////////////////// - -void main() -{ -//:: Declare major variables - object oNPC = OBJECT_SELF; - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION); //:: Determine the duration by getting the con modifier - int nIncrease = 9; - int nDuration = 1 + nCONMod; - if(nDuration == 0) { nDuration = 1; } - - - effect eDex = EffectAbilityIncrease(ABILITY_DEXTERITY, nIncrease); - effect eStr = EffectAbilityIncrease(ABILITY_STRENGTH, nIncrease); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); - effect eLink = EffectLinkEffects(eStr, eDex); - eLink = EffectLinkEffects(eLink, eDur); - eLink = ExtraordinaryEffect(eLink); //:: Make effect extraordinary - - //effect eVis = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE); - SignalEvent(oNPC, EventSpellCastAt(oNPC, SPELLABILITY_FEROCITY_3, FALSE)); - if (nCONMod > 0) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oNPC, RoundsToSeconds(nDuration)); - //ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF) ; - } -} diff --git a/src/prc8/scripts/nw_s1_gazechaos.nss b/src/prc8/scripts/nw_s1_gazechaos.nss deleted file mode 100644 index f15212d..0000000 --- a/src/prc8/scripts/nw_s1_gazechaos.nss +++ /dev/null @@ -1,69 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Destroy Law -//:: NW_S1_GazeChaos -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save and are of Lawful alignment. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 13, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DESTROY_LAW)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!/*WillSave*/PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGaze, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazecharm.nss b/src/prc8/scripts/nw_s1_gazecharm.nss deleted file mode 100644 index a4af8cb..0000000 --- a/src/prc8/scripts/nw_s1_gazecharm.nss +++ /dev/null @@ -1,76 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Charm -//:: NW_S1_GazeCharm -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectCharmed(); - - effect eVis = EffectVisualEffect(VFX_IMP_CHARM); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE); - effect eLink = EffectLinkEffects(eDur, eVisDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != OBJECT_SELF) - { - nDuration = GetScaledDuration(nDuration, oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_CHARM)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - eGaze = GetScaledEffect(eGaze, oTarget); - eLink = EffectLinkEffects(eLink, eGaze); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - - diff --git a/src/prc8/scripts/nw_s1_gazeconfu.nss b/src/prc8/scripts/nw_s1_gazeconfu.nss deleted file mode 100644 index c3225bc..0000000 --- a/src/prc8/scripts/nw_s1_gazeconfu.nss +++ /dev/null @@ -1,77 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Confusion -//:: NW_S1_GazeConfu -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectConfused(); - effect eVis = EffectVisualEffect(VFX_IMP_CONFUSION_S); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eLink = EffectLinkEffects(eDur, eVisDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_CONFUSION)); - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - eGaze = GetScaledEffect(eGaze, oTarget); - eLink = EffectLinkEffects(eLink, eGaze); - - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_gazedaze.nss b/src/prc8/scripts/nw_s1_gazedaze.nss deleted file mode 100644 index c5b386d..0000000 --- a/src/prc8/scripts/nw_s1_gazedaze.nss +++ /dev/null @@ -1,74 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Daze -//:: NW_S1_GazeDaze -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDazed(); - effect eVis = EffectVisualEffect(VFX_IMP_DAZED_S); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eLink = EffectLinkEffects(eGaze, eVisDur); - eLink = EffectLinkEffects(eLink, eDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DAZE)); - - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!/*WillSave*/PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazedeath.nss b/src/prc8/scripts/nw_s1_gazedeath.nss deleted file mode 100644 index 0909b00..0000000 --- a/src/prc8/scripts/nw_s1_gazedeath.nss +++ /dev/null @@ -1,66 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Death -//:: NW_S1_GazeDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) || oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DEATH)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGaze, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazedomn.nss b/src/prc8/scripts/nw_s1_gazedomn.nss deleted file mode 100644 index d4ab12d..0000000 --- a/src/prc8/scripts/nw_s1_gazedomn.nss +++ /dev/null @@ -1,78 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Dominate -//:: NW_S1_GazeDomn -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDominated(); - effect eVis = EffectVisualEffect(VFX_IMP_DOMINATE_S); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED); - effect eLink = EffectLinkEffects(eDur, eVisDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DOMINATE)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(GetIsEnemy(oTarget)) - { - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - eGaze = GetScaledEffect(eGaze, oTarget); - eLink = EffectLinkEffects(eLink, eGaze); - - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazedoom.nss b/src/prc8/scripts/nw_s1_gazedoom.nss deleted file mode 100644 index 77e3c54..0000000 --- a/src/prc8/scripts/nw_s1_gazedoom.nss +++ /dev/null @@ -1,74 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze of Doom -//:: NW_S1_GazeDoom.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - If the target fails a save they recieve a -2 - penalty to all saves, attack rolls, damage and - skill checks for the duration of the spell. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Oct 22, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eVis = EffectVisualEffect(VFX_IMP_DOOM); - effect eSaves = EffectSavingThrowDecrease(SAVING_THROW_ALL, 2); - effect eAttack = EffectAttackDecrease(2); - effect eDamage = EffectDamageDecrease(2); - effect eSkill = EffectSkillDecrease(SKILL_ALL_SKILLS, 2); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eAttack, eDamage); - eLink = EffectLinkEffects(eLink, eSaves); - eLink = EffectLinkEffects(eLink, eSkill); - eLink = EffectLinkEffects(eLink, eDur); - - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, PRCGetSpellTargetLocation()); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(oTarget != oNPC) - { - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DOOM)); - //Spell Resistance and Saving throw - if (!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC)) - { - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink , oTarget, RoundsToSeconds(nDuration)); - } - } - } - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, PRCGetSpellTargetLocation()); - } -} diff --git a/src/prc8/scripts/nw_s1_gazeevil.nss b/src/prc8/scripts/nw_s1_gazeevil.nss deleted file mode 100644 index 4bbb418..0000000 --- a/src/prc8/scripts/nw_s1_gazeevil.nss +++ /dev/null @@ -1,70 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Deatroy Good -//:: NW_S1_GazeEvil -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 13, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DEATH)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGaze, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazefear.nss b/src/prc8/scripts/nw_s1_gazefear.nss deleted file mode 100644 index beb4157..0000000 --- a/src/prc8/scripts/nw_s1_gazefear.nss +++ /dev/null @@ -1,74 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Fear -//:: NW_S1_GazeFear -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - nDuration = GetScaledDuration(nDuration , oTarget); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectFrightened(); - effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eLink = EffectLinkEffects(eGaze, eVisDur); - eLink = EffectLinkEffects(eLink, eDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - nDuration = GetScaledDuration(nDuration , oTarget); - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_FEAR)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazegood.nss b/src/prc8/scripts/nw_s1_gazegood.nss deleted file mode 100644 index cb5c239..0000000 --- a/src/prc8/scripts/nw_s1_gazegood.nss +++ /dev/null @@ -1,70 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Deatroy Evil -//:: NW_S1_GazeGood -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 13, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DEATH)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGaze, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazelaw.nss b/src/prc8/scripts/nw_s1_gazelaw.nss deleted file mode 100644 index b230f4a..0000000 --- a/src/prc8/scripts/nw_s1_gazelaw.nss +++ /dev/null @@ -1,71 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Deatroy Chaos -//:: NW_S1_GazeLaw -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 13, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - if(nDuration == 0) { nDuration = 1; } - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectDeath(); - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - if(GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_DESTROY_LAW)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!/*WillSave*/PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGaze, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_gazestun.nss b/src/prc8/scripts/nw_s1_gazestun.nss deleted file mode 100644 index 2c597e7..0000000 --- a/src/prc8/scripts/nw_s1_gazestun.nss +++ /dev/null @@ -1,73 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Gaze: Stun -//:: NW_S1_GazeStun -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Cone shape that affects all within the AoE if they - fail a Will Save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 9, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "x0_i0_match" - -void main() -{ -//-------------------------------------------------------------------------- -// Make sure we are not blind -//-------------------------------------------------------------------------- - if (GetHasEffect(EFFECT_TYPE_BLINDNESS, OBJECT_SELF)) - { - FloatingTextStrRefOnCreature(84530, OBJECT_SELF, FALSE); - return; - } - - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDuration = 1 + (nHD / 3); - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eGaze = EffectStunned(); - effect eVis = EffectVisualEffect(VFX_IMP_STUN); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eVisDur = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eLink = EffectLinkEffects(eDur, eVisDur); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_GAZE_STUNNED)); - //Determine effect delay - float fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!/*WillSave*/PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - eGaze = GetScaledEffect(eGaze, oTarget); - eLink = EffectLinkEffects(eLink, eGaze); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - diff --git a/src/prc8/scripts/nw_s1_golemgas.nss b/src/prc8/scripts/nw_s1_golemgas.nss deleted file mode 100644 index b9e4155..0000000 --- a/src/prc8/scripts/nw_s1_golemgas.nss +++ /dev/null @@ -1,43 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Golem Breath -//:: NW_S1_GolemGas -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Iron Golem spits out a cone of poison. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 22, 2001 -//::////////////////////////////////////////////// - -#include "prc_inc_spells" - -//#include "wm_include" -void main() -{ - //if (WildMagicOverride()) { return; } - //Declare major variables - location lTargetLocation = PRCGetSpellTargetLocation(); - object oTarget; - effect eCone = EffectPoison(POISON_IRON_GOLEM); - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != OBJECT_SELF) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_GOLEM_BREATH_GAS)); - //Determine effect delay - float fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; - //Apply poison effect - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 10.0, lTargetLocation, TRUE); - } -} - - - diff --git a/src/prc8/scripts/nw_s1_hndbreath.nss b/src/prc8/scripts/nw_s1_hndbreath.nss deleted file mode 100644 index 4851df7..0000000 --- a/src/prc8/scripts/nw_s1_hndbreath.nss +++ /dev/null @@ -1,66 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Hell Hound Fire Breath -//:: NW_S1_HndBreath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A cone of fire eminates from the hound. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nDamage = d6(2); - - float fDelay; - - location lTargetLocation = PRCGetSpellTargetLocation(); - - effect eCone; - effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HELL_HOUND_FIREBREATH)); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_FIRE); - - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - - //Set damage effect - eCone = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eCone, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTargetLocation, TRUE); - } -} - - - diff --git a/src/prc8/scripts/nw_s1_howlconf.nss b/src/prc8/scripts/nw_s1_howlconf.nss deleted file mode 100644 index f9d770e..0000000 --- a/src/prc8/scripts/nw_s1_howlconf.nss +++ /dev/null @@ -1,67 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Confuse -//:: NW_S1_HowlConf -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 20ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDuration = 1 + (nHD/4); - if(nDuration == 0) { nDuration = 1; } - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_CONFUSION_S); - effect eHowl = EffectConfused(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eDur2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_MIND); - effect eLink = EffectLinkEffects(eHowl, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_CONFUSE)); - fDelay = GetDistanceToObject(oTarget)/10; - //Make a saving throw check - if(!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_howldaze.nss b/src/prc8/scripts/nw_s1_howldaze.nss deleted file mode 100644 index bd8e20c..0000000 --- a/src/prc8/scripts/nw_s1_howldaze.nss +++ /dev/null @@ -1,65 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Daze -//:: NW_S1_HowlDaze -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDuration = 1 + (nHD/4); - if(nDuration == 0) { nDuration = 1; } - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_DAZED_S); - effect eHowl = EffectDazed(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eDur2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_MIND); - effect eLink = EffectLinkEffects(eHowl, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_DAZE)); - fDelay = GetDistanceToObject(oTarget)/10; - //Make a saving throw check - if(!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_howldeath.nss b/src/prc8/scripts/nw_s1_howldeath.nss deleted file mode 100644 index 5730647..0000000 --- a/src/prc8/scripts/nw_s1_howldeath.nss +++ /dev/null @@ -1,59 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Death -//:: NW_S1_HowlDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_ODD); - effect eHowl = EffectDeath(); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_DEATH)); - fDelay = GetDistanceToObject(oTarget)/10; - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - //ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_howlfear.nss b/src/prc8/scripts/nw_s1_howlfear.nss deleted file mode 100644 index 13dcfaf..0000000 --- a/src/prc8/scripts/nw_s1_howlfear.nss +++ /dev/null @@ -1,68 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Fear -//:: NW_S1_HowlFear -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDuration = 1 + (nHD/4); - if(nDuration == 0) { nDuration = 1; } - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); - effect eHowl = EffectFrightened(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eDur2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_MIND); - effect eLink = EffectLinkEffects(eHowl, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - fDelay = GetDistanceToObject(oTarget)/10; - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_FEAR)); - - //Make a saving throw check - if(!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_howlparal.nss b/src/prc8/scripts/nw_s1_howlparal.nss deleted file mode 100644 index b0ecd43..0000000 --- a/src/prc8/scripts/nw_s1_howlparal.nss +++ /dev/null @@ -1,65 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Paralysis -//:: NW_S1_HowlParal -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDuration = 1 + (nHD/4); - if(nDuration == 0) { nDuration = 1; } - - float fDelay; - - effect eHowl = EffectParalyze(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_ODD); - effect eLink = EffectLinkEffects(eHowl, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - fDelay = GetDistanceToObject(oTarget)/10; - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_PARALYSIS)); - - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_NONE, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_howlsonic.nss b/src/prc8/scripts/nw_s1_howlsonic.nss deleted file mode 100644 index 4de9768..0000000 --- a/src/prc8/scripts/nw_s1_howlsonic.nss +++ /dev/null @@ -1,65 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Sonic -//:: NW_S1_HowlSonic -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDamage; - int nSonic = nHD/4; - if(nSonic == 0) { nSonic = 1; } - - effect eVis = EffectVisualEffect(VFX_IMP_SONIC); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_WAR_CRY); - - float fDelay; - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsFriend(oTarget) && oTarget != oNPC) - { - fDelay = GetDistanceToObject(oTarget)/20; - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_SONIC)); - nDamage = d6(nSonic); - //Make a saving throw check - if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SONIC, oNPC, fDelay)) - { - nDamage = nDamage / 2; - } - //Set damage effect - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_SONIC); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} \ No newline at end of file diff --git a/src/prc8/scripts/nw_s1_howlstun.nss b/src/prc8/scripts/nw_s1_howlstun.nss deleted file mode 100644 index 962d9b9..0000000 --- a/src/prc8/scripts/nw_s1_howlstun.nss +++ /dev/null @@ -1,66 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Howl: Stun -//:: NW_S1_HowlStun -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A howl emanates from the creature which affects - all within 10ft unless they make a save. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "NW_I0_SPELLS" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/4); - int nDuration = 1 + (nHD/4); - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_STUN); - effect eHowl = EffectStunned(); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eDur2 = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eImpact = EffectVisualEffect(VFX_FNF_HOWL_MIND); - effect eLink = EffectLinkEffects(eHowl, eDur); - eLink = EffectLinkEffects(eLink, eDur2); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && !GetIsFriend(oTarget) && oTarget != oNPC) - { - fDelay = GetDistanceToObject(oTarget)/10; - nDuration = GetScaledDuration(nDuration , oTarget); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_HOWL_STUN)); - - //Make a saving throw check - if(!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_krenscare.nss b/src/prc8/scripts/nw_s1_krenscare.nss deleted file mode 100644 index 738463e..0000000 --- a/src/prc8/scripts/nw_s1_krenscare.nss +++ /dev/null @@ -1,61 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Krenshar Fear Stare -//:: NW_S1_KrenScare -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Causes those in the gaze to be struck with fear -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 8, 2002 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nMetaMagic = PRCGetMetaMagicFeat(); - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S); - effect eFear = EffectFrightened(); - effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - //Link the fear and mind effects - effect eLink = EffectLinkEffects(eFear, eMind); - eLink = EffectLinkEffects(eLink, eDur); - - - //Get first target in the spell cone - oTarget = GetFirstObjectInShape(SHAPE_CONE, 10.0, PRCGetSpellTargetLocation(), TRUE); - while(GetIsObjectValid(oTarget)) - { - //Make faction check - if(GetIsEnemy(oTarget)) - { - fDelay = GetDistanceToObject(oTarget)/20; - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_KRENSHAR_SCARE)); - //Make a will save - if(!/*Will Save*/ PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR)) - { - //Apply the linked effects and the VFX impact - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(3))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get next target in the spell cone - oTarget = GetNextObjectInShape(SHAPE_CONE, 10.0, PRCGetSpellTargetLocation(), TRUE); - } -} diff --git a/src/prc8/scripts/nw_s1_mephsalt.nss b/src/prc8/scripts/nw_s1_mephsalt.nss deleted file mode 100644 index 03b0b97..0000000 --- a/src/prc8/scripts/nw_s1_mephsalt.nss +++ /dev/null @@ -1,63 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Salt Mephit Breath -//:: NW_S1_MephSalt -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Salt Mephit shoots out a bolt of corrosive material - that causes 1d4 damage and reduces AC and Attack by 2 - - This should be a cone - Jaysyn -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nDamage = d4(); - - effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); - effect eBolt, eAttack, eAC; - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_ACID); - - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nDamage == 0) {nTouch = 0;} - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_MEPHIT_SALT_BREATH)); - - //Set damage, AC mod and attack mod effects - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_ACID); - eAC = EffectACDecrease(2); - eAttack = EffectAttackDecrease(2); - effect eLink = EffectLinkEffects(eAttack, eAC); - eLink = EffectLinkEffects(eLink, eDur); - - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(3)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_mephsteam.nss b/src/prc8/scripts/nw_s1_mephsteam.nss deleted file mode 100644 index 9b46d89..0000000 --- a/src/prc8/scripts/nw_s1_mephsteam.nss +++ /dev/null @@ -1,67 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Steam Mephit Breath -//:: NW_S1_MephSteam -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Steam Mephit shoots out a bolt of steam - that causes 1d4 damage and reduces AC by 4 - and Attack by 2 - - This should be a cone - Jaysyn -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 11, 2001 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nDamage = d4(); - - - effect eVis = EffectVisualEffect(VFX_IMP_ACID_S); - effect eBolt, eAttack, eAC; - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_FIRE); - - //Make a ranged touch attack - int nTouch = TouchAttackRanged(oTarget); - if(nDamage == 0) {nTouch = 0;} - - if(nTouch > 0) - { - if(nTouch == 2) - { - nDamage *= 2; - } - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_MEPHIT_STEAM_BREATH)); - - //Set damage, AC mod and attack mod effects - eBolt = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - eAC = EffectACDecrease(4); - eAttack = EffectAttackDecrease(2); - effect eLink = EffectLinkEffects(eAC, eAttack); - eLink = EffectLinkEffects(eLink, eDur); - - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(3)); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eBolt, oTarget); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); - } -} diff --git a/src/prc8/scripts/nw_s1_mumundead.nss b/src/prc8/scripts/nw_s1_mumundead.nss deleted file mode 100644 index f11db57..0000000 --- a/src/prc8/scripts/nw_s1_mumundead.nss +++ /dev/null @@ -1,53 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Bolster Undead -//:: NW_S1_MumUndead -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - This spell increases the Turn Resistance of - all undead around the caster by an amount - scaled with HD. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 22, 2002 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nScaling = nHD / 4; - - if(nScaling == 0) {nScaling = 1;} - - float fDelay; - - effect eTurn = EffectTurnResistanceIncrease(nScaling); - effect eVis = EffectVisualEffect(VFX_IMP_HEAD_EVIL); - effect eImpact = EffectVisualEffect(VFX_FNF_LOS_EVIL_30); - - ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetLocation(oNPC)); - - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(GetIsFriend(oTarget)) - { - fDelay = GetRandomDelay(); - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_MUMMY_BOLSTER_UNDEAD, FALSE)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTurn, oTarget, RoundsToSeconds(10))); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, GetLocation(oNPC)); - } -} diff --git a/src/prc8/scripts/nw_s1_pulschrdr.nss b/src/prc8/scripts/nw_s1_pulschrdr.nss deleted file mode 100644 index b55902c..0000000 --- a/src/prc8/scripts/nw_s1_pulschrdr.nss +++ /dev/null @@ -1,73 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Charisma Drain -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_CHARISMA)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_CHARISMA, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get first target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulscold.nss b/src/prc8/scripts/nw_s1_pulscold.nss deleted file mode 100644 index c5ff7d2..0000000 --- a/src/prc8/scripts/nw_s1_pulscold.nss +++ /dev/null @@ -1,68 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Cold -//:: NW_S1_PulsCold -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage = d6(nHD); - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_FROST_S); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_COLD); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_COLD)); - - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_COLD); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_COLD); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulscondr.nss b/src/prc8/scripts/nw_s1_pulscondr.nss deleted file mode 100644 index bfdbfcf..0000000 --- a/src/prc8/scripts/nw_s1_pulscondr.nss +++ /dev/null @@ -1,71 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Constitution Drain -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_CONSTITUTION)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_CONSTITUTION, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get first target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulsdeath.nss b/src/prc8/scripts/nw_s1_pulsdeath.nss deleted file mode 100644 index 7c949d1..0000000 --- a/src/prc8/scripts/nw_s1_pulsdeath.nss +++ /dev/null @@ -1,68 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Death -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_DEATH); - effect eHowl = EffectDeath(); - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - if(oTarget != OBJECT_SELF) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_DEATH)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_DEATH, oNPC, fDelay)) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - //DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulsdexdr.nss b/src/prc8/scripts/nw_s1_pulsdexdr.nss deleted file mode 100644 index d29872a..0000000 --- a/src/prc8/scripts/nw_s1_pulsdexdr.nss +++ /dev/null @@ -1,70 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Dexterity Drain -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_DEXTERITY)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_DEXTERITY, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get first target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulsdis.nss b/src/prc8/scripts/nw_s1_pulsdis.nss deleted file mode 100644 index f81568c..0000000 --- a/src/prc8/scripts/nw_s1_pulsdis.nss +++ /dev/null @@ -1,85 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Disease -//:: NW_S1_PulsDis -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of disease spreads out from the creature - and infects all those within 10ft -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Aug 14, 2000 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nRacial = MyPRCGetRacialType(oNPC); - int nHD = GetHitDice(oNPC); - int nDamage = d6(nHD); - int nDisease; - - float fDelay; - - effect eDisease; - effect ePulse = EffectVisualEffect(266); - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NATURE); - - ApplyEffectAtLocation(DURATION_TYPE_INSTANT, ePulse, GetLocation(oNPC)); - - //Determine the disease type based on the Racial Type - switch (nRacial) - { - case RACIAL_TYPE_VERMIN: - nDisease = DISEASE_VERMIN_MADNESS; - break; - case RACIAL_TYPE_UNDEAD: - nDisease = DISEASE_FILTH_FEVER; - break; - case RACIAL_TYPE_OUTSIDER: - nDisease = DISEASE_DEMON_FEVER; - break; - case RACIAL_TYPE_MAGICAL_BEAST: - nDisease = DISEASE_SOLDIER_SHAKES; - break; - case RACIAL_TYPE_ABERRATION: - nDisease = DISEASE_BLINDING_SICKNESS; - break; - default: - nDisease = DISEASE_MINDFIRE; - break; - } - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_PULSE_DISEASE)); - //Determine effect delay - fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; - eDisease = EffectDisease(nDisease); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDisease, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulselec.nss b/src/prc8/scripts/nw_s1_pulselec.nss deleted file mode 100644 index 2f85614..0000000 --- a/src/prc8/scripts/nw_s1_pulselec.nss +++ /dev/null @@ -1,68 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Lightning -//:: NW_S0_CallLghtn.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - All creatures within 10ft of the creature take - 1d6 per HD up to 10d6 -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 22, 2001 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - - effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S); - effect eLightning = EffectBeam(VFX_BEAM_LIGHTNING, oNPC, BODY_NODE_CHEST); - effect eHowl = EffectVisualEffect(VFX_IMP_PULSE_COLD); - - DelayCommand(0.5, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eHowl, GetLocation(oNPC))); - - float fDelay; - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_LIGHTNING)); - //Roll the damage - nDamage = d6(nHD); - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_ELECTRICITY); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_ELECTRICAL); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eLightning,oTarget, 0.5)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulsfire.nss b/src/prc8/scripts/nw_s1_pulsfire.nss deleted file mode 100644 index 9270aa9..0000000 --- a/src/prc8/scripts/nw_s1_pulsfire.nss +++ /dev/null @@ -1,69 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Fire -//:: NW_S1_PulsFire -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_FLAME_S); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_FIRE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, OBJECT_SELF); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != OBJECT_SELF) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_PULSE_FIRE)); - //Roll the damage - nDamage = d6(nHD); - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_FIRE); - //Determine effect delay - fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20; - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - if(nDamage > 0) - { - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulsholy.nss b/src/prc8/scripts/nw_s1_pulsholy.nss deleted file mode 100644 index 20ae463..0000000 --- a/src/prc8/scripts/nw_s1_pulsholy.nss +++ /dev/null @@ -1,89 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Holy -//:: NW_S1_PulsHoly -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. Undead are damaged, allies are healed. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_HEALING_M); - effect eVis2 = EffectVisualEffect(VFX_IMP_SUNSTRIKE); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_HOLY); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Roll the amount to heal or damage - nDamage = d4(nHD); - //If the target is not undead - if (MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) - { - //Make a faction check - if(oTarget != oNPC) - { - if(GetIsFriend(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_HOLY, FALSE)); - //Set heal effect - eHowl = EffectHeal(nDamage); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - else - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_DIVINE); - //Set damage effect - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_DIVINE) ; - if(nDamage > 0) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_HOLY)); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulsintdr.nss b/src/prc8/scripts/nw_s1_pulsintdr.nss deleted file mode 100644 index 8558364..0000000 --- a/src/prc8/scripts/nw_s1_pulsintdr.nss +++ /dev/null @@ -1,72 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Intelligence Drain -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_INTELLIGENCE)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_INTELLIGENCE, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get first target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulslvldr.nss b/src/prc8/scripts/nw_s1_pulslvldr.nss deleted file mode 100644 index f65e073..0000000 --- a/src/prc8/scripts/nw_s1_pulslvldr.nss +++ /dev/null @@ -1,62 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Level Drain -//:: NW_S1_PulsLvlDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetLocation(oNPC)); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - fDelay = GetSpellEffectDelay(GetLocation(oNPC), oTarget)/20; - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Apply the VFX impact and effects - eHowl = EffectNegativeLevel(1); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulsneg.nss b/src/prc8/scripts/nw_s1_pulsneg.nss deleted file mode 100644 index 9bfa749..0000000 --- a/src/prc8/scripts/nw_s1_pulsneg.nss +++ /dev/null @@ -1,87 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Negative -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. Undead are healed. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - int nDamage; - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_HEALING_M); - effect eVis2 = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Roll the amount to heal or damage - nDamage = d4(nHD); - //If the target is undead - if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) - { - //Make a faction check - if(GetIsFriend(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_HOLY, FALSE)); - //Set heal effect - eHowl = EffectHeal(nDamage); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - else - { - if(!GetIsReactionTypeFriendly(oTarget) && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD) - { - //Adjust the damage based on the Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE); - //Set damage effect - eHowl = EffectDamage(nDamage, DAMAGE_TYPE_NEGATIVE); - if(nDamage > 0) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_HOLY)); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget)); - } - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} diff --git a/src/prc8/scripts/nw_s1_pulspois.nss b/src/prc8/scripts/nw_s1_pulspois.nss deleted file mode 100644 index 252ae3a..0000000 --- a/src/prc8/scripts/nw_s1_pulspois.nss +++ /dev/null @@ -1,138 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Poison -//:: NW_S1_PulsPois -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. All who make a reflex save are not - poisoned. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 23, 2000 -//::////////////////////////////////////////////// -#include "prc_inc_racial" -//#include "wm_include" - -void main() -{ -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - int nRacial = MyPRCGetRacialType(oNPC); - int nPoison; - - float fDelay; - - effect ePoison; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NATURE); - - //Determine the poison type based on the Racial Type and HD - switch (nRacial) - { - case RACIAL_TYPE_OUTSIDER: - if (nHD <= 9) - { - nPoison = POISON_QUASIT_VENOM; - } - else if (nHD > 9 && nHD < 13) - { - nPoison = POISON_BEBILITH_VENOM; - } - else if (nHD >= 13) - { - nPoison = POISON_PIT_FIEND_ICHOR; - } - break; - case RACIAL_TYPE_VERMIN: - if (nHD < 3) - { - nPoison = POISON_TINY_SPIDER_VENOM; - } - else if (nHD <= 3 && nHD < 6) - { - nPoison = POISON_SMALL_SPIDER_VENOM; - } - else if (nHD <= 6 && nHD < 9) - { - nPoison = POISON_MEDIUM_SPIDER_VENOM; - } - else if (nHD <= 9 && nHD < 12) - { - nPoison = POISON_LARGE_SPIDER_VENOM; - } - else if (nHD <= 12 && nHD < 15) - { - nPoison = POISON_HUGE_SPIDER_VENOM; - } - else if (nHD <= 15 && nHD < 18) - { - nPoison = POISON_GARGANTUAN_SPIDER_VENOM; - } - else if (nHD >= 18) - { - nPoison = POISON_COLOSSAL_SPIDER_VENOM; - } - break; - default: - if (nHD < 3) - { - nPoison = POISON_NIGHTSHADE; - } - else if (nHD <= 3 && nHD < 6) - { - nPoison = POISON_BLADE_BANE; - } - else if (nHD <= 6 && nHD < 9) - { - nPoison = POISON_BLOODROOT; - } - else if (nHD <= 9 && nHD < 12) - { - nPoison = POISON_LARGE_SPIDER_VENOM; - } - else if (nHD <= 12 && nHD < 15) - { - nPoison = POISON_LICH_DUST; - } - else if (nHD <= 15 && nHD < 18) - { - nPoison = POISON_DARK_REAVER_POWDER; - } - else if (nHD >= 18 ) - { - nPoison = POISON_BLACK_LOTUS_EXTRACT; - } - break; - } - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_POISON)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - ePoison = EffectPoison(nPoison); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoison, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - - diff --git a/src/prc8/scripts/nw_s1_pulsspore.nss b/src/prc8/scripts/nw_s1_pulsspore.nss deleted file mode 100644 index 7e9e34d..0000000 --- a/src/prc8/scripts/nw_s1_pulsspore.nss +++ /dev/null @@ -1,50 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Vrock Spores -//:: NW_S1_PulsSpore -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of disease spreads out from the creature - and infects all those within 10ft -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 8, 2002 -//::////////////////////////////////////////////// -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - float fDelay; - effect eDisease; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NATURE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_DISEASE)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - eDisease = EffectDisease(DISEASE_SOLDIER_SHAKES); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDisease, oTarget)); - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetLocation(oNPC)); - } -} diff --git a/src/prc8/scripts/nw_s1_pulsstrdr.nss b/src/prc8/scripts/nw_s1_pulsstrdr.nss deleted file mode 100644 index 5f88eab..0000000 --- a/src/prc8/scripts/nw_s1_pulsstrdr.nss +++ /dev/null @@ -1,71 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Strength Drain -//:: NW_S1_PulsDeath -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - while(GetIsObjectValid(oTarget)) - { - if(oTarget != oNPC) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_STRENGTH)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_STRENGTH, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - } - //Get next target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} - diff --git a/src/prc8/scripts/nw_s1_pulswind.nss b/src/prc8/scripts/nw_s1_pulswind.nss deleted file mode 100644 index 0572407..0000000 --- a/src/prc8/scripts/nw_s1_pulswind.nss +++ /dev/null @@ -1,51 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse Whirlwind -//:: NW_S1_PulsWind -//:: Copyright (c) 2001 Bioware Corp. -//:://///////////////////////////////////////////// -/* - All those that fail a save are knocked - down by the elemental whirlwind. -*/ -//:://///////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 8, 2002 -//:://///////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nSTRMod = GetAbilityModifier(ABILITY_STRENGTH, oNPC); - int nDC = 10 +nSTRMod+ (nHD/2); - - effect eDown = EffectKnockdown(); - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_WIND); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oNPC); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != oNPC) - { - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDown, oTarget, 5.0); - } - //Get next target in spell area - } - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(oNPC)); - } -} diff --git a/src/prc8/scripts/nw_s1_pulswisdr.nss b/src/prc8/scripts/nw_s1_pulswisdr.nss deleted file mode 100644 index b1bf68c..0000000 --- a/src/prc8/scripts/nw_s1_pulswisdr.nss +++ /dev/null @@ -1,68 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Pulse: Wisdom Drain -//:: NW_S1_PulsWisDr -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - A wave of energy emanates from the creature which affects - all within 10ft. Damage can be reduced by half for all - damaging variants. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 14, 2000 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget; - - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - int nDamage = nHD/5; - - if (nDamage == 0) {nDamage = 1;} - - float fDelay; - - effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY); - effect eHowl; - effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_NEGATIVE); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, OBJECT_SELF); - - //Get first target in spell area - oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetLocation(OBJECT_SELF)); - while(GetIsObjectValid(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget) && oTarget != OBJECT_SELF) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_PULSE_ABILITY_DRAIN_WISDOM)); - //Determine effect delay - fDelay = GetDistanceBetween(oNPC, oTarget)/20; - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NEGATIVE, oNPC, fDelay)) - { - //Set the Ability mod and change to supernatural effect - eHowl = EffectAbilityDecrease(ABILITY_WISDOM, nDamage); - eHowl = SupernaturalEffect(eHowl); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHowl, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - //Get first target in spell area - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, GetLocation(OBJECT_SELF)); - } -} - diff --git a/src/prc8/scripts/nw_s1_smokeclaw.nss b/src/prc8/scripts/nw_s1_smokeclaw.nss deleted file mode 100644 index 6db3666..0000000 --- a/src/prc8/scripts/nw_s1_smokeclaw.nss +++ /dev/null @@ -1,64 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Smoke Claws -//:: NW_S1_SmokeClaw -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - If a Belker succeeds at a touch attack the - target breaths in part of the Belker and suffers - 3d4 damage per round until a Fortitude save is - made. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 23 , 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//#include "wm_include" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - - int bSave = FALSE; - - effect eVis = EffectVisualEffect(VFX_COM_BLOOD_REG_RED); - effect eSmoke; - float fDelay = 0.0; - - //Make a touch attack - if(TouchAttackMelee(oTarget)) - { - if(!GetIsReactionTypeFriendly(oTarget)) - { - //Make a saving throw check - while (bSave == FALSE) - { - //Make a saving throw check - if(!/*FortSave*/PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE, oNPC, fDelay)) - { - bSave = TRUE; - } - else - { - //Set damage - eSmoke = EffectDamage(d4(3)); - //Apply the VFX impact and effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSmoke, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - //Increment the delay - fDelay = fDelay + 6.0; - } - } - } - } -} diff --git a/src/prc8/scripts/nw_s1_stink_a.nss b/src/prc8/scripts/nw_s1_stink_a.nss deleted file mode 100644 index 67652dd..0000000 --- a/src/prc8/scripts/nw_s1_stink_a.nss +++ /dev/null @@ -1,57 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Stinking Cloud On Enter -//:: NW_S1_Stink_A.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Those within the area of effect must make a - fortitude save or be dazed. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 17, 2001 -//::////////////////////////////////////////////// - -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); //Get the first object in the persistant area - - int nHD = GetHitDice(oNPC); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oNPC); - int nDC = 10 +nCONMod+ (nHD/2); - - effect eStink = EffectDazed(); - effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eMind, eStink); - eLink = EffectLinkEffects(eLink, eDur); - - effect eVis = EffectVisualEffect(VFX_IMP_DAZED_S); - - float fDelay; - - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - if(MyPRCGetRacialType(oTarget) != RACIAL_TYPE_VERMIN) - { - if(GetIsEnemy(oTarget)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_STINKING_CLOUD)); - //Make a Fort Save - if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_POISON)) - { - fDelay = GetRandomDelay(0.25, 1.0); - //Apply the VFX impact and linked effects - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(2))); - } - } - } -} diff --git a/src/prc8/scripts/nw_s1_trogstink.nss b/src/prc8/scripts/nw_s1_trogstink.nss deleted file mode 100644 index 38cfb7f..0000000 --- a/src/prc8/scripts/nw_s1_trogstink.nss +++ /dev/null @@ -1,21 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Troglidyte Stench -//:: nw_s1_TrogStench.nss -//:: Copyright (c) 2004 Bioware Corp. -//::////////////////////////////////////////////// -/* - Objects entering the aura must make a fortitude saving - throw (DC 13) or suffer 1d6 points of Strength - Ability Damage -*/ -//::////////////////////////////////////////////// -//:: Created By: Craig Welburn -//:: Created On: Nov 6, 2004 -//::////////////////////////////////////////////// - -void main() -{ - effect eStench = EffectAreaOfEffect(AOE_MOB_TROGLODYTE_STENCH); - eStench = UnyieldingEffect(eStench); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStench, OBJECT_SELF); -} diff --git a/src/prc8/scripts/nw_s1_trogstinka.nss b/src/prc8/scripts/nw_s1_trogstinka.nss deleted file mode 100644 index 9f3c20e..0000000 --- a/src/prc8/scripts/nw_s1_trogstinka.nss +++ /dev/null @@ -1,66 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Aura of Troglodyte Stench On Enter -//:: nw_s1_trogstinkA.nss -//:: Copyright (c) 2004 Bioware Corp. -//::////////////////////////////////////////////// -/* - Objects entering the Stench must make a fortitude - saving throw (DC 13) or suffer 1D6 points of - Strength Ability Damage. -*/ -//::////////////////////////////////////////////// -//:: Created By: Craig Welburn -//:: Created On: Nov 6, 2004 -//::////////////////////////////////////////////// -#include "X0_I0_SPELLS" - - -//:: Modified to be CON based, like PnP - Jaysyn - -void main() -{ -//:: Declare major variables - object oTarget = GetEnteringObject(); - object oSource = GetAreaOfEffectCreator(); - - int nHD = GetHitDice(oSource); - int nCONMod = GetAbilityModifier(ABILITY_CONSTITUTION, oSource); - int nDC = 10 +nCONMod+ (nHD/2); - -//:: Declare all the required effects - effect eVis1; - effect eVis2; - effect eStrenghDrain; - - if(!GetHasSpellEffect(SPELLABILITY_TROGLODYTE_STENCH, oTarget)) - { - // Is the target a valid creature - if((GetIsEnemy(oTarget, oSource)) - && (GetIsReactionTypeFriendly(oTarget, oSource) != TRUE)) - { - // Notify the target that they are being attacked - SignalEvent(oTarget, EventSpellCastAt(oSource, AOE_MOB_TROGLODYTE_STENCH)); - - // Prepare the visual effect for the casting and saving throw - eVis1 = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE); - eVis2 = EffectVisualEffect(VFX_IMP_FORTITUDE_SAVING_THROW_USE); - - // Create the 1d6 strength reduction effect - // and make it supernatural so it can be dispelled - eStrenghDrain = EffectAbilityDecrease(ABILITY_STRENGTH, d6()); - eStrenghDrain = SupernaturalEffect(eStrenghDrain); - - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget); - - // Make a Fortitude saving throw, DC 13 and apply the effect if it fails - if (!MySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_POISON, oSource)) - { - if (GetIsImmune(oTarget, IMMUNITY_TYPE_POISON) == FALSE) - { - ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis1, oTarget); - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStrenghDrain, oTarget, RoundsToSeconds(10)); - } - } - } - } -} diff --git a/src/prc8/scripts/nw_s1_tyrantfga.nss b/src/prc8/scripts/nw_s1_tyrantfga.nss deleted file mode 100644 index a2752cb..0000000 --- a/src/prc8/scripts/nw_s1_tyrantfga.nss +++ /dev/null @@ -1,56 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Tyrant Fog Zombie Mist Heartbeat -//:: NW_S1_TyrantFgA.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creatures entering the area around the zombie - must save or take 1 point of Constitution - damage. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -#include "NW_I0_SPELLS" -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = GetAreaOfEffectCreator(); - object oTarget = GetEnteringObject(); - //if (NullMagicOverride(GetArea(oTarget), oTarget, oTarget)) {return;} - - int bAbsent = TRUE; - int nHD = GetHitDice(oNPC); - int nCHAMod = GetAbilityModifier(ABILITY_CHARISMA, oNPC); - int nDC = 10 +nCHAMod+ (nHD/2); - - effect eTest; - effect eCon = EffectAbilityDecrease(ABILITY_CONSTITUTION, 1); - eCon = ExtraordinaryEffect(eCon); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE); - effect eLink = EffectLinkEffects(eCon, eDur); - - if(!GetHasSpellEffect(SPELLABILITY_TYRANT_FOG_MIST, oTarget)) - { - if(bAbsent == TRUE) - { - if(GetIsEnemy(oTarget, oNPC)) - { - //Fire cast spell at event for the specified target - SignalEvent(oTarget, EventSpellCastAt(oNPC, SPELLABILITY_TYRANT_FOG_MIST)); - //Make a saving throw check - if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_POISON)) - { - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(5)); - } - } - } - } -} diff --git a/src/prc8/scripts/nw_s1_tyrantfog.nss b/src/prc8/scripts/nw_s1_tyrantfog.nss deleted file mode 100644 index e3ab9e6..0000000 --- a/src/prc8/scripts/nw_s1_tyrantfog.nss +++ /dev/null @@ -1,25 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Tyrant Fog Zombie Mist -//:: NW_S1_TyrantFog.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Creatures entering the area around the zombie - must save or take 1 point of Constitution - damage. -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: May 25, 2001 -//::////////////////////////////////////////////// -//#include "wm_include" -#include "prc_inc_spells" - -void main() -{ - //if (WildMagicOverride()) { return; } - - //Declare and apply the AOE - effect eAOE = EffectAreaOfEffect(AOE_MOB_TYRANT_FOG); - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eAOE, OBJECT_SELF, HoursToSeconds(100)); -} diff --git a/src/prc8/scripts/nw_s2_divprot.nss b/src/prc8/scripts/nw_s2_divprot.nss deleted file mode 100644 index fff40ab..0000000 --- a/src/prc8/scripts/nw_s2_divprot.nss +++ /dev/null @@ -1,45 +0,0 @@ -//:://///////////////////////////////////////////// -//:: Divine Protection -//:: NW_S2_DivProt.nss -//:: Copyright (c) 2001 Bioware Corp. -//::////////////////////////////////////////////// -/* - Makes the target creature invisible to hostile - creatures unless they make a Will Save to ignore - the Sanctuary Effect -*/ -//::////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 8, 2002 -//::////////////////////////////////////////////// -#include "prc_inc_spells" -//#include "wm_include" -void main() -{ - //if (WildMagicOverride()) { return; } - -//:: Declare major variables - object oNPC = OBJECT_SELF; - object oTarget = PRCGetSpellTargetObject(); - - effect eVis = EffectVisualEffect(VFX_DUR_SANCTUARY); - effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE); - int nDC = 10 + GetAbilityModifier(ABILITY_CHARISMA) + GetLevelByTypeDivine(oNPC); - effect eSanc = EffectSanctuary(nDC); - - effect eLink = EffectLinkEffects(eVis, eSanc); - eLink = EffectLinkEffects(eLink, eDur); - //Fire cast spell at event for the specified target - SignalEvent(OBJECT_SELF, EventSpellCastAt(oNPC, SPELLABILITY_DIVINE_PROTECTION, FALSE)); - - int nDuration = GetLevelByTypeDivine(oNPC); - //Enter Metamagic conditions - int nMetaMagic = PRCGetMetaMagicFeat(); - if (nMetaMagic == METAMAGIC_EXTEND) - { - nDuration = nDuration *2; //Duration is +100% - } - //Apply the VFX impact and effects - ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nDuration)); -} - diff --git a/src/prc8/scripts/nw_s3_balordeth.nss b/src/prc8/scripts/nw_s3_balordeth.nss deleted file mode 100644 index 96d0afb..0000000 --- a/src/prc8/scripts/nw_s3_balordeth.nss +++ /dev/null @@ -1,62 +0,0 @@ -// HCR v3.2.0 - Execute default death script after fireball effects is complete. -//:://////////////////////////////////////////////////////////////////////////// -//:: FileName: NW_S3_BALORDETH -//:://////////////////////////////////////////////////////////////////////////// -/* - Fireball explosion does 50 damage to all within 20ft. -*/ -//:://////////////////////////////////////////////////////////////////////////// -//:: Created By: Preston Watamaniuk -//:: Created On: Jan 9, 2002 -//:://////////////////////////////////////////////////////////////////////////// -#include "NW_I0_SPELLS" -#include "prc_inc_spells" -//:://////////////////////////////////////////////////////////////////////////// -void main() -{ - // Declare major variables. - int nMetaMagic = PRCGetMetaMagicFeat(); - int nDamage; - float fDelay; - effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); - effect eDam; - - // Apply the fireball explosion. - effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); - location lTarget = GetLocation(OBJECT_SELF); - ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplode, lTarget); - - // Cycle through the targets until an invalid object is captured. - object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR); - while (GetIsObjectValid(oTarget)) - { - // Fire cast spell at event for the specified target. - SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_FIREBALL)); - - // Calculate delay based on distance between explosion and the target. - fDelay = (GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20); - if (!PRCDoResistSpell(OBJECT_SELF, oTarget, FloatToInt(fDelay))) - { - // Adjust damage based on Reflex Save, Evasion and Improved Evasion. - nDamage = PRCGetReflexAdjustedDamage(50, oTarget, GetSpellSaveDC(), SAVING_THROW_TYPE_FIRE); - if (nDamage > 0) - { - // Apply effects to the currently selected target. - eDam = EffectDamage(nDamage, DAMAGE_TYPE_FIRE); - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); - - // This visual effect is applied to the target object not the - // location as above. This visual effect represents the flame that - // erupts on the target not on the ground. - DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); - } - } - - // Select the next target. - oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR); - } - - // HCR 3.0 - Call default death script. - ExecuteScript("nw_c2_default7", OBJECT_SELF); -} -//:://////////////////////////////////////////////////////////////////////////// diff --git a/unpack_haks.cmd b/unpack_haks.cmd new file mode 100644 index 0000000..6ecd98e --- /dev/null +++ b/unpack_haks.cmd @@ -0,0 +1 @@ +nasher unpack pepshak --verbose --removeDeleted:false \ No newline at end of file diff --git a/unpack_module.cmd b/unpack_module.cmd new file mode 100644 index 0000000..faad5fb --- /dev/null +++ b/unpack_module.cmd @@ -0,0 +1 @@ +nasher unpack default --verbose --removeDeleted:false \ No newline at end of file diff --git a/update_src_from_haks.cmd b/update_src_from_haks.cmd new file mode 100644 index 0000000..72dec37 --- /dev/null +++ b/update_src_from_haks.cmd @@ -0,0 +1 @@ +nasher unpack pepshak --verbose -y \ No newline at end of file diff --git a/update_src_from_module.cmd b/update_src_from_module.cmd new file mode 100644 index 0000000..44d2155 --- /dev/null +++ b/update_src_from_module.cmd @@ -0,0 +1 @@ +nasher unpack default --verbose -y \ No newline at end of file