diff --git a/cdtweaks/bam/cdhlfrls.bam b/cdtweaks/bam/cdhlfrls.bam deleted file mode 100644 index 9a56d478..00000000 Binary files a/cdtweaks/bam/cdhlfrls.bam and /dev/null differ diff --git a/cdtweaks/bam/cdhlgaim.bam b/cdtweaks/bam/cdhlgaim.bam deleted file mode 100644 index ae105c35..00000000 Binary files a/cdtweaks/bam/cdhlgaim.bam and /dev/null differ diff --git a/cdtweaks/bam/cdpsnsav.bam b/cdtweaks/bam/cdpsnsav.bam deleted file mode 100644 index 37d2bbc8..00000000 Binary files a/cdtweaks/bam/cdpsnsav.bam and /dev/null differ diff --git a/cdtweaks/bam/gtdrkbls.bam b/cdtweaks/bam/gtdrkbls.bam deleted file mode 100644 index 347e40bc..00000000 Binary files a/cdtweaks/bam/gtdrkbls.bam and /dev/null differ diff --git a/cdtweaks/bam/gtdvngrc.bam b/cdtweaks/bam/gtdvngrc.bam deleted file mode 100644 index 6fbb7c73..00000000 Binary files a/cdtweaks/bam/gtdvngrc.bam and /dev/null differ diff --git a/cdtweaks/bam/gtmharmr.bam b/cdtweaks/bam/gtmharmr.bam deleted file mode 100644 index 0422f3f8..00000000 Binary files a/cdtweaks/bam/gtmharmr.bam and /dev/null differ diff --git a/cdtweaks/bam/gtwpnfin.bam b/cdtweaks/bam/gtwpnfin.bam deleted file mode 100644 index 28ecaf8e..00000000 Binary files a/cdtweaks/bam/gtwpnfin.bam and /dev/null differ diff --git a/cdtweaks/languages/english/dual_wield.tra b/cdtweaks/languages/english/dual_wield.tra index f84ff0f3..df617344 100644 --- a/cdtweaks/languages/english/dual_wield.tra +++ b/cdtweaks/languages/english/dual_wield.tra @@ -1 +1 @@ -@0 = "Medium or Heavy Armor Equipped" \ No newline at end of file +@0 = "Dual-Wield" \ No newline at end of file diff --git a/cdtweaks/languages/english/nwn_barbarian_rage.tra b/cdtweaks/languages/english/nwn_barbarian_rage.tra new file mode 100644 index 00000000..3211329c --- /dev/null +++ b/cdtweaks/languages/english/nwn_barbarian_rage.tra @@ -0,0 +1,19 @@ +@0 = "Barbarian Rage + +The character is enraged for 7 rounds (plus a number of rounds equal to his Constitution modifier), which grants the character a +4 bonus to Strength and Constitution, a -2 penalty to Armor Class, and a +2 bonus to Saving Throws vs. Spell. + +Terrifying Rage: While the barbarian is raging, any enemy (with less than the barbarian's hit dice) that comes close to him must make a Save vs. Death or become panicked for 1d3 rounds. Opponents with the same hit dice as the barbarian will not flee but will receive a -2 penalty to attack and saving throw rolls. Creatures with more than the barbarian's hit dice are not affected by the rage. + +Thundering Rage: Any weapon the barbarian wields while in a rage does an additional 2d6 points of damage on a critical hit. There is a 25% chance for a creature hit by one of the barbarian's weapons to be deafened for 3 rounds. +" + +@1 = "Terrifying Rage" + +@2 = "Thundering Rage (Critical Hit)" +@3 = "Thundering Rage (Deafness)" +@4 = "Deafened" + +@5 = "The selected character is already under the effects of Barbarian Rage" +@6 = "Trembling with fear" +@7 = "Panic" +@8 = "Unaffected by effects from Terrifying Rage" \ No newline at end of file diff --git a/cdtweaks/languages/english/weidu.tra b/cdtweaks/languages/english/weidu.tra index 06daf4ee..9f100aba 100644 --- a/cdtweaks/languages/english/weidu.tra +++ b/cdtweaks/languages/english/weidu.tra @@ -457,34 +457,6 @@ The uninstall messages above are normal and expected. @264000 = "PnP Potions [Luke]" -@265000 = "Spontaneous Casting for Clerics [Luke]" - -@266000 = "Weapon Finesse feat for Thieves [Luke]" - -@267000 = "Dual-Wield feat for Rangers [Luke]" - -@268000 = ~"Force" the Archer kit to use bows [Luke]~ - -@269000 = "NWN-ish Armor vs. Dexterity [Luke]" - -@270000 = "Defensive Roll feat for Thieves [Luke]" - -@271000 = "Divine Grace / Dark Blessing feat for Paladins / Blackguards [Luke]" - -@272000 = "Good Aim racial feat for Halflings [Luke]" - -@273000 = "Cleave Feat for Fighters [Luke]" - -@274000 = "Sneak Attack class feat for Blackguards [Luke]" - -@275000 = "Fearless racial feat for Halflings [Luke]" - -@276000 = "Poison Save class feat for Assassins [Luke]" - -@277000 = "Planar Turning class feat for Clerics / Paladins [Luke]" - -@278000 = "Circle Kick class feat for Monks [Luke]" - /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ @@ -802,3 +774,39 @@ Use Baldur.lua options: a7_interval_ini @504000 = ~Allow Yeslick to Use Axes~ @505000 = ~Ensure Shar-Teel Doesn't Die in the Original Challenge~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// NWN-ish feats collection \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +@600030 = "Spontaneous Casting for Clerics [Luke (EEex)]" + +@600040 = "Weapon Finesse class feat for Thieves [Luke (EEex)]" + +@600050 = "Dual-Wield class feat for Rangers [Luke (EEex)]" + +@600060 = "NWN-ish Armor vs. Dexterity [Luke (EEex)]" + +@600070 = "Defensive Roll class feat for Thieves [Luke (EEex)]" + +@600080 = "Divine Grace / Dark Blessing feat for Paladins / Blackguards [Luke (EEex)]" + +@600090 = "Good Aim racial feat for Halflings [Luke (EEex)]" + +@600100 = "Cleave class feat for Fighters [Luke (EEex)]" + +@600110 = "Sneak Attack class feat for Blackguards [Luke (EEex)]" + +@600120 = "Fearless racial feat for Halflings [Luke (EEex)]" + +@600130 = "Poison Save class feat for Assassins [Luke (EEex)]" + +@600140 = "Planar Turning class feat for Clerics / Paladins [Luke (EEex)]" + +@600150 = "Circle Kick class feat for Monks [Luke (EEex)]" + +@600160 = "NWN-ish Barbarian Rage [Luke (EEex)]" \ No newline at end of file diff --git a/cdtweaks/languages/italian/dual_wield.tra b/cdtweaks/languages/italian/dual_wield.tra index 7b92d09c..b9274ac0 100644 --- a/cdtweaks/languages/italian/dual_wield.tra +++ b/cdtweaks/languages/italian/dual_wield.tra @@ -1 +1 @@ -@0 = "Armatura Media o Pesante Equipaggiata" \ No newline at end of file +@0 = "Doppia-Presa" \ No newline at end of file diff --git a/cdtweaks/languages/italian/nwn_barbarian_rage.tra b/cdtweaks/languages/italian/nwn_barbarian_rage.tra new file mode 100644 index 00000000..1191ce26 --- /dev/null +++ b/cdtweaks/languages/italian/nwn_barbarian_rage.tra @@ -0,0 +1,19 @@ +@0 = "Ira Barbarica + +La condizione di ira dura per 7 round (più un numero di round pari al modificatore di Costituzione del barbaro) e fornisce un bonus pari a +4 alla Forza e alla Costituzione, una penalità pari a -2 alla Classe Armatura e un bonus pari a +2 ai tiri-salvezza contro Incantesimi. + +Ira Terrificante: Mentre il barbaro è in preda all'ira, i nemici (con un dado-vita inferiore a quello del barbaro) che gli si avvicinano devono effettuare un tiro-salvezza contro Morte o cadere in preda al panico per 1d3 round. Nel caso in cui abbiano un dado-vita pari a quello del barbaro, riceveranno una penalità di -2 ai tiri-salvezza e al thac0. Se invece dovessero avere un dado-vita superiore a quello del barbaro, allora non subirebbero alcun effetto. + +Ira Tonante: Mentre il barbaro è in preda all'ira, i suoi colpi critici causano 2d6 punti danno aggiuntivi. Inoltre, i suoi attacchi hanno il 25% di possibilità di assordare la creatura colpita. +" + +@1 = "Ira Terrificante" + +@2 = "Ira Tonante (Colpo Critico)" +@3 = "Ira Tonante (Assordare)" +@4 = "Assordato" + +@5 = "Il personaggio selezionato è già in preda a Ira Barbarica" +@6 = "Tremando per la paura" +@7 = "Panico" +@8 = "Non soggetto agli effetti di Ira Terrificante" \ No newline at end of file diff --git a/cdtweaks/languages/italian/weidu.tra b/cdtweaks/languages/italian/weidu.tra index 738ea95a..973fd499 100644 --- a/cdtweaks/languages/italian/weidu.tra +++ b/cdtweaks/languages/italian/weidu.tra @@ -410,32 +410,6 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~ // @257000 = ~BGT: Limite di esperienza aggiuntivo mentre sei in BG~ // @257100 = ~BGT: Limite di esperienza aggiuntivo in SoA~ -@265000 = "Aggiungi talento di classe Lancio Spontaneo per i Chierici [Luke]" - -@266000 = "Aggiungi talento Arma Preferita per i Ladri [Luke]" - -@267000 = "Aggiungi talento Doppia-Presa per i Ranger [Luke]" - -@269000 = "Armatura vs. Destrezza in stile NWN [Luke]" - -@270000 = "Aggiungi talento Tiro Difensivo per i ladri [Luke]" - -@271000 = "Grazia Divina / Benedizione Oscura per Paladini / Guardie Nere [Luke]" - -@272000 = "Aggiungi talento razziale Buona Mira per gli Halfling [Luke]" - -@273000 = "Aggiungi talento di classe Incalzare per i Guerrieri [Luke]" - -@274000 = "Aggiungi talento di classe Attacco Furtivo per Guardie Nere [Luke]" - -@275000 = "Aggiungi talento razziale Temerario per gli Halfling [Luke]" - -@276000 = "Aggiungi talento di classe Resistenza ai Veleni per Assassini [Luke]" - -@277000 = "Aggiungi talento di classe Scacciare Creature Extraplanari per Paladini e Chierici [Luke]" - -@278000 = "Aggiungi talento di classe Calcio Rotante per i Monaci [Luke]" - /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ @@ -718,3 +692,39 @@ Usa opzioni di Baldur.lua: a7_interval_ini @504000 = ~Permettere a Yeslick di usare le asce~ @505000 = ~Assicura che Shar-Teel non muoia nella sfida iniziale~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Raccolta di talenti in stile NWN \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +@600030 = "Aggiungi talento di classe Lancio Spontaneo per i Chierici [Luke (EEex)]" + +@600040 = "Aggiungi talento di classe Arma Preferita per i Ladri [Luke (EEex)]" + +@600050 = "Aggiungi talento di classe Doppia-Presa per i Ranger [Luke (EEex)]" + +@600060 = "Armatura vs. Destrezza in stile NWN [Luke (EEex)]" + +@600070 = "Aggiungi talento di classe Tiro Difensivo per i ladri [Luke (EEex)]" + +@600080 = "Grazia Divina / Benedizione Oscura per Paladini / Guardie Nere [Luke (EEex)]" + +@600090 = "Aggiungi talento razziale Buona Mira per gli Halfling [Luke (EEex)]" + +@600100 = "Aggiungi talento di classe Incalzare per i Guerrieri [Luke (EEex)]" + +@600110 = "Aggiungi talento di classe Attacco Furtivo per Guardie Nere [Luke (EEex)]" + +@600120 = "Aggiungi talento razziale Temerario per gli Halfling [Luke (EEex)]" + +@600130 = "Aggiungi talento di classe Resistenza ai Veleni per Assassini [Luke (EEex)]" + +@600140 = "Aggiungi talento di classe Scacciare Creature Extraplanari per Paladini e Chierici [Luke (EEex)]" + +@600150 = "Aggiungi talento di classe Calcio Rotante per i Monaci [Luke (EEex)]" + +@600160 = "Ira Barbarica in stile NWN [Luke (EEex)]" \ No newline at end of file diff --git a/cdtweaks/lib/circle_kick.tph b/cdtweaks/lib/circle_kick.tph index ef9ab522..71bbd8a2 100644 --- a/cdtweaks/lib/circle_kick.tph +++ b/cdtweaks/lib/circle_kick.tph @@ -1,27 +1,41 @@ DEFINE_ACTION_FUNCTION "CIRCLE_KICK" BEGIN - CREATE "eff" "cdcrkick" - COPY_EXISTING "cdcrkick.eff" "override" - WRITE_LONG 0x10 402 // invoke lua - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "GTCKICK1" #8 // lua function - BUT_ONLY + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 8 + "type" = 4 + STR_VAR + "idsName" = "MONK_CIRCLE_KICK" + RET + "MONK_CIRCLE_KICK" = "resName" + END // - CREATE "spl" "cdcrkick" - COPY_EXISTING "cdcrkick.spl" "override" - WRITE_LONG NAME1 RESOLVE_STR_REF (@0) - WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic - WRITE_SHORT 0x1C 4 // type: innate - WRITE_LONG 0x34 1 // level + WITH_SCOPE BEGIN + ACTION_TO_LOWER "MONK_CIRCLE_KICK" // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + CREATE "eff" "%MONK_CIRCLE_KICK%b" + COPY_EXISTING "%MONK_CIRCLE_KICK%b.eff" "override" + WRITE_LONG 0x10 402 // invoke lua + WRITE_SHORT 0x2C 100 // prob1 + WRITE_LONG 0x1C 1 // parameter1 + WRITE_ASCII 0x30 "%MONK_CIRCLE_KICK%" #8 // lua function + BUT_ONLY // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "GTCKICK2" END // invoke lua - BUT_ONLY_IF_IT_CHANGES + CREATE "spl" "%MONK_CIRCLE_KICK%b" + COPY_EXISTING "%MONK_CIRCLE_KICK%b.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic + WRITE_SHORT 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 "parameter1" = 2 STR_VAR "resource" = "%MONK_CIRCLE_KICK%" END // invoke lua + BUT_ONLY_IF_IT_CHANGES + END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\circle_kick_grant.lua" "destRes" = "m_gtlstn" END - // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op402" "sourceFileSpec" = "cdtweaks\luke\lua\circle_kick.lua" "destRes" = "m_gt#402" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\circle_kick.lua" "destRes" = "m_gtspcl" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "AI-related stuff" "sourceFileSpec" = "cdtweaks\luke\lua\ai\object_type.lua" "destRes" = "m_gt#ai" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/cleave.tph b/cdtweaks/lib/cleave.tph index 77cbd1cb..f1f915b6 100644 --- a/cdtweaks/lib/cleave.tph +++ b/cdtweaks/lib/cleave.tph @@ -1,28 +1,42 @@ DEFINE_ACTION_FUNCTION "CLEAVE" BEGIN - CREATE "eff" "cdcleave" - COPY_EXISTING "cdcleave.eff" "override" - WRITE_LONG 0x10 402 // invoke lua - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "GTCLV01" #8 // lua function - BUT_ONLY + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 1 + "type" = 4 + STR_VAR + "idsName" = "FIGHTER_CLEAVE" + RET + "FIGHTER_CLEAVE" = "resName" + END // - CREATE "spl" "cdcleave" - COPY_EXISTING "cdcleave.spl" "override" - WRITE_LONG NAME1 RESOLVE_STR_REF (@0) - WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic - WRITE_SHORT 0x1C 4 // type: innate - WRITE_LONG 0x34 1 // level + WITH_SCOPE BEGIN + ACTION_TO_LOWER "FIGHTER_CLEAVE" // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + CREATE "eff" "%FIGHTER_CLEAVE%b" + COPY_EXISTING "%FIGHTER_CLEAVE%b.eff" "override" + WRITE_LONG 0x10 402 // invoke lua + WRITE_SHORT 0x2C 100 // prob1 + WRITE_LONG 0x1C 1 // parameter1 + WRITE_ASCII 0x30 "%FIGHTER_CLEAVE%" #8 // lua function + BUT_ONLY // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "timing" = 1 END // Set animation sequence (ATTACK) -- probably not needed...? - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "GTCLV02" END // invoke lua - BUT_ONLY_IF_IT_CHANGES + CREATE "spl" "%FIGHTER_CLEAVE%b" + COPY_EXISTING "%FIGHTER_CLEAVE%b.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic + WRITE_SHORT 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "timing" = 1 END // Set animation sequence (ATTACK) -- probably not needed...? + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 "parameter1" = 2 STR_VAR "resource" = "%FIGHTER_CLEAVE%" END // invoke lua + BUT_ONLY_IF_IT_CHANGES + END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\cleave_grant.lua" "destRes" = "m_gtlstn" END - // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op402" "sourceFileSpec" = "cdtweaks\luke\lua\cleave.lua" "destRes" = "m_gt#402" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\cleave.lua" "destRes" = "m_gtspcl" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "AI-related stuff" "sourceFileSpec" = "cdtweaks\luke\lua\ai\object_type.lua" "destRes" = "m_gt#ai" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/comp_2650.tpa b/cdtweaks/lib/comp_6030.tpa similarity index 100% rename from cdtweaks/lib/comp_2650.tpa rename to cdtweaks/lib/comp_6030.tpa diff --git a/cdtweaks/lib/comp_2660.tpa b/cdtweaks/lib/comp_6040.tpa similarity index 100% rename from cdtweaks/lib/comp_2660.tpa rename to cdtweaks/lib/comp_6040.tpa diff --git a/cdtweaks/lib/comp_2670.tpa b/cdtweaks/lib/comp_6050.tpa similarity index 100% rename from cdtweaks/lib/comp_2670.tpa rename to cdtweaks/lib/comp_6050.tpa diff --git a/cdtweaks/lib/comp_2690.tpa b/cdtweaks/lib/comp_6060.tpa similarity index 100% rename from cdtweaks/lib/comp_2690.tpa rename to cdtweaks/lib/comp_6060.tpa diff --git a/cdtweaks/lib/comp_2700.tpa b/cdtweaks/lib/comp_6070.tpa similarity index 100% rename from cdtweaks/lib/comp_2700.tpa rename to cdtweaks/lib/comp_6070.tpa diff --git a/cdtweaks/lib/comp_2710.tpa b/cdtweaks/lib/comp_6080.tpa similarity index 100% rename from cdtweaks/lib/comp_2710.tpa rename to cdtweaks/lib/comp_6080.tpa diff --git a/cdtweaks/lib/comp_2720.tpa b/cdtweaks/lib/comp_6090.tpa similarity index 100% rename from cdtweaks/lib/comp_2720.tpa rename to cdtweaks/lib/comp_6090.tpa diff --git a/cdtweaks/lib/comp_2730.tpa b/cdtweaks/lib/comp_6100.tpa similarity index 100% rename from cdtweaks/lib/comp_2730.tpa rename to cdtweaks/lib/comp_6100.tpa diff --git a/cdtweaks/lib/comp_2740.tpa b/cdtweaks/lib/comp_6110.tpa similarity index 100% rename from cdtweaks/lib/comp_2740.tpa rename to cdtweaks/lib/comp_6110.tpa diff --git a/cdtweaks/lib/comp_2750.tpa b/cdtweaks/lib/comp_6120.tpa similarity index 100% rename from cdtweaks/lib/comp_2750.tpa rename to cdtweaks/lib/comp_6120.tpa diff --git a/cdtweaks/lib/comp_2760.tpa b/cdtweaks/lib/comp_6130.tpa similarity index 100% rename from cdtweaks/lib/comp_2760.tpa rename to cdtweaks/lib/comp_6130.tpa diff --git a/cdtweaks/lib/comp_2770.tpa b/cdtweaks/lib/comp_6140.tpa similarity index 100% rename from cdtweaks/lib/comp_2770.tpa rename to cdtweaks/lib/comp_6140.tpa diff --git a/cdtweaks/lib/comp_2780.tpa b/cdtweaks/lib/comp_6150.tpa similarity index 100% rename from cdtweaks/lib/comp_2780.tpa rename to cdtweaks/lib/comp_6150.tpa diff --git a/cdtweaks/lib/comp_6160.tpa b/cdtweaks/lib/comp_6160.tpa new file mode 100644 index 00000000..d482b874 --- /dev/null +++ b/cdtweaks/lib/comp_6160.tpa @@ -0,0 +1,18 @@ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// ///// +///// NWN-ish Barbarian Rage \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +WITH_SCOPE BEGIN + INCLUDE "cdtweaks\luke\misc.tph" + INCLUDE "cdtweaks\ardanis\functions.tph" + // + INCLUDE "cdtweaks\lib\nwn_barbarian_rage.tph" + // + WITH_TRA "cdtweaks\languages\english\nwn_barbarian_rage.tra" "cdtweaks\languages\%LANGUAGE%\nwn_barbarian_rage.tra" BEGIN + LAF "NWN_BARBARIAN_RAGE" END + END +END \ No newline at end of file diff --git a/cdtweaks/lib/defensive_roll.tph b/cdtweaks/lib/defensive_roll.tph index f799dc9f..0bd4ca76 100644 --- a/cdtweaks/lib/defensive_roll.tph +++ b/cdtweaks/lib/defensive_roll.tph @@ -1,9 +1,22 @@ DEFINE_ACTION_FUNCTION "DEFENSIVE_ROLL" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 4 + "type" = 4 + STR_VAR + "idsName" = "ROGUE_DEFENSIVE_ROLL" + RET + "ROGUE_DEFENSIVE_ROLL" = "resName" + END + // WITH_SCOPE BEGIN OUTER_SET "feedback_strref" = RESOLVE_STR_REF (@0) - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op403" "sourceFileSpec" = "cdtweaks\luke\lua\defensive_roll.lua" "destRes" = "m_gt#403" END + // Listener: run 'func' each time a sprite has finished evaluating its effects + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\defensive_roll.lua" "destRes" = "m_gtspcl" END + END + // + ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN + COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" END - // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\defensive_roll_apply.lua" "destRes" = "m_gtlstn" END END \ No newline at end of file diff --git a/cdtweaks/lib/divine_grace_dark_blessing.tph b/cdtweaks/lib/divine_grace_dark_blessing.tph index 413c5649..88e9f1d2 100644 --- a/cdtweaks/lib/divine_grace_dark_blessing.tph +++ b/cdtweaks/lib/divine_grace_dark_blessing.tph @@ -1,18 +1,38 @@ DEFINE_ACTION_FUNCTION "DIVINE_GRACE_DARK_BLESSING" BEGIN - ACTION_IF !(FILE_EXISTS_IN_GAME "gtdvngrc.bam") BEGIN - COPY "cdtweaks\bam\gtdvngrc.bam" "override" + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 1 + "type" = 4 + STR_VAR + "idsName" = "PALADIN_DIVINE_GRACE" + RET + "PALADIN_DIVINE_GRACE" = "resName" END - ACTION_IF !(FILE_EXISTS_IN_GAME "gtdrkbls.bam") BEGIN - COPY "cdtweaks\bam\gtdrkbls.bam" "override" + // + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 1 + "type" = 4 + STR_VAR + "idsName" = "BLACKGUARD_DARK_BLESSING" + RET + "BLACKGUARD_DARK_BLESSING" = "resName" + END + // + WITH_SCOPE BEGIN + ACTION_TO_LOWER "BLACKGUARD_DARK_BLESSING" + ACTION_TO_LOWER "PALADIN_DIVINE_GRACE" + COPY "cdtweaks\luke\bam\kit\dark_blessing.bam" "override\%BLACKGUARD_DARK_BLESSING%d.bam" + COPY "cdtweaks\luke\bam\class\divine_grace.bam" "override\%PALADIN_DIVINE_GRACE%d.bam" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "gtdvngrc" RET "feedback_icon_paladin" = "index" END - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@1) STR_VAR "bam_file" = "gtdrkbls" RET "feedback_icon_blackguard" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%PALADIN_DIVINE_GRACE%D" RET "feedback_icon_paladin" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@1) STR_VAR "bam_file" = "%BLACKGUARD_DARK_BLESSING%D" RET "feedback_icon_blackguard" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\divine_grace.lua" "destRes" = "m_gtlstn" END - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\dark_blessing.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\divine_grace.lua" "destRes" = "m_gtspcl" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\kit\dark_blessing.lua" "destRes" = "m_gtspcl" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/dual_wield.tph b/cdtweaks/lib/dual_wield.tph index c17bfa1b..7ebac8f0 100644 --- a/cdtweaks/lib/dual_wield.tph +++ b/cdtweaks/lib/dual_wield.tph @@ -1,15 +1,24 @@ DEFINE_ACTION_FUNCTION "DUAL_WIELD" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 3 + "type" = 4 + STR_VAR + "idsName" = "RANGER_DUAL_WIELD" + RET + "RANGER_DUAL_WIELD" = "resName" + END + // WITH_SCOPE BEGIN - ACTION_IF !(FILE_EXISTS_IN_GAME "gtmharmr.bam") BEGIN - COPY "cdtweaks\bam\gtmharmr.bam" "override" - END + ACTION_TO_LOWER "RANGER_DUAL_WIELD" + COPY "cdtweaks\luke\bam\class\dual_wield.bam" "override\%RANGER_DUAL_WIELD%d.bam" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "gtmharmr" RET "feedback_icon" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%RANGER_DUAL_WIELD%D" RET "feedback_icon" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\dual_wield.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\dual_wield.lua" "destRes" = "m_gtspcl" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/fearless.tph b/cdtweaks/lib/fearless.tph index b3937c85..ae946a64 100644 --- a/cdtweaks/lib/fearless.tph +++ b/cdtweaks/lib/fearless.tph @@ -1,19 +1,27 @@ DEFINE_ACTION_FUNCTION "FEARLESS" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 3 + STR_VAR + "idsName" = "HALFLING_FEARLESS" + RET + "HALFLING_FEARLESS" = "resName" + END + // WITH_SCOPE BEGIN - COPY "cdtweaks\bam\cdhlfrls.bam" "override" + ACTION_TO_LOWER "HALFLING_FEARLESS" + COPY "cdtweaks\luke\bam\innate\fearless.bam" "override\%HALFLING_FEARLESS%d.bam" END // LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 20 STR_VAR "identifier" = "GT_IMMUNITY" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "cdhlfrls" RET "feedback_icon" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%HALFLING_FEARLESS%D" RET "feedback_icon" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\fearless_apply.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Innate Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\race\fearless.lua" "destRes" = "m_gtspin" END END // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op403" "sourceFileSpec" = "cdtweaks\luke\lua\fearless.lua" "destRes" = "m_gt#403" END - // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" END diff --git a/cdtweaks/lib/good_aim.tph b/cdtweaks/lib/good_aim.tph index 0d2cb378..7050b693 100644 --- a/cdtweaks/lib/good_aim.tph +++ b/cdtweaks/lib/good_aim.tph @@ -1,13 +1,23 @@ DEFINE_ACTION_FUNCTION "GOOD_AIM" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 3 + STR_VAR + "idsName" = "HALFLING_GOOD_AIM" + RET + "HALFLING_GOOD_AIM" = "resName" + END + // WITH_SCOPE BEGIN - COPY "cdtweaks\bam\cdhlgaim.bam" "override" + ACTION_TO_LOWER "HALFLING_GOOD_AIM" + COPY "cdtweaks\luke\bam\innate\good_aim.bam" "override\%HALFLING_GOOD_AIM%d.bam" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "cdhlgaim" RET "feedback_icon" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%HALFLING_GOOD_AIM%D" RET "feedback_icon" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\good_aim.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Innate)" "sourceFileSpec" = "cdtweaks\luke\lua\race\good_aim.lua" "destRes" = "m_gtspin" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/nwn-ish_armor_vs_dex.tph b/cdtweaks/lib/nwn-ish_armor_vs_dex.tph index 5500f038..5a600c20 100644 --- a/cdtweaks/lib/nwn-ish_armor_vs_dex.tph +++ b/cdtweaks/lib/nwn-ish_armor_vs_dex.tph @@ -1,12 +1,5 @@ DEFINE_ACTION_FUNCTION "NWN-ISH_ARMOR_VS_DEX" BEGIN - ACTION_IF !(FILE_EXISTS_IN_GAME "gtmharmr.bam") BEGIN - COPY "cdtweaks\bam\gtmharmr.bam" "override" - END - // - WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "gtmharmr" RET "feedback_icon" = "index" END - // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\nwn-ish_armor_vs_dex.lua" "destRes" = "m_gtlstn" END - END + // Listener: run 'func' each time a sprite has finished evaluating its effects + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Rule Changes)" "sourceFileSpec" = "cdtweaks\luke\lua\rule_changes\nwn-ish_armor_vs_dex.lua" "destRes" = "m_gtrule" END END \ No newline at end of file diff --git a/cdtweaks/lib/nwn_barbarian_rage.tph b/cdtweaks/lib/nwn_barbarian_rage.tph new file mode 100644 index 00000000..dc87071f --- /dev/null +++ b/cdtweaks/lib/nwn_barbarian_rage.tph @@ -0,0 +1,106 @@ +DEFINE_ACTION_FUNCTION "NWN_BARBARIAN_RAGE" +BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 1 + "preferredSlot" = 52 + STR_VAR + "idsName" = "BARBARIAN_RAGE" + RET + "BARBARIAN_RAGE" = "resName" + END + // update main asset + WITH_SCOPE BEGIN + COPY_EXISTING "spcl152.spl" "override" + WRITE_LONG UNIDENTIFIED_DESC RESOLVE_STR_REF (@0) + // + LPF "DELETE_EFFECT" END // fresh start + // cosmetic + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 215 "target" = 1 "duration" = 2 "parameter2" = 1 STR_VAR "resource" = "ICSTRENI" END // Play visual effect: Over target (attached) + // lua + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 1 "parameter1" = 1 STR_VAR "resource" = "%BARBARIAN_RAGE%" END // Invoke lua + BUT_ONLY + END + // terrifying rage + WITH_SCOPE BEGIN + ACTION_TO_LOWER "BARBARIAN_RAGE" + // + CREATE "spl" "%BARBARIAN_RAGE%b" + COPY_EXISTING "%BARBARIAN_RAGE%b.spl" "override" + WRITE_LONG NAME1 "-1" + WRITE_LONG UNIDENTIFIED_DESC "-1" + WRITE_LONG 0x18 (BIT9 BOR BIT10 BOR BIT14) // break sanctuary/invisibility, ignore dead/wild magic + WRITE_LONG 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + PATCH_WITH_SCOPE BEGIN + PATCH_IF IDS_OF_SYMBOL ("missile" "Area_Small_Not_Party_Ignore_Center") == "-1" BEGIN + INNER_ACTION BEGIN + ADD_PROJECTILE "cdtweaks\luke\pro\idpro402.pro" "Area_Small_Not_Party_Ignore_Center" + END + END + END + // + LPF ~ADD_SPELL_HEADER~ INT_VAR "target" = 5 "projectile" = IDS_OF_SYMBOL ("missile" "Area_Small_Not_Party_Ignore_Center") END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 139 "target" = 9 "parameter1" = RESOLVE_STR_REF (@1) END // display string + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 141 "target" = 2 "parameter2" = 16 END // lighting effects + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 "parameter1" = 2 STR_VAR "resource" = "%BARBARIAN_RAGE%" END // invoke lua + BUT_ONLY + END + // Thundering Rage + WITH_SCOPE BEGIN + ACTION_TO_LOWER "BARBARIAN_RAGE" + // 2d6 upon critical hits + CREATE "spl" "%BARBARIAN_RAGE%c" + COPY_EXISTING "%BARBARIAN_RAGE%c.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@2) + WRITE_LONG UNIDENTIFIED_DESC "-1" + WRITE_LONG 0x18 (BIT9 BOR BIT10 BOR BIT14) // break sanctuary/invisibility, ignore dead/wild magic + WRITE_LONG 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF ~ADD_SPELL_HEADER~ INT_VAR "range" = 30 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 "parameter1" = 3 STR_VAR "resource" = "%BARBARIAN_RAGE%" END // Invoke lua + BUT_ONLY + // deaf: 25% chance, no save + CREATE "eff" "%BARBARIAN_RAGE%d" + COPY_EXISTING "%BARBARIAN_RAGE%d.eff" "override" + WRITE_LONG 0x10 146 // cast spell + WRITE_LONG 0x20 1 // instant/ignore level + WRITE_ASCII 0x30 "%BARBARIAN_RAGE%D" #8 // spl resref + WRITE_SHORT 0x2C 24 // probability1 + BUT_ONLY + // + CREATE "spl" "%BARBARIAN_RAGE%d" + COPY_EXISTING "%BARBARIAN_RAGE%d.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@3) + WRITE_LONG UNIDENTIFIED_DESC "-1" + WRITE_LONG 0x18 (BIT9 BOR BIT10 BOR BIT14) // break sanctuary/invisibility, ignore dead/wild magic + WRITE_LONG 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF ~ADD_SPELL_HEADER~ INT_VAR "range" = 30 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 80 "target" = 2 "duration" = (6 * 3) END // deaf + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 142 "target" = 2 "parameter2" = 112 "duration" = (6 * 3) END // icon: deaf + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 139 "target" = 2 "parameter1" = RESOLVE_STR_REF (@4) END // string: deafened + BUT_ONLY + END + // lua + WITH_SCOPE BEGIN + OUTER_SET "feedback_strref_already_cast" = RESOLVE_STR_REF (@5) + OUTER_SET "feedback_strref_trembling_with_fear" = RESOLVE_STR_REF (@6) + OUTER_SET "feedback_strref_panic" = RESOLVE_STR_REF (@7) + OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@8) + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\kit\nwn_barbarian_rage.lua" "destRes" = "m_gtspcl" END + END + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Utility Functions / Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\utility\effect_check.lua" "destRes" = "m_gtutil" END + // + ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN + COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" + END +END \ No newline at end of file diff --git a/cdtweaks/lib/planar_turning.tph b/cdtweaks/lib/planar_turning.tph index 8382caa5..7e463cb8 100644 --- a/cdtweaks/lib/planar_turning.tph +++ b/cdtweaks/lib/planar_turning.tph @@ -1,23 +1,36 @@ DEFINE_ACTION_FUNCTION "PLANAR_TURNING" BEGIN - CREATE "spl" "cdplntrn" - COPY_EXISTING "cdplntrn.spl" "override" - WRITE_LONG NAME1 "-1" - WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic - WRITE_SHORT 0x1C 4 // type: innate - WRITE_LONG 0x34 1 // level - // - LPF "ADD_SPELL_HEADER" INT_VAR "target" = 5 "range" = 30 "projectile" = IDS_OF_SYMBOL ("projectl" "INAREANP") + 1 END + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 4 + "level" = 1 + STR_VAR + "idsName" = "PRIEST_PLANAR_TURNING" + RET + "PRIEST_PLANAR_TURNING" = "resName" + END + // + WITH_SCOPE BEGIN + ACTION_TO_LOWER "PRIEST_PLANAR_TURNING" // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 139 "target" = 1 "parameter1" = RESOLVE_STR_REF (@0) "timing" = 1 END // feedback message - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "GTPLNTRN" END // Invoke lua - BUT_ONLY_IF_IT_CHANGES + CREATE "spl" "%PRIEST_PLANAR_TURNING%" + COPY_EXISTING "%PRIEST_PLANAR_TURNING%.spl" "override" + WRITE_LONG NAME1 "-1" + WRITE_LONG UNIDENTIFIED_DESC "-1" + WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic + WRITE_SHORT 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF "ADD_SPELL_HEADER" INT_VAR "target" = 5 "range" = 30 "projectile" = IDS_OF_SYMBOL ("projectl" "INAREANP") + 1 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 139 "target" = 1 "parameter1" = RESOLVE_STR_REF (@0) "timing" = 1 END // feedback message + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%PRIEST_PLANAR_TURNING%" END // Invoke lua + BUT_ONLY_IF_IT_CHANGES + END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\planar_turning_modal.lua" "destRes" = "m_gtlstn" END - // WITH_SCOPE BEGIN OUTER_SET "feedback_strref" = RESOLVE_STR_REF (@1) - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op402" "sourceFileSpec" = "cdtweaks\luke\lua\planar_turning.lua" "destRes" = "m_gt#402" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Class / Kit)" "sourceFileSpec" = "cdtweaks\luke\lua\class\planar_turning.lua" "destRes" = "m_gtspcl" END END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN diff --git a/cdtweaks/lib/poison_save.tph b/cdtweaks/lib/poison_save.tph index 54f405db..dfcbf1b9 100644 --- a/cdtweaks/lib/poison_save.tph +++ b/cdtweaks/lib/poison_save.tph @@ -1,19 +1,28 @@ DEFINE_ACTION_FUNCTION "POISON_SAVE" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 4 + "level" = 4 + STR_VAR + "idsName" = "ASSASSIN_POISON_SAVE" + RET + "ASSASSIN_POISON_SAVE" = "resName" + END + // WITH_SCOPE BEGIN - COPY "cdtweaks\bam\cdpsnsav.bam" "override" + ACTION_TO_LOWER "ASSASSIN_POISON_SAVE" + COPY "cdtweaks\luke\bam\kit\poison_save.bam" "override\%ASSASSIN_POISON_SAVE%d.bam" END // LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 20 STR_VAR "identifier" = "GT_IMMUNITY" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "cdpsnsav" RET "feedback_icon" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ASSASSIN_POISON_SAVE%D" RET "feedback_icon" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\poison_save_apply.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\kit\poison_save.lua" "destRes" = "m_gtspcl" END END // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op403" "sourceFileSpec" = "cdtweaks\luke\lua\poison_save.lua" "destRes" = "m_gt#403" END - // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" END diff --git a/cdtweaks/lib/revised_archer.tph b/cdtweaks/lib/revised_archer.tph deleted file mode 100644 index ec69a908..00000000 --- a/cdtweaks/lib/revised_archer.tph +++ /dev/null @@ -1,120 +0,0 @@ -DEFINE_ACTION_FUNCTION "REVISED_ARCHER" -BEGIN - WITH_SCOPE BEGIN - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op402" "sourceFileSpec" = "cdtweaks\luke\lua\revised_archer_402.lua" "destRes" = "m_gt#402" END - // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\revised_archer_listener.lua" "destRes" = "m_gtlstn" END - // - ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN - COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" - END - END - // - WITH_SCOPE BEGIN - OUTER_SET "new_desc" = RESOLVE_STR_REF (@0) - COPY_EXISTING "kitlist.2da" "override" - COUNT_2DA_COLS "cols" - READ_2DA_ENTRIES_NOW "read_kitlist" "%cols%" - FOR ("i" = 0 ; "%i%" < "%read_kitlist%" ; "i" += 1) BEGIN - READ_2DA_ENTRY_FORMER "read_kitlist" "%i%" 1 "kitname" - PATCH_IF ("%kitname%" STR_EQ "FERALAN") BEGIN - READ_2DA_ENTRY_FORMER "read_kitlist" "%i%" 5 "clabfile" - READ_2DA_ENTRY_FORMER "read_kitlist" "%i%" 6 "weapprof_column_index" - SET_2DA_ENTRY "%i%" 4 "%cols%" "%new_desc%" // update description - SET "i" = "%read_kitlist%" // kill FOR-loop - END - END - BUT_ONLY - // - WITH_SCOPE BEGIN - COPY_EXISTING "%clabfile%.2da" "override" - PATCH_IF (GAME_IS "bgee bg2ee eet") BEGIN - REPLACE_TEXTUALLY CASE_INSENSITIVE EXACT_MATCH "AP_SPCL122" "****" - END ELSE BEGIN - REPLACE_TEXTUALLY CASE_INSENSITIVE EXACT_MATCH "AP_SPCL124" "****" - END - // formatting - PRETTY_PRINT_2DA - BUT_ONLY - END - // May only Specialize (two slots) in crossbows - WITH_SCOPE BEGIN - COPY_EXISTING "weapprof.2da" "override" - COUNT_2DA_COLS "cols" - READ_2DA_ENTRIES_NOW "read_weapprof" "%cols%" - FOR ("i" = 0 ; "%i%" < "%read_weapprof%" ; "i" += 1) BEGIN - READ_2DA_ENTRY_FORMER "read_weapprof" "%i%" 0 "profname" - PATCH_IF ("%profname%" STR_EQ "CROSSBOW") BEGIN - SET_2DA_ENTRY "%i%" "%weapprof_column_index%" "%cols%" 2 - SET "i" = "%read_weapprof%" // kill FOR-loop - END - END - BUT_ONLY - END - END - // Called Shot (bows only!) - WITH_SCOPE BEGIN - WITH_SCOPE BEGIN - COPY_EXISTING "spcl121.spl" "override\cdcl121.spl" - WRITE_LONG NAME1 "-1" // blank name - WRITE_LONG NAME2 "-1" - WRITE_LONG UNIDENTIFIED_DESC "-1" // blank description - WRITE_LONG DESC "-1" - WRITE_SHORT 0x1C 4 // innate - WRITE_LONG 0x34 1 // level - // - LPF "DELETE_EFFECT" END // fresh start - // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 54 "target" = 2 "parameter1" = "-1" "duration" = 20 END // Base THAC0 bonus - // - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 2 "opcode" = 37 "target" = 2 "parameter1" = "-1" "duration" = 15 END // Save vs. spell bonus - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 3 "opcode" = 37 "target" = 2 "parameter1" = "-1" "duration" = 15 END // Save vs. spell bonus - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 4 "opcode" = 37 "target" = 2 "parameter1" = "-1" "duration" = 15 END // Save vs. spell bonus - // - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 3 "opcode" = 44 "target" = 2 "parameter1" = "-1" "duration" = 10 END // Strength bonus - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 4 "opcode" = 44 "target" = 2 "parameter1" = "-1" "duration" = 10 END // Strength bonus - // - LPF "ADD_SPELL_EFFECT" INT_VAR "header" = 4 "opcode" = 12 "target" = 2 "parameter1" = 2 "parameter2" = IDS_OF_SYMBOL ("dmgtype" "missile") "timing" = 1 END // +2 (missile) Damage - BUT_ONLY - END - // - WITH_SCOPE BEGIN - COPY_EXISTING "spcl121.spl" "override" - GET_OFFSET_ARRAY "ab_array" SPL_V10_HEADERS - PHP_EACH "ab_array" AS "ab_ind" => "ab_off" BEGIN - PATCH_IF SHORT_AT ("%ab_off%" + 0x10) > 1 BEGIN - WRITE_BYTE "%ab_off%" 0xFF // mark for later deletion - END - END - LPF "DELETE_SPELL_HEADER" INT_VAR "header_type" = 0xFF END // enable deletion - // - LPF "ALTER_EFFECT" INT_VAR "match_opcode" = 249 STR_VAR "resource" = "cdcl121" END // Ranged hit effect - BUT_ONLY - END - // - WITH_SCOPE BEGIN - CREATE "eff" "cdcl121" - COPY_EXISTING "cdcl121.eff" "override" - WRITE_LONG 0x10 402 // Invoke Lua - WRITE_LONG 0x14 1 // Self - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "GTCLDSHT" #8 // Lua function - BUT_ONLY - END - END - // Point Blank Shot (bows only!) - WITH_SCOPE BEGIN - COPY_EXISTING "x-clserg.2da" "override" - COUNT_2DA_COLS "cols" - READ_2DA_ENTRIES_NOW "read_x-clserg" "%cols%" - FOR ("i" = 0 ; "%i%" < "%read_x-clserg%" ; "i" += 1) BEGIN - READ_2DA_ENTRY_FORMER "read_x-clserg" "%i%" 0 "kitName" - PATCH_IF ("%kitName%" STRING_EQUAL_CASE "FERALAN") BEGIN - SET_2DA_ENTRY "%i%" 1 "%cols%" 1 // BOW - SET "i" = "%read_x-clserg%" // kill FOR-loop - END - END - PRETTY_PRINT_2DA - BUT_ONLY - END -END \ No newline at end of file diff --git a/cdtweaks/lib/sneakatt_blackguard.tph b/cdtweaks/lib/sneakatt_blackguard.tph index 56abbb59..2060bfeb 100644 --- a/cdtweaks/lib/sneakatt_blackguard.tph +++ b/cdtweaks/lib/sneakatt_blackguard.tph @@ -1,41 +1,54 @@ DEFINE_ACTION_FUNCTION "SNEAKATT_BLACKGUARD" BEGIN - CREATE "eff" "cdblkgsa" - COPY_EXISTING "cdblkgsa.eff" "override" - WRITE_LONG 0x10 402 // invoke lua - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "GTBLKG01" #8 // lua function - BUT_ONLY + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 4 + "level" = 1 + STR_VAR + "idsName" = "BLACKGUARD_SNEAK_ATTACK" + RET + "BLACKGUARD_SNEAK_ATTACK" = "resName" + END // - CREATE "spl" "cdblkgsa" - COPY_EXISTING "cdblkgsa.spl" "override" - WRITE_LONG NAME1 RESOLVE_STR_REF (@0) - WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic - WRITE_SHORT 0x1C 4 // type: innate - WRITE_LONG 0x34 1 // level + WITH_SCOPE BEGIN + ACTION_TO_LOWER "BLACKGUARD_SNEAK_ATTACK" // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + CREATE "eff" "%BLACKGUARD_SNEAK_ATTACK%b" + COPY_EXISTING "%BLACKGUARD_SNEAK_ATTACK%b.eff" "override" + WRITE_LONG 0x10 402 // invoke lua + WRITE_SHORT 0x2C 100 // prob1 + WRITE_LONG 0x1C 1 // parameter1 + WRITE_ASCII 0x30 "%BLACKGUARD_SNEAK_ATTACK%" #8 // lua function + BUT_ONLY // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("kit" "barbarian") "parameter2" = 109 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message - PATCH_WITH_SCOPE BEGIN - LPF "ADD_SPLPROT_ENTRY" INT_VAR "stat" = IDS_OF_SYMBOL ("STATS" "IMMUNITY_TO_BACKSTAB") STR_VAR "value" = "-1" "relation" = "4" "label" = "STAT(IMMUNITY_TO_BACKSTAB) >= n" RET "index" END - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = 1 "parameter2" = "%index%" STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (IMMUNITY_TO_BACKSTAB >= 1) - END - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("general" "plant") "parameter2" = 103 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter2" = 55 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (RACE=GOLEM || GENERAL=UNDEAD) - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("general" "weapon") "parameter2" = 103 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (Animated weapons such as the Mordenkainen's Sword) - PATCH_WITH_SCOPE BEGIN - PATCH_FOR_EACH "race" IN "mist" "dragon" "beholder" "slime" "demonic" "mephit" "imp" "elemental" "salamander" "genie" "solar" "antisolar" "planatar" "darkplanatar" BEGIN - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("race" "%race%") "parameter2" = 104 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message + CREATE "spl" "%BLACKGUARD_SNEAK_ATTACK%b" + COPY_EXISTING "%BLACKGUARD_SNEAK_ATTACK%b.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG 0x18 BIT14 // flags: ignore dead/wild magic + WRITE_SHORT 0x1C 4 // type: innate + WRITE_LONG 0x34 1 // level + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("kit" "barbarian") "parameter2" = 109 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message + PATCH_WITH_SCOPE BEGIN + LPF "ADD_SPLPROT_ENTRY" INT_VAR "stat" = IDS_OF_SYMBOL ("STATS" "IMMUNITY_TO_BACKSTAB") STR_VAR "value" = "-1" "relation" = "4" "label" = "STAT(IMMUNITY_TO_BACKSTAB) >= n" RET "index" END + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = 1 "parameter2" = "%index%" STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (IMMUNITY_TO_BACKSTAB >= 1) END - END - // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "GTBLKG02" END // invoke lua - BUT_ONLY_IF_IT_CHANGES + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("general" "plant") "parameter2" = 103 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter2" = 55 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (RACE=GOLEM || GENERAL=UNDEAD) + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("general" "weapon") "parameter2" = 103 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message (Animated weapons such as the Mordenkainen's Sword) + PATCH_WITH_SCOPE BEGIN + PATCH_FOR_EACH "race" IN "mist" "dragon" "beholder" "slime" "demonic" "mephit" "imp" "elemental" "salamander" "genie" "solar" "antisolar" "planatar" "darkplanatar" BEGIN + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 324 "target" = 2 "parameter1" = IDS_OF_SYMBOL ("race" "%race%") "parameter2" = 104 STR_VAR "resource" = "%DEST_RES%" END // Immunity to resource and message + END + END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 "parameter1" = 2 STR_VAR "resource" = "%BLACKGUARD_SNEAK_ATTACK%" END // invoke lua + BUT_ONLY_IF_IT_CHANGES + END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\sneakatt_blackguard_grant.lua" "destRes" = "m_gtlstn" END - // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op402" "sourceFileSpec" = "cdtweaks\luke\lua\sneakatt_blackguard.lua" "destRes" = "m_gt#402" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\kit\sneakatt_blackguard.lua" "destRes" = "m_gtspcl" END // LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Utility Functions / Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\utility\is_invisible.lua" "destRes" = "m_gtutil" END // diff --git a/cdtweaks/lib/spontaneous_casting.tph b/cdtweaks/lib/spontaneous_casting.tph index ad8baadb..e9c265a9 100644 --- a/cdtweaks/lib/spontaneous_casting.tph +++ b/cdtweaks/lib/spontaneous_casting.tph @@ -5,10 +5,10 @@ BEGIN OUTER_FOR ("i" = 1 ; "%i%" <= 5 ; "i" += 1) BEGIN OUTER_SET "strref%i%" = RESOLVE_STR_REF (@0) END - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\spontaneous_casting\listener.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\spontaneous_casting\listener.lua" "destRes" = "m_gtspcl" END END // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Functions to be invoked via op214" "sourceFileSpec" = "cdtweaks\luke\lua\spontaneous_casting\custom_214.lua" "destRes" = "m_gt#214" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\spontaneous_casting\custom_214.lua" "destRes" = "m_gtspcl" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/lib/weapon_finesse.tph b/cdtweaks/lib/weapon_finesse.tph index 033562f0..1567c1a8 100644 --- a/cdtweaks/lib/weapon_finesse.tph +++ b/cdtweaks/lib/weapon_finesse.tph @@ -1,13 +1,24 @@ DEFINE_ACTION_FUNCTION "WEAPON_FINESSE" BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "type" = 4 + "level" = 4 + STR_VAR + "idsName" = "ROGUE_WEAPON_FINESSE" + RET + "ROGUE_WEAPON_FINESSE" = "resName" + END + // WITH_SCOPE BEGIN - COPY "cdtweaks\bam\gtwpnfin.bam" "override" + ACTION_TO_LOWER "ROGUE_WEAPON_FINESSE" + COPY "cdtweaks\luke\bam\class\weapon_finesse.bam" "override\%ROGUE_WEAPON_FINESSE%d.bam" END // WITH_SCOPE BEGIN - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "gtwpnfin" RET "feedback_icon" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_WEAPON_FINESSE%D" RET "feedback_icon" = "index" END // Listener: run 'func' each time a sprite has finished evaluating its effects - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\weapon_finesse.lua" "destRes" = "m_gtlstn" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\weapon_finesse.lua" "destRes" = "m_gtspcl" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" diff --git a/cdtweaks/luke/bam/class/divine_grace.bam b/cdtweaks/luke/bam/class/divine_grace.bam new file mode 100644 index 00000000..cc58cd65 Binary files /dev/null and b/cdtweaks/luke/bam/class/divine_grace.bam differ diff --git a/cdtweaks/luke/bam/class/dual_wield.bam b/cdtweaks/luke/bam/class/dual_wield.bam new file mode 100644 index 00000000..c5aa2fd5 Binary files /dev/null and b/cdtweaks/luke/bam/class/dual_wield.bam differ diff --git a/cdtweaks/luke/bam/class/weapon_finesse.bam b/cdtweaks/luke/bam/class/weapon_finesse.bam new file mode 100644 index 00000000..730ec660 Binary files /dev/null and b/cdtweaks/luke/bam/class/weapon_finesse.bam differ diff --git a/cdtweaks/luke/bam/innate/fearless.bam b/cdtweaks/luke/bam/innate/fearless.bam new file mode 100644 index 00000000..725ac796 Binary files /dev/null and b/cdtweaks/luke/bam/innate/fearless.bam differ diff --git a/cdtweaks/luke/bam/innate/good_aim.bam b/cdtweaks/luke/bam/innate/good_aim.bam new file mode 100644 index 00000000..1a810814 Binary files /dev/null and b/cdtweaks/luke/bam/innate/good_aim.bam differ diff --git a/cdtweaks/luke/bam/kit/dark_blessing.bam b/cdtweaks/luke/bam/kit/dark_blessing.bam new file mode 100644 index 00000000..3ab4a6b3 Binary files /dev/null and b/cdtweaks/luke/bam/kit/dark_blessing.bam differ diff --git a/cdtweaks/luke/bam/kit/poison_save.bam b/cdtweaks/luke/bam/kit/poison_save.bam new file mode 100644 index 00000000..54fda95f Binary files /dev/null and b/cdtweaks/luke/bam/kit/poison_save.bam differ diff --git a/cdtweaks/luke/lua/ai/object_type.lua b/cdtweaks/luke/lua/ai/object_type.lua new file mode 100644 index 00000000..7cb96d92 --- /dev/null +++ b/cdtweaks/luke/lua/ai/object_type.lua @@ -0,0 +1,10 @@ +--[[ ++---------------------------------------------------------------------------------+ +| Compiled objects for use with ``EEex_Sprite_GetAllOfTypeInRange()`` and friends | ++---------------------------------------------------------------------------------+ +--]] + +GT_AI_ObjectType = { + ["EVILCUTOFF"] = EEex_Object_ParseString("[EVILCUTOFF]"), + ["GOODCUTOFF"] = EEex_Object_ParseString("[GOODCUTOFF]"), +} diff --git a/cdtweaks/luke/lua/circle_kick.lua b/cdtweaks/luke/lua/circle_kick.lua deleted file mode 100644 index bc86ee43..00000000 --- a/cdtweaks/luke/lua/circle_kick.lua +++ /dev/null @@ -1,69 +0,0 @@ --- cdtweaks, NWN-ish Circle Kick class feat for Monks -- - -function GTCKICK1(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - -- - local sourceSeeInvisible = sourceSprite.m_derivedStats.m_bSeeInvisible + sourceSprite.m_bonusStats.m_bSeeInvisible - -- - local inWeaponRange = EEex_Trigger_ParseConditionalString("InWeaponRange(EEex_LuaObject)") - local reallyForceSpell = EEex_Action_ParseResponseString('ReallyForceSpellRES("CDCRKICK",EEex_LuaObject)') - -- limit to once per round - local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksCircleKickTimer","LOCALS")') - local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksCircleKickTimer","LOCALS",6)') - -- - local spriteArray = {} - if sourceSprite.m_typeAI.m_EnemyAlly > 200 then -- EVILCUTOFF - spriteArray = EEex_Sprite_GetAllOfTypeStringInRange(sourceSprite, "[GOODCUTOFF]", sourceSprite:virtual_GetVisualRange(), nil, nil, nil) - elseif sourceSprite.m_typeAI.m_EnemyAlly < 30 then -- GOODCUTOFF - spriteArray = EEex_Sprite_GetAllOfTypeStringInRange(sourceSprite, "[EVILCUTOFF]", sourceSprite:virtual_GetVisualRange(), nil, nil, nil) - end - -- - for _, itrSprite in ipairs(spriteArray) do - if itrSprite.m_id ~= CGameSprite.m_id then -- skip current target - EEex_LuaObject = itrSprite -- must be global - local spriteGeneralState = itrSprite.m_derivedStats.m_generalState + itrSprite.m_bonusStats.m_generalState - -- - if getTimer:evalConditionalAsAIBase(sourceSprite) and inWeaponRange:evalConditionalAsAIBase(sourceSprite) and EEex_IsBitUnset(spriteGeneralState, 11) then - if EEex_IsBitUnset(spriteGeneralState, 0x4) or sourceSeeInvisible > 0 then - reallyForceSpell:executeResponseAsAIBaseInstantly(sourceSprite) - break - end - end - end - end - -- - getTimer:free() - setTimer:free() - inWeaponRange:free() - reallyForceSpell:free() -end - --- cdtweaks, NWN-ish Circle Kick class feat for Monks -- - -function GTCKICK2(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - -- - local equipment = sourceSprite.m_equipment - local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedWeapon.pRes.pHeader -- Item_Header_st - -- - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st - -- - local randomValue = math.random(0, 1) - local damageType = {16, 0, 256, 128, 2048, 16 * randomValue, randomValue == 0 and 16 or 256, 256 * randomValue} -- piercing, crushing, slashing, missile, non-lethal, piercing/crushing, piercing/slashing, slashing/crushing - if damageType[itemAbility.damageType] then - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 12, -- Damage - ["dwFlags"] = damageType[itemAbility.damageType] * 0x10000, -- Normal - ["durationType"] = 1, - ["numDice"] = itemAbility.damageDiceCount, - ["diceSize"] = itemAbility.damageDice, - ["effectAmount"] = itemAbility.damageDiceBonus, - ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), - ["m_sourceType"] = CGameEffect.m_sourceType, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end -end diff --git a/cdtweaks/luke/lua/circle_kick_grant.lua b/cdtweaks/luke/lua/circle_kick_grant.lua deleted file mode 100644 index f50b78ec..00000000 --- a/cdtweaks/luke/lua/circle_kick_grant.lua +++ /dev/null @@ -1,55 +0,0 @@ --- cdtweaks: NWN-ish Circle Kick class feat for Monks -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- Sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual feat - local apply = function() - -- Mark the creature as 'feat applied' - sprite:setLocalInt("cdtweaksCircleKick", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDCRKICK", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 248, -- Melee hit effect - ["dwFlags"] = 4, -- fist-only - ["durationType"] = 9, - ["res"] = "CDCRKICK", -- EFF file - ["m_sourceRes"] = "CDCRKICK", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's class / flags - local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] - -- - local applyAbility = spriteClassStr == "MONK" - -- - if sprite:getLocalInt("cdtweaksCircleKick") == 0 then - if applyAbility then - apply() - end - else - if applyAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksCircleKick", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDCRKICK", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/class/circle_kick.lua b/cdtweaks/luke/lua/class/circle_kick.lua new file mode 100644 index 00000000..ebcff976 --- /dev/null +++ b/cdtweaks/luke/lua/class/circle_kick.lua @@ -0,0 +1,150 @@ +--[[ ++----------------------------------------------------+ +| cdtweaks, NWN-ish Circle Kick class feat for Monks | ++----------------------------------------------------+ +--]] + +-- Apply Ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual feat + local apply = function() + -- Mark the creature as 'feat applied' + sprite:setLocalInt("cdtweaksCircleKick", 1) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%MONK_CIRCLE_KICK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 248, -- Melee hit effect + ["dwFlags"] = 4, -- fist-only + ["durationType"] = 9, + ["res"] = "%MONK_CIRCLE_KICK%B", -- EFF file + ["m_sourceRes"] = "%MONK_CIRCLE_KICK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check creature's class / flags + local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] + -- + local applyAbility = spriteClassStr == "MONK" + -- + if sprite:getLocalInt("cdtweaksCircleKick") == 0 then + if applyAbility then + apply() + end + else + if applyAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksCircleKick", 0) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%MONK_CIRCLE_KICK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) + +-- Core function -- + +function %MONK_CIRCLE_KICK%(CGameEffect, CGameSprite) + if CGameEffect.m_effectAmount == 1 then -- check if can perform a circle kick + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + local sourceActiveStats = EEex_Sprite_GetActiveStats(sourceSprite) + -- limit to once per round + local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksCircleKickTimer","LOCALS") \n InWeaponRange(EEex_Target("GT_MonkCircleKickTarget"))') + local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksCircleKickTimer","LOCALS",6) \n ReallyForceSpellRES("%MONK_CIRCLE_KICK%B",EEex_Target("GT_MonkCircleKickTarget"))') + -- + local spriteArray = {} + if sourceSprite.m_typeAI.m_EnemyAlly > 200 then -- EVILCUTOFF + spriteArray = EEex_Sprite_GetAllOfTypeInRange(sourceSprite, GT_AI_ObjectType["GOODCUTOFF"], sourceSprite:virtual_GetVisualRange(), nil, nil, nil) + elseif sourceSprite.m_typeAI.m_EnemyAlly < 30 then -- GOODCUTOFF + spriteArray = EEex_Sprite_GetAllOfTypeInRange(sourceSprite, GT_AI_ObjectType["EVILCUTOFF"], sourceSprite:virtual_GetVisualRange(), nil, nil, nil) + end + -- + for _, itrSprite in ipairs(spriteArray) do + if itrSprite.m_id ~= CGameSprite.m_id then -- skip current target + --EEex_LuaObject = itrSprite -- must be global (we are not confortable with global / singleton vars...) + sourceSprite:setStoredScriptingTarget("GT_MonkCircleKickTarget", itrSprite) + -- + local itrSpriteActiveStats = EEex_Sprite_GetActiveStats(itrSprite) + -- + if getTimer:evalConditionalAsAIBase(sourceSprite) and EEex_IsBitUnset(itrSpriteActiveStats.m_generalState, 11) then -- if not dead + if EEex_IsBitUnset(itrSpriteActiveStats.m_generalState, 0x4) or sourceActiveStats.m_bSeeInvisible > 0 then -- if not invisible or can see through invisibility + if itrSpriteActiveStats.m_bSanctuary == 0 then + setTimer:executeResponseAsAIBaseInstantly(sourceSprite) + break + end + end + end + end + end + -- + getTimer:free() + setTimer:free() + elseif CGameEffect.m_effectAmount == 2 then -- actual feat + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + -- + local equipment = sourceSprite.m_equipment -- CGameSpriteEquipment + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) -- CItem + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- Item_Header_st + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + -- + local immunityToDamage = EEex_Trigger_ParseConditionalString("EEex_IsImmuneToOpcode(Myself,12)") + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local itmAbilityDamageTypeToIDS = { + 0x10, -- piercing + 0x0, -- crushing + 0x100, -- slashing + 0x80, -- missile + 0x800, -- non-lethal + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistCrushing and 0x0 or 0x10, -- piercing/crushing (better) + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistSlashing and 0x100 or 0x10, -- piercing/slashing (better) + targetActiveStats.m_nResistCrushing > targetActiveStats.m_nResistSlashing and 0x0 or 0x100, -- slashing/crushing (worse) + } + -- + if itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] then -- sanity check + if not immunityToDamage:evalConditionalAsAIBase(CGameSprite) then + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 0xC, -- Damage + ["dwFlags"] = itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] * 0x10000, -- mode: normal + ["numDice"] = selectedWeaponAbility.damageDiceCount, + ["diceSize"] = selectedWeaponAbility.damageDice, + ["effectAmount"] = selectedWeaponAbility.damageDiceBonus, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 324, -- Immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + immunityToDamage:free() + end +end diff --git a/cdtweaks/luke/lua/class/cleave.lua b/cdtweaks/luke/lua/class/cleave.lua new file mode 100644 index 00000000..f5a8f983 --- /dev/null +++ b/cdtweaks/luke/lua/class/cleave.lua @@ -0,0 +1,159 @@ +--[[ ++--------------------------------------------------+ +| cdtweaks, NWN-ish Cleave class feat for Fighters | ++--------------------------------------------------+ +--]] + +-- Apply Ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual feat + local apply = function() + -- Mark the creature as 'feat applied' + sprite:setLocalInt("cdtweaksCleave", 1) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%FIGHTER_CLEAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 248, -- Melee hit effect + ["durationType"] = 9, + ["res"] = "%FIGHTER_CLEAVE%B", -- EFF file + ["m_sourceRes"] = "%FIGHTER_CLEAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check creature's class / flags + local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] + -- + local spriteFlags = sprite.m_baseStats.m_flags + -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine + local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 + local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 + -- any fighter class (single/multi/(complete)dual) + local applyAbility = spriteClassStr == "FIGHTER" or spriteClassStr == "FIGHTER_MAGE_THIEF" or spriteClassStr == "FIGHTER_MAGE_CLERIC" + or (spriteClassStr == "FIGHTER_MAGE" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) + or (spriteClassStr == "FIGHTER_CLERIC" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) + or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) + or (spriteClassStr == "FIGHTER_DRUID" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) + -- + if sprite:getLocalInt("cdtweaksCleave") == 0 then + if applyAbility then + apply() + end + else + if applyAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksCleave", 0) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%FIGHTER_CLEAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) + +-- Core function -- + +function %FIGHTER_CLEAVE%(CGameEffect, CGameSprite) + if CGameEffect.m_effectAmount == 1 then -- check if can perform Cleave + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + local sourceActiveStats = EEex_Sprite_GetActiveStats(sourceSprite) + -- + local inWeaponRange = EEex_Trigger_ParseConditionalString('InWeaponRange(EEex_Target("GT_FighterCleaveTarget"))') + local reallyForceSpell = EEex_Action_ParseResponseString('ReallyForceSpellRES("%FIGHTER_CLEAVE%B",EEex_Target("GT_FighterCleaveTarget"))') + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + if EEex_IsBitSet(targetActiveStats.m_generalState, 11) then -- if STATE_DEAD (BIT11) + local spriteArray = {} + if sourceSprite.m_typeAI.m_EnemyAlly > 200 then -- EVILCUTOFF + spriteArray = EEex_Sprite_GetAllOfTypeInRange(sourceSprite, GT_AI_ObjectType["GOODCUTOFF"], sourceSprite:virtual_GetVisualRange(), nil, nil, nil) + elseif sourceSprite.m_typeAI.m_EnemyAlly < 30 then -- GOODCUTOFF + spriteArray = EEex_Sprite_GetAllOfTypeInRange(sourceSprite, GT_AI_ObjectType["EVILCUTOFF"], sourceSprite:virtual_GetVisualRange(), nil, nil, nil) + end + -- + for _, itrSprite in ipairs(spriteArray) do + sourceSprite:setStoredScriptingTarget("GT_FighterCleaveTarget", itrSprite) + -- + local itrSpriteActiveStats = EEex_Sprite_GetActiveStats(itrSprite) + -- + if inWeaponRange:evalConditionalAsAIBase(sourceSprite) and EEex_IsBitUnset(itrSpriteActiveStats.m_generalState, 11) then -- if not dead + if EEex_IsBitUnset(itrSpriteActiveStats.m_generalState, 0x4) or sourceActiveStats.m_bSeeInvisible > 0 then + if itrSpriteActiveStats.m_bSanctuary == 0 then + reallyForceSpell:executeResponseAsAIBaseInstantly(sourceSprite) + break + end + end + end + end + end + -- + inWeaponRange:free() + reallyForceSpell:free() + elseif CGameEffect.m_effectAmount == 2 then -- actual feat + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + -- + local equipment = sourceSprite.m_equipment -- CGameSpriteEquipment + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) -- CItem + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- Item_Header_st + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + -- + local immunityToDamage = EEex_Trigger_ParseConditionalString("EEex_IsImmuneToOpcode(Myself,12)") + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local itmAbilityDamageTypeToIDS = { + 0x10, -- piercing + 0x0, -- crushing + 0x100, -- slashing + 0x80, -- missile + 0x800, -- non-lethal + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistCrushing and 0x0 or 0x10, -- piercing/crushing (better) + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistSlashing and 0x100 or 0x10, -- piercing/slashing (better) + targetActiveStats.m_nResistCrushing > targetActiveStats.m_nResistSlashing and 0x0 or 0x100, -- slashing/crushing (worse) + } + -- + if itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] then -- sanity check + if not immunityToDamage:evalConditionalAsAIBase(CGameSprite) then + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 0xC, -- Damage + ["dwFlags"] = itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] * 0x10000, -- mode: normal + ["numDice"] = selectedWeaponAbility.damageDiceCount, + ["diceSize"] = selectedWeaponAbility.damageDice, + ["effectAmount"] = selectedWeaponAbility.damageDiceBonus, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 324, -- Immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + immunityToDamage:free() + end +end diff --git a/cdtweaks/luke/lua/defensive_roll_apply.lua b/cdtweaks/luke/lua/class/defensive_roll.lua similarity index 55% rename from cdtweaks/luke/lua/defensive_roll_apply.lua rename to cdtweaks/luke/lua/class/defensive_roll.lua index 6b471742..f6511749 100644 --- a/cdtweaks/luke/lua/defensive_roll_apply.lua +++ b/cdtweaks/luke/lua/class/defensive_roll.lua @@ -1,4 +1,10 @@ --- cdtweaks: NWN Defensive Roll feat for Rogues -- +--[[ ++--------------------------------------------------------+ +| cdtweaks, NWN-ish Defensive Roll class feat for Rogues | ++--------------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -12,16 +18,15 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDEFRLL", + ["res"] = "%ROGUE_DEFENSIVE_ROLL%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) sprite:applyEffect({ ["effectID"] = 403, -- Screen effects ["durationType"] = 9, - ["res"] = "GTDEFRLL", - ["m_sourceRes"] = "CDDEFRLL", + ["res"] = "%ROGUE_DEFENSIVE_ROLL%", -- Lua func + ["m_sourceRes"] = "%ROGUE_DEFENSIVE_ROLL%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -83,11 +88,50 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDEFRLL", + ["res"] = "%ROGUE_DEFENSIVE_ROLL%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end end end) + +-- Core function -- + +function %ROGUE_DEFENSIVE_ROLL%(op403CGameEffect, CGameEffect, CGameSprite) + local dmgtype = GT_Resource_SymbolToIDS["dmgtype"] + local damageAmount = CGameEffect.m_effectAmount + -- + local spriteHP = CGameSprite.m_baseStats.m_hitPoints + local spriteSaveVSBreathRoll = CGameSprite.m_saveVSBreathRoll + -- + local spriteActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local state = GT_Resource_SymbolToIDS["state"] + local stats = GT_Resource_SymbolToIDS["stats"] + -- + local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksDefensiveRollTimer","LOCALS")') + local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksDefensiveRollTimer","LOCALS",2400)') + -- If the character is struck by a potentially lethal blow, he makes a save vs. breath. If successful, he takes only half damage from the blow. + if CGameEffect.m_effectId == 0xC and EEex_IsMaskUnset(CGameEffect.m_dWFlags, dmgtype["STUNNING"]) and CGameEffect.m_slotNum == -1 and CGameEffect.m_sourceType == 0 and CGameEffect.m_sourceRes:get() == "" -- base weapon damage (all damage types but STUNNING) + and EEex_BAnd(spriteActiveStats.m_generalState, state["CD_STATE_NOTVALID"]) == 0 + and spriteActiveStats.m_nSaveVSBreath <= spriteSaveVSBreathRoll + and damageAmount >= spriteHP + and getTimer:evalConditionalAsAIBase(CGameSprite) + then + CGameEffect.m_effectAmount = math.floor(damageAmount / 2) + -- + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 139, -- Display string + ["effectAmount"] = %feedback_strref%, + ["sourceID"] = op403CGameEffect.m_sourceId, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it... + ["sourceTarget"] = op403CGameEffect.m_sourceTarget, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it... + }) + -- + setTimer:executeResponseAsAIBaseInstantly(CGameSprite) + end + -- + getTimer:free() + setTimer:free() +end diff --git a/cdtweaks/luke/lua/divine_grace.lua b/cdtweaks/luke/lua/class/divine_grace.lua similarity index 74% rename from cdtweaks/luke/lua/divine_grace.lua rename to cdtweaks/luke/lua/class/divine_grace.lua index e91e21a3..23f620f5 100644 --- a/cdtweaks/luke/lua/divine_grace.lua +++ b/cdtweaks/luke/lua/class/divine_grace.lua @@ -1,4 +1,10 @@ --- cdtweaks: NWN Divine Grace feat for Paladins -- +--[[ ++--------------------------------------------------------+ +| cdtweaks, NWN-ish Divine Grace class feat for Paladins | ++--------------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -8,14 +14,13 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- internal function that applies the actual bonus local apply = function(bonus) -- Update var - sprite:setLocalInt("cdtweaksDivineGraceHelper", bonus) + sprite:setLocalInt("cdtweaksDivineGraceBonus", bonus) -- Mark the creature as 'bonus applied' sprite:setLocalInt("cdtweaksDivineGrace", 1) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDVNGRC", + ["res"] = "%PALADIN_DIVINE_GRACE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -23,7 +28,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 325, -- All saving throws bonus ["durationType"] = 9, ["effectAmount"] = bonus, - ["m_sourceRes"] = "CDDVNGRC", + ["m_sourceRes"] = "%PALADIN_DIVINE_GRACE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -31,7 +36,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 142, -- Display portrait icon ["durationType"] = 9, ["dwFlags"] = %feedback_icon_paladin%, - ["m_sourceRes"] = "CDDVNGRC", + ["m_sourceRes"] = "%PALADIN_DIVINE_GRACE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -47,16 +52,16 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- local bonus = math.floor((spriteCharisma - 10) / 2) -- The paladin adds its charisma bonus (if positive) to all saving throws (provided it is not fallen) - local applyCondition = spriteClassStr == "PALADIN" and spriteKitStr ~= "Blackguard" and bonus and bonus > 0 and EEex_IsBitUnset(spriteFlags, 0x9) + local applyAbility = spriteClassStr == "PALADIN" and spriteKitStr ~= "Blackguard" and bonus and bonus > 0 and EEex_IsBitUnset(spriteFlags, 0x9) -- if sprite:getLocalInt("cdtweaksDivineGrace") == 0 then - if applyCondition then + if applyAbility then apply(bonus) end else - if applyCondition then + if applyAbility then -- Check if Charisma has changed since the last application - if bonus ~= sprite:getLocalInt("cdtweaksDivineGraceHelper") then + if bonus ~= sprite:getLocalInt("cdtweaksDivineGraceBonus") then apply(bonus) end else @@ -65,8 +70,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDVNGRC", + ["res"] = "%PALADIN_DIVINE_GRACE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/dual_wield.lua b/cdtweaks/luke/lua/class/dual_wield.lua similarity index 65% rename from cdtweaks/luke/lua/dual_wield.lua rename to cdtweaks/luke/lua/class/dual_wield.lua index 76aa6a76..6e203302 100644 --- a/cdtweaks/luke/lua/dual_wield.lua +++ b/cdtweaks/luke/lua/class/dual_wield.lua @@ -1,4 +1,10 @@ --- cdtweaks, dual-wield feat for rangers: Force the targeted creature to wield light armors (or no armor) in order to benefit from Two-Weapon Style -- +--[[ ++-----------------------------------------------------+ +| cdtweaks, NWN-ish Dual-Wield class feat for Rangers | ++-----------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -7,7 +13,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end -- internal function that applies the actual penalty local apply = function(spriteProficiency2Weapon) - -- Update var + -- Update tracking var sprite:setLocalInt("cdtweaksDualWieldHelper", spriteProficiency2Weapon) -- local stylbonu = GT_Resource_2DA["stylbonu"] @@ -20,44 +26,41 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDLWLD", + ["res"] = "%RANGER_DUAL_WIELD%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) sprite:applyEffect({ - ["effectID"] = 306, -- Main-hand THAC0 bonus - ["durationType"] = 9, - ["effectAmount"] = curThac0RightPenalty - maxThac0RightPenalty, - ["m_sourceRes"] = "CDDLWLD", + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%RANGER_DUAL_WIELD%B", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) sprite:applyEffect({ - ["effectID"] = 305, -- Off-hand THAC0 bonus + ["effectID"] = 306, -- Main-hand THAC0 bonus ["durationType"] = 9, - ["effectAmount"] = curThac0LeftPenalty - maxThac0LeftPenalty, - ["m_sourceRes"] = "CDDLWLD", + ["effectAmount"] = curThac0RightPenalty - maxThac0RightPenalty, + ["m_sourceRes"] = "%RANGER_DUAL_WIELD%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) sprite:applyEffect({ - ["effectID"] = 142, -- Display portrait icon + ["effectID"] = 305, -- Off-hand THAC0 bonus ["durationType"] = 9, - ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDDLWLD", + ["effectAmount"] = curThac0LeftPenalty - maxThac0LeftPenalty, + ["m_sourceRes"] = "%RANGER_DUAL_WIELD%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end -- Check creature's equipment / class local equipment = sprite.m_equipment - local selectedItem = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedItem.pRes.pHeader + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- - local mainHandFlags = itemHeader.itemFlags - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st - local mainHandAbilityType = itemAbility.type + local selectedWeaponHeaderFlags = selectedWeaponHeader.itemFlags + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + local selectedWeaponAbilityType = selectedWeaponAbility.type -- local items = sprite.m_equipment.m_items -- Array -- @@ -65,16 +68,16 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local armorTypeStr = nil local armorAnimation = nil if armor then -- if the character is equipped with an armor... - local itemHeader = armor.pRes.pHeader -- Item_Header_st - armorTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] - armorAnimation = EEex_CastUD(itemHeader.animationType, "CResRef"):get() -- certain engine types are nonsensical. We usually create fixups for the bindings whenever we run into them. We'll need to cast the value to properly read them + local pHeader = armor.pRes.pHeader -- Item_Header_st + armorTypeStr = GT_Resource_IDSToSymbol["itemcat"][pHeader.itemType] + armorAnimation = EEex_CastUD(pHeader.animationType, "CResRef"):get() -- certain engine types are nonsensical. We usually create fixups for the bindings whenever we run into them. We'll need to cast the value to properly read them end -- local offHand = items:get(9) -- CItem (index from "slots.ids") local offHandTypeStr = nil if offHand then - local itemHeader = offHand.pRes.pHeader -- Item_Header_st - offHandTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] + local pHeader = offHand.pRes.pHeader -- Item_Header_st + offHandTypeStr = GT_Resource_IDSToSymbol["itemcat"][pHeader.itemType] end -- local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] @@ -86,8 +89,8 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 -- If the Ranger is dual-wielding and is equipped with medium or heavy armor... - local applyCondition = EEex_BAnd(mainHandFlags, itemflag["TWOHANDED"]) == 0 - and mainHandAbilityType == 1 -- type: melee + local applyAbility = EEex_BAnd(selectedWeaponHeaderFlags, itemflag["TWOHANDED"]) == 0 + and selectedWeaponAbilityType == 1 -- type: melee and offHand and offHandTypeStr ~= "SHIELD" and armor and armorTypeStr == "ARMOR" and (armorAnimation == "3A" or armorAnimation == "4A") and (spriteClassStr == "RANGER" @@ -96,11 +99,11 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) and EEex_IsBitUnset(spriteFlags, 10) -- not Fallen Ranger -- if sprite:getLocalInt("cdtweaksDualWield") == 0 then - if applyCondition then + if applyAbility then apply(sprite.m_derivedStats.m_nProficiency2Weapon) -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine end else - if applyCondition then + if applyAbility then -- Check if ``m_nProficiency2Weapon`` has changed since the last application local spriteProficiency2Weapon = sprite.m_derivedStats.m_nProficiency2Weapon -- @@ -113,8 +116,21 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDLWLD", + ["res"] = "%RANGER_DUAL_WIELD%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%RANGER_DUAL_WIELD%B", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 142, -- Display portrait icon + ["durationType"] = 9, + ["dwFlags"] = %feedback_icon%, + ["m_sourceRes"] = "%RANGER_DUAL_WIELD%B", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/class/planar_turning.lua b/cdtweaks/luke/lua/class/planar_turning.lua new file mode 100644 index 00000000..99468945 --- /dev/null +++ b/cdtweaks/luke/lua/class/planar_turning.lua @@ -0,0 +1,96 @@ +--[[ ++----------------------------------------------------------------------+ +| cdtweaks, NWN-ish Planar Turning class feat for Paladins and Clerics | ++----------------------------------------------------------------------+ +--]] + +-- Check if turning undead -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual turning + local turnPlanarMode = function() + sprite:applyEffect({ + ["effectID"] = 146, -- Cast spell + ["dwFlags"] = 1, -- instant / ignore level + ["res"] = "%PRIEST_PLANAR_TURNING%", -- SPL file + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check if the creature is turning undead + local turnUndeadMode = EEex_Sprite_GetModalState(sprite) == 4 and EEex_Sprite_GetModalTimer(sprite) == 0 + -- + if turnUndeadMode then + turnPlanarMode() + end +end) + +-- Core function -- + +function %PRIEST_PLANAR_TURNING%(CGameEffect, CGameSprite) + local parentResRef = CGameEffect.m_sourceRes:get() + -- + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + -- + local isEvil = EEex_Trigger_ParseConditionalString("Alignment(Myself,MASK_EVIL)") + -- + local sourceActiveStats = EEex_Sprite_GetActiveStats(sourceSprite) + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local targetRaceStr = GT_Resource_IDSToSymbol["race"][CGameSprite.m_typeAI.m_Race] + -- + local roll = math.random(0, 3) -- engine: ((int)((rand() & 0x7fff) << 2) >> 0xf) => generates a random number, keeps its lower 15 bits, multiplies by 2^2, divides by 2^15 + -- + local effectCodes = {} + -- + if targetRaceStr == "DEMONIC" or targetRaceStr == "MEPHIT" or targetRaceStr == "IMP" or targetRaceStr == "ELEMENTAL" or targetRaceStr == "SALAMANDER" or targetRaceStr == "SOLAR" or targetRaceStr == "ANTISOLAR" or targetRaceStr == "DARKPLANATAR" or targetRaceStr == "PLANATAR" or targetRaceStr == "GENIE" then -- if extraplanar ... + if sourceActiveStats.m_nTurnUndeadLevel < (targetActiveStats.m_nLevel1 + roll) + 5 then + if sourceActiveStats.m_nTurnUndeadLevel >= (targetActiveStats.m_nLevel1 + roll) then -- turn + effectCodes = { + {["op"] = 174, ["res"] = "ACT_06"}, -- play sound + {["op"] = 141, ["p2"] = 24}, -- lighting effects (invocation air) + {["op"] = 321, ["res"] = parentResRef}, -- remove effects by resource + {["op"] = 24, ["p2"] = 1, ["dur"] = 60}, -- panic (bypass immunity) + {["op"] = 142, ["p2"] = 36, ["dur"] = 60} -- icon: panic + {["op"] = 139, ["p1"] = %feedback_strref%}, -- feedback string + } + end + else -- destroy or take control + if isEvil:evalConditionalAsAIBase(sourceSprite) then -- take control + effectCodes = { + {["op"] = 174, ["res"] = "ACT_06"}, -- play sound + {["op"] = 141, ["p2"] = 24}, -- lighting effects (invocation air) + {["op"] = 321, ["res"] = parentResRef}, -- remove effects by resource + {["op"] = 241, ["p2"] = 4, ["dur"] = 60}, -- control creature (charm type: controlled) + } + else -- destroy + effectCodes = { + {["op"] = 174, ["res"] = "ACT_06"}, -- play sound + {["op"] = 141, ["p2"] = 24}, -- lighting effects (invocation air) + {["op"] = 13, ["p2"] = 0x4, ["tmg"] = 4}, -- kill (normal death) + } + end + end + -- + for _, attributes in ipairs(effectCodes) do + CGameSprite:applyEffect({ + ["effectID"] = attributes["op"] or EEex_Error("opcode number not specified"), + ["effectAmount"] = attributes["p1"] or 0, + ["dwFlags"] = attributes["p2"] or 0, + ["res"] = attributes["res"] or "", + ["duration"] = attributes["dur"] or 0, + ["durationType"] = attributes["tmg"] or 0, + ["noSave"] = true, + ["m_sourceRes"] = parentResRef, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + isEvil:free() +end diff --git a/cdtweaks/luke/lua/weapon_finesse.lua b/cdtweaks/luke/lua/class/weapon_finesse.lua similarity index 68% rename from cdtweaks/luke/lua/weapon_finesse.lua rename to cdtweaks/luke/lua/class/weapon_finesse.lua index 269c2796..447424cc 100644 --- a/cdtweaks/luke/lua/weapon_finesse.lua +++ b/cdtweaks/luke/lua/class/weapon_finesse.lua @@ -1,4 +1,16 @@ --- cdtweaks: Weapon Finesse feat for Thieves -- +--[[ ++---------------------------------------------------------+ +| cdtweaks, NWN-ish Weapon Finesse class feat for Thieves | ++---------------------------------------------------------+ +--]] + +-- Unusually large weapons -- + +local cdtweaks_WeaponFinesse_UnusuallyLargeWeapon = { + ["BDBONE02"] = true, -- Ettin Club +1 +} + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -7,15 +19,14 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end -- internal function that applies the actual bonus local apply = function(value) - -- Update var + -- Update tracking var sprite:setLocalInt("cdtweaksWeaponFinesseHelper", value) -- Mark the creature as 'bonus applied' sprite:setLocalInt("cdtweaksWeaponFinesse", 1) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDWPNFIN", + ["res"] = "%ROGUE_WEAPON_FINESSE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -23,7 +34,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 306, -- Main-hand THAC0 bonus ["durationType"] = 9, ["effectAmount"] = value, - ["m_sourceRes"] = "CDWPNFIN", + ["m_sourceRes"] = "%ROGUE_WEAPON_FINESSE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -31,22 +42,19 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 142, -- Display portrait icon ["durationType"] = 9, ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDWPNFIN", + ["m_sourceRes"] = "%ROGUE_WEAPON_FINESSE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end -- Check creature's equipment / stats / class local equipment = sprite.m_equipment - local selectedItem = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedItem.pRes.pHeader + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- - local itemResRef = string.upper(selectedItem.pRes.resref:get()) - local unusuallyLargeWeapon = { - ["BDBONE02"] = true -- Ettin Club +1 - } + local selectedWeaponResRef = string.upper(selectedWeapon.pRes.resref:get()) -- - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st -- local strmod = GT_Resource_2DA["strmod"] local strmodex = GT_Resource_2DA["strmodex"] @@ -58,7 +66,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] -- - local weaponTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] + local selectedWeaponTypeStr = GT_Resource_IDSToSymbol["itemcat"][selectedWeaponHeader.itemType] -- local spriteFlags = sprite.m_baseStats.m_flags -- @@ -68,12 +76,12 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local curStrBonus = tonumber(strmod[string.format("%s", spriteSTR)]["TO_HIT"] + strmodex[string.format("%s", spriteSTRExtra)]["TO_HIT"]) local curDexBonus = tonumber(dexmod[string.format("%s", spriteDEX)]["MISSILE"]) -- if the thief is wielding a small blade / mace / club that scales with STR and "dexmod.2da" is better than "strmod.2da" + "strmodex.2da" ... - local applyCondition = (weaponTypeStr == "DAGGER" or weaponTypeStr == "SMSWORD" or weaponTypeStr == "MACE") - and not unusuallyLargeWeapon[itemResRef] + local applyAbility = (selectedWeaponTypeStr == "DAGGER" or selectedWeaponTypeStr == "SMSWORD" or selectedWeaponTypeStr == "MACE") + and not cdtweaks_WeaponFinesse_UnusuallyLargeWeapon[selectedWeaponResRef] and curDexBonus > curStrBonus - and itemAbility.quickSlotType == 1 -- Location: Weapon - and itemAbility.type == 1 -- Type: Melee - and (EEex_IsBitSet(itemAbility.abilityFlags, 0x0) or EEex_IsBitSet(itemAbility.abilityFlags, 0x3)) + and selectedWeaponAbility.quickSlotType == 1 -- Location: Weapon + and selectedWeaponAbility.type == 1 -- Type: Melee + and (EEex_IsBitSet(selectedWeaponAbility.abilityFlags, 0x0) or EEex_IsBitSet(selectedWeaponAbility.abilityFlags, 0x3)) and (spriteClassStr == "THIEF" or spriteClassStr == "FIGHTER_MAGE_THIEF" -- incomplete dual-class characters are not supposed to benefit from Weapon Finesse or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) @@ -81,11 +89,11 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2))) -- if sprite:getLocalInt("cdtweaksWeaponFinesse") == 0 then - if applyCondition then + if applyAbility then apply(curDexBonus - curStrBonus) end else - if applyCondition then + if applyAbility then -- Check if STR/STREx/DEX have changed since the last application if (curDexBonus - curStrBonus) ~= sprite:getLocalInt("cdtweaksWeaponFinesseHelper") then apply(curDexBonus - curStrBonus) @@ -96,8 +104,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDWPNFIN", + ["res"] = "%ROGUE_WEAPON_FINESSE%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/cleave.lua b/cdtweaks/luke/lua/cleave.lua deleted file mode 100644 index 35e6f43f..00000000 --- a/cdtweaks/luke/lua/cleave.lua +++ /dev/null @@ -1,66 +0,0 @@ --- cdtweaks, NWN-ish Cleave feat for Fighters -- - -function GTCLV01(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - -- - local sourceSeeInvisible = sourceSprite.m_derivedStats.m_bSeeInvisible + sourceSprite.m_bonusStats.m_bSeeInvisible - -- - local inWeaponRange = EEex_Trigger_ParseConditionalString("InWeaponRange(EEex_LuaObject)") - local reallyForceSpell = EEex_Action_ParseResponseString('ReallyForceSpellRES("CDCLEAVE",EEex_LuaObject)') - -- - local targetGeneralState = CGameSprite.m_derivedStats.m_generalState + CGameSprite.m_bonusStats.m_generalState - -- - if EEex_IsBitSet(targetGeneralState, 11) then -- STATE_DEAD (BIT11) - local spriteArray = {} - if sourceSprite.m_typeAI.m_EnemyAlly > 200 then -- EVILCUTOFF - spriteArray = EEex_Sprite_GetAllOfTypeStringInRange(sourceSprite, "[GOODCUTOFF]", sourceSprite:virtual_GetVisualRange(), nil, nil, nil) - elseif sourceSprite.m_typeAI.m_EnemyAlly < 30 then -- GOODCUTOFF - spriteArray = EEex_Sprite_GetAllOfTypeStringInRange(sourceSprite, "[EVILCUTOFF]", sourceSprite:virtual_GetVisualRange(), nil, nil, nil) - end - -- - for _, itrSprite in ipairs(spriteArray) do - EEex_LuaObject = itrSprite -- must be global - local spriteGeneralState = itrSprite.m_derivedStats.m_generalState + itrSprite.m_bonusStats.m_generalState - -- - if inWeaponRange:evalConditionalAsAIBase(sourceSprite) and EEex_IsBitUnset(spriteGeneralState, 11) then - if EEex_IsBitUnset(spriteGeneralState, 0x4) or sourceSeeInvisible > 0 then - reallyForceSpell:executeResponseAsAIBaseInstantly(sourceSprite) - break - end - end - end - end - -- - inWeaponRange:free() - reallyForceSpell:free() -end - --- cdtweaks, NWN-ish Cleave feat for Fighters -- - -function GTCLV02(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - -- - local equipment = sourceSprite.m_equipment - local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedWeapon.pRes.pHeader -- Item_Header_st - -- - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st - -- - local randomValue = math.random(0, 1) - local damageType = {16, 0, 256, 128, 2048, 16 * randomValue, randomValue == 0 and 16 or 256, 256 * randomValue} -- piercing, crushing, slashing, missile, non-lethal, piercing/crushing, piercing/slashing, slashing/crushing - if damageType[itemAbility.damageType] then - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 12, -- Damage - ["dwFlags"] = damageType[itemAbility.damageType] * 0x10000, -- Normal - ["durationType"] = 1, - ["numDice"] = itemAbility.damageDiceCount, - ["diceSize"] = itemAbility.damageDice, - ["effectAmount"] = itemAbility.damageDiceBonus, - ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), - ["m_sourceType"] = CGameEffect.m_sourceType, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end -end diff --git a/cdtweaks/luke/lua/cleave_grant.lua b/cdtweaks/luke/lua/cleave_grant.lua deleted file mode 100644 index 165f8305..00000000 --- a/cdtweaks/luke/lua/cleave_grant.lua +++ /dev/null @@ -1,63 +0,0 @@ --- cdtweaks: NWN-ish Cleave feat for Fighters -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- Sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual feat - local apply = function() - -- Mark the creature as 'feat applied' - sprite:setLocalInt("cdtweaksCleave", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDCLEAVE", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 248, -- Melee hit effect - ["durationType"] = 9, - ["res"] = "CDCLEAVE", -- EFF file - ["m_sourceRes"] = "CDCLEAVE", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's class / flags - local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] - -- - local spriteFlags = sprite.m_baseStats.m_flags - -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine - local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 - local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 - -- any fighter class (single/multi/(complete)dual) - local applyAbility = spriteClassStr == "FIGHTER" or spriteClassStr == "FIGHTER_MAGE_THIEF" or spriteClassStr == "FIGHTER_MAGE_CLERIC" - or (spriteClassStr == "FIGHTER_MAGE" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) - or (spriteClassStr == "FIGHTER_CLERIC" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) - or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) - or (spriteClassStr == "FIGHTER_DRUID" and (EEex_IsBitUnset(spriteFlags, 0x3) or spriteLevel2 > spriteLevel1)) - -- - if sprite:getLocalInt("cdtweaksCleave") == 0 then - if applyAbility then - apply() - end - else - if applyAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksCleave", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDCLEAVE", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/defensive_roll.lua b/cdtweaks/luke/lua/defensive_roll.lua deleted file mode 100644 index 757a66c8..00000000 --- a/cdtweaks/luke/lua/defensive_roll.lua +++ /dev/null @@ -1,41 +0,0 @@ --- cdtweaks: Defensive Roll class feat for rogues -- - -function GTDEFRLL(op403CGameEffect, CGameEffect, CGameSprite) - local damageTypeStr = GT_Resource_IDSToSymbol["dmgtype"][CGameEffect.m_dWFlags] - local damageAmount = CGameEffect.m_effectAmount - -- - local spriteHP = CGameSprite.m_baseStats.m_hitPoints - -- - local spriteState = CGameSprite.m_derivedStats.m_generalState + CGameSprite.m_bonusStats.m_generalState - local state = GT_Resource_SymbolToIDS["state"] - -- - local stats = GT_Resource_SymbolToIDS["stats"] - -- - local spriteSaveVSBreath = CGameSprite.m_derivedStats.m_nSaveVSBreath + CGameSprite.m_bonusStats.m_nSaveVSBreath - -- - local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksDefensiveRollTimer","LOCALS")') - local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksDefensiveRollTimer","LOCALS",7200)') - -- - local roll = Infinity_RandomNumber(1, 20) -- 1d20 - -- If the character is struck by a potentially lethal blow, he makes a save vs. breath. If successful, he takes only half damage from the blow. - if CGameEffect.m_effectId == 0xC and damageTypeStr ~= "STUNNING" and CGameEffect.m_slotNum == -1 and CGameEffect.m_sourceType == 0 and CGameEffect.m_sourceRes:get() == "" -- base weapon damage (all damage types but STUNNING) - and EEex_BAnd(spriteState, state["CD_STATE_NOTVALID"]) == 0 - and spriteSaveVSBreath <= roll - and damageAmount >= spriteHP - and getTimer:evalConditionalAsAIBase(CGameSprite) - then - CGameEffect.m_effectAmount = math.floor(damageAmount / 2) - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 139, -- Display string - ["durationType"] = 1, - ["effectAmount"] = %feedback_strref%, - ["sourceID"] = op403CGameEffect.m_sourceId, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it... - ["sourceTarget"] = op403CGameEffect.m_sourceTarget, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it... - }) - setTimer:executeResponseAsAIBaseInstantly(CGameSprite) - end - -- - getTimer:free() - setTimer:free() -end diff --git a/cdtweaks/luke/lua/fearless.lua b/cdtweaks/luke/lua/fearless.lua deleted file mode 100644 index 2360793f..00000000 --- a/cdtweaks/luke/lua/fearless.lua +++ /dev/null @@ -1,120 +0,0 @@ --- cdtweaks, Fearless (Halflings): This feat grants a +2 bonus on saving throws against fear effects -- - -function GTHLFRLS(op403CGameEffect, CGameEffect, CGameSprite) - local parentResRef = CGameEffect.m_sourceRes:get() - -- - local stats = GT_Resource_SymbolToIDS["stats"] - -- - if CGameEffect.m_effectId == 24 then -- Panic - local success = false - local spriteDerivedStats = CGameSprite.m_derivedStats - local spriteBonusStats = CGameSprite.m_bonusStats - local spriteRoll = -1 - local adjustedRoll = -1 - local spriteSaveVS = -1 - local feedbackStr = "" - -- - local savingThrowTable = { - [0] = {CGameSprite.m_saveVSSpellRoll, spriteDerivedStats.m_nSaveVSSpell + spriteBonusStats.m_nSaveVSSpell, 14003}, - [1] = {CGameSprite.m_saveVSBreathRoll, spriteDerivedStats.m_nSaveVSBreath + spriteBonusStats.m_nSaveVSBreath, 14004}, - [2] = {CGameSprite.m_saveVSDeathRoll, spriteDerivedStats.m_nSaveVSDeath + spriteBonusStats.m_nSaveVSDeath, 14009}, - [3] = {CGameSprite.m_saveVSWandsRoll, spriteDerivedStats.m_nSaveVSWands + spriteBonusStats.m_nSaveVSWands, 14006}, - [4] = {CGameSprite.m_saveVSPolyRoll, spriteDerivedStats.m_nSaveVSPoly + spriteBonusStats.m_nSaveVSPoly, 14005} - } - -- - for k, v in pairs(savingThrowTable) do - if EEex_IsBitSet(CGameEffect.m_savingThrow, k) then - spriteRoll = v[1] - adjustedRoll = v[1] + 2 + CGameEffect.m_saveMod -- the greater ``CGameEffect.m_saveMod``, the easier is to succeed - spriteSaveVS = v[2] - feedbackStr = Infinity_FetchString(v[3]) - if adjustedRoll >= spriteSaveVS then - success = true - end - break - end - end - -- - if success == true then - -- keep track of its duration (needed to remove ancillary op174 effects) - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 401, -- Set extended stat - ["dwFlags"] = 1, -- set - ["effectAmount"] = 2, - ["res"] = parentResRef, - ["m_effectAmount2"] = CGameEffect.m_duration, - ["special"] = stats["GT_IMMUNITY"], - ["sourceID"] = CGameSprite.m_id, - ["sourceTarget"] = CGameSprite.m_id, - }) - -- Mark ancillary effects - EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(fx) - if fx.m_sourceRes:get() == parentResRef then - if fx.m_effectId == 142 then -- Display portrait icon - if fx.m_dWFlags == 36 then - fx.m_sourceRes:set("CDREMOVE") - end - elseif fx.m_effectId == 215 then -- Play visual effect - if fx.m_res:get() == "CDHORROR" then - fx.m_sourceRes:set("CDREMOVE") - end - elseif fx.m_effectId == 174 and fx.m_durationType == 7 then -- Play sound - if math.floor((fx.m_duration - fx.m_effectAmount5) / 15) == CGameEffect.m_duration then - fx.m_sourceRes:set("CDREMOVE") - end - elseif fx.m_effectId == 23 or fx.m_effectId == 54 or fx.m_effectId == 106 then -- morale bonus, base thac0 bonus, morale break - fx.m_sourceRes:set("CDREMOVE") - end - end - end) - -- Remove ancillary effects - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 321, -- Remove effects by resource - ["res"] = "CDREMOVE", - ["durationType"] = 1, - ["sourceID"] = CGameSprite.m_id, - ["sourceTarget"] = CGameSprite.m_id, - }) - -- feedback string (avoid displaying duplicate messages, i.e.: print this only if the +2 bonus makes a difference) - if spriteRoll < spriteSaveVS then - Infinity_DisplayString(CGameSprite:getName() .. ": " .. feedbackStr .. " : " .. adjustedRoll) - end - -- block op24 - return true - end - else - -- block ancillary effects - local duration = -1 - -- - EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(fx) - if fx.m_effectId == 401 and fx.m_special == stats["GT_IMMUNITY"] and fx.m_effectAmount == 2 and fx.m_res:get() == parentResRef then - duration = fx.m_effectAmount2 - return true - end - end) - -- - if duration > -1 then - if CGameEffect.m_effectId == 142 then -- Display portrait icon - if CGameEffect.m_dWFlags == 36 then - return true - end - elseif CGameEffect.m_effectId == 215 then -- Play visual effect - if CGameEffect.m_res:get() == "CDHORROR" then - return true - end - elseif CGameEffect.m_effectId == 139 then -- Display string - if CGameEffect.m_effectAmount == 14007 or CGameEffect.m_effectAmount == 20568 then - return true - end - elseif CGameEffect.m_effectId == 174 then -- Play sound - if CGameEffect.m_duration == duration then - return true - end - elseif CGameEffect.m_effectId == 23 or CGameEffect.m_effectId == 54 or CGameEffect.m_effectAmount == 106 then -- morale bonus, base thac0 bonus, morale break - return true - end - end - end -end diff --git a/cdtweaks/luke/lua/fearless_apply.lua b/cdtweaks/luke/lua/fearless_apply.lua deleted file mode 100644 index a03872ff..00000000 --- a/cdtweaks/luke/lua/fearless_apply.lua +++ /dev/null @@ -1,62 +0,0 @@ --- cdtweaks, Fearless (Halflings): This racial feat grants a +2 bonus on saving throws against fear effects -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual feat - local apply = function() - -- Mark the creature as 'feat applied' - sprite:setLocalInt("cdtweaksFearless", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDHLFRLS", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 403, -- Screen effects - ["durationType"] = 9, - ["res"] = "GTHLFRLS", -- lua function - ["m_sourceRes"] = "CDHLFRLS", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 142, -- Display portrait icon - ["durationType"] = 9, - ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDHLFRLS", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's race - local spriteRaceStr = GT_Resource_IDSToSymbol["race"][sprite.m_typeAI.m_Race] - -- - local applyAbility = spriteRaceStr == "HALFLING" - -- - if sprite:getLocalInt("cdtweaksFearless") == 0 then - if applyAbility then - apply() - end - else - if applyAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksFearless", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDHLFRLS", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/dark_blessing.lua b/cdtweaks/luke/lua/kit/dark_blessing.lua similarity index 73% rename from cdtweaks/luke/lua/dark_blessing.lua rename to cdtweaks/luke/lua/kit/dark_blessing.lua index 398c60d1..eaf0361b 100644 --- a/cdtweaks/luke/lua/dark_blessing.lua +++ b/cdtweaks/luke/lua/kit/dark_blessing.lua @@ -1,4 +1,10 @@ --- cdtweaks: NWN Dark Blessing feat for Blackguards -- +--[[ ++----------------------------------------------------------+ +| cdtweaks, NWN-ish Dark Blessing kit feat for Blackguards | ++----------------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -7,15 +13,14 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end -- internal function that applies the actual bonus local apply = function(bonus) - -- Update var - sprite:setLocalInt("cdtweaksDarkBlessingHelper", bonus) + -- Update tracking var + sprite:setLocalInt("cdtweaksDarkBlessingBonus", bonus) -- Mark the creature as 'bonus applied' sprite:setLocalInt("cdtweaksDarkBlessing", 1) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDRKBLS", + ["res"] = "%BLACKGUARD_DARK_BLESSING%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -23,7 +28,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 325, -- All saving throws bonus ["durationType"] = 9, ["effectAmount"] = bonus, - ["m_sourceRes"] = "CDDRKBLS", + ["m_sourceRes"] = "%BLACKGUARD_DARK_BLESSING%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -31,7 +36,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 142, -- Display portrait icon ["durationType"] = 9, ["dwFlags"] = %feedback_icon_blackguard%, - ["m_sourceRes"] = "CDDRKBLS", + ["m_sourceRes"] = "%BLACKGUARD_DARK_BLESSING%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -47,16 +52,16 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- local bonus = math.floor((spriteCharisma - 10) / 2) -- The blackguard adds its charisma bonus to all saving throws (provided it is not fallen) - local applyCondition = spriteClassStr == "PALADIN" and spriteKitStr == "Blackguard" and bonus and EEex_IsBitUnset(spriteFlags, 0x9) + local applyAbility = spriteClassStr == "PALADIN" and spriteKitStr == "Blackguard" and bonus and EEex_IsBitUnset(spriteFlags, 0x9) -- if sprite:getLocalInt("cdtweaksDarkBlessing") == 0 then - if applyCondition then + if applyAbility then apply(bonus) end else - if applyCondition then + if applyAbility then -- Check if Charisma has changed since the last application - if bonus ~= sprite:getLocalInt("cdtweaksDarkBlessingHelper") then + if bonus ~= sprite:getLocalInt("cdtweaksDarkBlessingBonus") then apply(bonus) end else @@ -65,8 +70,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDDRKBLS", + ["res"] = "%BLACKGUARD_DARK_BLESSING%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/kit/nwn_barbarian_rage.lua b/cdtweaks/luke/lua/kit/nwn_barbarian_rage.lua new file mode 100644 index 00000000..4bab6c64 --- /dev/null +++ b/cdtweaks/luke/lua/kit/nwn_barbarian_rage.lua @@ -0,0 +1,182 @@ +--[[ ++----------------------------------+ +| cdtweaks, NWN-ish Barbarian Rage | ++----------------------------------+ +--]] + +-- Terrifying Rage -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- + local enraged = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksTerrifyingRage","LOCALS") \n CheckSpellState(Myself,BARBARIAN_RAGE)') + local terrifyingRage = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksTerrifyingRage","LOCALS",6) \n ReallyForceSpellRES("%BARBARIAN_RAGE%B",Myself)') + -- + if enraged:evalConditionalAsAIBase(sprite) then + terrifyingRage:executeResponseAsAIBaseInstantly(sprite) + end + -- + enraged:free() + terrifyingRage:free() +end) + +-- Rage / Terrifying Rage / Thundering Rage -- + +function %BARBARIAN_RAGE%(CGameEffect, CGameSprite) + if CGameEffect.m_effectAmount == 1 then + local spriteActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local conModifier = math.floor((spriteActiveStats.m_nCON - 10) / 2) + -- + local splstate = GT_Resource_SymbolToIDS["splstate"] + -- + local effectCodes = { + {["op"] = 328, ["p2"] = splstate["BARBARIAN_RAGE"], ["spec"] = 1}, -- set spell state + {["op"] = 282, ["p2"] = 3, ["p1"] = 1}, -- modify script state + {["op"] = 44, ["p1"] = 4}, -- STR mod (+4) + {["op"] = 10, ["p1"] = 4}, -- CON mod (+4) + {["op"] = 37, ["p1"] = 2}, -- save vs. spell bonus (+2) + {["op"] = 0, ["p1"] = -2}, -- AC bonus (-2) + {["op"] = 341, ["res"] = "%BARBARIAN_RAGE%C", ["spec"] = 1}, -- critical hit effect (melee attacks only, +2d6 extra damage) + {["op"] = 248, ["res"] = "%BARBARIAN_RAGE%D"}, -- melee hit effect (deafness, 25% chance, no save) + {["op"] = 142, ["p2"] = 138} -- icon: rage + {["op"] = 206, ["res"] = CGameEffect.m_sourceRes:get(), ["p1"] = %feedback_strref_already_cast%}, -- protection from spell + } + -- + for _, attributes in ipairs(effectCodes) do + CGameSprite:applyEffect({ + ["effectID"] = attributes["op"] or EEex_Error("opcode number not specified"), + ["effectAmount"] = attributes["p1"] or 0, + ["dwFlags"] = attributes["p2"] or 0, + ["special"] = attributes["spec"] or 0, + ["res"] = attributes["res"] or "", + ["duration"] = (6 * 7) + (6 * conModifier), + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameSprite.m_id, + ["sourceTarget"] = CGameSprite.m_id, + }) + end + elseif CGameEffect.m_effectAmount == 2 then -- Terrifying Rage + local roll = Infinity_RandomNumber(1, 3) -- 1d3 + -- + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + local sourceActiveStats = EEex_Sprite_GetActiveStats(sourceSprite) + -- + if not GT_Utility_EffectCheck(CGameSprite, {["op"] = 0x65, ["p2"] = 24}) then + local effectCodes = {} + -- + if sourceActiveStats.m_nLevel1 > 1 then + effectCodes = { + {["op"] = 54, ["dur"] = 6 * roll, ["p1"] = -2, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- base thac0 bonus (-2) + {["op"] = 325, ["dur"] = 6 * roll, ["p1"] = -2, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- save vs. all bonus (-2) + {["op"] = 139, ["p1"] = %feedback_strref_trembling_with_fear%, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- string: trembling with fear + -- + {["op"] = 24, ["dur"] = 6 * roll, ["maxLvl"] = sourceActiveStats.m_nLevel1 - 1}, -- panic + {["op"] = 142, ["dur"] = 6 * roll, ["p2"] = 36, ["maxLvl"] = sourceActiveStats.m_nLevel1 - 1}, -- icon: panic + {["op"] = 139, ["p1"] = %feedback_strref_panic%, ["maxLvl"] = sourceActiveStats.m_nLevel1 - 1}, -- string: panic + } + else + effectCodes = { + {["op"] = 54, ["dur"] = 6 * roll, ["p1"] = -2, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- base thac0 bonus (-2) + {["op"] = 325, ["dur"] = 6 * roll, ["p1"] = -2, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- save vs. all bonus (-2) + {["op"] = 139, ["p1"] = %feedback_strref_trembling_with_fear%, ["minLvl"] = sourceActiveStats.m_nLevel1, ["maxLvl"] = sourceActiveStats.m_nLevel1}, -- string: trembling with fear + } + end + -- + local savebonus = math.floor((sourceActiveStats.m_nLevel1 - 1) / 4) -- +1 every 4 levels, starting at 0 + if savebonus > 7 then + savebonus = 7 -- cap at 7 + end + -- + for _, attributes in ipairs(effectCodes) do + CGameSprite:applyEffect({ + ["effectID"] = attributes["op"] or EEex_Error("opcode number not specified"), + ["effectAmount"] = attributes["p1"] or 0, + ["dwFlags"] = attributes["p2"] or 0, + ["duration"] = attributes["dur"] or 0, + ["savingThrow"] = 0x4, -- save vs. death + ["saveMod"] = -1 * savebonus, + ["m_minLevel"] = attributes["minLvl"] or 0, + ["m_maxLevel"] = attributes["maxLvl"] or 0, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + elseif CGameEffect.m_effectAmount == 3 then -- Thundering Rage + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + -- + local equipment = sourceSprite.m_equipment + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- Item_Header_st + -- + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + -- + local items = sourceSprite.m_equipment.m_items -- Array + local offHand = items:get(9) -- CItem + if offHand and sourceSprite.m_leftAttack == 1 then + local pHeader = offHand.pRes.pHeader -- Item_Header_st + if not (pHeader.itemType == 0xC) then -- if not shield, then overwrite item ability... + selectedWeaponAbility = EEex_Resource_GetItemAbility(pHeader, 0) -- Item_ability_st + end + end + -- + local immunityToDamage = EEex_Trigger_ParseConditionalString("EEex_IsImmuneToOpcode(Myself,12)") + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local itmAbilityDamageTypeToIDS = { + 0x10, -- piercing + 0x0, -- crushing + 0x100, -- slashing + 0x80, -- missile + 0x800, -- non-lethal + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistCrushing and 0x0 or 0x10, -- piercing/crushing (better) + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistSlashing and 0x100 or 0x10, -- piercing/slashing (better) + targetActiveStats.m_nResistCrushing > targetActiveStats.m_nResistSlashing and 0x0 or 0x100, -- slashing/crushing (worse) + } + -- + if itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] then -- sanity check + if not immunityToDamage:evalConditionalAsAIBase(CGameSprite) then + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 0xC, -- Damage + ["dwFlags"] = itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] * 0x10000, -- mode: normal + ["numDice"] = 2, + ["diceSize"] = 6, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 324, -- Immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + immunityToDamage:free() + end +end diff --git a/cdtweaks/luke/lua/kit/poison_save.lua b/cdtweaks/luke/lua/kit/poison_save.lua new file mode 100644 index 00000000..445eceb9 --- /dev/null +++ b/cdtweaks/luke/lua/kit/poison_save.lua @@ -0,0 +1,226 @@ +--[[ ++------------------------------------------------------+ +| cdtweaks, NWN-ish Poison Save kit feat for Assassins | ++------------------------------------------------------+ +--]] + +local cdtweaks_PoisonSave_FeedbackString = { + ["Poison"] = true, + ["Poisoned"] = true, +} + +local cdtweaks_PoisonSave_FeedbackIcon = { + [6] = true, -- Poisoned + [101] = true, -- Decaying (see ``CLERIC_DOLOROUS_DECAY``) +} + +-- Apply ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual feat + local apply = function() + -- Mark the creature as 'feat applied' + sprite:setLocalInt("cdtweaksPoisonSave", 1) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%ASSASSIN_POISON_SAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 403, -- Screen effects + ["durationType"] = 9, + ["res"] = "%ASSASSIN_POISON_SAVE%", -- lua function + ["m_sourceRes"] = "%ASSASSIN_POISON_SAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 142, -- Display portrait icon + ["durationType"] = 9, + ["dwFlags"] = %feedback_icon%, + ["m_sourceRes"] = "%ASSASSIN_POISON_SAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check creature's class / kit + local spriteFlags = sprite.m_baseStats.m_flags + local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] + -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine + local spriteKitStr = GT_Resource_IDSToSymbol["kit"][sprite.m_derivedStats.m_nKit] + local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 + local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 + -- single/multi/(complete)dual assassins + local applyAbility = spriteClassStr == "THIEF" + or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + or (spriteClassStr == "MAGE_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + local applyAbility = applyAbility and spriteKitStr == "ASSASIN" + -- + if sprite:getLocalInt("cdtweaksPoisonSave") == 0 then + if applyAbility then + apply() + end + else + if applyAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksPoisonSave", 0) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%ASSASSIN_POISON_SAVE%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) + +-- This class feat grants a +2 bonus on saving throws against poison effects -- + +function %ASSASSIN_POISON_SAVE%(op403CGameEffect, CGameEffect, CGameSprite) + local language = Infinity_GetINIString('Language', 'Text', 'should not happen') + local displaySubtitles = Infinity_GetINIValue('Program Options', 'Display Subtitles', -1) + -- + local parentResRef = CGameEffect.m_sourceRes:get() + -- + local stats = GT_Resource_SymbolToIDS["stats"] + -- + if CGameEffect.m_effectId == 25 or (CGameEffect.m_effectId == 12 and EEex_IsMaskSet(CGameEffect.m_dWFlags, 0x200000)) then -- Poison || Damage (poison) + local success = false + local spriteActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + local spriteRoll = -1 + local adjustedRoll = -1 + local spriteSaveVS = -1 + local feedbackStr = "" + -- + local savingThrowTable = { + [0] = {CGameSprite.m_saveVSSpellRoll, spriteActiveStats.m_nSaveVSSpell, 14003}, + [1] = {CGameSprite.m_saveVSBreathRoll, spriteActiveStats.m_nSaveVSBreath, 14004}, + [2] = {CGameSprite.m_saveVSDeathRoll, spriteActiveStats.m_nSaveVSDeath, 14009}, + [3] = {CGameSprite.m_saveVSWandsRoll, spriteActiveStats.m_nSaveVSWands, 14006}, + [4] = {CGameSprite.m_saveVSPolyRoll, spriteActiveStats.m_nSaveVSPoly, 14005} + } + -- + for k, v in pairs(savingThrowTable) do + if EEex_IsBitSet(CGameEffect.m_savingThrow, k) then + spriteRoll = v[1] + adjustedRoll = v[1] + 2 + CGameEffect.m_saveMod -- the greater ``CGameEffect.m_saveMod``, the easier is to succeed + spriteSaveVS = v[2] + feedbackStr = Infinity_FetchString(v[3]) + if adjustedRoll >= spriteSaveVS then + success = true + end + break + end + end + -- + if success == true then + -- keep track of its duration (needed to remove ancillary op174 effects) + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 401, -- Set extended stat + ["dwFlags"] = 1, -- set + ["effectAmount"] = 3, + ["res"] = parentResRef, + ["m_effectAmount2"] = CGameEffect.m_duration, + ["special"] = stats["GT_IMMUNITY"], + ["sourceID"] = CGameSprite.m_id, + ["sourceTarget"] = CGameSprite.m_id, + }) + -- Mark ancillary effects + EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(effect) + if effect.m_sourceRes:get() == parentResRef then + if effect.m_effectId == 142 then -- Display portrait icon + if cdtweaks_PoisonSave_FeedbackIcon[effect.m_dWFlags] then + effect.m_sourceRes:set("CDREMOVE") + end + elseif effect.m_effectId == 174 and effect.m_durationType == 7 then -- Play sound + if math.floor((effect.m_duration - effect.m_effectAmount5) / 15) == CGameEffect.m_duration then + effect.m_sourceRes:set("CDREMOVE") + end + elseif effect.m_effectId == 139 then -- Display string + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_PoisonSave_FeedbackString[Infinity_FetchString(effect.m_effectAmount)] then + effect.m_sourceRes:set("CDREMOVE") + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + end + end + end) + -- Remove ancillary effects + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "CDREMOVE", + ["sourceID"] = CGameSprite.m_id, + ["sourceTarget"] = CGameSprite.m_id, + }) + -- feedback string (avoid displaying duplicate messages, i.e.: print this only if the +2 bonus makes a difference) + if spriteRoll < spriteSaveVS then + Infinity_DisplayString(CGameSprite:getName() .. ": " .. feedbackStr .. " : " .. adjustedRoll) + end + -- block op25/12 + return true + end + else + -- block ancillary effects + local duration = -1 + -- + EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(effect) + if effect.m_effectId == 401 and effect.m_special == stats["GT_IMMUNITY"] and effect.m_effectAmount == 3 and effect.m_res:get() == parentResRef then + duration = effect.m_effectAmount2 + return true + end + end) + -- + if duration > -1 then + if CGameEffect.m_effectId == 142 then -- Display portrait icon + if cdtweaks_PoisonSave_FeedbackIcon[CGameEffect.m_dWFlags] then + return true + end + elseif CGameEffect.m_effectId == 139 then -- Display string + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_PoisonSave_FeedbackString[Infinity_FetchString(CGameEffect.m_effectAmount)] then + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + -- + return true + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + elseif CGameEffect.m_effectId == 174 then -- Play sound + if CGameEffect.m_duration == duration and (CGameEffect.m_durationType == 3 or CGameEffect.m_durationType == 4) then + return true + end + end + elseif CGameEffect.m_effectId == 139 then + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_PoisonSave_FeedbackString[Infinity_FetchString(CGameEffect.m_effectAmount)] then + -- make sure instantaneous effects get applied *after* the poison opcode (so that we can properly block them) + if CGameEffect.m_durationType == 0 or CGameEffect.m_durationType == 1 or CGameEffect.m_durationType == 9 or CGameEffect.m_durationType == 10 then + -- 0-sec delay (instantaneous delay) + CGameEffect.m_durationType = 4 + CGameEffect.m_duration = 0 + end + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + end + end +end diff --git a/cdtweaks/luke/lua/kit/sneakatt_blackguard.lua b/cdtweaks/luke/lua/kit/sneakatt_blackguard.lua new file mode 100644 index 00000000..2be726d0 --- /dev/null +++ b/cdtweaks/luke/lua/kit/sneakatt_blackguard.lua @@ -0,0 +1,166 @@ +--[[ ++---------------------------------------------------------+ +| cdtweaks, NWN-ish Sneak Attack kit feat for Blackguards | ++---------------------------------------------------------+ +--]] + +-- Apply ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual bonus + local apply = function() + -- Mark the creature as 'feat applied' + sprite:setLocalInt("cdtweaksSneakattBlackguard", 1) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%BLACKGUARD_SNEAK_ATTACK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 248, -- Melee hit effect + ["res"] = "%BLACKGUARD_SNEAK_ATTACK%B", -- EFF file + ["durationType"] = 9, + ["m_sourceRes"] = "%BLACKGUARD_SNEAK_ATTACK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 249, -- Ranged hit effect + ["res"] = "%BLACKGUARD_SNEAK_ATTACK%B", -- EFF file + ["durationType"] = 9, + ["m_sourceRes"] = "%BLACKGUARD_SNEAK_ATTACK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check creature's class / kit / flags + local spriteFlags = sprite.m_baseStats.m_flags + local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] + -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine + local spriteKitStr = GT_Resource_IDSToSymbol["kit"][sprite.m_derivedStats.m_nKit] + -- Grant the feat to Blackguards (must not be fallen) + local applyAbility = spriteClassStr == "PALADIN" and spriteKitStr == "Blackguard" and EEex_IsBitUnset(spriteFlags, 9) + -- + if sprite:getLocalInt("cdtweaksSneakattBlackguard") == 0 then + if applyAbility then + apply() + end + else + if applyAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksSneakattBlackguard", 0) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%BLACKGUARD_SNEAK_ATTACK%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) + +-- Core function -- + +function %BLACKGUARD_SNEAK_ATTACK%(CGameEffect, CGameSprite) + if CGameEffect.m_effectAmount == 1 then -- check if can perform a sneak attack + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- limit to once per round + local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksSneakattBlckgrdTimer","LOCALS")') + local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksSneakattBlckgrdTimer","LOCALS",6)') + -- + if getTimer:evalConditionalAsAIBase(sourceSprite) then + -- if the target is incapacitated || the target is in combat with someone else || the blackguard is invisible + if EEex_BAnd(targetActiveStats.m_generalState, 0x100029) ~= 0 or CGameSprite.m_targetId ~= sourceSprite.m_id or sourceSprite:getLocalInt("gtSpriteIsInvisible") == 1 then + setTimer:executeResponseAsAIBaseInstantly(sourceSprite) + -- + CGameSprite:applyEffect({ + ["effectID"] = 146, -- Cast spell + ["res"] = "%BLACKGUARD_SNEAK_ATTACK%B", -- SPL file + ["dwFlags"] = 1, -- cast instantly / ignore level + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + getTimer:free() + setTimer:free() + elseif CGameEffect.m_effectAmount == 2 then -- actual sneak attack + local sneakatt = GT_Resource_2DA["sneakatt"] + -- + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) + local sourceActiveStats = EEex_Sprite_GetActiveStats(sourceSprite) + -- + local equipment = sourceSprite.m_equipment + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) + local selectedWeaponHeader = selectedWeapon.pRes.pHeader -- Item_Header_st + -- + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + -- + if selectedWeaponAbility.type == 1 and sourceSprite.m_leftAttack == 1 then -- if attacking with offhand ... + local items = sourceSprite.m_equipment.m_items -- Array + local offHand = items:get(9) -- CItem + -- + if offHand then + local pHeader = offHand.pRes.pHeader -- Item_Header_st + if not (pHeader.itemType == 0xC) then -- if not shield, then overwrite item ability... + selectedWeaponAbility = EEex_Resource_GetItemAbility(pHeader, 0) -- Item_ability_st + end + end + end + -- + local immunityToDamage = EEex_Trigger_ParseConditionalString("EEex_IsImmuneToOpcode(Myself,12)") + -- + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + -- + local itmAbilityDamageTypeToIDS = { + 0x10, -- piercing + 0x0, -- crushing + 0x100, -- slashing + 0x80, -- missile + 0x800, -- non-lethal + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistCrushing and 0x0 or 0x10, -- piercing/crushing (better) + targetActiveStats.m_nResistPiercing > targetActiveStats.m_nResistSlashing and 0x100 or 0x10, -- piercing/slashing (better) + targetActiveStats.m_nResistCrushing > targetActiveStats.m_nResistSlashing and 0x0 or 0x100, -- slashing/crushing (worse) + } + -- + if itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] then -- sanity check + if not immunityToDamage:evalConditionalAsAIBase(CGameSprite) then + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 0xC, -- Damage + ["dwFlags"] = itmAbilityDamageTypeToIDS[selectedWeaponAbility.damageType] * 0x10000, -- mode: normal + ["numDice"] = tonumber(sneakatt["STALKER"][string.format("%s", sourceActiveStats.m_nLevel1)]), + ["diceSize"] = 6, + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 324, -- Immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), + ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + -- + immunityToDamage:free() + end +end diff --git a/cdtweaks/luke/lua/m_gttbls.lua b/cdtweaks/luke/lua/m_gttbls.lua index 6861a6c6..9dc55ef3 100644 --- a/cdtweaks/luke/lua/m_gttbls.lua +++ b/cdtweaks/luke/lua/m_gttbls.lua @@ -1,4 +1,8 @@ --- Lua tables derived from .2DA / .IDS resources (it's not needed per se, but we'll be getting hash map levels of performance instead of linear search) -- +--[[ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Utility: Lua tables derived from .2DA / .IDS resources (it's not needed per se, but we'll be getting hash map levels of performance instead of linear search) | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +--]] GT_Resource_2DA = {} GT_Resource_IDSToSymbol = {} diff --git a/cdtweaks/luke/lua/planar_turning.lua b/cdtweaks/luke/lua/planar_turning.lua deleted file mode 100644 index e1c2b9fd..00000000 --- a/cdtweaks/luke/lua/planar_turning.lua +++ /dev/null @@ -1,124 +0,0 @@ --- cdtweaks, Planar Turning class feat for Paladins and Clerics -- - -function GTPLNTRN(CGameEffect, CGameSprite) - local parentResRef = CGameEffect.m_sourceRes:get() - -- - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - local isEvil = EEex_Trigger_ParseConditionalString("Alignment(Myself,MASK_EVIL)") - local sourceTurnUndeadLevel = sourceSprite.m_derivedStats.m_nTurnUndeadLevel + sourceSprite.m_bonusStats.m_nTurnUndeadLevel - -- - local targetRaceStr = GT_Resource_IDSToSymbol["race"][CGameSprite.m_typeAI.m_Race] - local targetLevel = CGameSprite.m_derivedStats.m_nLevel1 + CGameSprite.m_bonusStats.m_nLevel1 - -- - local roll = math.random(0, 3) -- engine: ((int)((rand() & 0x7fff) << 2) >> 0xf) => generates a random number, keeps its lower 15 bits, multiplies by 2^2, divides by 2^15 - -- - if targetRaceStr == "DEMONIC" or targetRaceStr == "MEPHIT" or targetRaceStr == "IMP" or targetRaceStr == "ELEMENTAL" or targetRaceStr == "SALAMANDER" or targetRaceStr == "SOLAR" or targetRaceStr == "ANTISOLAR" or targetRaceStr == "DARKPLANATAR" or targetRaceStr == "PLANATAR" or targetRaceStr == "GENIE" then -- if extraplanar ... - if sourceTurnUndeadLevel < (targetLevel + roll) + 5 then - if sourceTurnUndeadLevel >= (targetLevel + roll) then -- turn - CGameSprite:applyEffect({ - ["effectID"] = 174, -- Play sound - ["durationType"] = 1, - ["res"] = "ACT_06", - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 141, -- Lighting effects - ["durationType"] = 1, - ["dwFlags"] = 24, -- Effect: Invocation air - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 24, -- Panic - ["dwFlags"] = 1, -- bypass immunity - ["noSave"] = true, -- redundant...? - ["duration"] = 60, - ["m_sourceRes"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 142, -- Feedback icon - ["dwFlags"] = 36, -- icon: panic - ["noSave"] = true, - ["duration"] = 60, - ["m_sourceRes"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 139, -- Display string - ["durationType"] = 1, - ["effectAmount"] = %feedback_strref%, - ["m_sourceRes"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - else -- destroy or take control - if isEvil:evalConditionalAsAIBase(sourceSprite) then -- take control - CGameSprite:applyEffect({ - ["effectID"] = 174, -- Play sound - ["durationType"] = 1, - ["res"] = "ACT_06", - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 141, -- Lighting effects - ["durationType"] = 1, - ["dwFlags"] = 24, -- Effect: Invocation air - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 241, -- Control creature - ["dwFlags"] = 4, -- charm type: controlled - ["duration"] = 60, - ["m_sourceRes"] = parentResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - else -- destroy - CGameSprite:applyEffect({ - ["effectID"] = 174, -- Play sound - ["durationType"] = 1, - ["res"] = "ACT_06", - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 141, -- Lighting effects - ["durationType"] = 1, - ["dwFlags"] = 24, -- Effect: Invocation air - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - CGameSprite:applyEffect({ - ["effectID"] = 13, -- Kill creature - ["durationType"] = 1, - ["dwFlags"] = 4, -- normal death - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - end - end - -- - isEvil:free() -end diff --git a/cdtweaks/luke/lua/planar_turning_modal.lua b/cdtweaks/luke/lua/planar_turning_modal.lua deleted file mode 100644 index 306e75c4..00000000 --- a/cdtweaks/luke/lua/planar_turning_modal.lua +++ /dev/null @@ -1,25 +0,0 @@ --- cdtweaks, Planar Turning class feat for Paladins and Clerics -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual turning - local turnPlanarMode = function() - sprite:applyEffect({ - ["effectID"] = 146, -- Cast spell - ["durationType"] = 1, - ["dwFlags"] = 1, -- instant / ignore level - ["res"] = "CDPLNTRN", -- SPL file - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check if the creature is turning undead - local turnUndeadMode = EEex_Sprite_GetModalState(sprite) == 4 and EEex_Sprite_GetModalTimer(sprite) == 0 - -- - if turnUndeadMode then - turnPlanarMode() - end -end) diff --git a/cdtweaks/luke/lua/poison_save.lua b/cdtweaks/luke/lua/poison_save.lua deleted file mode 100644 index 588978fa..00000000 --- a/cdtweaks/luke/lua/poison_save.lua +++ /dev/null @@ -1,108 +0,0 @@ --- cdtweaks, Poison Save (Assassins): This class feat grants a +2 bonus on saving throws against poison effects -- - -function GTPSNSAV(op403CGameEffect, CGameEffect, CGameSprite) - local parentResRef = CGameEffect.m_sourceRes:get() - -- - local stats = GT_Resource_SymbolToIDS["stats"] - -- - if CGameEffect.m_effectId == 25 or (CGameEffect.m_effectId == 12 and EEex_IsMaskSet(CGameEffect.m_dWFlags, 0x200000)) then -- Poison || Damage (poison) - local success = false - local spriteDerivedStats = CGameSprite.m_derivedStats - local spriteBonusStats = CGameSprite.m_bonusStats - local spriteRoll = -1 - local adjustedRoll = -1 - local spriteSaveVS = -1 - local feedbackStr = "" - -- - local savingThrowTable = { - [0] = {CGameSprite.m_saveVSSpellRoll, spriteDerivedStats.m_nSaveVSSpell + spriteBonusStats.m_nSaveVSSpell, 14003}, - [1] = {CGameSprite.m_saveVSBreathRoll, spriteDerivedStats.m_nSaveVSBreath + spriteBonusStats.m_nSaveVSBreath, 14004}, - [2] = {CGameSprite.m_saveVSDeathRoll, spriteDerivedStats.m_nSaveVSDeath + spriteBonusStats.m_nSaveVSDeath, 14009}, - [3] = {CGameSprite.m_saveVSWandsRoll, spriteDerivedStats.m_nSaveVSWands + spriteBonusStats.m_nSaveVSWands, 14006}, - [4] = {CGameSprite.m_saveVSPolyRoll, spriteDerivedStats.m_nSaveVSPoly + spriteBonusStats.m_nSaveVSPoly, 14005} - } - -- - for k, v in pairs(savingThrowTable) do - if EEex_IsBitSet(CGameEffect.m_savingThrow, k) then - spriteRoll = v[1] - adjustedRoll = v[1] + 2 + CGameEffect.m_saveMod -- the greater ``CGameEffect.m_saveMod``, the easier is to succeed - spriteSaveVS = v[2] - feedbackStr = Infinity_FetchString(v[3]) - if adjustedRoll >= spriteSaveVS then - success = true - end - break - end - end - -- - if success == true then - -- keep track of its duration (needed to remove ancillary op174 effects) - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 401, -- Set extended stat - ["dwFlags"] = 1, -- set - ["effectAmount"] = 3, - ["res"] = parentResRef, - ["m_effectAmount2"] = CGameEffect.m_duration, - ["special"] = stats["GT_IMMUNITY"], - ["sourceID"] = CGameSprite.m_id, - ["sourceTarget"] = CGameSprite.m_id, - }) - -- Mark ancillary effects - EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(fx) - if fx.m_sourceRes:get() == parentResRef then - if fx.m_effectId == 142 then -- Display portrait icon - if fx.m_dWFlags == 6 or fx.m_dWFlags == 101 then -- this includes the "Decaying" icon (see ``CLERIC_DOLOROUS_DECAY``) - fx.m_sourceRes:set("CDREMOVE") - end - elseif fx.m_effectId == 174 and fx.m_durationType == 7 then -- Play sound - if math.floor((fx.m_duration - fx.m_effectAmount5) / 15) == CGameEffect.m_duration then - fx.m_sourceRes:set("CDREMOVE") - end - end - end - end) - -- Remove ancillary effects - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 321, -- Remove effects by resource - ["res"] = "CDREMOVE", - ["durationType"] = 1, - ["sourceID"] = CGameSprite.m_id, - ["sourceTarget"] = CGameSprite.m_id, - }) - -- feedback string (avoid displaying duplicate messages, i.e.: print this only if the +2 bonus makes a difference) - if spriteRoll < spriteSaveVS then - Infinity_DisplayString(CGameSprite:getName() .. ": " .. feedbackStr .. " : " .. adjustedRoll) - end - -- block op25/12 - return true - end - else - -- block ancillary effects - local duration = -1 - -- - EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(fx) - if fx.m_effectId == 401 and fx.m_special == stats["GT_IMMUNITY"] and fx.m_effectAmount == 3 and fx.m_res:get() == parentResRef then - duration = fx.m_effectAmount2 - return true - end - end) - -- - if duration > -1 then - if CGameEffect.m_effectId == 142 then -- Display portrait icon - if CGameEffect.m_dWFlags == 6 or CGameEffect.m_dWFlags == 101 then -- this includes the "Decaying" icon (see ``CLERIC_DOLOROUS_DECAY``) - return true - end - elseif CGameEffect.m_effectId == 139 then -- Display string - if CGameEffect.m_effectAmount == 14017 or CGameEffect.m_effectAmount == 37607 then - return true - end - elseif CGameEffect.m_effectId == 174 then -- Play sound - if CGameEffect.m_duration == duration then - return true - end - end - end - end -end diff --git a/cdtweaks/luke/lua/poison_save_apply.lua b/cdtweaks/luke/lua/poison_save_apply.lua deleted file mode 100644 index f4610cca..00000000 --- a/cdtweaks/luke/lua/poison_save_apply.lua +++ /dev/null @@ -1,71 +0,0 @@ --- cdtweaks, Poison Save (Assassins): This class feat grants a +2 bonus on saving throws against poison effects -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual feat - local apply = function() - -- Mark the creature as 'feat applied' - sprite:setLocalInt("cdtweaksPoisonSave", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDPSNSAV", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 403, -- Screen effects - ["durationType"] = 9, - ["res"] = "GTPSNSAV", -- lua function - ["m_sourceRes"] = "CDPSNSAV", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 142, -- Display portrait icon - ["durationType"] = 9, - ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDPSNSAV", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's class / kit - local spriteFlags = sprite.m_baseStats.m_flags - local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] - -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine - local spriteKitStr = GT_Resource_IDSToSymbol["kit"][sprite.m_derivedStats.m_nKit] - local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 - local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 - -- single/multi/(complete)dual assassins - local applyAbility = spriteClassStr == "THIEF" - or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) - or (spriteClassStr == "MAGE_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) - or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) - local applyAbility = applyAbility and spriteKitStr == "ASSASIN" - -- - if sprite:getLocalInt("cdtweaksPoisonSave") == 0 then - if applyAbility then - apply() - end - else - if applyAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksPoisonSave", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDPSNSAV", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/race/fearless.lua b/cdtweaks/luke/lua/race/fearless.lua new file mode 100644 index 00000000..f286a458 --- /dev/null +++ b/cdtweaks/luke/lua/race/fearless.lua @@ -0,0 +1,231 @@ +--[[ ++------------------------------------------------------+ +| cdtweaks, NWN-ish Fearless racial feat for Halflings | ++------------------------------------------------------+ +--]] + +local cdtweaks_Fearless_FeedbackString = { + ["Panic"] = true, + ["*flees in terror*"] = true, + ["Morale Failure: Panic"] = true, +} + +local cdtweaks_Fearless_FeedbackVFX = { + ["CDHORROR"] = true, + ["OHRMIND"] = true, + ["SPMINDAT"] = true, +} + +-- Apply ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that applies the actual feat + local apply = function() + -- Mark the creature as 'feat applied' + sprite:setLocalInt("cdtweaksFearless", 1) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%HALFLING_FEARLESS%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 403, -- Screen effects + ["durationType"] = 9, + ["res"] = "%HALFLING_FEARLESS%", -- lua function + ["m_sourceRes"] = "%HALFLING_FEARLESS%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 142, -- Display portrait icon + ["durationType"] = 9, + ["dwFlags"] = %feedback_icon%, + ["m_sourceRes"] = "%HALFLING_FEARLESS%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- Check creature's race + local spriteRaceStr = GT_Resource_IDSToSymbol["race"][sprite.m_typeAI.m_Race] + -- + local applyAbility = spriteRaceStr == "HALFLING" + -- + if sprite:getLocalInt("cdtweaksFearless") == 0 then + if applyAbility then + apply() + end + else + if applyAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksFearless", 0) + -- + sprite:applyEffect({ + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "%HALFLING_FEARLESS%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) + +-- This feat grants a +2 bonus on saving throws against fear effects -- + +function %HALFLING_FEARLESS%(op403CGameEffect, CGameEffect, CGameSprite) + local language = Infinity_GetINIString('Language', 'Text', 'should not happen') + local displaySubtitles = Infinity_GetINIValue('Program Options', 'Display Subtitles', -1) + -- + local parentResRef = CGameEffect.m_sourceRes:get() + -- + local stats = GT_Resource_SymbolToIDS["stats"] + -- + if CGameEffect.m_effectId == 24 then -- Panic + local success = false + local spriteActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) + local spriteRoll = -1 + local adjustedRoll = -1 + local spriteSaveVS = -1 + local feedbackStr = "" + -- + local savingThrowTable = { + [0] = {CGameSprite.m_saveVSSpellRoll, spriteActiveStats.m_nSaveVSSpell, 14003}, + [1] = {CGameSprite.m_saveVSBreathRoll, spriteActiveStats.m_nSaveVSBreath, 14004}, + [2] = {CGameSprite.m_saveVSDeathRoll, spriteActiveStats.m_nSaveVSDeath, 14009}, + [3] = {CGameSprite.m_saveVSWandsRoll, spriteActiveStats.m_nSaveVSWands, 14006}, + [4] = {CGameSprite.m_saveVSPolyRoll, spriteActiveStats.m_nSaveVSPoly, 14005} + } + -- + for k, v in pairs(savingThrowTable) do + if EEex_IsBitSet(CGameEffect.m_savingThrow, k) then + spriteRoll = v[1] + adjustedRoll = v[1] + 2 + CGameEffect.m_saveMod -- the greater ``CGameEffect.m_saveMod``, the easier is to succeed + spriteSaveVS = v[2] + feedbackStr = Infinity_FetchString(v[3]) + if adjustedRoll >= spriteSaveVS then + success = true + end + break + end + end + -- + if success == true then + -- keep track of its duration (needed to remove ancillary op174 effects) + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 401, -- Set extended stat + ["dwFlags"] = 1, -- set + ["effectAmount"] = 2, + ["res"] = parentResRef, + ["m_effectAmount2"] = CGameEffect.m_duration, + ["special"] = stats["GT_IMMUNITY"], + ["sourceID"] = CGameSprite.m_id, + ["sourceTarget"] = CGameSprite.m_id, + }) + -- Mark ancillary effects + EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(effect) + if effect.m_sourceRes:get() == parentResRef then + if effect.m_effectId == 142 then -- Display portrait icon + if effect.m_dWFlags == 36 then + effect.m_sourceRes:set("CDREMOVE") + end + elseif effect.m_effectId == 215 then -- Play visual effect + if cdtweaks_Fearless_FeedbackVFX[effect.m_res:get()] then + effect.m_sourceRes:set("CDREMOVE") + end + elseif effect.m_effectId == 174 and effect.m_durationType == 7 then -- Play sound + if math.floor((effect.m_duration - effect.m_effectAmount5) / 15) == CGameEffect.m_duration then + effect.m_sourceRes:set("CDREMOVE") + end + elseif effect.m_effectId == 23 or effect.m_effectId == 54 or effect.m_effectId == 106 then -- morale bonus, base thac0 bonus, morale break + effect.m_sourceRes:set("CDREMOVE") + elseif effect.m_effectId == 139 then -- Display string + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_Fearless_FeedbackString[Infinity_FetchString(effect.m_effectAmount)] then + effect.m_sourceRes:set("CDREMOVE") + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + end + end + end) + -- Remove ancillary effects + EEex_GameObject_ApplyEffect(CGameSprite, + { + ["effectID"] = 321, -- Remove effects by resource + ["res"] = "CDREMOVE", + ["sourceID"] = CGameSprite.m_id, + ["sourceTarget"] = CGameSprite.m_id, + }) + -- feedback string (avoid displaying duplicate messages, i.e.: print this only if the +2 bonus makes a difference) + if spriteRoll < spriteSaveVS then + Infinity_DisplayString(CGameSprite:getName() .. ": " .. feedbackStr .. " : " .. adjustedRoll) + end + -- block op24 + return true + end + else + -- block ancillary effects + local duration = -1 + -- + EEex_Utility_IterateCPtrList(CGameSprite.m_timedEffectList, function(effect) + if effect.m_effectId == 401 and effect.m_special == stats["GT_IMMUNITY"] and effect.m_effectAmount == 2 and effect.m_res:get() == parentResRef then + duration = effect.m_effectAmount2 + return true + end + end) + -- + if duration > -1 then + if CGameEffect.m_effectId == 142 then -- Display portrait icon + if CGameEffect.m_dWFlags == 36 then + return true + end + elseif CGameEffect.m_effectId == 215 then -- Play visual effect + if cdtweaks_Fearless_FeedbackVFX[CGameEffect.m_res:get()] then + return true + end + elseif CGameEffect.m_effectId == 139 then -- Display string + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_Fearless_FeedbackString[Infinity_FetchString(CGameEffect.m_effectAmount)] then + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + -- + return true + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + elseif CGameEffect.m_effectId == 174 then -- Play sound + if CGameEffect.m_duration == duration then + return true + end + elseif CGameEffect.m_effectId == 23 or CGameEffect.m_effectId == 54 or CGameEffect.m_effectId == 106 then -- morale bonus, base thac0 bonus, morale break + return true + end + elseif CGameEffect.m_effectId == 139 then + -- temporarily set language to English + Infinity_SetLanguage("en_US", 0) + -- + if cdtweaks_Fearless_FeedbackString[Infinity_FetchString(CGameEffect.m_effectAmount)] then + -- make sure instantaneous effects get applied *after* the panic opcode (so that we can properly block them) + if CGameEffect.m_durationType == 0 or CGameEffect.m_durationType == 1 or CGameEffect.m_durationType == 9 or CGameEffect.m_durationType == 10 then + -- 0-sec delay (instantaneous delay) + CGameEffect.m_durationType = 4 + CGameEffect.m_duration = 0 + end + end + -- restore original language / subtitles + Infinity_SetLanguage(language, displaySubtitles) + end + end +end diff --git a/cdtweaks/luke/lua/good_aim.lua b/cdtweaks/luke/lua/race/good_aim.lua similarity index 62% rename from cdtweaks/luke/lua/good_aim.lua rename to cdtweaks/luke/lua/race/good_aim.lua index ef7b1d9b..84ec51f1 100644 --- a/cdtweaks/luke/lua/good_aim.lua +++ b/cdtweaks/luke/lua/race/good_aim.lua @@ -1,4 +1,10 @@ --- cdtweaks, good aim racial feat for halflings -- +--[[ ++--------------------------------------------------+ +| cdtweaks, NWN Good Aim racial feat for Halflings | ++--------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -12,8 +18,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDHLGAIM", + ["res"] = "%HALFLING_GOOD_AIM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -21,7 +26,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 167, -- Missile THAC0 bonus ["effectAmount"] = 1, ["durationType"] = 9, - ["m_sourceRes"] = "CDHLGAIM", + ["m_sourceRes"] = "%HALFLING_GOOD_AIM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -29,23 +34,23 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 142, -- Display portrait icon ["durationType"] = 9, ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDHLGAIM", + ["m_sourceRes"] = "%HALFLING_GOOD_AIM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end -- Check creature's equipment / race local equipment = sprite.m_equipment - local selectedItem = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedItem.pRes.pHeader - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st + local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) + local selectedWeaponHeader = selectedWeapon.pRes.pHeader + local selectedWeaponAbility = EEex_Resource_GetItemAbility(selectedWeaponHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st -- local spriteRaceStr = GT_Resource_IDSToSymbol["race"][sprite.m_typeAI.m_Race] -- - local itemTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] + local selectedWeaponTypeStr = GT_Resource_IDSToSymbol["itemcat"][selectedWeaponHeader.itemType] -- This feat grants a +1 thac0 bonus with throwing weapons (throwing daggers, throwing axes, darts, throwing hammers) - local applyAbility = (itemTypeStr == "DAGGER" or itemTypeStr == "AXE" or itemTypeStr == "HAMMER" or itemTypeStr == "DART") - and itemAbility.type == 2 -- Ranged + local applyAbility = (selectedWeaponTypeStr == "DAGGER" or selectedWeaponTypeStr == "AXE" or selectedWeaponTypeStr == "HAMMER" or selectedWeaponTypeStr == "DART") + and selectedWeaponAbility.type == 2 -- Ranged and spriteRaceStr == "HALFLING" -- if sprite:getLocalInt("cdtweaksGoodAim") == 0 then @@ -61,8 +66,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDHLGAIM", + ["res"] = "%HALFLING_GOOD_AIM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/revised_archer_402.lua b/cdtweaks/luke/lua/revised_archer_402.lua deleted file mode 100644 index 9b6c6b2a..00000000 --- a/cdtweaks/luke/lua/revised_archer_402.lua +++ /dev/null @@ -1,20 +0,0 @@ --- cdtweaks, revised archer kit: Called Shot ability (bows only!) -- - -function GTCLDSHT(CGameEffect, CGameSprite) - local equipment = CGameSprite.m_equipment -- CGameSpriteEquipment - local selectedItem = equipment.m_items:get(equipment.m_selectedWeapon) -- CItem - local itemHeader = selectedItem.pRes.pHeader -- Item_Header_st - -- - local selectedWeaponTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] - -- - if selectedWeaponTypeStr == "ARROW" or selectedWeaponTypeStr == "BOW" then -- bow with arrows equipped || bow with unlimited ammo equipped - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 326, -- Apply effects list - ["durationType"] = 1, - ["res"] = "CDCL121", - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end -end \ No newline at end of file diff --git a/cdtweaks/luke/lua/revised_archer_listener.lua b/cdtweaks/luke/lua/revised_archer_listener.lua deleted file mode 100644 index 6242ff13..00000000 --- a/cdtweaks/luke/lua/revised_archer_listener.lua +++ /dev/null @@ -1,103 +0,0 @@ --- cdtweaks, revised archer kit: +X missile thac0/damage bonus with bows only! -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- Sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual bonus via "CDFRLNTD.SPL" - local apply = function(spriteLevel1, spriteLevel2, spriteLevel3) - -- Update vars - sprite:setLocalInt("cdtweaksRevisedArcherHelper1", spriteLevel1) - sprite:setLocalInt("cdtweaksRevisedArcherHelper2", spriteLevel2) - sprite:setLocalInt("cdtweaksRevisedArcherHelper3", spriteLevel3) - -- Mark the creature as 'bonus applied' - sprite:setLocalInt("cdtweaksRevisedArcher", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDFRLNTD", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 167, -- Missile THAC0 bonus - ["durationType"] = 9, - ["effectAmount"] = bonus, - ["m_sourceRes"] = "CDFRLNTD", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 286, -- Missile weapon damage bonus - ["durationType"] = 9, - ["effectAmount"] = bonus, - ["m_sourceRes"] = "CDFRLNTD", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's equipment / class / kit / levels - local equipment = sprite.m_equipment - local selectedItem = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedItem.pRes.pHeader - -- - local spriteKitStr = GT_Resource_IDSToSymbol["kit"][EEex_BOr(EEex_LShift(sprite.m_baseStats.m_mageSpecUpperWord, 16), sprite.m_baseStats.m_mageSpecialization)] - -- - local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] - -- - local selectedWeaponTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] - -- - local spriteFlags = sprite.m_baseStats.m_flags - -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine - local spriteLevel1 = sprite.m_derivedStats.m_nLevel1 - local spriteLevel2 = sprite.m_derivedStats.m_nLevel2 - -- - local bonus = 0 - if spriteClassStr == "RANGER" then - if spriteLevel1 <= 18 then - bonus = math.floor(spriteLevel1 / 3) - else - bonus = math.floor((spriteLevel1 - 18) / 5) + (18 / 3) - end - else - if spriteLevel2 <= 18 then - bonus = math.floor(spriteLevel2 / 3) - else - bonus = math.floor((spriteLevel2 - 18) / 5) + (18 / 3) - end - end - -- (Bow with arrows equipped || bow with unlimited ammo equipped) && Archer kit - local applyCondition = (selectedWeaponTypeStr == "ARROW" or selectedWeaponTypeStr == "BOW") - and spriteKitStr == "FERALAN" - and (spriteClassStr == "RANGER" - -- incomplete dual-class characters are not supposed to benefit from this passive feat - or (spriteClassStr == "CLERIC_RANGER" and (EEex_IsBitUnset(spriteFlags, 0x8) or spriteLevel1 > spriteLevel2))) - and EEex_IsBitUnset(spriteFlags, 10) -- not Fallen Ranger - and bonus > 0 - -- - if sprite:getLocalInt("cdtweaksRevisedArcher") == 0 then - if applyCondition then - apply(bonus) - end - else - if applyCondition then - -- Check if level has changed since the last application - if bonus ~= sprite:getLocalInt("cdtweaksRevisedArcherHelper") then - apply(bonus) - end - else - -- Mark the creature as 'bonus removed' - sprite:setLocalInt("cdtweaksRevisedArcher", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDFRLNTD", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/revised_backstab_immunity.lua b/cdtweaks/luke/lua/revised_backstab_immunity.lua index 15c6de70..add1fa43 100644 --- a/cdtweaks/luke/lua/revised_backstab_immunity.lua +++ b/cdtweaks/luke/lua/revised_backstab_immunity.lua @@ -1,4 +1,10 @@ --- cdtweaks, revised backstab immunity (component #2620) -- +--[[ ++-------------------------------------------------------+ +| cdtweaks, revised backstab immunity (component #2620) | ++-------------------------------------------------------+ +--]] + +-- Apply ability -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -12,7 +18,6 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, ["res"] = "CDBSTIMM", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, @@ -48,7 +53,6 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, ["res"] = "CDBSTIMM", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, diff --git a/cdtweaks/luke/lua/nwn-ish_armor_vs_dex.lua b/cdtweaks/luke/lua/rule_changes/nwn-ish_armor_vs_dex.lua similarity index 71% rename from cdtweaks/luke/lua/nwn-ish_armor_vs_dex.lua rename to cdtweaks/luke/lua/rule_changes/nwn-ish_armor_vs_dex.lua index c31246a5..9d9fc760 100644 --- a/cdtweaks/luke/lua/nwn-ish_armor_vs_dex.lua +++ b/cdtweaks/luke/lua/rule_changes/nwn-ish_armor_vs_dex.lua @@ -1,4 +1,10 @@ --- cdtweaks: NWN-ish Armor vs. Dexterity -- +--[[ ++---------------------------------------+ +| cdtweaks, NWN-ish Armor vs. Dexterity | ++---------------------------------------+ +--]] + +-- Apply condition -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -7,15 +13,14 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end -- internal function that applies the actual malus local apply = function(ACMalus) - -- Update var + -- Update tracking var sprite:setLocalInt("cdtweaksNWNArmorHelper", ACMalus) -- Mark the creature as 'malus applied' sprite:setLocalInt("cdtweaksNWNArmor", 1) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDNWNARM", + ["res"] = "GTRULE00", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -23,15 +28,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["effectID"] = 0, -- AC bonus ["durationType"] = 9, ["effectAmount"] = ACMalus, - ["m_sourceRes"] = "CDNWNARM", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 142, -- Display portrait icon - ["durationType"] = 9, - ["dwFlags"] = %feedback_icon%, - ["m_sourceRes"] = "CDNWNARM", + ["m_sourceRes"] = "GTRULE00", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -43,9 +40,9 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local armorTypeStr = nil local armorAnimation = nil if armor then -- if the character is equipped with an armor... - local itemHeader = armor.pRes.pHeader -- Item_Header_st - armorTypeStr = GT_Resource_IDSToSymbol["itemcat"][itemHeader.itemType] - armorAnimation = EEex_CastUD(itemHeader.animationType, "CResRef"):get() -- certain engine types are nonsensical. We usually create fixups for the bindings whenever we run into them. We'll need to cast the value to properly read them + local pHeader = armor.pRes.pHeader -- Item_Header_st + armorTypeStr = GT_Resource_IDSToSymbol["itemcat"][pHeader.itemType] + armorAnimation = EEex_CastUD(pHeader.animationType, "CResRef"):get() -- certain engine types are nonsensical. We usually create fixups for the bindings whenever we run into them. We'll need to cast the value to properly read them end -- local dexmod = GT_Resource_2DA["dexmod"] @@ -57,7 +54,9 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) if armor then if armorAnimation == "3A" then ACMalus = math.floor(AC / 2) - if ACMalus == 0 then ACMalus = -1 end -- in case the base bonus is ``-1``, ``ACMalus`` should not be ``0``... + if ACMalus == 0 then + ACMalus = -1 -- in case the base bonus is ``-1``, ``ACMalus`` should not be ``0``... + end elseif armorAnimation == "4A" then ACMalus = AC end @@ -81,8 +80,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "CDNWNARM", + ["res"] = "GTRULE00", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) diff --git a/cdtweaks/luke/lua/sneakatt_blackguard.lua b/cdtweaks/luke/lua/sneakatt_blackguard.lua deleted file mode 100644 index 871a50e3..00000000 --- a/cdtweaks/luke/lua/sneakatt_blackguard.lua +++ /dev/null @@ -1,61 +0,0 @@ --- cdtweaks, Sneak Attack feat for Blackguards -- - -function GTBLKG01(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - -- - local targetGeneralState = CGameSprite.m_derivedStats.m_generalState + CGameSprite.m_bonusStats.m_generalState - -- limit to once per round - local getTimer = EEex_Trigger_ParseConditionalString('!GlobalTimerNotExpired("cdtweaksSneakattBlckgrdTimer","LOCALS")') - local setTimer = EEex_Action_ParseResponseString('SetGlobalTimer("cdtweaksSneakattBlckgrdTimer","LOCALS",6)') - -- - if getTimer:evalConditionalAsAIBase(sourceSprite) then - -- if the target is incapacitated || the target is in combat with someone else || the blackguard is invisible - if EEex_BAnd(targetGeneralState, 0x100029) ~= 0 or CGameSprite.m_targetId ~= sourceSprite.m_id or sourceSprite:getLocalInt("gtIsInvisible") == 1 then - setTimer:executeResponseAsAIBaseInstantly(sourceSprite) - -- - CGameSprite:applyEffect({ - ["effectID"] = 146, -- Cast spell - ["res"] = "GTBLKGSA", -- SPL file - ["dwFlags"] = 1, -- cast instantly / ignore level - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - end - -- - getTimer:free() - setTimer:free() -end - --- cdtweaks, Sneak Attack feat for Blackguards -- - -function GTBLKG02(CGameEffect, CGameSprite) - local sneakatt = GT_Resource_2DA["sneakatt"] - -- - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) - local sourceLevel = sourceSprite.m_derivedStats.m_nLevel1 + sourceSprite.m_bonusStats.m_nLevel1 - -- - local equipment = sourceSprite.m_equipment - local selectedWeapon = equipment.m_items:get(equipment.m_selectedWeapon) - local itemHeader = selectedWeapon.pRes.pHeader -- Item_Header_st - -- - local itemAbility = EEex_Resource_GetItemAbility(itemHeader, equipment.m_selectedWeaponAbility) -- Item_ability_st - -- - local randomValue = math.random(0, 1) - local damageType = {16, 0, 256, 128, 2048, 16 * randomValue, randomValue == 0 and 16 or 256, 256 * randomValue} -- piercing, crushing, slashing, missile, non-lethal, piercing/crushing, piercing/slashing, slashing/crushing - -- - if damageType[itemAbility.damageType] and tonumber(sneakatt["STALKER"][string.format("%s", sourceLevel)]) > 0 then - EEex_GameObject_ApplyEffect(CGameSprite, - { - ["effectID"] = 12, -- Damage - ["dwFlags"] = damageType[itemAbility.damageType] * 0x10000, -- Normal - ["durationType"] = 1, - ["numDice"] = tonumber(sneakatt["STALKER"][string.format("%s", sourceLevel)]), - ["diceSize"] = 6, - ["m_sourceRes"] = CGameEffect.m_sourceRes:get(), - ["m_sourceType"] = CGameEffect.m_sourceType, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end -end diff --git a/cdtweaks/luke/lua/sneakatt_blackguard_grant.lua b/cdtweaks/luke/lua/sneakatt_blackguard_grant.lua deleted file mode 100644 index 9ed7d9b0..00000000 --- a/cdtweaks/luke/lua/sneakatt_blackguard_grant.lua +++ /dev/null @@ -1,65 +0,0 @@ --- cdtweaks, Sneak Attack feat for Blackguards -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that applies the actual bonus - local apply = function() - -- Mark the creature as 'feat applied' - sprite:setLocalInt("cdtweaksSneakattBlackguard", 1) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "GTBLKGSA", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 248, -- Melee hit effect - ["res"] = "GTBLKGSA", -- EFF file - ["durationType"] = 9, - ["m_sourceRes"] = "GTBLKGSA", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 249, -- Ranged hit effect - ["res"] = "GTBLKGSA", -- EFF file - ["durationType"] = 9, - ["m_sourceRes"] = "GTBLKGSA", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- Check creature's class / kit / flags - local spriteFlags = sprite.m_baseStats.m_flags - local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class] - -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine - local spriteKitStr = GT_Resource_IDSToSymbol["kit"][sprite.m_derivedStats.m_nKit] - -- Grant the feat to Blackguards (must not be fallen) - local applyAbility = spriteClassStr == "PALADIN" and spriteKitStr == "Blackguard" and EEex_IsBitUnset(spriteFlags, 9) - -- - if sprite:getLocalInt("cdtweaksSneakattBlackguard") == 0 then - if applyAbility then - apply() - end - else - if applyAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksSneakattBlackguard", 0) - -- - sprite:applyEffect({ - ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, - ["res"] = "GTBLKGSA", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/luke/lua/spontaneous_casting/listener.lua b/cdtweaks/luke/lua/spontaneous_casting/listener.lua index f775fb51..3a9cb682 100644 --- a/cdtweaks/luke/lua/spontaneous_casting/listener.lua +++ b/cdtweaks/luke/lua/spontaneous_casting/listener.lua @@ -10,24 +10,13 @@ EEex_Key_AddPressedListener(function(key) for _, v in ipairs(metamagicRes) do sprite:applyEffect({ ["effectID"] = 321, -- Remove effects by resource - ["durationType"] = 1, ["res"] = v, ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end -- check for op145 - local found = false - local disableSpellcasting = function(effect) - if (effect.m_effectId == 0x91) and (effect.m_dWFlags == 1 or effect.m_dWFlags == 3) then - found = true - return true - end - end - EEex_Utility_IterateCPtrList(sprite.m_timedEffectList, disableSpellcasting) - if not found then - EEex_Utility_IterateCPtrList(sprite.m_equipedEffectList, disableSpellcasting) - end + local disableSpellcasting = GT_Utility_EffectCheck(sprite, {["op"] = 0x91, ["p2"] = 1}) or GT_Utility_EffectCheck(sprite, {["op"] = 0x91, ["p2"] = 3}) -- local lastState = EEex_Actionbar_GetLastState() -- Check creature's class / flags / alignment @@ -44,7 +33,7 @@ EEex_Key_AddPressedListener(function(key) or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x5) or spriteLevel2 > spriteLevel1)) or (spriteClassStr == "CLERIC_MAGE" and (EEex_IsBitUnset(spriteFlags, 0x5) or spriteLevel2 > spriteLevel1)) -- - if not found then + if not disableSpellcasting then if canSpontaneouslyCast then if (lastState >= 1 and lastState <= 21) and EEex_Sprite_GetCastTimer(sprite) == -1 and sprite.m_typeAI.m_EnemyAlly == 2 and key == 0x400000E2 and (EEex_Actionbar_GetState() == 103 or EEex_Actionbar_GetState() == 113) then -- if PC, the Left Alt key is pressed, and the aura is free ... if isGood:evalConditionalAsAIBase(sprite) then diff --git a/cdtweaks/luke/lua/utility/is_invisible.lua b/cdtweaks/luke/lua/utility/is_invisible.lua index 85805ff6..0795b03c 100644 --- a/cdtweaks/luke/lua/utility/is_invisible.lua +++ b/cdtweaks/luke/lua/utility/is_invisible.lua @@ -1,4 +1,8 @@ --- Utility: if a sprite is invisible, flag it (needed to implement custom sneak attacks) -- +--[[ ++---------------------------------------------------------------------------------------+ +| Utility: if a sprite is invisible, flag it (needed to implement custom sneak attacks) | ++---------------------------------------------------------------------------------------+ +--]] EEex_Opcode_AddListsResolvedListener(function(sprite) -- sanity check @@ -7,14 +11,14 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end -- internal function that flags the creature local apply = function() - sprite:setLocalInt("gtIsInvisible", 1) + sprite:setLocalInt("gtSpriteIsInvisible", 1) end -- Check state -- since ``EEex_Opcode_AddListsResolvedListener`` is running after the effect lists have been evaluated, ``m_bonusStats`` has already been added to ``m_derivedStats`` by the engine local spriteGeneralState = sprite.m_derivedStats.m_generalState local applyCondition = EEex_IsBitSet(spriteGeneralState, 0x4) -- STATE_INVISIBLE (BIT4) -- - if sprite:getLocalInt("gtIsInvisible") == 0 then + if sprite:getLocalInt("gtSpriteIsInvisible") == 0 then if applyCondition then apply() end @@ -22,7 +26,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) if applyCondition then -- do nothing else - sprite:setLocalInt("gtIsInvisible", 0) + sprite:setLocalInt("gtSpriteIsInvisible", 0) end end end) diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index f539c3ea..750abb79 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -1,7 +1,7 @@ /* -==================================================================================== -**ADD_IDS_ENTRY** (borrowed from Argent77, tweaked by me) -==================================================================================== ++-------------------------------------------------------+ +| ADD_IDS_ENTRY (borrowed from Argent77, tweaked by me) | ++-------------------------------------------------------+ */ DEFINE_DIMORPHIC_FUNCTION "ADD_IDS_ENTRY" @@ -83,9 +83,11 @@ BEGIN END END -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ -// Add a new entry to "statdesc.2da" (tweaked from CamDawg) \\ -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ +/* ++----------------------------------------------------------+ +| Add a new entry to "statdesc.2da" (tweaked from CamDawg) | ++----------------------------------------------------------+ +*/ DEFINE_DIMORPHIC_FUNCTION "ADD_STATDESC_ENTRY" INT_VAR @@ -121,9 +123,11 @@ BEGIN END END -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ -// Get the (english) string corresponding to StringRef "%strref%" \\ -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ +/* ++----------------------------------------------------------------+ +| Get the (english) string corresponding to StringRef "%strref%" | ++----------------------------------------------------------------+ +*/ DEFINE_DIMORPHIC_FUNCTION "GT_GET_STRING" INT_VAR @@ -140,9 +144,11 @@ BEGIN BUT_ONLY_IF_IT_CHANGES END -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ -// Set a var for each entry in "spell.ids" \\ -////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\ +/* ++-----------------------------------------+ +| Set a var for each entry in "spell.ids" | ++-----------------------------------------+ +*/ DEFINE_ACTION_MACRO "READ_SPELL_IDS" BEGIN @@ -268,10 +274,9 @@ BEGIN END /* -===================================================================================================== -**ADD_EXTENDED_STAT** -- For use with EEex (https://eeex-docs.readthedocs.io/en/latest/EEex%20Opcodes/index.html#opcode-401) -===================================================================================================== ++------------------------------------------------------------------------------------------------------------------------+ +| ADD_EXTENDED_STAT: For use with EEex (https://eeex-docs.readthedocs.io/en/latest/EEex%20Opcodes/index.html#opcode-401) | ++------------------------------------------------------------------------------------------------------------------------+ */ DEFINE_DIMORPHIC_FUNCTION "ADD_EXTENDED_STAT" @@ -312,9 +317,14 @@ BEGIN END /* -============================================================================================================================================================================================================ -**ADD_SPLPROT_ENTRY** - Adds a new entry to "SPLPROT.2DA" and returns its index. If an identical entry already exists it will return the index of that entry instead (borrowed from Argent77, tweaked by me) -============================================================================================================================================================================================================ ++---------------------------------------------------------------------------------------------------+ +| ADD_SPLPROT_ENTRY (borrowed from Argent77, tweaked by me) | ++---------------------------------------------------------------------------------------------------+ +| Adds a new entry to "SPLPROT.2DA" and returns its index | ++---------------------------------------------------------------------------------------------------+ +| return: | +| integer (if an identical entry already exists it will return the index of that entry instead) | ++---------------------------------------------------------------------------------------------------+ */ DEFINE_DIMORPHIC_FUNCTION "ADD_SPLPROT_ENTRY" @@ -384,9 +394,9 @@ BEGIN END /* -===================================================================================================== -**APPEND_LUA_FUNCTION** -===================================================================================================== ++---------------------+ +| APPEND_LUA_FUNCTION | ++---------------------+ */ DEFINE_DIMORPHIC_FUNCTION "APPEND_LUA_FUNCTION" @@ -401,8 +411,8 @@ BEGIN ACTION_IF !(FILE_EXISTS_IN_GAME "%destRes%.lua") BEGIN COPY ".../cdtweaks-inlined/empty" "override\%destRes%.lua" DELETE_BYTES 0x0 BUFFER_LENGTH - INSERT_BYTES 0x0 STRING_LENGTH "-- %description% --%WNL%%WNL%" - WRITE_ASCII 0x0 "-- %description% --%WNL%%WNL%" + INSERT_BYTES 0x0 STRING_LENGTH "--[[ %description% --]]%WNL%%WNL%" + WRITE_ASCII 0x0 "--[[ %description% --]]%WNL%%WNL%" BUT_ONLY_IF_IT_CHANGES END // diff --git a/cdtweaks/luke/pro/idpro402.pro b/cdtweaks/luke/pro/idpro402.pro new file mode 100644 index 00000000..d09047f4 Binary files /dev/null and b/cdtweaks/luke/pro/idpro402.pro differ diff --git a/cdtweaks/readme-cdtweaks.html b/cdtweaks/readme-cdtweaks.html index 84c933fc..03facb85 100644 --- a/cdtweaks/readme-cdtweaks.html +++ b/cdtweaks/readme-cdtweaks.html @@ -972,132 +972,6 @@

Rule Changes

Permanent potions, such as potions of healing, and potions that can end prematurely, such as Potion of Invisibility, would be considered still in effect for 1 turn (60 seconds) after drinking them.

The aforementioned special events can occur only upon quaffing potions. As a result, there is no risk in using 1 Oil (f.i. Oil of Speed) and 1 Potion, as oils are applied to the skin, not consumed, so they wouldn't mix.

-

"Force" the Archer kit to use bows [Luke]
- EEex

-

This component aims at making sure the Archer is really the epitome of skill with the bow. - As a result, after installing it, its abilities modify as follows:

-
    -
  • +1 to hit and damage rolls with bows every 3 levels
  • -
  • May achieve Grand Mastery (5 slots) in longbows and shortbows -
      -
    • May only Specialize (2 slots) in crossbows
    • -
    -
  • -
  • When equipped with a bow, it may use the Called Shot ability once per day
  • -
  • New passive trait: Point Blank Shot -
      -
    • When wielding a bow, the Archer negates the -8 thac0 penalty for using ranged weapons in close combat
    • -
    -
  • -
-

So to sum up, its core features are now all built around the bow (instead of any missile weapon).

-

Spontaneous Casting for Clerics [Luke]
- EEex

-

This component aims at giving Clerics some Spontaneous Casting capabilities.

-

As a result, after installing this component, Clerics will be able to spontaneously cast the "cure" and "cause" spells (from light to critical wounds), which will consume a readied spell slot of the appropriate level.

-

As a completely artificial example, suppose a Cleric has the following level 1 spells memorized: Armor of Faith, Armor of Faith, Bless. Even if Cure Light Wounds is missing, it will still be able to cast it! Upon casting it, all level 1 spells memorized will be decremented by one, meaning that it will end up with only Armor of Faith memorized (in other words, it can "sacrifice" one of the two Armor of Faith and Bless to spontaneously cast Cure Light Wounds).

-

Spells that can be spontaneously cast can be accessed via pressing the Left Alt key while being in "Cast Spell" mode (F7 button).

-

On top of that, note that:

-
    -
  • only good-aligned Clerics can spontaneously cast the "cure" wounds spells
  • -
  • only evil-aligned Clerics can spontaneously cast the "cause" wounds spells
  • -
-

As a result, neutral-aligned Clerics are unaffected by this mechanic.

-

Weapon Finesse [Luke]
- EEex

-

This component aims at implementing 3E Weapon Finesse feat for Thieves.

-

As a result, after installing it, every time a Thief is wielding a small blade (f.i. daggers, short swords, wakizashis, etc...) or a club/mace, his/her THAC0 will scale with Dexterity (as per the MISSILE column of dexmod.2da) instead of Strength.

-

As a completely artificial example, suppose a Thief has 9 Strength and 18 Dexterity. Upon equipping a dagger, he/she will gain a THAC0 bonus of 2 (instead of 0). Note that nothing happens if the bonus from Strength is better (or equal) than the bonus from Dexterity.

-

Dual-Wield feat for Rangers [Luke]
- EEex

-

This component simply forces Rangers to wield light armors (or no armor) in order to benefit from Two-Weapon Fighting.

-

NWN-ish Armor vs. Dexterity [Luke]
- EEex

-

This component simply "forces" characters to wield light armors (or no armor) if they have high Dexterity. - In particular:

-
    -
  • If a character is equipped with a Medium Armor, it will only benefit from half the bonus derived from its Dexterity (see dexmod.2da) -
      -
    • So for instance, a character with 18 DEX equipped with a Chain Mail Armor will suffer a -4 / 2 = -2 AC penalty.
    • -
    -
  • -
  • If a character is equipped with a Heavy Armor, it will not benefit from the bonus derived from its Dexterity (see dexmod.2da) -
      -
    • So for instance, a character with 18 DEX equipped with a Plate Mail will suffer a -4 AC penalty.
    • -
    -
  • -
-

Defensive Roll feat for Thieves [Luke]
- EEex

-

This component aims at implementing the NWN feat Defensive Roll. As a result, after installing it, if the character is struck by a potentially lethal blow, he makes a Save vs. Breath. If successful, he takes only half damage from the blow.

-

Notes:

-
    -
  • This feat is only available to thieves (level 10) and Shadowdancers (level 5).
  • -
  • A "potentially lethal blow" refers to a standard attack with a weapon that would, if not for this feat, reduce the target below one hit point with just its physical damage.
  • -
  • Use: automatic, but limited to one use per day. Incapacitated characters cannot make a defensive roll.
  • -
-

Divine Grace / Dark Blessing feat for Paladins / Blackguards [Luke]
- EEex

-

This component adds the passive feats Divine Grace and Dark Blessing to Paladins and Blackguards.

-
    -
  • Divine Grace: The paladin adds its charisma bonus (if positive) to all saving throws.
  • -
  • Dark Blessing: Blackguards add their charisma bonus to all saving throws.
  • -
- Here is how the bonus scales with charisma: -
    -
  • starting from 10, every +2 points of charisma result in +1 bonus to all saves -
      -
    • So a 18 CHA character will get a +4 bonus
    • -
    -
  • -
  • starting from 10, every -2 points of charisma result in -1 penalty to all saves -
      -
    • So a 8 CHA character will get a -1 penalty
    • -
    -
  • -
-

Good Aim racial feat for Halflings [Luke]
- EEex

-

This passive feat grants Halflings a +1 THAC0 bonus with throwing weapons (i.e. throwing daggers, throwing axes, throwing hammers, darts).

-

Cleave class feat for Fighters [Luke]
- EEex

-

This component aims at implementing the NWN feat Cleave.
- As a result, after installing it, if the character kills an opponent, he gets a free attack against any opponent who is within melee weapon range.
- Notes:

-
    -
  • Use: automatic, but only available to Fighters.
  • -
-

Sneak Attack class feat for Blackguards [Luke]
- EEex

-

This component adds the passive feat Sneak Attack to Blackguards.
- Whenever the character makes a successful attack against an opponent who is incapacitated, cannot see them, or who is in combat with someone else, the character's blow delivers extra damage as if it was a STALKER of the same level (see sneakatt.2da).
- Notes:

-
    -
  • Use: automatic, but limited to once per round.
  • -
  • Creatures without discernible anatomies (see component Make Certain Creatures Immune to Backstab/Sneak Attack ) or that are otherwise immune to sneak attacks, either via spells/items or naturally (f.i. Barbarians), are unaffected by this feat.
  • -
  • Sneak attacks can be made with both melee and ranged weapons.
  • -
-

Fearless racial feat for halflings [Luke]
- EEex

-

This component adds the passive racial feat Fearless to halflings.
- This feat grants a +2 bonus on saving throws against fear spells and effects.

-

Poison Save class feat for Assassins [Luke]
- EEex

-

This component adds the class feat Poison Save to Assassins.
- This passive feat grants a +2 bonus on saving throws against poison spells and effects.

-

Planar Turning class feat for Paladins / Clerics [Luke]
- EEex

-

This component adds the class feat Planar Turning to Paladins and Clerics.
- This feat allows outsiders (solars, planetars, elementals, imps, mephits, demons, devils, salamanders, genies and the like) to be turned like undead.
- As a result, when the Turn Undead ability is activated, any extraplanar being in visual range of the priest are turned, fleeing in terror, if the priest's level is high enough. Especially high-level priests destroy these creatures instead. Evil priests gain control of these extraplanar beings instead of destroying them.

-

Circle Kick class feat for Monks [Luke]
- EEex

-

This component aims at implementing the NWN feat Circle Kick.
- As a result, after installing it, if the character succeeds in hitting an opponent with an unarmed attack, that character gets an additional free attack against another, nearby enemy. There is a maximum of one free attack per round.
- Notes:

-
    -
  • Use: automatic, but only available to Monks.
  • -

Convenience Tweaks and/or Cheats

@@ -1461,6 +1335,163 @@

Joinable +

NWN-ish Feats Collection

+

+
+
+
+

Components in this category are inspired from NWN and are aimed at providing new class/kit abilities.

+ +

Spontaneous Casting for Clerics [Luke]
+ EEex

+

This component aims at giving Clerics some Spontaneous Casting capabilities.

+

As a result, after installing this component, Clerics will be able to spontaneously cast the "cure" and "cause" spells (from light to critical wounds), which will consume a readied spell slot of the appropriate level.

+

As a completely artificial example, suppose a Cleric has the following level 1 spells memorized: Armor of Faith, Armor of Faith, Bless. Even if Cure Light Wounds is missing, it will still be able to cast it! Upon casting it, all level 1 spells memorized will be decremented by one, meaning that it will end up with only Armor of Faith memorized (in other words, it can "sacrifice" one of the two Armor of Faith and Bless to spontaneously cast Cure Light Wounds).

+

Spells that can be spontaneously cast can be accessed via pressing the Left Alt key while being in "Cast Spell" mode (F7 button).

+

On top of that, note that:

+
    +
  • only good-aligned Clerics can spontaneously cast the "cure" wounds spells
  • +
  • only evil-aligned Clerics can spontaneously cast the "cause" wounds spells
  • +
+

As a result, neutral-aligned Clerics are unaffected by this mechanic.

+ +

Weapon Finesse class feat for Rogues [Luke]
+ EEex

+

This component aims at implementing 3E Weapon Finesse feat for Thieves.

+

As a result, after installing it, every time a Thief is wielding a small blade (f.i. daggers, short swords, wakizashis, etc...) or a club/mace, his/her THAC0 will scale with Dexterity (as per the MISSILE column of dexmod.2da) instead of Strength.

+

As a completely artificial example, suppose a Thief has 9 Strength and 18 Dexterity. Upon equipping a dagger, he/she will gain a THAC0 bonus of 2 (instead of 0). Note that nothing happens if the bonus from Strength is better (or equal) than the bonus from Dexterity.

+ +

Dual-Wield class feat for Rangers [Luke]
+ EEex

+

This component simply forces Rangers to wield light armors (or no armor) in order to benefit from Two-Weapon Fighting.

+ +

NWN-ish Armor vs. Dexterity [Luke]
+ EEex

+

This component simply "forces" characters to wield light armors (or no armor) if they have high Dexterity. + In particular:

+
    +
  • If a character is equipped with a Medium Armor, it will only benefit from half the bonus derived from its Dexterity (see dexmod.2da) +
      +
    • So for instance, a character with 18 DEX equipped with a Chain Mail Armor will suffer a -4 / 2 = -2 AC penalty.
    • +
    +
  • +
  • If a character is equipped with a Heavy Armor, it will not benefit from the bonus derived from its Dexterity (see dexmod.2da) +
      +
    • So for instance, a character with 18 DEX equipped with a Plate Mail will suffer a -4 AC penalty.
    • +
    +
  • +
+ +

Defensive Roll class feat for Thieves [Luke]
+ EEex

+

This component aims at implementing the NWN feat Defensive Roll. As a result, after installing it, if the character is struck by a potentially lethal blow, he makes a Save vs. Breath. If successful, he takes only half damage from the blow.

+

Notes:

+
    +
  • This feat is only available to thieves (level 10) and Shadowdancers (level 5).
  • +
  • A "potentially lethal blow" refers to a standard attack with a weapon that would, if not for this feat, reduce the target below one hit point with just its physical damage.
  • +
  • Use: automatic, but limited to one use per 8 in-game hours. Incapacitated characters cannot make a defensive roll.
  • +
+ +

Divine Grace / Dark Blessing class feat for Paladins / Blackguards [Luke]
+ EEex

+

This component adds the passive feats Divine Grace and Dark Blessing to Paladins and Blackguards.

+
    +
  • Divine Grace: The paladin adds its charisma bonus (if positive) to all saving throws.
  • +
  • Dark Blessing: Blackguards add their charisma bonus to all saving throws.
  • +
+ Here is how the bonus scales with charisma: +
    +
  • starting from 10, every +2 points of charisma result in +1 bonus to all saves +
      +
    • So a 18 CHA character will get a +4 bonus
    • +
    +
  • +
  • starting from 10, every -2 points of charisma result in -1 penalty to all saves +
      +
    • So a 8 CHA character will get a -1 penalty
    • +
    +
  • +
+ +

Good Aim racial feat for Halflings [Luke]
+ EEex

+

This passive feat grants Halflings a +1 THAC0 bonus with throwing weapons (i.e. throwing daggers, throwing axes, throwing hammers, darts).

+ +

Cleave class feat for Fighters [Luke]
+ EEex

+

This component aims at implementing the NWN feat Cleave.
+ As a result, after installing it, if the character kills an opponent, he gets a free attack against any opponent who is within melee weapon range.
+ Notes:

+
    +
  • Use: automatic, but only available to Fighters (starting from level 1).
  • +
+ +

Sneak Attack class feat for Blackguards [Luke]
+ EEex

+

This component adds the passive feat Sneak Attack to Blackguards.
+ Whenever the character makes a successful attack against an opponent who is incapacitated, cannot see them, or who is in combat with someone else, the character's blow delivers extra damage as if it was a STALKER of the same level (see sneakatt.2da).
+ Notes:

+
    +
  • Use: automatic, but limited to once per round.
  • +
  • Creatures without discernible anatomies (see component Make Certain Creatures Immune to Backstab/Sneak Attack ) or that are otherwise immune to sneak attacks, either via spells/items or naturally (f.i. Barbarians), are unaffected by this feat.
  • +
  • Sneak attacks can be made with both melee and ranged weapons.
  • +
+ +

Fearless racial feat for halflings [Luke]
+ EEex

+

This component adds the passive racial feat Fearless to halflings.
+ This feat grants a +2 bonus on saving throws against fear spells and effects.

+ +

Poison Save class feat for Assassins [Luke]
+ EEex

+

This component adds the class feat Poison Save to Assassins.
+ This passive feat grants a +2 bonus on saving throws against poison spells and effects.

+ +

Planar Turning class feat for Paladins / Clerics [Luke]
+ EEex

+

This component adds the class feat Planar Turning to Paladins and Clerics.
+ This feat allows outsiders (solars, planetars, elementals, imps, mephits, demons, devils, salamanders, genies and the like) to be turned like undead.
+ As a result, when the Turn Undead ability is activated, any extraplanar being in visual range of the priest are turned, fleeing in terror, if the priest's level is high enough. Especially high-level priests destroy these creatures instead. Evil priests gain control of these extraplanar beings instead of destroying them.

+ +

Circle Kick class feat for Monks [Luke]
+ EEex

+

This component aims at implementing the NWN feat Circle Kick.
+ As a result, after installing it, if the character succeeds in hitting an opponent with an unarmed attack, that character gets an additional free attack against another, nearby enemy. There is a maximum of one free attack per round.
+ Notes:

+
    +
  • Use: automatic, but only available to Monks (starting from level 1).
  • +
+ +

NWN-ish Barbarian Rage [Luke]
+ EEex

+

This component reworks the Barbarian Rage so as to behave as the one in NWN (kinda, sort of).

+

+ Here is the revised description:
+ The character is enraged for 7 rounds (plus a number of rounds equal to his Constitution modifier), which grants the character a +4 bonus to Strength and Constitution, a -2 penalty to Armor Class, and a +2 bonus to Saving Throws vs. Spell.

+ + Terrifying Rage: While the barbarian is raging, any enemy (with less than the barbarian's hit dice) that comes close to him must make a Save vs. Death or become panicked for 1d3 rounds. Opponents with the same hit dice as the barbarian will not flee but will receive a -2 penalty to attack and saving throw rolls. Creatures with more than the barbarian's hit dice are not affected by the rage.

+ + Thundering Rage: Any weapon the barbarian wields while in a rage does an additional 2d6 points of damage on a critical hit. There is a 25% chance for a creature hit by one of the barbarian's weapons to be deafened for 3 rounds. +

+ +

+ Notes: +

    +
  • Constitution modifier: (Constitution - 10) / 2 , rounded down
  • +
  • + Terrifying Rage: the save penalty decreases by 1 for every 4 levels of the barbarian (capped at -7 at level 29). +
      +
    • In case of multi/dual-class characters, the level of the barbarian (i.e. the Fighter class level) is the one that matters.
    • +
    +
  • +
  • Thundering Rage: there is no save against the Deafness effect.
  • +
+

+ +
+

Contact Information

diff --git a/cdtweaks/setup-cdtweaks.tp2 b/cdtweaks/setup-cdtweaks.tp2 index 5e97fb6f..939cfd36 100644 --- a/cdtweaks/setup-cdtweaks.tp2 +++ b/cdtweaks/setup-cdtweaks.tp2 @@ -2793,203 +2793,6 @@ REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/pnp_potions.tra~ @7 LABEL ~cd_tweaks_pnp_potions~ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Spontaneous Casting for Clerics \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @265000 DESIGNATED 2650 -GROUP @9 -REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 -REQUIRE_PREDICATE MOD_IS_INSTALLED "EEex.tp2" 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/spontaneous_casting.tra~ @7 -LABEL ~cd_tweaks_spontaneous_casting~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Weapon Finesse \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @266000 DESIGNATED 2660 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/weapon_finesse.tra~ @7 -LABEL ~cd_tweaks_weapon_finesse~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Dual-Wield feat for Rangers \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @267000 DESIGNATED 2670 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/dual_wield.tra~ @7 -LABEL ~cd_tweaks_dual_wield~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// "Force" the Archer kit to use bows \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @268000 DESIGNATED 2680 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/revised_archer.tra~ @7 -LABEL ~cd_tweaks_revised_archer~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// NWN-ish Armor vs. Dexterity \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @269000 DESIGNATED 2690 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/nwn-ish_armor_vs_dex.tra~ @7 -LABEL ~cd_tweaks_nwn-ish_armor_vs_dex~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Defensive Roll feat for Thieves \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @270000 DESIGNATED 2700 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/defensive_roll.tra~ @7 -LABEL ~cd_tweaks_defensive_roll~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Divine Grace / Dark Blessing feat for Paladins / Blackguards \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @271000 DESIGNATED 2710 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/divine_grace_dark_blessing.tra~ @7 -LABEL ~cd_tweaks_divine_grace_dark_blessing~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Good Aim feat for Halflings \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -BEGIN @272000 DESIGNATED 2720 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/good_aim.tra~ @7 -LABEL ~cd_tweaks_good_aim~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Cleave feat for Fighters \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @273000 DESIGNATED 2730 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/cleave.tra~ @7 -LABEL ~cd_tweaks_cleave~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Sneak Attack class feat Blackguards \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @274000 DESIGNATED 2740 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/sneakatt_blackguard.tra~ @7 -LABEL ~cd_tweaks_sneakatt_blackguard~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Fearless racial feat for Halflings \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @275000 DESIGNATED 2750 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/fearless.tra~ @7 -LABEL ~cd_tweaks_fearless~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Poison Save class feat for Assassins \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @276000 DESIGNATED 2760 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/poison_save.tra~ @7 -LABEL ~cd_tweaks_poison_save~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Planar Turning class feat for Paladins / Clerics \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @277000 DESIGNATED 2770 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/planar_turning.tra~ @7 -LABEL ~cd_tweaks_planar_turning~ - -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -///// \\\\\///// -///// Circle Kick class feat for Monks \\\\\ -///// \\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// - -BEGIN @278000 DESIGNATED 2780 -GROUP @9 -REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/circle_kick.tra~ @7 -LABEL ~cd_tweaks_circle_kick~ - /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ @@ -4903,3 +4706,221 @@ GROUP @0 REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet~ @25 REQUIRE_PREDICATE MOD_IS_INSTALLED "EEex.tp2" 0 @29 LABEL ~cd_tweaks_dorns_sword~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// NWN-ish feats collection \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Spontaneous Casting for Clerics \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600030 DESIGNATED 6030 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED "EEex.tp2" 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/spontaneous_casting.tra~ @7 +LABEL ~cd_tweaks_nwn_spontaneous_casting~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Weapon Finesse \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600040 DESIGNATED 6040 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/weapon_finesse.tra~ @7 +LABEL ~cd_tweaks_nwn_weapon_finesse~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Dual-Wield feat for Rangers \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600050 DESIGNATED 6050 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/dual_wield.tra~ @7 +LABEL ~cd_tweaks_nwn_dual_wield~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// NWN-ish Armor vs. Dexterity \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600060 DESIGNATED 6060 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/nwn-ish_armor_vs_dex.tra~ @7 +LABEL ~cd_tweaks_nwn_armor_vs_dex~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Defensive Roll feat for Thieves \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600070 DESIGNATED 6070 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/defensive_roll.tra~ @7 +LABEL ~cd_tweaks_nwn_defensive_roll~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Divine Grace / Dark Blessing feat for Paladins / Blackguards \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600080 DESIGNATED 6080 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/divine_grace_dark_blessing.tra~ @7 +LABEL ~cd_tweaks_nwn_divine_grace_dark_blessing~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Good Aim feat for Halflings \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @600090 DESIGNATED 6090 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/good_aim.tra~ @7 +LABEL ~cd_tweaks_nwn_good_aim~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Cleave feat for Fighters \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600100 DESIGNATED 6100 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/cleave.tra~ @7 +LABEL ~cd_tweaks_nwn_cleave~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Sneak Attack class feat Blackguards \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600110 DESIGNATED 6110 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/sneakatt_blackguard.tra~ @7 +LABEL ~cd_tweaks_nwn_sneakatt_blackguard~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Fearless racial feat for Halflings \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600120 DESIGNATED 6120 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/fearless.tra~ @7 +LABEL ~cd_tweaks_nwn_fearless~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Poison Save class feat for Assassins \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600130 DESIGNATED 6130 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/poison_save.tra~ @7 +LABEL ~cd_tweaks_nwn_poison_save~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Planar Turning class feat for Paladins / Clerics \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600140 DESIGNATED 6140 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/planar_turning.tra~ @7 +LABEL ~cd_tweaks_nwn_planar_turning~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// Circle Kick class feat for Monks \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600150 DESIGNATED 6150 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/circle_kick.tra~ @7 +LABEL ~cd_tweaks_nwn_circle_kick~ + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +///// \\\\\///// +///// NWN-ish Barbarian Rage \\\\\ +///// \\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\///// + +BEGIN @600160 DESIGNATED 6160 +GROUP @30 +REQUIRE_PREDICATE GAME_IS ~bgee bg2ee eet iwdee~ @25 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/nwn_barbarian_rage.tra~ @7 +LABEL ~cd_tweaks_nwn_barbarian_rage~ \ No newline at end of file