From 2fe497f43329f409041cbe9661d11bf8384e6f7c Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 4 Sep 2024 18:38:43 +0200 Subject: [PATCH 01/33] Knockdown --- cdtweaks/languages/english/knockdowm.tra | 16 + cdtweaks/languages/english/weidu.tra | 2 + cdtweaks/languages/italian/knockdown.tra | 16 + cdtweaks/languages/italian/weidu.tra | 2 + cdtweaks/lib/comp_2810.tpa | 17 + cdtweaks/lib/knockdown.tph | 77 +++++ cdtweaks/luke/bam/gtprone.bam | Bin 0 -> 1015 bytes .../luke/bam/innate/knockdown/spl_icon.bam | Bin 0 -> 1298 bytes .../innate/knockdown/spl_portrait_icon.bam | Bin 0 -> 974 bytes cdtweaks/luke/lua/innate/knockdown.lua | 316 ++++++++++++++++++ cdtweaks/luke/lua/m_gttbls.lua | 2 +- cdtweaks/luke/lua/utility/key_exists.lua | 15 + cdtweaks/luke/misc.tph | 216 ++++++++++++ cdtweaks/readme-cdtweaks.html | 25 ++ cdtweaks/setup-cdtweaks.tp2 | 14 + 15 files changed, 717 insertions(+), 1 deletion(-) create mode 100644 cdtweaks/languages/english/knockdowm.tra create mode 100644 cdtweaks/languages/italian/knockdown.tra create mode 100644 cdtweaks/lib/comp_2810.tpa create mode 100644 cdtweaks/lib/knockdown.tph create mode 100644 cdtweaks/luke/bam/gtprone.bam create mode 100644 cdtweaks/luke/bam/innate/knockdown/spl_icon.bam create mode 100644 cdtweaks/luke/bam/innate/knockdown/spl_portrait_icon.bam create mode 100644 cdtweaks/luke/lua/innate/knockdown.lua create mode 100644 cdtweaks/luke/lua/utility/key_exists.lua diff --git a/cdtweaks/languages/english/knockdowm.tra b/cdtweaks/languages/english/knockdowm.tra new file mode 100644 index 00000000..8a4b548d --- /dev/null +++ b/cdtweaks/languages/english/knockdowm.tra @@ -0,0 +1,16 @@ +@0 = "Knockdown" + +@1 = "Knockdown + +A character with this feat can attempt to knock his opponents to the ground. The character makes an attack roll at -4, and if successful the defender makes a Save vs. Death. If failed, the defender is knocked to a prone position." + +@50 = "Prone" + +@100 = "The selected target is out of range" +@101 = "The selected target is already prone" +@102 = "The selected target is too large" +@103 = "This feat cannot be used while wielding a ranged weapon" + +@104 = "The character cannot perform more than one action per round" + +@105 = "Unaffected by effects from Knockdown" \ No newline at end of file diff --git a/cdtweaks/languages/english/weidu.tra b/cdtweaks/languages/english/weidu.tra index 06daf4ee..bc5b9a3c 100644 --- a/cdtweaks/languages/english/weidu.tra +++ b/cdtweaks/languages/english/weidu.tra @@ -485,6 +485,8 @@ The uninstall messages above are normal and expected. @278000 = "Circle Kick class feat for Monks [Luke]" +@281000 = "Knockdown class feat for Fighters and Monks [Luke]" + /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ diff --git a/cdtweaks/languages/italian/knockdown.tra b/cdtweaks/languages/italian/knockdown.tra new file mode 100644 index 00000000..ff54744f --- /dev/null +++ b/cdtweaks/languages/italian/knockdown.tra @@ -0,0 +1,16 @@ +@0 = "Buttare a Terra" + +@1 = "Buttare a Terra + +Un personaggio con questo talento può tentare di far cadere a terra i suoi avversari. Il personaggio effettua un attacco con una penalità di -4 ai tiri per colpire e, se ha successo, il difensore effettua un tiro-salvezza contro Morte. Se fallisce, il difensore viene buttato a terra." + +@50 = "Steso a Terra" + +@100 = "Il bersaglio selezionato è fuori portata" +@101 = "Il bersaglio selezionato è già a terra" +@102 = "Il bersaglio selezionato è troppo grande" +@103 = "Questo talento non può essere usato mentre si brandisce un'arma a distanza" + +@104 = "Il personaggio non può compiere più di un'azione per round" + +@105 = "Non soggetto agli effetti di Buttare a Terra" \ No newline at end of file diff --git a/cdtweaks/languages/italian/weidu.tra b/cdtweaks/languages/italian/weidu.tra index 738ea95a..4fbf9ee8 100644 --- a/cdtweaks/languages/italian/weidu.tra +++ b/cdtweaks/languages/italian/weidu.tra @@ -436,6 +436,8 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~ @278000 = "Aggiungi talento di classe Calcio Rotante per i Monaci [Luke]" +@281000 = "Aggiungi talento di classe Buttare a Terra per i Guerrieri e i Monaci [Luke]" + /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ diff --git a/cdtweaks/lib/comp_2810.tpa b/cdtweaks/lib/comp_2810.tpa new file mode 100644 index 00000000..77749ea5 --- /dev/null +++ b/cdtweaks/lib/comp_2810.tpa @@ -0,0 +1,17 @@ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Knockdown class feat for Fighters and Monks \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +WITH_SCOPE BEGIN + INCLUDE "cdtweaks\luke\misc.tph" + INCLUDE "cdtweaks\ardanis\functions.tph" + // + INCLUDE "cdtweaks\lib\knockdown.tph" + WITH_TRA "cdtweaks\languages\english\knockdown.tra" "cdtweaks\languages\%LANGUAGE%\knockdown.tra" BEGIN + LAF "KNOCKDOWN" END + END +END \ No newline at end of file diff --git a/cdtweaks/lib/knockdown.tph b/cdtweaks/lib/knockdown.tph new file mode 100644 index 00000000..c0177943 --- /dev/null +++ b/cdtweaks/lib/knockdown.tph @@ -0,0 +1,77 @@ +DEFINE_ACTION_FUNCTION "KNOCKDOWN" +BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 3 + STR_VAR + "idsName" = "INNATE_KNOCKDOWN" + RET + "INNATE_KNOCKDOWN" = "resName" + END + // + LAF "ADD_EXTENDED_STAT" STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END + // + WITH_SCOPE BEGIN + ACTION_TO_LOWER "INNATE_KNOCKDOWN" + // Knockdown (spl file) + CREATE "spl" "%INNATE_KNOCKDOWN%" + COPY_EXISTING "%INNATE_KNOCKDOWN%.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG NAME2 "-1" + WRITE_LONG UNIDENTIFIED_DESC RESOLVE_STR_REF (@1) + WRITE_LONG DESC "-1" + WRITE_LONG 0x18 (BIT14 BOR BIT25) // ignore dead/wild magic, castable when silenced + WRITE_SHORT 0x1C 4 // innate + WRITE_LONG 0x34 1 // level + WRITE_ASCII 0x3A "%DEST_RES%B" #8 // icon + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 321 "target" = 1 STR_VAR "resource" = "%DEST_RES%" END // Remove effects by resource (cannot be used in conjunction with other feats such as my revised Called Shot. Such feats all share the same parent, i.e. "GTFEAT00") + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua + BUT_ONLY + // EFF + CREATE "eff" "%INNATE_KNOCKDOWN%b" + COPY_EXISTING "%INNATE_KNOCKDOWN%b.eff" "override" + WRITE_LONG 0x10 402 // Invoke Lua + WRITE_LONG 0x14 2 // Projectile target + WRITE_LONG 0x1C 1 // p1 + WRITE_SHORT 0x2C 100 // prob1 + WRITE_ASCII 0x30 "%INNATE_KNOCKDOWN%" #8 // Lua function + BUT_ONLY + // icons + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@50) STR_VAR "bam_file" = "GTPRONE" RET "feedback_icon" = "index" END + COPY "cdtweaks\luke\bam\innate\knockdown\spl_icon.bam" "override\%INNATE_KNOCKDOWN%b.bam" "cdtweaks\luke\bam\gtprone.bam" "override" + // + CREATE "eff" "gtprone" + COPY_EXISTING "gtprone.eff" "override" + WRITE_LONG 0x10 39 // Sleep + WRITE_LONG 0x14 2 // Projectile target + WRITE_LONG 0x20 1 // p2: wake on damage? no + WRITE_SHORT 0x2C 100 // prob1 + WRITE_LONG 0x48 "%feedback_icon%" // icon + BUT_ONLY + END + // lua + WITH_SCOPE BEGIN + OUTER_SET "feedback_strref_outOfRange" = RESOLVE_STR_REF (@100) + OUTER_SET "feedback_strref_alreadyProne" = RESOLVE_STR_REF (@101) + OUTER_SET "feedback_strref_tooLarge" = RESOLVE_STR_REF (@102) + OUTER_SET "feedback_strref_meleeOnly" = RESOLVE_STR_REF (@103) + OUTER_SET "feedback_strref_auraFree" = RESOLVE_STR_REF (@104) + OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@105) + // + WITH_SCOPE BEGIN + ACTION_TO_LOWER "INNATE_KNOCKDOWN" + COPY "cdtweaks\luke\bam\innate\knockdown\spl_portrait_icon.bam" "override\%INNATE_KNOCKDOWN%d.bam" + END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%INNATE_KNOCKDOWN%D" RET "feedback_icon_canKnockdown" = "index" END + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Innate)" "sourceFileSpec" = "cdtweaks\luke\lua\innate\knockdown.lua" "destRes" = "m_gt#int" END + // + ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN + COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" + END + END +END \ No newline at end of file diff --git a/cdtweaks/luke/bam/gtprone.bam b/cdtweaks/luke/bam/gtprone.bam new file mode 100644 index 0000000000000000000000000000000000000000..f64ae14da36cdee2fe3dd64cc3144937de90e623 GIT binary patch literal 1015 zcmVvdLCFs+pn!_pCXEd# z{cFah1_U*9bx1a*gsfoW6FK#POBoD0Vxus#*u^!xY&EgeP_sMj5DT;0UWA3BGIJ6b zMiheF?J(21z3(~id7m@SInT*^W`BIi*7$e@3Sxl77A+hmBrM0m z+?$4sOwc94YAx*4$MM(V3*;BT_8n0A3Upk~=Hd^~bQvZ?HH?RwINT1F8#hQZ)Ql&H#ktlCn=rurq~o^51ZRwackf5Rb>lmDg2v!X~cqKMmz zYM)(TpJ7$`A4DFTMP1@XQ)ow>W@Oz#Cu>V=X!Ac}qhXks9VYbEU$N%sLlLhfBew{L zYXY7dMU`#g;?-f$-$oHzO3IN5sv15ep~wL_;_P%6XmU{GK0vE0gRMTa2?pfXL&!BD zw7FqqV+gY~Ot#+0hwT=0X>G^_f-4#fh7dkq7>lK!*w{F_YTQ`NRzCmaDg{{vtj+zH ztIUj>$C-D`V=~lZ`^JXvz~2%iJx0 zk?@b-yzQ$_8^;&e%67Q9#5+42lS5qnvzCMh(QsPcq1f{!EFz%74J)oo6AR%Xf zwMoL)1LNPxl*#Z#*Fl=!f+AVV%pD6elhD{85t>`c$7j_{-F=Cglh5-=(ERri%+A7Z zzr)X7=>HaMHn?^TE(p1p-hsM$c(odiA4l8?6cXVq7R#QHYp1R4 z45g(djE#-b($XwqAr=-En46mud}l@O41quZuh)yi;b353K=8IY}5g1Cz;w z(P*TyvQqFiP*6~SEZ$77*OQi(Mtpoc8jVKqSMh&&JUGV6;4eWx5y7$UF{i)Vi?Tc5 zzvK;Gw>#aJ{C>aNt@H$Yd#?BP+6P^(L8s8KTj^BV2YXyj_s}iy_YNtYZsGg9DE_p2 ll|#OvF>kk_k{oe literal 0 HcmV?d00001 diff --git a/cdtweaks/luke/bam/innate/knockdown/spl_icon.bam b/cdtweaks/luke/bam/innate/knockdown/spl_icon.bam new file mode 100644 index 0000000000000000000000000000000000000000..841b7cdd5b51eb4e6c7121e508cbf4449e238db3 GIT binary patch literal 1298 zcmV+t1?~DmK}|zeF(4o`3jhFkob8m&cM@k5hkt4kNTQM$n^0?0Xw^VXBUnubo78|t z1q%Ykm|)`v!!(f@A-rQUCNoaR$b^$4JJ}U?W~aMmSC@6C%Pjk^&`Uo2sKPnj_Vk(a zD3l<0h^Kv5S_SX@MDv4jHC@MeSIFUtC>BsMnER1U%Jfu)!bd0q6Bn zIC$I~IJcYPfzR!P$LXXs2QT$5r-ynMoD>(GcWthnaP+ugr)ueR!fCg|O}*3ZfXi!x z&u61+EU?r04x1fzn~g%%ZbL^$2W%EQtkw?LE!11Blnz+w_hH@q1YU1E#{c|Rq5pur zt%E<=I3Idi+k6*Bf|t)mV>nHn(30MgyUE$}h-w zyROenXu6RutiWPz8w#EY2d|7xM+NQh0FzvKS(#V#3|d;xjK)SIg%k1m!TrSQ;-Be&1y%tTSB$)>^~Pt#m6Q2tA6dim~csQS~6C2MWe|m-G`Ty6TLH24^AJE z6ftKQ8O21)o|fTgOyVbwC;PJ5efUtC9tUzw@o1?&GkMo z&E<@aJ;aoH$DeAy2O_&z6p6|^-Cci?{AHzSaPRwS8B_-Q0Kj^)xuuLl2 zy%5)n2KKZEFYoGPvLfWZ>GotL<=By&5|a|Qb)#yaX@pxnKR4s(?CzR+I6KZ1Z}+z| z`qIgjYE?m#uXS~`v#a;$9AmPWmX+n319uX)`wCT^hI`NR8O_i#88$mDX=ZlWG!_?< zOGciaP&h5-lzWnCD6(1A=JR=DId2$w16DD|BK)K3EYpfK)Mx|EG!3++q;S?S1=Y+K zj1^5a49zTJUraXX3Fx#*RWVK4`G9U{I(2#Uf1ts(0(E##jF0(;DIf9)ZQkdT2EC(> zN^i$?jM~|}u2l|iy1wI+-hRMG4u8yBss9as I1BP;&*aY8#Z~y=R literal 0 HcmV?d00001 diff --git a/cdtweaks/luke/bam/innate/knockdown/spl_portrait_icon.bam b/cdtweaks/luke/bam/innate/knockdown/spl_portrait_icon.bam new file mode 100644 index 0000000000000000000000000000000000000000..b35d38d97c8ed8b4da3ef993db57448a945ae3f0 GIT binary patch literal 974 zcmV;<12OzUK}|zeF(4q01ONbdoMn@JOw@H8$6w&@(%J6N=Fg`h&mK6zfR!m?PEK^e z8N`DKKASf@x&tyu%}}Edk&Tm7Zs-QtXget8#R$%Jc{VxoX0ri9V1@@<7Co%=x_m-e zzh7Ubf3)>|_n^evb% zlazcLa#AWx((rw6AAI2AhwG!r2i?RS^|D}N3G z;ooY9EsgMs8RjRzoEUWVH<1&wSiJLuxbGNPJ0V-d#b?2^NTl>iA`Xq9eYKQb7Zj)# zG22{_auAZwuqn^el; zRayA^MxbyAO^%CC&h&^xj*5Nrh&?cZwd!-C3jOegID1_;%t|Dz;12Rj8z5&8d65}Y zt%B*Og1ke;RIT9rR%L0bjiV=B7*^I{Di&`I*J0kTFc?sAwVmV1ry@C4(nqV)P3vc0 zkeXoTwEY|nRww<=VS@g9>@k<&{o2dm`Zi`t5jf(k+%q^Z%Fp98ZAWeBVC1x$XoG>5 z7cF9q$;9t#EvP;}-8F|fySoTATgEU=qAD#8)%y|MZ^v=x)E1ntN&H$onLJ}GwgidN zGy`_wGYK-fizNmtV7S@DhGo!Jw+Z`J$V!q4UUL!jKt+Lsa(N0LmutDvn?s2;4dn{_ zBj^+oJpJh$479^Hr@$*{(q0FRV$XdRcrPD{HbVYdQA$CL?A4H&42kiedmJ>6_u+9nf&=l0?9xVW>kA|3J&O%*l-R&!)HiY2Mrr!Pu1-IQ!{B8V*OH44Ww0Hjfnv zGq~KDg7S-vvf?E?xW0?p50e@Ht(Kmyy{LaR6B{!R^=~&fuD22#?L@uXjl0dk#q&;- z`#-XO-@BYV;h^sLG4gVAxi&P!5xX5lQ5YK=_ghC;L!5~+!US(il0KeZ)S63Ha zuNSA&NmEl3_4W0Xm6c($*|1nFn9XJ~GBPlUni-8o;^X7d>-Fe#Iy4#$kJ|Kr&%=~} wPY(AmSt#HCRrr6b$0pPSm=y5&WC1-sVIaK1@H~_grq366s61%@1?mWhMVcbxp#T5? literal 0 HcmV?d00001 diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua new file mode 100644 index 00000000..439425a6 --- /dev/null +++ b/cdtweaks/luke/lua/innate/knockdown.lua @@ -0,0 +1,316 @@ +-- cdtweaks, NWN-ish Knockdown ability. Creatures already on the ground / levitating / etc. -- + +local cdtweaks_ImmuneToKnockdown = { + {"WEAPON"}, -- GENERAL.IDS + {"DRAGON", "BEHOLDER", "ANKHEG", "SLIME", "DEMILICH", "WILL-O-WISP", "SPECTRAL_UNDEAD", "SHADOW", "SPECTRE", "WRAITH", "MIST", "GENIE", "ELEMENTAL", "SALAMANDER"}, -- RACE.IDS + {"WIZARD_EYE", "SPECTRAL_TROLL", "SPIDER_WRAITH"}, -- CLASS.IDS + -- ANIMATE.IDS + { + "DOOM_GUARD", "DOOM_GUARD_LARGER", + "SNAKE", "BLOB_MIST_CREATURE", "MIST_CREATURE", "HAKEASHAR", "NISHRUU", "SNAKE_WATER", "DANCING_SWORD", + "SHADOW_SMALL", "SHADOW_LARGE", "WATER_WEIRD" + }, +} + +-- cdtweaks, NWN-ish Knockdown ability -- + +function %INNATE_KNOCKDOWN%(CGameEffect, CGameSprite) + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite + -- Check creature's currently selected weapon + local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") + -- Get personal space + local sourcePersonalSpace = sourceSprite.m_animation.m_animation.m_personalSpace + local targetPersonalSpace = CGameSprite.m_animation.m_animation.m_personalSpace + -- + local inWeaponRange = EEex_Trigger_ParseConditionalString("InWeaponRange(EEex_LuaObject)") + -- + local attackOneRound = EEex_Action_ParseResponseString("AttackOneRound(EEex_LuaObject)") + -- + local stats = GT_Resource_SymbolToIDS["stats"] + local class = GT_Resource_SymbolToIDS["class"] + -- + local targetGeneralStr = GT_Resource_IDSToSymbol["general"][CGameSprite.m_typeAI.m_General] + local targetRaceStr = GT_Resource_IDSToSymbol["race"][CGameSprite.m_typeAI.m_Race] + local targetClassStr = GT_Resource_IDSToSymbol["class"][CGameSprite.m_typeAI.m_Class] + local targetAnimateStr = GT_Resource_IDSToSymbol["animate"][CGameSprite.m_animation.m_animation.m_animationID] + -- + local targetIDS = {targetGeneralStr, targetRaceStr, targetClassStr, targetAnimateStr} + -- Melee weapon equipped! + if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then + if CGameEffect.m_effectAmount == 0 then + EEex_LuaObject = CGameSprite -- must be global + -- check range + if inWeaponRange:evalConditionalAsAIBase(sourceSprite) then + -- + local effectCodes = { + {["op"] = 401, ["p2"] = 1, ["p1"] = 1, ["tmg"] = 10, ["dur"] = 1, ["spec"] = stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]}, -- set extended stat + {["op"] = 284, ["tmg"] = 1, ["p1"] = -4}, -- melee thac0 bonus + {["op"] = 142, ["tmg"] = 1, ["p2"] = %feedback_icon_canKnockdown%}, -- feedback icon + {["op"] = 248, ["tmg"] = 1, ["res"] = "%INNATE_KNOCKDOWN%B"}, -- melee hit effect + } + -- + for _, attributes in ipairs(effectCodes) do + sourceSprite:applyEffect({ + ["effectID"] = attributes["op"] or -1, + ["effectAmount"] = attributes["p1"] or 0, + ["dwFlags"] = attributes["p2"] or 0, + ["special"] = attributes["spec"] or 0, + ["res"] = attributes["res"] or "", + ["duration"] = attributes["dur"] or 0, + ["durationType"] = attributes["tmg"] or 0, + ["m_sourceRes"] = "%INNATE_KNOCKDOWN%", + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + end + -- + attackOneRound:queueResponseOnAIBase(sourceSprite) + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_outOfRange%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + elseif CGameEffect.m_effectAmount == 1 then + -- immunity check + local found = false + do + for index, symbolList in ipairs(cdtweaks_ImmuneToKnockdown) do + for _, symbol in ipairs(symbolList) do + if targetIDS[index] == symbol then + found = true + break + end + end + end + end + -- + if not found then + if (sourcePersonalSpace - targetPersonalSpace) >= -1 then + -- SLOT_FIST is always equipped, even if not in use... As a result, we want to apply op39 via op182... + local fistResRef = {} + if CGameSprite.m_typeAI.m_Class == class["MONK"] then + local monkfist = GT_Resource_2DA["monkfist"] + for lvl = 1, 50 do + if GT_Utility_KeyExists(GT_Resource_2DA, "monkfist", tostring(lvl), "RESREF") then + fistResRef[monkfist[tostring(lvl)]["RESREF"]] = true + end + end + else + local items = CGameSprite.m_equipment.m_items -- Array + local item = items:get(10) -- CItem + if item then + fistResRef[item.pRes.resref:get()] = true -- should be "FIST.ITM" + end + end + -- set ``savebonus`` + local savebonus = 0 + if (sourcePersonalSpace - targetPersonalSpace) > 0 then + savebonus = -4 + elseif (sourcePersonalSpace - targetPersonalSpace) < 0 then + savebonus = 4 + end + -- + local effectCodes = {} + for resref, _ in pairs(fistResRef) do + table.insert(effectCodes, {["op"] = 182, ["res"] = resref, ["res2"] = "GTPRONE"}) -- apply EFF while FIST/MFIST[1-8] is equipped (i.e. always). We need this to bypass op101 and make op39 uncurable (i.e. immune to op2) + end + table.insert(effectCodes, {["op"] = 206, ["p1"] = %feedback_strref_alreadyProne%, ["res"] = "%INNATE_KNOCKDOWN%B"}) -- protection from spell + -- + for _, attributes in ipairs(effectCodes) do + CGameSprite:applyEffect({ + ["effectID"] = attributes["op"] or -1, + ["effectAmount"] = attributes["p1"] or 0, + ["duration"] = 6, + ["savingThrow"] = 0x4, -- save vs. death + ["saveMod"] = savebonus, + ["m_res2"] = attributes["res2"] or "", + ["m_sourceRes"] = "%INNATE_KNOCKDOWN%B", + ["m_sourceType"] = 1, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_tooLarge%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + else + sourceSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_meleeOnly%, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + end + -- + inWeaponRange:free() + isWeaponRanged:free() + attackOneRound:free() +end + +-- cdtweaks, NWN-ish Knockdown ability. Make sure one and only one attack roll is performed -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- + local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") + -- + if sprite:getLocalInt("cdtweaksKnockdown") == 1 then + local knockdownMode = false + -- + EEex_Utility_IterateCPtrList(sprite.m_timedEffectList, function(effect) + if effect.m_effectId == 248 and effect.m_res:get() == "%INNATE_KNOCKDOWN%B" then + knockdownMode = true + return true + end + end) + -- + if knockdownMode then + if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 1) + elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + -- + sprite.m_curAction.m_actionID = 0 -- nuke current action + -- + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + else + -- in case the character dies while swinging... + if sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + end + end + end + -- + isWeaponRanged:free() +end) + +-- cdtweaks, NWN-ish Knockdown ability. Make sure it cannot be disrupted -- + +EEex_Action_AddSpriteStartedActionListener(function(sprite, action) + if sprite:getLocalInt("cdtweaksKnockdown") == 1 then + local stats = GT_Resource_SymbolToIDS["stats"] + -- + if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%INNATE_KNOCKDOWN%" then + if EEex_Sprite_GetCastTimer(sprite) == -1 then + action.m_actionID = 113 -- ForceSpell() + -- + sprite.m_castCounter = 0 + else + action.m_actionID = 0 -- nuke current action + -- + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_auraFree%, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + else + if EEex_Sprite_GetStat(sprite, stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]) == 0 then + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end + end +end) + +-- cdtweaks, NWN-ish Knockdown ability. Gain ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that grants the ability + local gain = function() + -- Mark the creature as 'feat granted' + sprite:setLocalInt("cdtweaksKnockdown", 1) + -- + local effectCodes = { + {["op"] = 172}, -- remove spell + {["op"] = 171}, -- give spell + } + -- + for _, attributes in ipairs(effectCodes) do + sprite:applyEffect({ + ["effectID"] = attributes["op"] or -1, + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end + -- Check creature's class + 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 + -- + local gainAbility = spriteClassStr == "MONK" or 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("cdtweaksKnockdown") == 0 then + if gainAbility then + gain() + end + else + if gainAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksKnockdown", 0) + -- + sprite:applyEffect({ + ["effectID"] = 172, -- remove spell + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) diff --git a/cdtweaks/luke/lua/m_gttbls.lua b/cdtweaks/luke/lua/m_gttbls.lua index 6861a6c6..bde99f95 100644 --- a/cdtweaks/luke/lua/m_gttbls.lua +++ b/cdtweaks/luke/lua/m_gttbls.lua @@ -7,7 +7,7 @@ GT_Resource_SymbolToIDS = {} EEex_GameState_AddInitializedListener(function() -- 2DA EEex_Utility_NewScope(function() - local resources = { "STRMOD", "STRMODEX", "DEXMOD", "STYLBONU", "SNEAKATT" } + local resources = { "STRMOD", "STRMODEX", "DEXMOD", "STYLBONU", "SNEAKATT", "MONKFIST" } -- for _, v in ipairs(resources) do local data = EEex_Resource_Load2DA(v) diff --git a/cdtweaks/luke/lua/utility/key_exists.lua b/cdtweaks/luke/lua/utility/key_exists.lua new file mode 100644 index 00000000..721f4aa1 --- /dev/null +++ b/cdtweaks/luke/lua/utility/key_exists.lua @@ -0,0 +1,15 @@ +-- Utility: check if a key exists in a table (should work for any kind of table, from simple to nested tables...) -- + +function GT_Utility_KeyExists(tbl, ...) -- NB.: ``...`` is called ``vararg`` (variable argument). It allows the function to accept a variable number of arguments. This is useful when we don't know in advance how many arguments will be passed to the function + local keys = {...} + local current = tbl + + for _, key in ipairs(keys) do + if type(current) ~= "table" or current[key] == nil then + return false + end + current = current[key] + end + + return true +end diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index f539c3ea..dc4a0b8b 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -413,4 +413,220 @@ BEGIN COPY_EXISTING "%destRes%.lua" "override" APPEND_FILE_EVALUATE TEXT "%sourceFileSpec%" BUT_ONLY UNLESS "%fileContent%" +END + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + +Custom ADD_SPELL + +*/ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +DEFINE_DIMORPHIC_FUNCTION "GT_ADD_SPELL" +INT_VAR + "type" = 3 // GTINXXX + "level" = 0 + "sort" = 1 // boolean +STR_VAR + "idsName" = "INNATE_NO_NAME" +RET + "resName" +BEGIN + OUTER_TEXT_SPRINT "resName" "" + // + ACTION_IF !(FILE_EXISTS_IN_GAME "gtspell.ids") BEGIN + COPY_EXISTING "spell.ids" "override\gtspell.ids" + DELETE_BYTES 0x0 BUFFER_LENGTH + BUT_ONLY + END + // + ACTION_IF (IDS_OF_SYMBOL ("GTSPELL" "%idsName%") == "-1") BEGIN + ACTION_MATCH "%type%" WITH + 1 BEGIN + OUTER_SET "min" = 0 + OUTER_SET "max" = 99 + OUTER_TEXT_SPRINT "prefix" "gtpr" + END + 2 BEGIN + OUTER_SET "min" = 0 + OUTER_SET "max" = 99 + OUTER_TEXT_SPRINT "prefix" "gtwi" + END + 3 BEGIN + OUTER_SET "min" = 0 + OUTER_SET "max" = 99 + OUTER_TEXT_SPRINT "prefix" "gtin" + END + 4 BEGIN + OUTER_SET "min" = 0 + OUTER_SET "max" = 99 + OUTER_TEXT_SPRINT "prefix" "gtcl" + END + DEFAULT + FAIL "GT_ADD_SPELL: invalid spell type (%type%)" + END + // + OUTER_FOR ("i" = "%min%" ; "%i%" <= "%max%" ; "i" += 1) BEGIN + ACTION_IF (STRING_LENGTH "%i%" == 1) BEGIN + OUTER_TEXT_SPRINT "i" "0%i%" + END + ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%i%.spl") BEGIN + APPEND "GTSPELL.IDS" "%type%%level%%i% %idsName%" + OUTER_TEXT_SPRINT "resName" "%prefix%%level%%i%" + OUTER_SET "i" = "%max%" // kill FOR-loop + END + END + // + ACTION_IF "%sort%" BEGIN + LAF "SORT_IDS_FILE" STR_VAR "idsFile" = "gtspell" END + END + END ELSE BEGIN + LAF "GT_RES_NUM_OF_SPELL_NAME" STR_VAR "spell_name" = "%idsName%" RET "resName" = "spell_res" END + END +END + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + +*/ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +DEFINE_DIMORPHIC_FUNCTION "GT_RES_NUM_OF_SPELL_NAME" +STR_VAR + "spell_name" = "" +RET + "spell_num" + "spell_res" +BEGIN + OUTER_TEXT_SPRINT "spell_res" "" + OUTER_SET "spell_num" = "-1" + // + COPY_EXISTING - "gtspell.ids" "override" + COUNT_2DA_COLS "cols" + READ_2DA_ENTRIES_NOW "read_gtspell" "%cols%" + FOR ("i" = 0 ; "%i%" < "%read_gtspell%" ; "i" += 1) BEGIN + READ_2DA_ENTRY_FORMER "read_gtspell" "%i%" 1 "current_spell_name" + PATCH_IF ("%current_spell_name%" STR_EQ "%spell_name%") BEGIN + READ_2DA_ENTRY_FORMER "read_gtspell" "%i%" 0 "spell_num" + INNER_PATCH "%spell_num%" BEGIN + READ_ASCII 0x0 "type" (1) + READ_ASCII 0x1 "spell_id" (3) + PATCH_MATCH "%type%" WITH + 1 BEGIN + TEXT_SPRINT "spell_res" "gtpr%spell_id%" + END + 2 BEGIN + TEXT_SPRINT "spell_res" "gtwi%spell_id%" + END + 3 BEGIN + TEXT_SPRINT "spell_res" "gtin%spell_id%" + END + 4 BEGIN + TEXT_SPRINT "spell_res" "gtcl%spell_id%" + END + DEFAULT + PATCH_FAIL "Should not happen" + END + END + SET "i" = "%read_gtspell%" // kill FOR-loop + END + END + BUT_ONLY_IF_IT_CHANGES +END + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + +*/ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +DEFINE_DIMORPHIC_FUNCTION "GT_NAME_NUM_OF_SPELL_RES" +STR_VAR + "spell_res" = "" +RET + "spell_num" + "spell_name" +BEGIN + OUTER_TEXT_SPRINT "spell_name" "" + OUTER_SET "spell_num" = "-1" + // + COPY_EXISTING - "gtspell.ids" "override" + COUNT_2DA_COLS "cols" + READ_2DA_ENTRIES_NOW "read_gtspell" "%cols%" + FOR ("i" = 0 ; "%i%" < "%read_gtspell%" ; "i" += 1) BEGIN + READ_2DA_ENTRY_FORMER "read_gtspell" "%i%" 0 "current_spell_num" + INNER_PATCH "%spell_res%" BEGIN + READ_ASCII 0x2 "type" (2) + READ_ASCII 0x4 "spell_id" (3) + PATCH_MATCH "%type%" WITH + "pr" BEGIN + TEXT_SPRINT "spell_num" "1%spell_id%" + END + "wi" BEGIN + TEXT_SPRINT "spell_num" "2%spell_id%" + END + "in" BEGIN + TEXT_SPRINT "spell_num" "3%spell_id%" + END + "cl" BEGIN + TEXT_SPRINT "spell_num" "4%spell_id%" + END + DEFAULT + PATCH_FAIL "Should not happen" + END + END + PATCH_IF ("%current_spell_num%" == "%spell_num%") BEGIN + READ_2DA_ENTRY_FORMER "read_gtspell" "%i%" 1 "spell_name" + SET "i" = "%read_gtspell%" // kill FOR-loop + END + END + BUT_ONLY_IF_IT_CHANGES +END + +/* +============================================================================================================== +**SORT_IDS_FILE** +- Sort "%idsFile%" in ascending numerical order +- Do not use without a real reason (it may take up to several seconds... probably not a big deal...) +============================================================================================================== +*/ + +DEFINE_DIMORPHIC_FUNCTION "SORT_IDS_FILE" +STR_VAR + "idsFile" = "" +BEGIN + ACTION_CLEAR_ARRAY "ids_sorted" + // + COPY_EXISTING "%idsFile%.ids" "override" + COUNT_2DA_COLS "cols" + READ_2DA_ENTRIES_NOW "sort_ids_file" "%cols%" + // Header + READ_2DA_ENTRY_FORMER "sort_ids_file" 0 0 "value" + PATCH_IF ("%value%" STR_EQ "IDS") BEGIN + SET "#_entries" = "%sort_ids_file%" - 1 + END ELSE BEGIN + SET "#_entries" = "%sort_ids_file%" + END + // Body + FOR ("row" = 0 ; "%row%" < "%sort_ids_file%" ; "row" += 1) BEGIN + READ_2DA_ENTRY_FORMER "sort_ids_file" "%row%" 0 "value" + PATCH_IF ("%value%" STRING_COMPARE_CASE "IDS") BEGIN + READ_2DA_ENTRY_FORMER "sort_ids_file" "%row%" 1 "identifier" + DEFINE_ASSOCIATIVE_ARRAY "ids_sorted" BEGIN + "%value%" , "%row%" => "%identifier%" // preserve duplicate entries + END + END + END + // Main + DELETE_BYTES 0x0 BUFFER_LENGTH + INSERT_2DA_ROW 0 0 "IDS V1.0" + INSERT_2DA_ROW 1 0 "%#_entries%" + SORT_ARRAY_INDICES "ids_sorted" NUMERICALLY + SET "row" = 2 + PHP_EACH "ids_sorted" AS "value" => "identifier" BEGIN + INSERT_2DA_ROW "%row%" 0 "%value% %identifier%" + SET "row" += 1 + END + BUT_ONLY_IF_IT_CHANGES END \ No newline at end of file diff --git a/cdtweaks/readme-cdtweaks.html b/cdtweaks/readme-cdtweaks.html index 84c933fc..e3d558f2 100644 --- a/cdtweaks/readme-cdtweaks.html +++ b/cdtweaks/readme-cdtweaks.html @@ -1098,6 +1098,31 @@

Rule Changes

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

Knockdown class feat for Fighters and Monks [Luke]
+ EEex

+

This component aims at implementing the NWN feat Knockdown.
+ A character with this feat can attempt to knock his opponents to the ground. The character makes an attack roll at -4, and if successful the defender makes a Save vs. Death. If failed, the defender is knocked to a prone position.
+ Notes:

+
    +
  • Use: selected, unlimited uses per day. Only available to Fighters and Monks (starting from level 1).
  • +
  • The prone state lasts for one round.
  • +
  • This feat cannot be used while wielding a ranged weapon.
  • +
  • + A character can only make a knockdown attempt on opponents that are one size category larger than himself, or smaller. +
      +
    • As a rule of thumb, look at the defender's circle size: if smaller, equal or just a little bit bigger than the one of the attacker, then it is fine; otherwise, the creature is too large to be knocked down.
    • +
    • + On top of it: +
        +
      • if the attacker is larger than the defender, the saving throw penalty is -4 (i.e., it's easier to succeed).
      • +
      • Conversely, the saving throw penalty is +4 (i.e., it's harder to succeed).
      • +
      +
    • +
    +
  • +
  • Creatures already on the ground (f.i. snakes, slimes, salamanders ...), magically levitating creatures (beholders, demiliches, ...) and certain special creatures (f.i. spectral undead, elementals, ...) cannot be knocked down.
  • +

Convenience Tweaks and/or Cheats

diff --git a/cdtweaks/setup-cdtweaks.tp2 b/cdtweaks/setup-cdtweaks.tp2 index 5e97fb6f..0baadd59 100644 --- a/cdtweaks/setup-cdtweaks.tp2 +++ b/cdtweaks/setup-cdtweaks.tp2 @@ -2990,6 +2990,20 @@ 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~ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Knockdown class feat for Fighters and Monks \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +BEGIN @281000 DESIGNATED 2810 +GROUP @9 +REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/knockdown.tra~ @7 +LABEL ~cd_tweaks_knockdown~ + /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ From ff8cc14cf63310e04645702dcf98d8974c236d91 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 4 Sep 2024 20:07:43 +0200 Subject: [PATCH 02/33] Update knockdown.lua --- cdtweaks/luke/lua/innate/knockdown.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua index 439425a6..a07ff66d 100644 --- a/cdtweaks/luke/lua/innate/knockdown.lua +++ b/cdtweaks/luke/lua/innate/knockdown.lua @@ -227,6 +227,13 @@ EEex_Action_AddSpriteStartedActionListener(function(sprite, action) action.m_actionID = 0 -- nuke current action -- EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%INNATE_KNOCKDOWN%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + EEex_GameObject_ApplyEffect(sprite, { ["effectID"] = 139, -- display string ["effectAmount"] = %feedback_strref_auraFree%, From ab88ec4546edc0a950aadf2e8f9cb690a33a2a52 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Thu, 5 Sep 2024 19:17:25 +0200 Subject: [PATCH 03/33] Misc tweaks --- cdtweaks/lib/knockdown.tph | 17 ++++++---- ...pl_portrait_icon.bam => portrait_icon.bam} | Bin cdtweaks/luke/lua/innate/knockdown.lua | 2 +- .../lua/{utility => tools}/key_exists.lua | 4 +-- cdtweaks/luke/misc.tph | 30 +++++++++++++----- 5 files changed, 35 insertions(+), 18 deletions(-) rename cdtweaks/luke/bam/innate/knockdown/{spl_portrait_icon.bam => portrait_icon.bam} (100%) rename cdtweaks/luke/lua/{utility => tools}/key_exists.lua (68%) diff --git a/cdtweaks/lib/knockdown.tph b/cdtweaks/lib/knockdown.tph index c0177943..245ea678 100644 --- a/cdtweaks/lib/knockdown.tph +++ b/cdtweaks/lib/knockdown.tph @@ -2,7 +2,8 @@ DEFINE_ACTION_FUNCTION "KNOCKDOWN" BEGIN LAF "GT_ADD_SPELL" INT_VAR - "level" = 3 + "level" = 1 + "preferredSlot" = 44 STR_VAR "idsName" = "INNATE_KNOCKDOWN" RET @@ -64,14 +65,16 @@ BEGIN // WITH_SCOPE BEGIN ACTION_TO_LOWER "INNATE_KNOCKDOWN" - COPY "cdtweaks\luke\bam\innate\knockdown\spl_portrait_icon.bam" "override\%INNATE_KNOCKDOWN%d.bam" + COPY "cdtweaks\luke\bam\innate\knockdown\portrait_icon.bam" "override\%INNATE_KNOCKDOWN%d.bam" END LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%INNATE_KNOCKDOWN%D" RET "feedback_icon_canKnockdown" = "index" END // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Innate)" "sourceFileSpec" = "cdtweaks\luke\lua\innate\knockdown.lua" "destRes" = "m_gt#int" END - // - ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN - COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" - END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Innate)" "sourceFileSpec" = "cdtweaks\luke\lua\innate\knockdown.lua" "destRes" = "m_gtspin" END + END + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" 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/luke/bam/innate/knockdown/spl_portrait_icon.bam b/cdtweaks/luke/bam/innate/knockdown/portrait_icon.bam similarity index 100% rename from cdtweaks/luke/bam/innate/knockdown/spl_portrait_icon.bam rename to cdtweaks/luke/bam/innate/knockdown/portrait_icon.bam diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua index a07ff66d..f1a21fc7 100644 --- a/cdtweaks/luke/lua/innate/knockdown.lua +++ b/cdtweaks/luke/lua/innate/knockdown.lua @@ -95,7 +95,7 @@ function %INNATE_KNOCKDOWN%(CGameEffect, CGameSprite) if CGameSprite.m_typeAI.m_Class == class["MONK"] then local monkfist = GT_Resource_2DA["monkfist"] for lvl = 1, 50 do - if GT_Utility_KeyExists(GT_Resource_2DA, "monkfist", tostring(lvl), "RESREF") then + if GT_LuaTool_KeyExists(GT_Resource_2DA, "monkfist", tostring(lvl), "RESREF") then fistResRef[monkfist[tostring(lvl)]["RESREF"]] = true end end diff --git a/cdtweaks/luke/lua/utility/key_exists.lua b/cdtweaks/luke/lua/tools/key_exists.lua similarity index 68% rename from cdtweaks/luke/lua/utility/key_exists.lua rename to cdtweaks/luke/lua/tools/key_exists.lua index 721f4aa1..05f04d36 100644 --- a/cdtweaks/luke/lua/utility/key_exists.lua +++ b/cdtweaks/luke/lua/tools/key_exists.lua @@ -1,6 +1,6 @@ --- Utility: check if a key exists in a table (should work for any kind of table, from simple to nested tables...) -- +-- Tool: Check if a key exists in a table (should work for any kind of table, from simple to nested tables...) -- -function GT_Utility_KeyExists(tbl, ...) -- NB.: ``...`` is called ``vararg`` (variable argument). It allows the function to accept a variable number of arguments. This is useful when we don't know in advance how many arguments will be passed to the function +function GT_LuaTool_KeyExists(tbl, ...) -- NB.: ``...`` is called ``vararg`` (variable argument). It allows the function to accept a variable number of arguments. This is useful when we don't know in advance how many arguments will be passed to the function local keys = {...} local current = tbl diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index dc4a0b8b..0ba8ef72 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -428,12 +428,21 @@ INT_VAR "type" = 3 // GTINXXX "level" = 0 "sort" = 1 // boolean + "preferredSlot" = 0 STR_VAR "idsName" = "INNATE_NO_NAME" RET "resName" BEGIN OUTER_TEXT_SPRINT "resName" "" + // sanity check + ACTION_IF ("%preferredSlot%" >= 0 AND "%preferredSlot%" <= 99) BEGIN + ACTION_IF ("%preferredSlot%" < 10) BEGIN + OUTER_TEXT_SPRINT "preferredSlot" "0%preferredSlot%" + END + END ELSE BEGIN + OUTER_TEXT_SPRINT "preferredSlot" "00" + END // ACTION_IF !(FILE_EXISTS_IN_GAME "gtspell.ids") BEGIN COPY_EXISTING "spell.ids" "override\gtspell.ids" @@ -467,14 +476,19 @@ BEGIN FAIL "GT_ADD_SPELL: invalid spell type (%type%)" END // - OUTER_FOR ("i" = "%min%" ; "%i%" <= "%max%" ; "i" += 1) BEGIN - ACTION_IF (STRING_LENGTH "%i%" == 1) BEGIN - OUTER_TEXT_SPRINT "i" "0%i%" - END - ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%i%.spl") BEGIN - APPEND "GTSPELL.IDS" "%type%%level%%i% %idsName%" - OUTER_TEXT_SPRINT "resName" "%prefix%%level%%i%" - OUTER_SET "i" = "%max%" // kill FOR-loop + ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%preferredSlot%.spl") BEGIN + APPEND "GTSPELL.IDS" "%type%%level%%preferredSlot% %idsName%" + OUTER_TEXT_SPRINT "resName" "%prefix%%level%%preferredSlot%" + END ELSE BEGIN + OUTER_FOR ("i" = "%min%" ; "%i%" <= "%max%" ; "i" += 1) BEGIN + ACTION_IF (STRING_LENGTH "%i%" == 1) BEGIN + OUTER_TEXT_SPRINT "i" "0%i%" + END + ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%i%.spl") BEGIN + APPEND "GTSPELL.IDS" "%type%%level%%i% %idsName%" + OUTER_TEXT_SPRINT "resName" "%prefix%%level%%i%" + OUTER_SET "i" = "%max%" // kill FOR-loop + END END END // From d351190709c2027ccbe9d58abaae38ada41a83d2 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 6 Sep 2024 10:22:23 +0200 Subject: [PATCH 04/33] Update knockdown.lua --- cdtweaks/luke/lua/innate/knockdown.lua | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua index f1a21fc7..5fd5cbd9 100644 --- a/cdtweaks/luke/lua/innate/knockdown.lua +++ b/cdtweaks/luke/lua/innate/knockdown.lua @@ -176,16 +176,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") -- if sprite:getLocalInt("cdtweaksKnockdown") == 1 then - local knockdownMode = false - -- - EEex_Utility_IterateCPtrList(sprite.m_timedEffectList, function(effect) - if effect.m_effectId == 248 and effect.m_res:get() == "%INNATE_KNOCKDOWN%B" then - knockdownMode = true - return true - end - end) - -- - if knockdownMode then + if GT_Utility_EffectCheck(sprite, {["m_effectId"] = 0xF8, ["m_res"] = "%INNATE_KNOCKDOWN%B"}) then if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then sprite:setLocalInt("gtCGameSpriteStartedSwing", 1) elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then From 14d435f70cf76a8b81ee325c8c423eda3f3c4e79 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 6 Sep 2024 10:22:39 +0200 Subject: [PATCH 05/33] Update knockdown.tph --- cdtweaks/lib/knockdown.tph | 1 + 1 file changed, 1 insertion(+) diff --git a/cdtweaks/lib/knockdown.tph b/cdtweaks/lib/knockdown.tph index 245ea678..93a49944 100644 --- a/cdtweaks/lib/knockdown.tph +++ b/cdtweaks/lib/knockdown.tph @@ -73,6 +73,7 @@ BEGIN END // LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\wrap_userdata.lua" "destRes" = "m_gttool" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN COPY "cdtweaks\luke\lua\m_gttbls.lua" "override" From 08af72f485064e8966e24ec62d20586eac9ccc2c Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 6 Sep 2024 18:47:55 +0200 Subject: [PATCH 06/33] Update knockdown.tph --- cdtweaks/lib/knockdown.tph | 1 + 1 file changed, 1 insertion(+) diff --git a/cdtweaks/lib/knockdown.tph b/cdtweaks/lib/knockdown.tph index 93a49944..0e2be3ad 100644 --- a/cdtweaks/lib/knockdown.tph +++ b/cdtweaks/lib/knockdown.tph @@ -73,6 +73,7 @@ BEGIN END // LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" END + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Utility Functions / Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\utility\effect_check.lua" "destRes" = "m_gtutil" END LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\wrap_userdata.lua" "destRes" = "m_gttool" END // ACTION_IF !(FILE_EXISTS_IN_GAME "m_gttbls.lua") BEGIN From e4a7878d660787b1d1f3dd9ddb1a3b3cc2709a9a Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 6 Sep 2024 18:50:19 +0200 Subject: [PATCH 07/33] Update knockdown.lua --- cdtweaks/luke/lua/innate/knockdown.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua index 5fd5cbd9..d1bb5dca 100644 --- a/cdtweaks/luke/lua/innate/knockdown.lua +++ b/cdtweaks/luke/lua/innate/knockdown.lua @@ -22,9 +22,9 @@ function %INNATE_KNOCKDOWN%(CGameEffect, CGameSprite) local sourcePersonalSpace = sourceSprite.m_animation.m_animation.m_personalSpace local targetPersonalSpace = CGameSprite.m_animation.m_animation.m_personalSpace -- - local inWeaponRange = EEex_Trigger_ParseConditionalString("InWeaponRange(EEex_LuaObject)") + local inWeaponRange = EEex_Trigger_ParseConditionalString('InWeaponRange(EEex_Target("GT_InnateKnockdownTarget"))') -- - local attackOneRound = EEex_Action_ParseResponseString("AttackOneRound(EEex_LuaObject)") + local attackOneRound = EEex_Action_ParseResponseString('AttackOneRound(EEex_Target("GT_InnateKnockdownTarget"))') -- local stats = GT_Resource_SymbolToIDS["stats"] local class = GT_Resource_SymbolToIDS["class"] @@ -38,7 +38,7 @@ function %INNATE_KNOCKDOWN%(CGameEffect, CGameSprite) -- Melee weapon equipped! if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then if CGameEffect.m_effectAmount == 0 then - EEex_LuaObject = CGameSprite -- must be global + sourceSprite:setStoredScriptingTarget("GT_InnateKnockdownTarget", CGameSprite) -- check range if inWeaponRange:evalConditionalAsAIBase(sourceSprite) then -- From acadb212eebe844ff6c61f5485e3aab8d01f0dcb Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Mon, 30 Sep 2024 20:02:57 +0200 Subject: [PATCH 08/33] Disarm --- cdtweaks/languages/english/disarm.tra | 13 + cdtweaks/languages/english/knockdowm.tra | 16 - cdtweaks/languages/english/weidu.tra | 2 +- cdtweaks/languages/italian/disarm.tra | 13 + cdtweaks/languages/italian/knockdown.tra | 16 - cdtweaks/languages/italian/weidu.tra | 2 +- cdtweaks/lib/{comp_2810.tpa => comp_2840.tpa} | 8 +- cdtweaks/lib/disarm.tph | 73 ++++ cdtweaks/lib/knockdown.tph | 82 ---- cdtweaks/luke/lua/class/disarm.lua | 372 ++++++++++++++++++ cdtweaks/luke/lua/innate/knockdown.lua | 314 --------------- cdtweaks/readme-cdtweaks.html | 27 +- cdtweaks/setup-cdtweaks.tp2 | 8 +- 13 files changed, 497 insertions(+), 449 deletions(-) create mode 100644 cdtweaks/languages/english/disarm.tra delete mode 100644 cdtweaks/languages/english/knockdowm.tra create mode 100644 cdtweaks/languages/italian/disarm.tra delete mode 100644 cdtweaks/languages/italian/knockdown.tra rename cdtweaks/lib/{comp_2810.tpa => comp_2840.tpa} (69%) create mode 100644 cdtweaks/lib/disarm.tph delete mode 100644 cdtweaks/lib/knockdown.tph create mode 100644 cdtweaks/luke/lua/class/disarm.lua delete mode 100644 cdtweaks/luke/lua/innate/knockdown.lua diff --git a/cdtweaks/languages/english/disarm.tra b/cdtweaks/languages/english/disarm.tra new file mode 100644 index 00000000..3bdf5c96 --- /dev/null +++ b/cdtweaks/languages/english/disarm.tra @@ -0,0 +1,13 @@ +@0 = "Disarm" + +@1 = "Disarm + +The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands." + +@100 = "The selected target is out of range" +@101 = "Disarm Canceled: Inventory full" +@102 = "Disarm: Resisted" +@103 = "Disarm: Hit" +@104 = "This feat cannot be used while wielding a ranged weapon" +@105 = "The character cannot perform more than one action per round" +@106 = "Unaffected by effects from Disarm" \ No newline at end of file diff --git a/cdtweaks/languages/english/knockdowm.tra b/cdtweaks/languages/english/knockdowm.tra deleted file mode 100644 index 8a4b548d..00000000 --- a/cdtweaks/languages/english/knockdowm.tra +++ /dev/null @@ -1,16 +0,0 @@ -@0 = "Knockdown" - -@1 = "Knockdown - -A character with this feat can attempt to knock his opponents to the ground. The character makes an attack roll at -4, and if successful the defender makes a Save vs. Death. If failed, the defender is knocked to a prone position." - -@50 = "Prone" - -@100 = "The selected target is out of range" -@101 = "The selected target is already prone" -@102 = "The selected target is too large" -@103 = "This feat cannot be used while wielding a ranged weapon" - -@104 = "The character cannot perform more than one action per round" - -@105 = "Unaffected by effects from Knockdown" \ No newline at end of file diff --git a/cdtweaks/languages/english/weidu.tra b/cdtweaks/languages/english/weidu.tra index bc5b9a3c..c6c4bea4 100644 --- a/cdtweaks/languages/english/weidu.tra +++ b/cdtweaks/languages/english/weidu.tra @@ -485,7 +485,7 @@ The uninstall messages above are normal and expected. @278000 = "Circle Kick class feat for Monks [Luke]" -@281000 = "Knockdown class feat for Fighters and Monks [Luke]" +@284000 = "Disarm class feat for Rogues [Luke]" /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ diff --git a/cdtweaks/languages/italian/disarm.tra b/cdtweaks/languages/italian/disarm.tra new file mode 100644 index 00000000..8a6f9c87 --- /dev/null +++ b/cdtweaks/languages/italian/disarm.tra @@ -0,0 +1,13 @@ +@0 = "Disarmare" + +@1 = "Disarmare + +Il personaggio può tentare di disarmare un avversario durante un combattimento in mischia. Il tentativo di disarmare applica una penalità di -6 al tiro per colpire del personaggio, e il combattente con l'arma più grande ottiene un bonus di +2 per ogni categoria di taglia di differenza. Un colpo andato a segno infligge danni normalmente e, se l'avversario fallisce un tiro-salvezza contro Soffio, l'arma gli vola via dalle mani." + +@100 = "Il bersaglio selezionato è fuori portata" +@101 = "Disarmare Annullato: Inventario pieno" +@102 = "Disarmare: Resistito" +@103 = "Disarmare: Colpito" +@104 = "Questa abilità non può essere usata mentre si brandisce un'arma a distanza" +@105 = "Il personaggio non può compiere più di un'azione per round" +@106 = "Non soggetto agli effetti di Disarmare" \ No newline at end of file diff --git a/cdtweaks/languages/italian/knockdown.tra b/cdtweaks/languages/italian/knockdown.tra deleted file mode 100644 index ff54744f..00000000 --- a/cdtweaks/languages/italian/knockdown.tra +++ /dev/null @@ -1,16 +0,0 @@ -@0 = "Buttare a Terra" - -@1 = "Buttare a Terra - -Un personaggio con questo talento può tentare di far cadere a terra i suoi avversari. Il personaggio effettua un attacco con una penalità di -4 ai tiri per colpire e, se ha successo, il difensore effettua un tiro-salvezza contro Morte. Se fallisce, il difensore viene buttato a terra." - -@50 = "Steso a Terra" - -@100 = "Il bersaglio selezionato è fuori portata" -@101 = "Il bersaglio selezionato è già a terra" -@102 = "Il bersaglio selezionato è troppo grande" -@103 = "Questo talento non può essere usato mentre si brandisce un'arma a distanza" - -@104 = "Il personaggio non può compiere più di un'azione per round" - -@105 = "Non soggetto agli effetti di Buttare a Terra" \ No newline at end of file diff --git a/cdtweaks/languages/italian/weidu.tra b/cdtweaks/languages/italian/weidu.tra index 4fbf9ee8..78824642 100644 --- a/cdtweaks/languages/italian/weidu.tra +++ b/cdtweaks/languages/italian/weidu.tra @@ -436,7 +436,7 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~ @278000 = "Aggiungi talento di classe Calcio Rotante per i Monaci [Luke]" -@281000 = "Aggiungi talento di classe Buttare a Terra per i Guerrieri e i Monaci [Luke]" +@284000 = "Aggiungi talento di classe Disarmare per i Ladri [Luke]" /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ diff --git a/cdtweaks/lib/comp_2810.tpa b/cdtweaks/lib/comp_2840.tpa similarity index 69% rename from cdtweaks/lib/comp_2810.tpa rename to cdtweaks/lib/comp_2840.tpa index 77749ea5..927b7eab 100644 --- a/cdtweaks/lib/comp_2810.tpa +++ b/cdtweaks/lib/comp_2840.tpa @@ -1,7 +1,7 @@ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ -///// Knockdown class feat for Fighters and Monks \\\\\ +///// Disarm class feat for Rogues \\\\\ ///// \\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ @@ -10,8 +10,8 @@ WITH_SCOPE BEGIN INCLUDE "cdtweaks\luke\misc.tph" INCLUDE "cdtweaks\ardanis\functions.tph" // - INCLUDE "cdtweaks\lib\knockdown.tph" - WITH_TRA "cdtweaks\languages\english\knockdown.tra" "cdtweaks\languages\%LANGUAGE%\knockdown.tra" BEGIN - LAF "KNOCKDOWN" END + INCLUDE "cdtweaks\lib\disarm.tph" + WITH_TRA "cdtweaks\languages\english\disarm.tra" "cdtweaks\languages\%LANGUAGE%\disarm.tra" BEGIN + LAF "DISARM" END END END \ No newline at end of file diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph new file mode 100644 index 00000000..ecdf629f --- /dev/null +++ b/cdtweaks/lib/disarm.tph @@ -0,0 +1,73 @@ +DEFINE_ACTION_FUNCTION "DISARM" +BEGIN + LAF "GT_ADD_SPELL" + INT_VAR + "level" = 4 + "preferredSlot" = 44 + "type" = 4 + STR_VAR + "idsName" = "ROGUE_DISARM" + RET + "ROGUE_DISARM" = "resName" + END + // + LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 3 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END + // + WITH_SCOPE BEGIN + ACTION_TO_LOWER "ROGUE_DISARM" + // Disarm (main spl file) + CREATE "spl" "%ROGUE_DISARM%" + COPY_EXISTING "%ROGUE_DISARM%.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG NAME2 "-1" + WRITE_LONG UNIDENTIFIED_DESC RESOLVE_STR_REF (@1) + WRITE_LONG DESC "-1" + WRITE_LONG 0x18 (BIT14 BOR BIT25) // ignore dead/wild magic, castable when silenced + WRITE_SHORT 0x1C 4 // innate + WRITE_LONG 0x34 1 // level + WRITE_ASCII 0x3A "%DEST_RES%B" #8 // icon + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 321 "target" = 1 STR_VAR "resource" = "%DEST_RES%" END // Remove effects by resource + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua + BUT_ONLY + // EFF + CREATE "eff" "%ROGUE_DISARM%b" + COPY_EXISTING "%ROGUE_DISARM%b.eff" "override" + WRITE_LONG 0x10 402 // Invoke Lua + WRITE_LONG 0x14 2 // Projectile target + WRITE_LONG 0x1C 1 // p1 + WRITE_SHORT 0x2C 100 // prob1 + WRITE_ASCII 0x30 "%ROGUE_DISARM%" #8 // Lua function + BUT_ONLY + // icon + COPY "cdtweaks\luke\bam\class\disarm\spl_icon.bam" "override\%ROGUE_DISARM%b.bam" + END + // lua + WITH_SCOPE BEGIN + OUTER_SET "feedback_strref_outOfRange" = RESOLVE_STR_REF (@100) + OUTER_SET "feedback_strref_inventoryFull" = RESOLVE_STR_REF (@101) + OUTER_SET "feedback_strref_resisted" = RESOLVE_STR_REF (@102) + OUTER_SET "feedback_strref_hit" = RESOLVE_STR_REF (@103) + OUTER_SET "feedback_strref_meleeOnly" = RESOLVE_STR_REF (@104) + OUTER_SET "feedback_strref_auraFree" = RESOLVE_STR_REF (@105) + OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@106) + // + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_DISARM%D" RET "feedback_icon_canDisarm" = "index" END + WITH_SCOPE BEGIN + ACTION_TO_LOWER "ROGUE_DISARM" + COPY "cdtweaks\luke\bam\class\disarm\portrait_icon.bam" "override\%ROGUE_DISARM%d.bam" + END + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\disarm.lua" "destRes" = "m_gtspcl" END + END + // + LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" 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/knockdown.tph b/cdtweaks/lib/knockdown.tph deleted file mode 100644 index 0e2be3ad..00000000 --- a/cdtweaks/lib/knockdown.tph +++ /dev/null @@ -1,82 +0,0 @@ -DEFINE_ACTION_FUNCTION "KNOCKDOWN" -BEGIN - LAF "GT_ADD_SPELL" - INT_VAR - "level" = 1 - "preferredSlot" = 44 - STR_VAR - "idsName" = "INNATE_KNOCKDOWN" - RET - "INNATE_KNOCKDOWN" = "resName" - END - // - LAF "ADD_EXTENDED_STAT" STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END - // - WITH_SCOPE BEGIN - ACTION_TO_LOWER "INNATE_KNOCKDOWN" - // Knockdown (spl file) - CREATE "spl" "%INNATE_KNOCKDOWN%" - COPY_EXISTING "%INNATE_KNOCKDOWN%.spl" "override" - WRITE_LONG NAME1 RESOLVE_STR_REF (@0) - WRITE_LONG NAME2 "-1" - WRITE_LONG UNIDENTIFIED_DESC RESOLVE_STR_REF (@1) - WRITE_LONG DESC "-1" - WRITE_LONG 0x18 (BIT14 BOR BIT25) // ignore dead/wild magic, castable when silenced - WRITE_SHORT 0x1C 4 // innate - WRITE_LONG 0x34 1 // level - WRITE_ASCII 0x3A "%DEST_RES%B" #8 // icon - // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END - // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 321 "target" = 1 STR_VAR "resource" = "%DEST_RES%" END // Remove effects by resource (cannot be used in conjunction with other feats such as my revised Called Shot. Such feats all share the same parent, i.e. "GTFEAT00") - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua - BUT_ONLY - // EFF - CREATE "eff" "%INNATE_KNOCKDOWN%b" - COPY_EXISTING "%INNATE_KNOCKDOWN%b.eff" "override" - WRITE_LONG 0x10 402 // Invoke Lua - WRITE_LONG 0x14 2 // Projectile target - WRITE_LONG 0x1C 1 // p1 - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "%INNATE_KNOCKDOWN%" #8 // Lua function - BUT_ONLY - // icons - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@50) STR_VAR "bam_file" = "GTPRONE" RET "feedback_icon" = "index" END - COPY "cdtweaks\luke\bam\innate\knockdown\spl_icon.bam" "override\%INNATE_KNOCKDOWN%b.bam" "cdtweaks\luke\bam\gtprone.bam" "override" - // - CREATE "eff" "gtprone" - COPY_EXISTING "gtprone.eff" "override" - WRITE_LONG 0x10 39 // Sleep - WRITE_LONG 0x14 2 // Projectile target - WRITE_LONG 0x20 1 // p2: wake on damage? no - WRITE_SHORT 0x2C 100 // prob1 - WRITE_LONG 0x48 "%feedback_icon%" // icon - BUT_ONLY - END - // lua - WITH_SCOPE BEGIN - OUTER_SET "feedback_strref_outOfRange" = RESOLVE_STR_REF (@100) - OUTER_SET "feedback_strref_alreadyProne" = RESOLVE_STR_REF (@101) - OUTER_SET "feedback_strref_tooLarge" = RESOLVE_STR_REF (@102) - OUTER_SET "feedback_strref_meleeOnly" = RESOLVE_STR_REF (@103) - OUTER_SET "feedback_strref_auraFree" = RESOLVE_STR_REF (@104) - OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@105) - // - WITH_SCOPE BEGIN - ACTION_TO_LOWER "INNATE_KNOCKDOWN" - COPY "cdtweaks\luke\bam\innate\knockdown\portrait_icon.bam" "override\%INNATE_KNOCKDOWN%d.bam" - END - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%INNATE_KNOCKDOWN%D" RET "feedback_icon_canKnockdown" = "index" END - // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Misc Tweaks (Innate)" "sourceFileSpec" = "cdtweaks\luke\lua\innate\knockdown.lua" "destRes" = "m_gtspin" END - END - // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" END - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Utility Functions / Listeners" "sourceFileSpec" = "cdtweaks\luke\lua\utility\effect_check.lua" "destRes" = "m_gtutil" END - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\wrap_userdata.lua" "destRes" = "m_gttool" 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/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua new file mode 100644 index 00000000..7b31eb71 --- /dev/null +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -0,0 +1,372 @@ +-- cdtweaks, NWN-ish Disarm ability. Light / Medium / Heavy weapons -- + +local cdtweaks_Disarm_WeaponSize = { + ["small"] = {"", "CL", "DD", "F2", "M2", "MC", "SL", "SS"}, + ["medium"] = {"AX", "BS", "CB", "FS", "MS", "S1", "SC", "WH"}, + ["large"] = {"BW", "F0", "F1", "F3", "FL", "GS", "HB", "Q2", "Q3", "Q4", "QS", "S0", "S2", "S3", "SP"}, +} + +local function cdtweaks_Disarm_CheckWeaponSize(animationType) + for size, animationTypeList in pairs(cdtweaks_Disarm_WeaponSize) do + for _, value in ipairs(animationTypeList) do + if value == animationType then + return size + end + end + end + return "none" -- should not happen +end + +-- cdtweaks, NWN-ish Disarm ability -- + +function %ROGUE_DISARM%(CGameEffect, CGameSprite) + local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite + -- Check source's currently selected weapon + local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") + -- + local inventoryFull = EEex_Trigger_ParseConditionalString("InventoryFull(Myself)") + -- Get source's currently selected weapon + local sourceEquipment = sourceSprite.m_equipment + local sourceSelectedWeapon = sourceEquipment.m_items:get(sourceEquipment.m_selectedWeapon) -- CItem + -- + local sourceSelectedWeaponHeader = sourceSelectedWeapon.pRes.pHeader -- Item_Header_st + -- Get target's currently selected weapon + local targetEquipment = CGameSprite.m_equipment + local targetSelectedWeapon = targetEquipment.m_items:get(targetEquipment.m_selectedWeapon) -- CItem + -- Get launcher if needed + local targetSelectedWeapon = CGameSprite:getLauncher(targetSelectedWeapon:getAbility(targetEquipment.m_selectedWeaponAbility)) or targetSelectedWeapon + -- + local targetSelectedWeaponResRef = targetSelectedWeapon.pRes.resref:get() + local targetSelectedWeaponHeader = targetSelectedWeapon.pRes.pHeader -- Item_Header_st + -- + local inWeaponRange = EEex_Trigger_ParseConditionalString('InWeaponRange(EEex_Target("GT_RogueDisarmTarget"))') + -- + local attackOneRound = EEex_Action_ParseResponseString('AttackOneRound(EEex_Target("GT_RogueDisarmTarget"))') + -- + local stats = GT_Resource_SymbolToIDS["stats"] + -- Melee weapon equipped! + if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then + if CGameEffect.m_effectAmount == 0 then + sourceSprite:setStoredScriptingTarget("GT_RogueDisarmTarget", CGameSprite) + -- check range + if inWeaponRange:evalConditionalAsAIBase(sourceSprite) then + -- + local effectCodes = { + {["op"] = 401, ["p2"] = 1, ["p1"] = 3, ["tmg"] = 10, ["dur"] = 1, ["spec"] = stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]}, -- set extended stat + {["op"] = 284, ["tmg"] = 1, ["p1"] = -6}, -- melee thac0 bonus + {["op"] = 142, ["tmg"] = 1, ["p2"] = %feedback_icon_canDisarm%}, -- feedback icon + {["op"] = 248, ["tmg"] = 1, ["res"] = "%ROGUE_DISARM%B"}, -- melee hit effect + } + -- + for _, attributes in ipairs(effectCodes) do + sourceSprite:applyEffect({ + ["effectID"] = attributes["op"] or -1, + ["effectAmount"] = attributes["p1"] or 0, + ["dwFlags"] = attributes["p2"] or 0, + ["special"] = attributes["spec"] or 0, + ["res"] = attributes["res"] or "", + ["duration"] = attributes["dur"] or 0, + ["durationType"] = attributes["tmg"] or 0, + ["m_sourceRes"] = "%ROGUE_DISARM%", + ["m_sourceType"] = CGameEffect.m_sourceType, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + end + -- + attackOneRound:queueResponseOnAIBase(sourceSprite) + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_outOfRange%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + elseif CGameEffect.m_effectAmount == 1 then + -- check if inventory is full + if not inventoryFull:evalConditionalAsAIBase(sourceSprite) then + -- check if NONDROPABLE + if EEex_IsBitUnset(targetSelectedWeapon.m_flags, 0x3) then + -- check if DROPPABLE + if EEex_IsBitSet(targetSelectedWeaponHeader.itemFlags, 0x2) then + -- check if CURSED + if EEex_IsBitUnset(targetSelectedWeaponHeader.itemFlags, 0x4) then + -- + local sourceAnimationType = EEex_CastUD(sourceSelectedWeaponHeader.animationType, "CResRef"):get() + local targetAnimationType = EEex_CastUD(targetSelectedWeaponHeader.animationType, "CResRef"):get() + -- sanity check (only darts are supposed to have a null animation) + if (targetAnimationType ~= "") or (targetSelectedWeaponHeader.itemType == 24) then + -- set ``savebonus`` + local savebonus = 0 + -- + local sourceWeaponSize = cdtweaks_Disarm_CheckWeaponSize(sourceAnimationType) + local targetWeaponSize = cdtweaks_Disarm_CheckWeaponSize(targetAnimationType) + -- + if (sourceWeaponSize == "small" and targetWeaponSize == "medium") or (sourceWeaponSize == "medium" and targetWeaponSize == "large") then + savebonus = 2 + elseif (sourceWeaponSize == "medium" and targetWeaponSize == "small") or (sourceWeaponSize == "large" and targetWeaponSize == "medium") then + savebonus = -2 + elseif sourceWeaponSize == "small" and targetWeaponSize == "large" then + savebonus = 4 + elseif sourceWeaponSize == "large" and targetWeaponSize == "small" then + savebonus = -4 + end + -- + local targetSaveVSBreath = CGameSprite.m_derivedStats.m_nSaveVSBreath + CGameSprite.m_bonusStats.m_nSaveVSBreath + local adjustedRoll = CGameSprite.m_saveVSBreathRoll + savebonus + -- + if adjustedRoll >= targetSaveVSBreath then + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_resisted%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_hit%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + -- + sourceSprite:applyEffect({ + ["effectID"] = 122, -- create inventory item + ["effectAmount"] = targetSelectedWeapon.m_useCount1, + ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, + ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, + ["res"] = targetSelectedWeaponResRef, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + -- restore ``CItem`` flags + local sourceItems = sourceEquipment.m_items -- Array + for i = 18, 33 do -- inventory slots + local item = sourceItems:get(i) -- CItem + if item then + local resref = item.pRes.resref:get() + if resref == targetSelectedWeaponResRef then + if item.m_flags == 0 then + if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then + if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then + if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then + item.m_flags = targetSelectedWeapon.m_flags + break + end + end + end + end + end + end + end + -- + CGameSprite:applyEffect({ + ["effectID"] = 112, -- remove item + ["res"] = targetSelectedWeaponResRef, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_immune%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_inventoryFull%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_meleeOnly%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + end + -- + inWeaponRange:free() + isWeaponRanged:free() + inventoryFull:free() + attackOneRound:free() +end + +-- cdtweaks, NWN-ish Disarm ability. Make sure one and only one attack roll is performed -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- + local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") + -- + if sprite:getLocalInt("cdtweaksDisarm") == 1 then + if GT_Utility_EffectCheck(sprite, {["op"] = 0xF8, ["res"] = "%ROGUE_DISARM%B"}) then + if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 1) + elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + -- + sprite.m_curAction.m_actionID = 0 -- nuke current action + -- + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + else + -- in case the character dies while swinging... + if sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) then + sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + end + end + end + -- + isWeaponRanged:free() +end) + +-- cdtweaks, NWN-ish Disarm ability. Make sure it cannot be disrupted -- + +EEex_Action_AddSpriteStartedActionListener(function(sprite, action) + if sprite:getLocalInt("cdtweaksDisarm") == 1 then + local stats = GT_Resource_SymbolToIDS["stats"] + -- + if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%" then + if EEex_Sprite_GetCastTimer(sprite) == -1 then + action.m_actionID = 113 -- ForceSpell() + -- + sprite.m_castCounter = 0 + else + action.m_actionID = 0 -- nuke current action + -- + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_auraFree%, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + else + if EEex_Sprite_GetStat(sprite, stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]) ~= 3 then + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end + end +end) + +-- cdtweaks, NWN-ish Disarm ability. Gain ability -- + +EEex_Opcode_AddListsResolvedListener(function(sprite) + -- Sanity check + if not EEex_GameObject_IsSprite(sprite) then + return + end + -- internal function that grants the ability + local gain = function() + -- Mark the creature as 'feat granted' + sprite:setLocalInt("cdtweaksDisarm", 1) + -- + local effectCodes = { + {["op"] = 172}, -- remove spell + {["op"] = 171}, -- give spell + } + -- + for _, attributes in ipairs(effectCodes) do + sprite:applyEffect({ + ["effectID"] = attributes["op"] or -1, + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end + -- Check creature's class + 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 + -- + local gainAbility = spriteClassStr == "THIEF" or spriteClassStr == "FIGHTER_MAGE_THIEF" + or (spriteClassStr == "MAGE_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) + -- + if sprite:getLocalInt("cdtweaksDisarm") == 0 then + if gainAbility then + gain() + end + else + if gainAbility then + -- do nothing + else + -- Mark the creature as 'feat removed' + sprite:setLocalInt("cdtweaksDisarm", 0) + -- + sprite:applyEffect({ + ["effectID"] = 172, -- remove spell + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + sprite:applyEffect({ + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + end +end) diff --git a/cdtweaks/luke/lua/innate/knockdown.lua b/cdtweaks/luke/lua/innate/knockdown.lua deleted file mode 100644 index d1bb5dca..00000000 --- a/cdtweaks/luke/lua/innate/knockdown.lua +++ /dev/null @@ -1,314 +0,0 @@ --- cdtweaks, NWN-ish Knockdown ability. Creatures already on the ground / levitating / etc. -- - -local cdtweaks_ImmuneToKnockdown = { - {"WEAPON"}, -- GENERAL.IDS - {"DRAGON", "BEHOLDER", "ANKHEG", "SLIME", "DEMILICH", "WILL-O-WISP", "SPECTRAL_UNDEAD", "SHADOW", "SPECTRE", "WRAITH", "MIST", "GENIE", "ELEMENTAL", "SALAMANDER"}, -- RACE.IDS - {"WIZARD_EYE", "SPECTRAL_TROLL", "SPIDER_WRAITH"}, -- CLASS.IDS - -- ANIMATE.IDS - { - "DOOM_GUARD", "DOOM_GUARD_LARGER", - "SNAKE", "BLOB_MIST_CREATURE", "MIST_CREATURE", "HAKEASHAR", "NISHRUU", "SNAKE_WATER", "DANCING_SWORD", - "SHADOW_SMALL", "SHADOW_LARGE", "WATER_WEIRD" - }, -} - --- cdtweaks, NWN-ish Knockdown ability -- - -function %INNATE_KNOCKDOWN%(CGameEffect, CGameSprite) - local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite - -- Check creature's currently selected weapon - local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") - -- Get personal space - local sourcePersonalSpace = sourceSprite.m_animation.m_animation.m_personalSpace - local targetPersonalSpace = CGameSprite.m_animation.m_animation.m_personalSpace - -- - local inWeaponRange = EEex_Trigger_ParseConditionalString('InWeaponRange(EEex_Target("GT_InnateKnockdownTarget"))') - -- - local attackOneRound = EEex_Action_ParseResponseString('AttackOneRound(EEex_Target("GT_InnateKnockdownTarget"))') - -- - local stats = GT_Resource_SymbolToIDS["stats"] - local class = GT_Resource_SymbolToIDS["class"] - -- - local targetGeneralStr = GT_Resource_IDSToSymbol["general"][CGameSprite.m_typeAI.m_General] - local targetRaceStr = GT_Resource_IDSToSymbol["race"][CGameSprite.m_typeAI.m_Race] - local targetClassStr = GT_Resource_IDSToSymbol["class"][CGameSprite.m_typeAI.m_Class] - local targetAnimateStr = GT_Resource_IDSToSymbol["animate"][CGameSprite.m_animation.m_animation.m_animationID] - -- - local targetIDS = {targetGeneralStr, targetRaceStr, targetClassStr, targetAnimateStr} - -- Melee weapon equipped! - if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then - if CGameEffect.m_effectAmount == 0 then - sourceSprite:setStoredScriptingTarget("GT_InnateKnockdownTarget", CGameSprite) - -- check range - if inWeaponRange:evalConditionalAsAIBase(sourceSprite) then - -- - local effectCodes = { - {["op"] = 401, ["p2"] = 1, ["p1"] = 1, ["tmg"] = 10, ["dur"] = 1, ["spec"] = stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]}, -- set extended stat - {["op"] = 284, ["tmg"] = 1, ["p1"] = -4}, -- melee thac0 bonus - {["op"] = 142, ["tmg"] = 1, ["p2"] = %feedback_icon_canKnockdown%}, -- feedback icon - {["op"] = 248, ["tmg"] = 1, ["res"] = "%INNATE_KNOCKDOWN%B"}, -- melee hit effect - } - -- - for _, attributes in ipairs(effectCodes) do - sourceSprite:applyEffect({ - ["effectID"] = attributes["op"] or -1, - ["effectAmount"] = attributes["p1"] or 0, - ["dwFlags"] = attributes["p2"] or 0, - ["special"] = attributes["spec"] or 0, - ["res"] = attributes["res"] or "", - ["duration"] = attributes["dur"] or 0, - ["durationType"] = attributes["tmg"] or 0, - ["m_sourceRes"] = "%INNATE_KNOCKDOWN%", - ["m_sourceType"] = CGameEffect.m_sourceType, - ["sourceID"] = sourceSprite.m_id, - ["sourceTarget"] = sourceSprite.m_id, - }) - end - -- - attackOneRound:queueResponseOnAIBase(sourceSprite) - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_outOfRange%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - elseif CGameEffect.m_effectAmount == 1 then - -- immunity check - local found = false - do - for index, symbolList in ipairs(cdtweaks_ImmuneToKnockdown) do - for _, symbol in ipairs(symbolList) do - if targetIDS[index] == symbol then - found = true - break - end - end - end - end - -- - if not found then - if (sourcePersonalSpace - targetPersonalSpace) >= -1 then - -- SLOT_FIST is always equipped, even if not in use... As a result, we want to apply op39 via op182... - local fistResRef = {} - if CGameSprite.m_typeAI.m_Class == class["MONK"] then - local monkfist = GT_Resource_2DA["monkfist"] - for lvl = 1, 50 do - if GT_LuaTool_KeyExists(GT_Resource_2DA, "monkfist", tostring(lvl), "RESREF") then - fistResRef[monkfist[tostring(lvl)]["RESREF"]] = true - end - end - else - local items = CGameSprite.m_equipment.m_items -- Array - local item = items:get(10) -- CItem - if item then - fistResRef[item.pRes.resref:get()] = true -- should be "FIST.ITM" - end - end - -- set ``savebonus`` - local savebonus = 0 - if (sourcePersonalSpace - targetPersonalSpace) > 0 then - savebonus = -4 - elseif (sourcePersonalSpace - targetPersonalSpace) < 0 then - savebonus = 4 - end - -- - local effectCodes = {} - for resref, _ in pairs(fistResRef) do - table.insert(effectCodes, {["op"] = 182, ["res"] = resref, ["res2"] = "GTPRONE"}) -- apply EFF while FIST/MFIST[1-8] is equipped (i.e. always). We need this to bypass op101 and make op39 uncurable (i.e. immune to op2) - end - table.insert(effectCodes, {["op"] = 206, ["p1"] = %feedback_strref_alreadyProne%, ["res"] = "%INNATE_KNOCKDOWN%B"}) -- protection from spell - -- - for _, attributes in ipairs(effectCodes) do - CGameSprite:applyEffect({ - ["effectID"] = attributes["op"] or -1, - ["effectAmount"] = attributes["p1"] or 0, - ["duration"] = 6, - ["savingThrow"] = 0x4, -- save vs. death - ["saveMod"] = savebonus, - ["m_res2"] = attributes["res2"] or "", - ["m_sourceRes"] = "%INNATE_KNOCKDOWN%B", - ["m_sourceType"] = 1, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_tooLarge%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - end - else - sourceSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_meleeOnly%, - ["sourceID"] = sourceSprite.m_id, - ["sourceTarget"] = sourceSprite.m_id, - }) - end - -- - inWeaponRange:free() - isWeaponRanged:free() - attackOneRound:free() -end - --- cdtweaks, NWN-ish Knockdown ability. Make sure one and only one attack roll is performed -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- Sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- - local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") - -- - if sprite:getLocalInt("cdtweaksKnockdown") == 1 then - if GT_Utility_EffectCheck(sprite, {["m_effectId"] = 0xF8, ["m_res"] = "%INNATE_KNOCKDOWN%B"}) then - if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 1) - elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) - -- - sprite.m_curAction.m_actionID = 0 -- nuke current action - -- - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - else - -- in case the character dies while swinging... - if sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) - end - end - end - -- - isWeaponRanged:free() -end) - --- cdtweaks, NWN-ish Knockdown ability. Make sure it cannot be disrupted -- - -EEex_Action_AddSpriteStartedActionListener(function(sprite, action) - if sprite:getLocalInt("cdtweaksKnockdown") == 1 then - local stats = GT_Resource_SymbolToIDS["stats"] - -- - if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%INNATE_KNOCKDOWN%" then - if EEex_Sprite_GetCastTimer(sprite) == -1 then - action.m_actionID = 113 -- ForceSpell() - -- - sprite.m_castCounter = 0 - else - action.m_actionID = 0 -- nuke current action - -- - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_auraFree%, - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - else - if EEex_Sprite_GetStat(sprite, stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]) == 0 then - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end - end -end) - --- cdtweaks, NWN-ish Knockdown ability. Gain ability -- - -EEex_Opcode_AddListsResolvedListener(function(sprite) - -- Sanity check - if not EEex_GameObject_IsSprite(sprite) then - return - end - -- internal function that grants the ability - local gain = function() - -- Mark the creature as 'feat granted' - sprite:setLocalInt("cdtweaksKnockdown", 1) - -- - local effectCodes = { - {["op"] = 172}, -- remove spell - {["op"] = 171}, -- give spell - } - -- - for _, attributes in ipairs(effectCodes) do - sprite:applyEffect({ - ["effectID"] = attributes["op"] or -1, - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end - -- Check creature's class - 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 - -- - local gainAbility = spriteClassStr == "MONK" or 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("cdtweaksKnockdown") == 0 then - if gainAbility then - gain() - end - else - if gainAbility then - -- do nothing - else - -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksKnockdown", 0) - -- - sprite:applyEffect({ - ["effectID"] = 172, -- remove spell - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%INNATE_KNOCKDOWN%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - end -end) diff --git a/cdtweaks/readme-cdtweaks.html b/cdtweaks/readme-cdtweaks.html index e3d558f2..5cf2e257 100644 --- a/cdtweaks/readme-cdtweaks.html +++ b/cdtweaks/readme-cdtweaks.html @@ -1099,29 +1099,34 @@

Rule Changes

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

    Knockdown class feat for Fighters and Monks [Luke]
    +

    Disarm class feat for Rogues [Luke]
    EEex

    -

    This component aims at implementing the NWN feat Knockdown.
    - A character with this feat can attempt to knock his opponents to the ground. The character makes an attack roll at -4, and if successful the defender makes a Save vs. Death. If failed, the defender is knocked to a prone position.
    +

    This component aims at implementing the NWN feat Disarm.
    + The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands.
    Notes:

      -
    • Use: selected, unlimited uses per day. Only available to Fighters and Monks (starting from level 1).
    • -
    • The prone state lasts for one round.
    • +
    • Use: selected, unlimited uses per day. Only available to Rogues (starting from level 1).
    • +
    • When the weapon flies from the opponent's hands, the attacker automatically picks it up (provided its Inventory is not full).
    • This feat cannot be used while wielding a ranged weapon.
    • - A character can only make a knockdown attempt on opponents that are one size category larger than himself, or smaller. + As far as weapon sizes are concerned:
        -
      • As a rule of thumb, look at the defender's circle size: if smaller, equal or just a little bit bigger than the one of the attacker, then it is fine; otherwise, the creature is too large to be knocked down.
      • +
      • Small: unarmed fists, clubs, maces, slings, darts, daggers, short swords.
      • +
      • Medium: battle axes, throwing axes, long swords, shortbows, crossbows, morningstars, scimitars, war hammers.
      • +
      • Large: bastard swords, katanas, halberds, staves, two-handed swords, spears, flails.
      • - On top of it: + Some examples:
          -
        • if the attacker is larger than the defender, the saving throw penalty is -4 (i.e., it's easier to succeed).
        • -
        • Conversely, the saving throw penalty is +4 (i.e., it's harder to succeed).
        • +
        • if the attacker is wielding a dagger and the defender is wielding a katana, the saving throw penalty is -4 (i.e., it's harder to succeed).
        • +
        • if the attacker is wielding a katana and the defender is wielding a dagger, the saving throw penalty is +4 (i.e., it's easier to succeed).
        • +
        • if the attacker is wielding a dagger and the defender is wielding a shortbow, the saving throw penalty is -2 (i.e., it's harder to succeed).
        • +
        • if the attacker is wielding a scimitar and the defender is wielding a dagger, the saving throw penalty is +2 (i.e., it's easier to succeed).
        • +
        • if the attacker is wielding a katana and the defender is wielding a katana, the saving throw penalty is 0 (i.e., neutral).
    • -
    • Creatures already on the ground (f.i. snakes, slimes, salamanders ...), magically levitating creatures (beholders, demiliches, ...) and certain special creatures (f.i. spectral undead, elementals, ...) cannot be knocked down.
    • +
    • Not all creatures can be disarmed. Natural weapons cannot be disarmed, nor can cursed / magically created weapons.
    diff --git a/cdtweaks/setup-cdtweaks.tp2 b/cdtweaks/setup-cdtweaks.tp2 index 0baadd59..0bbffe68 100644 --- a/cdtweaks/setup-cdtweaks.tp2 +++ b/cdtweaks/setup-cdtweaks.tp2 @@ -2993,16 +2993,16 @@ LABEL ~cd_tweaks_circle_kick~ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ -///// Knockdown class feat for Fighters and Monks \\\\\ +///// Disarm class feat for Rogues \\\\\ ///// \\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -BEGIN @281000 DESIGNATED 2810 +BEGIN @284000 DESIGNATED 2840 GROUP @9 REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29 -REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/knockdown.tra~ @7 -LABEL ~cd_tweaks_knockdown~ +REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/disarm.tra~ @7 +LABEL ~cd_tweaks_disarm~ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ From 5fe699b7815e703ffd93c9b008f3d84f05a3d9a6 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Tue, 1 Oct 2024 16:26:45 +0200 Subject: [PATCH 09/33] Add missing bam files Make a separate GROUP for this kind of tweaks. --- cdtweaks/languages/english/weidu.tra | 13 ++++++- cdtweaks/languages/italian/weidu.tra | 13 ++++++- .../luke/bam/class/disarm/portrait_icon.bam | Bin 0 -> 381 bytes cdtweaks/luke/bam/class/disarm/spl_icon.bam | Bin 0 -> 1274 bytes cdtweaks/luke/lua/class/disarm.lua | 2 +- cdtweaks/setup-cdtweaks.tp2 | 36 +++++++++++------- 6 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 cdtweaks/luke/bam/class/disarm/portrait_icon.bam create mode 100644 cdtweaks/luke/bam/class/disarm/spl_icon.bam diff --git a/cdtweaks/languages/english/weidu.tra b/cdtweaks/languages/english/weidu.tra index c6c4bea4..ec251b16 100644 --- a/cdtweaks/languages/english/weidu.tra +++ b/cdtweaks/languages/english/weidu.tra @@ -36,6 +36,7 @@ @27 = ~DLC Merger is required before mods can be installed on this game. Check the readme for more information and a link to download DLC Merger.~ @28 = ~There are not enough free spell state or secondary type slots available to install this component.~ @29 = "Requires EEex (https://github.com/Bubb13/EEex)." +@30 = "NWN-ish feats" @100 = ~Batch Installer -- EXPERIMENTAL, use at own risk. Check the readme.~ @101 = ~ @@ -485,8 +486,6 @@ The uninstall messages above are normal and expected. @278000 = "Circle Kick class feat for Monks [Luke]" -@284000 = "Disarm class feat for Rogues [Luke]" - /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ @@ -804,3 +803,13 @@ 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 \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +@600000 = "Disarm class feat for Rogues [Luke]" \ No newline at end of file diff --git a/cdtweaks/languages/italian/weidu.tra b/cdtweaks/languages/italian/weidu.tra index 78824642..03d5c388 100644 --- a/cdtweaks/languages/italian/weidu.tra +++ b/cdtweaks/languages/italian/weidu.tra @@ -36,6 +36,7 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~ @27 = ~E' necessario utilizzare Modmerge prima che i mod possano essere installati su questo gioco. Controllare il readme per ulteriori informazioni e per un link per scaricare Modmerge.~ @28 = ~Non sono disponibili abbastanza slot per lo stato dell'incantesimo o di tipo secondario per installare questo componente.~ @29 = "Questo componente richiede EEex (https://github.com/Bubb13/EEex)." +@30 = "Talenti in stile NWN" // questo componente non è pronto, puoi saltare la traduzione di questo blocco //@100 = ~Programma di installazione automatizzato~ @@ -436,8 +437,6 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~ @278000 = "Aggiungi talento di classe Calcio Rotante per i Monaci [Luke]" -@284000 = "Aggiungi talento di classe Disarmare per i Ladri [Luke]" - /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ ///// \\\\\ @@ -720,3 +719,13 @@ 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 \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +@600000 = "Aggiungi talento di classe Disarmare per i Ladri [Luke]" diff --git a/cdtweaks/luke/bam/class/disarm/portrait_icon.bam b/cdtweaks/luke/bam/class/disarm/portrait_icon.bam new file mode 100644 index 0000000000000000000000000000000000000000..1a4b0bb32ef95c14f6d92a9fb7e8b6fe3135f543 GIT binary patch literal 381 zcmV-@0fPQQK}|zeF(4ps1ONbdoTZaJO9Md=hUX;2v#_xc%amg0Pte}hA9RLPCJ+#W zpb|ujOVWvG`~bONp#&nB_<EM)CZMg#2gJZ#x`S5R*sRi z=9${E>Ztcw7pWXd9p zo_YXY!3y`t#3-m*mcbhR@4&VEJfHt1L(G|7QktV~f)aDw1G}u{O1ft<&wVoaSD1Uv z>P>M#-!-j2`2L2;<%RogzTJlEeTlVYyY=HYo=(e%=Y`^WULbBV$y+Q8#7U)miTl9< b#Px%+xMA53WH^K=FyhdmvW$HLEadSpPl&_x literal 0 HcmV?d00001 diff --git a/cdtweaks/luke/bam/class/disarm/spl_icon.bam b/cdtweaks/luke/bam/class/disarm/spl_icon.bam new file mode 100644 index 0000000000000000000000000000000000000000..34706e4099d87dad7c900ecadfca154c5ef3c287 GIT binary patch literal 1274 zcmVuxLG9fL9%+(@nbTGP|zXwM&-$S5i6QHB96g z_I!8loI7(y_uSVfK6fp)kc`E;(Tym8bh`(DnAh5jzcr49@I#juyS#=SV0(KTzdzf; zAFVAsYyE~+^9g=!w$N-g(cJtQk2jlm;y%S@{YN~kH}TNi#EYjU{(EHN#iM2X`_nR> zKPLERo#6TU9JU|I*j%>IatmnI^4KzF@OL$j?P?CK2RvGL^Jw1X@z-J+%~Bd$w-b0a zpTOp98m)N-%{d0GsTekMF}SV^x8`82=0el!&?_}8dR<=9pvg;+Wf=u|0X4D$ja0En zG!$;jC>3PXygG#<0Vx!5t3XgF6p+78u#or0`J1@zMgGbhCiy%v6L}=Ed6>lv+yw^t z%oHwX3YbXpNO?UT&qJO{Ld(UWW#W*NF_23!6h>*dxhS-WeiSbCBR|>?dDx4C5#*T= z(#bJgNTv}VO(PXgBSQ~k)QcnWB_W_`n|CKOoW7mB5KZOehc@8%d>cEYQoaY%2A|MUFq%lS(0SU}S_% z#%ZeyS(Mf|ix?4v$criPX5_0!cO(IgU(XWbHRdZ}F!SdO0BFeg? zNQ;x7m?deWYSb-+0!)JAazs%jv1;6)?y99#+pz5oghFhBFU^Q5A(A>vMGawgWzoTDCe);ws%Y$J-x%p(Im&o5?|6OI;MG_UmaSo>)I-Mn9K+}E(p`o9rNS9 zAxj`c5a>bO?<~X4! zuMC}TC^OSmSy^*jMc?u6$+1im-NQLfBt-xAL`Aj5)$f+-wp}rHT*Gm^g9v0Rx_RGT zQzc_n)~ai+W2@_R$22!A1S{5Bd81T!Bt Date: Tue, 1 Oct 2024 17:06:46 +0200 Subject: [PATCH 10/33] Update readme-cdtweaks.html --- cdtweaks/readme-cdtweaks.html | 74 ++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/cdtweaks/readme-cdtweaks.html b/cdtweaks/readme-cdtweaks.html index 5cf2e257..6011cb69 100644 --- a/cdtweaks/readme-cdtweaks.html +++ b/cdtweaks/readme-cdtweaks.html @@ -113,7 +113,7 @@

    Contents

    -

    The Tweaks Anthology has many components, which can be installed completely independently of one another. For convenience, they are grouped into five broad categories: Cosmetic Changes, Content Changes, Rule Changes, Convenience Tweaks and/or Cheats, and Joinable NPC Tweaks. At installation time, players can select or ignore entire categories to streamline the installation process.

    +

    The Tweaks Anthology has many components, which can be installed completely independently of one another. For convenience, they are grouped into six broad categories: Cosmetic Changes, Content Changes, Rule Changes, Convenience Tweaks and/or Cheats, Joinable NPC Tweaks, and NWN-ish Feats Collection. At installation time, players can select or ignore entire categories to streamline the installation process.

    Italics running underneath each component indicate availability for various games. Unless specified, a component will work on a game with or without its expansions unless noted, e.g. a component labeled BG2 would work on Baldur's Gate II with or without the Throne of Bhaal expansion. If the expansion is required or forbidden, the note will either be BG2 (requires ToB) or BG2 (without ToB) respectively. Components that are not available for your game will be skipped automatically by the installer.

    @@ -1098,36 +1098,6 @@

    Rule Changes

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

    Disarm class feat for Rogues [Luke]
    - EEex

    -

    This component aims at implementing the NWN feat Disarm.
    - The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands.
    - Notes:

    -
      -
    • Use: selected, unlimited uses per day. Only available to Rogues (starting from level 1).
    • -
    • When the weapon flies from the opponent's hands, the attacker automatically picks it up (provided its Inventory is not full).
    • -
    • This feat cannot be used while wielding a ranged weapon.
    • -
    • - As far as weapon sizes are concerned: -
        -
      • Small: unarmed fists, clubs, maces, slings, darts, daggers, short swords.
      • -
      • Medium: battle axes, throwing axes, long swords, shortbows, crossbows, morningstars, scimitars, war hammers.
      • -
      • Large: bastard swords, katanas, halberds, staves, two-handed swords, spears, flails.
      • -
      • - Some examples: -
          -
        • if the attacker is wielding a dagger and the defender is wielding a katana, the saving throw penalty is -4 (i.e., it's harder to succeed).
        • -
        • if the attacker is wielding a katana and the defender is wielding a dagger, the saving throw penalty is +4 (i.e., it's easier to succeed).
        • -
        • if the attacker is wielding a dagger and the defender is wielding a shortbow, the saving throw penalty is -2 (i.e., it's harder to succeed).
        • -
        • if the attacker is wielding a scimitar and the defender is wielding a dagger, the saving throw penalty is +2 (i.e., it's easier to succeed).
        • -
        • if the attacker is wielding a katana and the defender is wielding a katana, the saving throw penalty is 0 (i.e., neutral).
        • -
        -
      • -
      -
    • -
    • Not all creatures can be disarmed. Natural weapons cannot be disarmed, nor can cursed / magically created weapons.
    • -

    Convenience Tweaks and/or Cheats

    @@ -1491,6 +1461,48 @@

    Joinable +

    NWN-ish Feats Collection

    +

    +
    +
    +
    +

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

    + +

    Disarm class feat for Rogues [Luke]
    + EEex

    +

    This component aims at implementing the NWN feat Disarm.
    + The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands.
    + Notes:

    +
      +
    • Use: selected, unlimited uses per day. Only available to Rogues (starting from level 1).
    • +
    • When the weapon flies from the opponent's hands, the attacker automatically picks it up (provided its Inventory is not full).
    • +
    • This feat cannot be used while wielding a ranged weapon.
    • +
    • + As far as weapon sizes are concerned: +
        +
      • Small: unarmed fists, clubs, maces, slings, darts, daggers, short swords.
      • +
      • Medium: battle axes, throwing axes, long swords, shortbows, crossbows, morningstars, scimitars, war hammers.
      • +
      • Large: bastard swords, katanas, halberds, staves, two-handed swords, spears, flails.
      • +
      • + Some examples: +
          +
        • if the attacker is wielding a dagger and the defender is wielding a katana, the saving throw penalty is -4 (i.e., it's harder to succeed).
        • +
        • if the attacker is wielding a katana and the defender is wielding a dagger, the saving throw penalty is +4 (i.e., it's easier to succeed).
        • +
        • if the attacker is wielding a dagger and the defender is wielding a shortbow, the saving throw penalty is -2 (i.e., it's harder to succeed).
        • +
        • if the attacker is wielding a scimitar and the defender is wielding a dagger, the saving throw penalty is +2 (i.e., it's easier to succeed).
        • +
        • if the attacker is wielding a katana and the defender is wielding a katana, the saving throw penalty is 0 (i.e., neutral).
        • +
        +
      • +
      +
    • +
    • If the opponent is dual-wielding, only the main-hand weapon can be disarmed.
    • +
    • Not all creatures can be disarmed. Natural weapons cannot be disarmed, nor can cursed / magically created weapons.
    • +
    +
    + +

    Contact Information

    From afbd0ce4557bfa06a109fb97d1ffe8681584290d Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Tue, 1 Oct 2024 20:04:39 +0200 Subject: [PATCH 11/33] Update disarm.tph --- cdtweaks/lib/disarm.tph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index ecdf629f..2ae03171 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -11,7 +11,7 @@ BEGIN "ROGUE_DISARM" = "resName" END // - LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 3 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END + LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 25 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END // WITH_SCOPE BEGIN ACTION_TO_LOWER "ROGUE_DISARM" From 21cc411e0f3315c10cc8bc2174ade10f5bf77604 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 2 Oct 2024 09:50:17 +0200 Subject: [PATCH 12/33] Delete comp_2840.tpa --- cdtweaks/lib/comp_2840.tpa | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 cdtweaks/lib/comp_2840.tpa diff --git a/cdtweaks/lib/comp_2840.tpa b/cdtweaks/lib/comp_2840.tpa deleted file mode 100644 index 927b7eab..00000000 --- a/cdtweaks/lib/comp_2840.tpa +++ /dev/null @@ -1,17 +0,0 @@ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -///// \\\\\ -///// Disarm class feat for Rogues \\\\\ -///// \\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ - -WITH_SCOPE BEGIN - INCLUDE "cdtweaks\luke\misc.tph" - INCLUDE "cdtweaks\ardanis\functions.tph" - // - INCLUDE "cdtweaks\lib\disarm.tph" - WITH_TRA "cdtweaks\languages\english\disarm.tra" "cdtweaks\languages\%LANGUAGE%\disarm.tra" BEGIN - LAF "DISARM" END - END -END \ No newline at end of file From ee5345fc1f4c247f0a3244a8a0ad7217a8119bc7 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 2 Oct 2024 09:50:26 +0200 Subject: [PATCH 13/33] Create comp_6000.tpa --- cdtweaks/lib/comp_6000.tpa | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cdtweaks/lib/comp_6000.tpa diff --git a/cdtweaks/lib/comp_6000.tpa b/cdtweaks/lib/comp_6000.tpa new file mode 100644 index 00000000..927b7eab --- /dev/null +++ b/cdtweaks/lib/comp_6000.tpa @@ -0,0 +1,17 @@ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// Disarm class feat for Rogues \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +WITH_SCOPE BEGIN + INCLUDE "cdtweaks\luke\misc.tph" + INCLUDE "cdtweaks\ardanis\functions.tph" + // + INCLUDE "cdtweaks\lib\disarm.tph" + WITH_TRA "cdtweaks\languages\english\disarm.tra" "cdtweaks\languages\%LANGUAGE%\disarm.tra" BEGIN + LAF "DISARM" END + END +END \ No newline at end of file From c50eb10e48a507b16b2efa7e8bf38176fa336089 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 2 Oct 2024 09:52:44 +0200 Subject: [PATCH 14/33] Update setup-cdtweaks.tp2 --- cdtweaks/setup-cdtweaks.tp2 | 1 + 1 file changed, 1 insertion(+) diff --git a/cdtweaks/setup-cdtweaks.tp2 b/cdtweaks/setup-cdtweaks.tp2 index f0f5d52e..343a28e9 100644 --- a/cdtweaks/setup-cdtweaks.tp2 +++ b/cdtweaks/setup-cdtweaks.tp2 @@ -4922,6 +4922,7 @@ LABEL ~cd_tweaks_dorns_sword~ BEGIN @600000 DESIGNATED 6000 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%/disarm.tra~ @7 LABEL ~cd_tweaks_nwn_disarm~ \ No newline at end of file From 2bfc8066fff3e6251b95fa5a6ce401fccd28ad9c Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 18 Oct 2024 11:41:21 +0200 Subject: [PATCH 15/33] Slightly tweak implementation --- cdtweaks/lib/disarm.tph | 17 +- cdtweaks/luke/lua/class/disarm.lua | 268 +++++++++++++---------------- 2 files changed, 130 insertions(+), 155 deletions(-) diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index 2ae03171..2932c8ae 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -11,7 +11,7 @@ BEGIN "ROGUE_DISARM" = "resName" END // - LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 25 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END + //LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 25 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END // WITH_SCOPE BEGIN ACTION_TO_LOWER "ROGUE_DISARM" @@ -29,9 +29,9 @@ BEGIN // LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY + /*LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 321 "target" = 1 STR_VAR "resource" = "%DEST_RES%" END // Remove effects by resource - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua*/ BUT_ONLY // EFF CREATE "eff" "%ROGUE_DISARM%b" @@ -47,15 +47,14 @@ BEGIN END // lua WITH_SCOPE BEGIN - OUTER_SET "feedback_strref_outOfRange" = RESOLVE_STR_REF (@100) - OUTER_SET "feedback_strref_inventoryFull" = RESOLVE_STR_REF (@101) + OUTER_SET "feedback_strref_inventory_full" = RESOLVE_STR_REF (@101) OUTER_SET "feedback_strref_resisted" = RESOLVE_STR_REF (@102) OUTER_SET "feedback_strref_hit" = RESOLVE_STR_REF (@103) - OUTER_SET "feedback_strref_meleeOnly" = RESOLVE_STR_REF (@104) - OUTER_SET "feedback_strref_auraFree" = RESOLVE_STR_REF (@105) + OUTER_SET "feedback_strref_melee_only" = RESOLVE_STR_REF (@104) + OUTER_SET "feedback_strref_aura_free" = RESOLVE_STR_REF (@105) OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@106) // - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_DISARM%D" RET "feedback_icon_canDisarm" = "index" END + LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_DISARM%D" RET "feedback_icon_can_disarm" = "index" END WITH_SCOPE BEGIN ACTION_TO_LOWER "ROGUE_DISARM" COPY "cdtweaks\luke\bam\class\disarm\portrait_icon.bam" "override\%ROGUE_DISARM%d.bam" @@ -64,7 +63,7 @@ BEGIN LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\disarm.lua" "destRes" = "m_gtspcl" END END // - LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" END + //LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" 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 diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index c806b9cc..bfa1b1ac 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -1,3 +1,7 @@ +--[[ + *************************************************************************************************************************** +--]] + -- cdtweaks, NWN-ish Disarm ability. Small / Medium / Large weapons -- local cdtweaks_Disarm_WeaponSize = { @@ -39,139 +43,89 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) local targetSelectedWeaponResRef = targetSelectedWeapon.pRes.resref:get() local targetSelectedWeaponHeader = targetSelectedWeapon.pRes.pHeader -- Item_Header_st -- - local inWeaponRange = EEex_Trigger_ParseConditionalString('InWeaponRange(EEex_Target("GT_RogueDisarmTarget"))') - -- - local attackOneRound = EEex_Action_ParseResponseString('AttackOneRound(EEex_Target("GT_RogueDisarmTarget"))') - -- - local stats = GT_Resource_SymbolToIDS["stats"] + local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) -- Melee weapon equipped! if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then - if CGameEffect.m_effectAmount == 0 then - sourceSprite:setStoredScriptingTarget("GT_RogueDisarmTarget", CGameSprite) - -- check range - if inWeaponRange:evalConditionalAsAIBase(sourceSprite) then - -- - local effectCodes = { - {["op"] = 401, ["p2"] = 1, ["p1"] = 3, ["tmg"] = 10, ["dur"] = 1, ["spec"] = stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]}, -- set extended stat - {["op"] = 284, ["tmg"] = 1, ["p1"] = -6}, -- melee thac0 bonus - {["op"] = 142, ["tmg"] = 1, ["p2"] = %feedback_icon_canDisarm%}, -- feedback icon - {["op"] = 248, ["tmg"] = 1, ["res"] = "%ROGUE_DISARM%B"}, -- melee hit effect - } - -- - for _, attributes in ipairs(effectCodes) do - sourceSprite:applyEffect({ - ["effectID"] = attributes["op"] or -1, - ["effectAmount"] = attributes["p1"] or 0, - ["dwFlags"] = attributes["p2"] or 0, - ["special"] = attributes["spec"] or 0, - ["res"] = attributes["res"] or "", - ["duration"] = attributes["dur"] or 0, - ["durationType"] = attributes["tmg"] or 0, - ["m_sourceRes"] = "%ROGUE_DISARM%", - ["m_sourceType"] = CGameEffect.m_sourceType, - ["sourceID"] = sourceSprite.m_id, - ["sourceTarget"] = sourceSprite.m_id, - }) - end - -- - attackOneRound:queueResponseOnAIBase(sourceSprite) - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_outOfRange%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - end - elseif CGameEffect.m_effectAmount == 1 then - -- check if inventory is full - if not inventoryFull:evalConditionalAsAIBase(sourceSprite) then - -- check if NONDROPABLE - if EEex_IsBitUnset(targetSelectedWeapon.m_flags, 0x3) then - -- check if DROPPABLE - if EEex_IsBitSet(targetSelectedWeaponHeader.itemFlags, 0x2) then - -- check if CURSED - if EEex_IsBitUnset(targetSelectedWeaponHeader.itemFlags, 0x4) then + -- Check if inventory is full + if not inventoryFull:evalConditionalAsAIBase(sourceSprite) then + -- check if NONDROPABLE + if EEex_IsBitUnset(targetSelectedWeapon.m_flags, 0x3) then + -- check if DROPPABLE + if EEex_IsBitSet(targetSelectedWeaponHeader.itemFlags, 0x2) then + -- check if CURSED + if EEex_IsBitUnset(targetSelectedWeaponHeader.itemFlags, 0x4) then + -- + local sourceAnimationType = EEex_CastUD(sourceSelectedWeaponHeader.animationType, "CResRef"):get() + local targetAnimationType = EEex_CastUD(targetSelectedWeaponHeader.animationType, "CResRef"):get() + -- sanity check (only darts are supposed to have a null animation) + if (targetAnimationType ~= "") or (targetSelectedWeaponHeader.itemType == 24) then + -- set ``savebonus`` + local savebonus = 0 -- - local sourceAnimationType = EEex_CastUD(sourceSelectedWeaponHeader.animationType, "CResRef"):get() - local targetAnimationType = EEex_CastUD(targetSelectedWeaponHeader.animationType, "CResRef"):get() - -- sanity check (only darts are supposed to have a null animation) - if (targetAnimationType ~= "") or (targetSelectedWeaponHeader.itemType == 24) then - -- set ``savebonus`` - local savebonus = 0 - -- - local sourceWeaponSize = cdtweaks_Disarm_CheckWeaponSize(sourceAnimationType) - local targetWeaponSize = cdtweaks_Disarm_CheckWeaponSize(targetAnimationType) - -- - if (sourceWeaponSize == "small" and targetWeaponSize == "medium") or (sourceWeaponSize == "medium" and targetWeaponSize == "large") then - savebonus = 2 - elseif (sourceWeaponSize == "medium" and targetWeaponSize == "small") or (sourceWeaponSize == "large" and targetWeaponSize == "medium") then - savebonus = -2 - elseif sourceWeaponSize == "small" and targetWeaponSize == "large" then - savebonus = 4 - elseif sourceWeaponSize == "large" and targetWeaponSize == "small" then - savebonus = -4 - end - -- - local targetSaveVSBreath = CGameSprite.m_derivedStats.m_nSaveVSBreath + CGameSprite.m_bonusStats.m_nSaveVSBreath - local adjustedRoll = CGameSprite.m_saveVSBreathRoll + savebonus + local sourceWeaponSize = cdtweaks_Disarm_CheckWeaponSize(sourceAnimationType) + local targetWeaponSize = cdtweaks_Disarm_CheckWeaponSize(targetAnimationType) + -- + if (sourceWeaponSize == "small" and targetWeaponSize == "medium") or (sourceWeaponSize == "medium" and targetWeaponSize == "large") then + savebonus = 2 + elseif (sourceWeaponSize == "medium" and targetWeaponSize == "small") or (sourceWeaponSize == "large" and targetWeaponSize == "medium") then + savebonus = -2 + elseif sourceWeaponSize == "small" and targetWeaponSize == "large" then + savebonus = 4 + elseif sourceWeaponSize == "large" and targetWeaponSize == "small" then + savebonus = -4 + end + -- + local targetSaveVSBreath = targetActiveStats.m_nSaveVSBreath + local adjustedRoll = CGameSprite.m_saveVSBreathRoll + savebonus + -- + if adjustedRoll >= targetSaveVSBreath then + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_resisted%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_hit%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) -- - if adjustedRoll >= targetSaveVSBreath then - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_resisted%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_hit%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - -- - sourceSprite:applyEffect({ - ["effectID"] = 122, -- create inventory item - ["effectAmount"] = targetSelectedWeapon.m_useCount1, - ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, - ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, - ["res"] = targetSelectedWeaponResRef, - ["sourceID"] = sourceSprite.m_id, - ["sourceTarget"] = sourceSprite.m_id, - }) - -- restore ``CItem`` flags - local sourceItems = sourceEquipment.m_items -- Array - for i = 18, 33 do -- inventory slots - local item = sourceItems:get(i) -- CItem - if item then - local resref = item.pRes.resref:get() - if resref == targetSelectedWeaponResRef then - if item.m_flags == 0 then - if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then - if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then - if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then - item.m_flags = targetSelectedWeapon.m_flags - break - end + sourceSprite:applyEffect({ + ["effectID"] = 122, -- create inventory item + ["effectAmount"] = targetSelectedWeapon.m_useCount1, + ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, + ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, + ["res"] = targetSelectedWeaponResRef, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + -- restore ``CItem`` flags + local sourceItems = sourceEquipment.m_items -- Array + for i = 18, 33 do -- inventory slots + local item = sourceItems:get(i) -- CItem + if item then + local resref = item.pRes.resref:get() + if resref == targetSelectedWeaponResRef then + if item.m_flags == 0 then + if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then + if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then + if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then + item.m_flags = targetSelectedWeapon.m_flags + break end end end end end end - -- - CGameSprite:applyEffect({ - ["effectID"] = 112, -- remove item - ["res"] = targetSelectedWeaponResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) end - else + -- CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 112, -- remove item + ["res"] = targetSelectedWeaponResRef, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) @@ -203,25 +157,30 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) else CGameSprite:applyEffect({ ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_inventoryFull%, + ["effectAmount"] = %feedback_strref_immune%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_inventory_full%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) end else CGameSprite:applyEffect({ ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_meleeOnly%, + ["effectAmount"] = %feedback_strref_melee_only%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end -- - inWeaponRange:free() isWeaponRanged:free() inventoryFull:free() - attackOneRound:free() end -- cdtweaks, NWN-ish Disarm ability. Make sure one and only one attack roll is performed -- @@ -236,10 +195,10 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- if sprite:getLocalInt("cdtweaksDisarm") == 1 then if GT_Utility_EffectCheck(sprite, {["op"] = 0xF8, ["res"] = "%ROGUE_DISARM%B"}) then - if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 1) - elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtDisarmSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtDisarmSwing", 1) + elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtDisarmSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:setLocalInt("gtDisarmSwing", 0) -- sprite.m_curAction.m_actionID = 0 -- nuke current action -- @@ -253,8 +212,8 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end else -- in case the character dies while swinging... - if sprite:getLocalInt("gtCGameSpriteStartedSwing") == 1) then - sprite:setLocalInt("gtCGameSpriteStartedSwing", 0) + if sprite:getLocalInt("gtDisarmSwing") == 1) then + sprite:setLocalInt("gtDisarmSwing", 0) end end end @@ -262,15 +221,34 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) isWeaponRanged:free() end) --- cdtweaks, NWN-ish Disarm ability. Make sure it cannot be disrupted -- +-- cdtweaks, NWN-ish Disarm ability. Morph the spell action into an attack action -- EEex_Action_AddSpriteStartedActionListener(function(sprite, action) if sprite:getLocalInt("cdtweaksDisarm") == 1 then - local stats = GT_Resource_SymbolToIDS["stats"] - -- if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%" then if EEex_Sprite_GetCastTimer(sprite) == -1 then - action.m_actionID = 113 -- ForceSpell() + local effectCodes = { + {["op"] = 321, ["res"] = "%ROGUE_DISARM%"}, -- remove effects by resource + {["op"] = 284, ["p1"] = -6}, -- melee thac0 bonus + {["op"] = 142, ["p2"] = %feedback_icon_can_disarm%}, -- feedback icon + {["op"] = 248, ["res"] = "%ROGUE_DISARM%B"}, -- melee hit effect + } + -- + for _, attributes in ipairs(effectCodes) do + sprite: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 "", + ["durationType"] = 1, + ["m_sourceRes"] = "%ROGUE_DISARM%", + ["m_sourceType"] = 1, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + -- + action.m_actionID = 3 -- Attack() -- sprite.m_castCounter = 0 else @@ -286,21 +264,19 @@ EEex_Action_AddSpriteStartedActionListener(function(sprite, action) EEex_GameObject_ApplyEffect(sprite, { ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_auraFree%, + ["effectAmount"] = %feedback_strref_aura_free%, ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) end else - if EEex_Sprite_GetStat(sprite, stats["GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER"]) ~= 3 then - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%ROGUE_DISARM%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end + EEex_GameObject_ApplyEffect(sprite, + { + ["effectID"] = 321, -- remove effects by resource + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) end end end) @@ -324,7 +300,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- for _, attributes in ipairs(effectCodes) do sprite:applyEffect({ - ["effectID"] = attributes["op"] or -1, + ["effectID"] = attributes["op"] or EEex_Error("opcode number not specified"), ["res"] = "%ROGUE_DISARM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, From db2645c7e0ac5da8fe7cb6cd6e55955f22d6d957 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 18 Oct 2024 16:53:27 +0200 Subject: [PATCH 16/33] Update disarm.lua --- cdtweaks/luke/lua/class/disarm.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index bfa1b1ac..ac29cefd 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -212,7 +212,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) end else -- in case the character dies while swinging... - if sprite:getLocalInt("gtDisarmSwing") == 1) then + if sprite:getLocalInt("gtDisarmSwing") == 1 then sprite:setLocalInt("gtDisarmSwing", 0) end end From 13ddb863088171d15bd57f52ee393dcce13cafe3 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 18 Oct 2024 17:24:39 +0200 Subject: [PATCH 17/33] Update disarm.tph --- cdtweaks/lib/disarm.tph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index 2932c8ae..5ef45d99 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -38,7 +38,7 @@ BEGIN COPY_EXISTING "%ROGUE_DISARM%b.eff" "override" WRITE_LONG 0x10 402 // Invoke Lua WRITE_LONG 0x14 2 // Projectile target - WRITE_LONG 0x1C 1 // p1 + //WRITE_LONG 0x1C 1 // p1 WRITE_SHORT 0x2C 100 // prob1 WRITE_ASCII 0x30 "%ROGUE_DISARM%" #8 // Lua function BUT_ONLY From f86dd1ebdcf24d94e746dfe2848afb1b1f478869 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Sun, 20 Oct 2024 12:18:40 +0200 Subject: [PATCH 18/33] Update disarm.lua --- cdtweaks/luke/lua/class/disarm.lua | 174 ++++++++++++++--------------- 1 file changed, 84 insertions(+), 90 deletions(-) diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index ac29cefd..c9db4296 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -25,8 +25,6 @@ end function %ROGUE_DISARM%(CGameEffect, CGameSprite) local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite - -- Check source's currently selected weapon - local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") -- local inventoryFull = EEex_Trigger_ParseConditionalString("InventoryFull(Myself)") -- Get source's currently selected weapon @@ -44,96 +42,87 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) local targetSelectedWeaponHeader = targetSelectedWeapon.pRes.pHeader -- Item_Header_st -- local targetActiveStats = EEex_Sprite_GetActiveStats(CGameSprite) - -- Melee weapon equipped! - if not isWeaponRanged:evalConditionalAsAIBase(sourceSprite) then - -- Check if inventory is full - if not inventoryFull:evalConditionalAsAIBase(sourceSprite) then - -- check if NONDROPABLE - if EEex_IsBitUnset(targetSelectedWeapon.m_flags, 0x3) then - -- check if DROPPABLE - if EEex_IsBitSet(targetSelectedWeaponHeader.itemFlags, 0x2) then - -- check if CURSED - if EEex_IsBitUnset(targetSelectedWeaponHeader.itemFlags, 0x4) then + -- MAIN -- + -- Check if inventory is full + if not inventoryFull:evalConditionalAsAIBase(sourceSprite) then + -- check if NONDROPABLE + if EEex_IsBitUnset(targetSelectedWeapon.m_flags, 0x3) then + -- check if DROPPABLE + if EEex_IsBitSet(targetSelectedWeaponHeader.itemFlags, 0x2) then + -- check if CURSED + if EEex_IsBitUnset(targetSelectedWeaponHeader.itemFlags, 0x4) then + -- + local sourceAnimationType = EEex_CastUD(sourceSelectedWeaponHeader.animationType, "CResRef"):get() + local targetAnimationType = EEex_CastUD(targetSelectedWeaponHeader.animationType, "CResRef"):get() + -- sanity check (only darts are supposed to have a null animation) + if (targetAnimationType ~= "") or (targetSelectedWeaponHeader.itemType == 24) then + -- set ``savebonus`` + local savebonus = 0 -- - local sourceAnimationType = EEex_CastUD(sourceSelectedWeaponHeader.animationType, "CResRef"):get() - local targetAnimationType = EEex_CastUD(targetSelectedWeaponHeader.animationType, "CResRef"):get() - -- sanity check (only darts are supposed to have a null animation) - if (targetAnimationType ~= "") or (targetSelectedWeaponHeader.itemType == 24) then - -- set ``savebonus`` - local savebonus = 0 - -- - local sourceWeaponSize = cdtweaks_Disarm_CheckWeaponSize(sourceAnimationType) - local targetWeaponSize = cdtweaks_Disarm_CheckWeaponSize(targetAnimationType) - -- - if (sourceWeaponSize == "small" and targetWeaponSize == "medium") or (sourceWeaponSize == "medium" and targetWeaponSize == "large") then - savebonus = 2 - elseif (sourceWeaponSize == "medium" and targetWeaponSize == "small") or (sourceWeaponSize == "large" and targetWeaponSize == "medium") then - savebonus = -2 - elseif sourceWeaponSize == "small" and targetWeaponSize == "large" then - savebonus = 4 - elseif sourceWeaponSize == "large" and targetWeaponSize == "small" then - savebonus = -4 - end - -- - local targetSaveVSBreath = targetActiveStats.m_nSaveVSBreath - local adjustedRoll = CGameSprite.m_saveVSBreathRoll + savebonus + local sourceWeaponSize = cdtweaks_Disarm_CheckWeaponSize(sourceAnimationType) + local targetWeaponSize = cdtweaks_Disarm_CheckWeaponSize(targetAnimationType) + -- + if (sourceWeaponSize == "small" and targetWeaponSize == "medium") or (sourceWeaponSize == "medium" and targetWeaponSize == "large") then + savebonus = 2 + elseif (sourceWeaponSize == "medium" and targetWeaponSize == "small") or (sourceWeaponSize == "large" and targetWeaponSize == "medium") then + savebonus = -2 + elseif sourceWeaponSize == "small" and targetWeaponSize == "large" then + savebonus = 4 + elseif sourceWeaponSize == "large" and targetWeaponSize == "small" then + savebonus = -4 + end + -- + local targetSaveVSBreath = targetActiveStats.m_nSaveVSBreath + local adjustedRoll = CGameSprite.m_saveVSBreathRoll + savebonus + -- + if adjustedRoll >= targetSaveVSBreath then + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_resisted%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) + else + CGameSprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_hit%, + ["sourceID"] = CGameEffect.m_sourceId, + ["sourceTarget"] = CGameEffect.m_sourceTarget, + }) -- - if adjustedRoll >= targetSaveVSBreath then - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_resisted%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - else - CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_hit%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) - -- - sourceSprite:applyEffect({ - ["effectID"] = 122, -- create inventory item - ["effectAmount"] = targetSelectedWeapon.m_useCount1, - ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, - ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, - ["res"] = targetSelectedWeaponResRef, - ["sourceID"] = sourceSprite.m_id, - ["sourceTarget"] = sourceSprite.m_id, - }) - -- restore ``CItem`` flags - local sourceItems = sourceEquipment.m_items -- Array - for i = 18, 33 do -- inventory slots - local item = sourceItems:get(i) -- CItem - if item then - local resref = item.pRes.resref:get() - if resref == targetSelectedWeaponResRef then - if item.m_flags == 0 then - if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then - if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then - if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then - item.m_flags = targetSelectedWeapon.m_flags - break - end + sourceSprite:applyEffect({ + ["effectID"] = 122, -- create inventory item + ["effectAmount"] = targetSelectedWeapon.m_useCount1, + ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, + ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, + ["res"] = targetSelectedWeaponResRef, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, + }) + -- restore ``CItem`` flags + local sourceItems = sourceEquipment.m_items -- Array + for i = 18, 33 do -- inventory slots + local item = sourceItems:get(i) -- CItem + if item then + local resref = item.pRes.resref:get() + if resref == targetSelectedWeaponResRef then + if item.m_flags == 0 then + if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then + if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then + if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then + item.m_flags = targetSelectedWeapon.m_flags + break end end end end end end - -- - CGameSprite:applyEffect({ - ["effectID"] = 112, -- remove item - ["res"] = targetSelectedWeaponResRef, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, - }) end - else + -- CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 112, -- remove item + ["res"] = targetSelectedWeaponResRef, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) @@ -165,7 +154,7 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) else CGameSprite:applyEffect({ ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_inventory_full%, + ["effectAmount"] = %feedback_strref_immune%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) @@ -173,13 +162,12 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) else CGameSprite:applyEffect({ ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_melee_only%, + ["effectAmount"] = %feedback_strref_inventory_full%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end -- - isWeaponRanged:free() inventoryFull:free() end @@ -209,11 +197,15 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) - end - else - -- in case the character dies while swinging... - if sprite:getLocalInt("gtDisarmSwing") == 1 then - sprite:setLocalInt("gtDisarmSwing", 0) + -- + if isWeaponRanged:evalConditionalAsAIBase(sprite) then + sprite:applyEffect({ + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_melee_only%, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end end end end @@ -248,6 +240,8 @@ EEex_Action_AddSpriteStartedActionListener(function(sprite, action) }) end -- + sprite:setLocalInt("gtDisarmSwing", 0) + -- action.m_actionID = 3 -- Attack() -- sprite.m_castCounter = 0 From 8e0788e09cce65964f298935282583aae49d6f95 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Thu, 24 Oct 2024 12:14:54 +0200 Subject: [PATCH 19/33] Better feedback --- cdtweaks/lib/disarm.tph | 23 +++++++++++++++++++---- cdtweaks/luke/lua/class/disarm.lua | 25 ++++++++++++++++--------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index 5ef45d99..45f77f44 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -36,11 +36,27 @@ BEGIN // EFF CREATE "eff" "%ROGUE_DISARM%b" COPY_EXISTING "%ROGUE_DISARM%b.eff" "override" - WRITE_LONG 0x10 402 // Invoke Lua + WRITE_LONG 0x10 146 // Cast spell WRITE_LONG 0x14 2 // Projectile target - //WRITE_LONG 0x1C 1 // p1 + WRITE_LONG 0x20 1 // Mode: instant/ignore level WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "%ROGUE_DISARM%" #8 // Lua function + WRITE_ASCII 0x30 "%DEST_RES%" #8 // spl file + BUT_ONLY + // Disarm (auxiliary spl file) + CREATE "spl" "%ROGUE_DISARM%b" + COPY_EXISTING "%ROGUE_DISARM%b.spl" "override" + WRITE_LONG NAME1 RESOLVE_STR_REF (@0) + WRITE_LONG NAME2 "-1" + WRITE_LONG UNIDENTIFIED_DESC "-1" + WRITE_LONG DESC "-1" + WRITE_LONG 0x18 (BIT14 BOR BIT25) // ignore dead/wild magic, castable when silenced + WRITE_SHORT 0x1C 4 // innate + WRITE_LONG 0x34 1 // level + WRITE_ASCII 0x3A "%DEST_RES%" #8 // icon + // + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%" END + // + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%ROGUE_DISARM%" END // Invoke lua BUT_ONLY // icon COPY "cdtweaks\luke\bam\class\disarm\spl_icon.bam" "override\%ROGUE_DISARM%b.bam" @@ -52,7 +68,6 @@ BEGIN OUTER_SET "feedback_strref_hit" = RESOLVE_STR_REF (@103) OUTER_SET "feedback_strref_melee_only" = RESOLVE_STR_REF (@104) OUTER_SET "feedback_strref_aura_free" = RESOLVE_STR_REF (@105) - OUTER_SET "feedback_strref_immune" = RESOLVE_STR_REF (@106) // LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_DISARM%D" RET "feedback_icon_can_disarm" = "index" END WITH_SCOPE BEGIN diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index c9db4296..e03e1bfc 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -129,32 +129,32 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) end else CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 324, -- immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 324, -- immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 324, -- immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_immune%, + ["effectID"] = 324, -- immunity to resource and message + ["res"] = CGameEffect.m_sourceRes:get(), ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) @@ -216,6 +216,8 @@ end) -- cdtweaks, NWN-ish Disarm ability. Morph the spell action into an attack action -- EEex_Action_AddSpriteStartedActionListener(function(sprite, action) + local ea = GT_Resource_SymbolToIDS["ea"] + -- if sprite:getLocalInt("cdtweaksDisarm") == 1 then if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%" then if EEex_Sprite_GetCastTimer(sprite) == -1 then @@ -242,7 +244,12 @@ EEex_Action_AddSpriteStartedActionListener(function(sprite, action) -- sprite:setLocalInt("gtDisarmSwing", 0) -- - action.m_actionID = 3 -- Attack() + if sprite.m_typeAI.m_EnemyAlly < ea["GOODCUTOFF"] then + action.m_actionID = 3 -- Attack() + else + action.m_actionID = 134 -- AttackReevaluate() + action.m_specificID = 100 -- ReevaluationPeriod + end -- sprite.m_castCounter = 0 else From aa2b07d1ff7cffad256f38dbb7f0dc720dfcbbec Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Thu, 24 Oct 2024 12:50:57 +0200 Subject: [PATCH 20/33] Update disarm.tph --- cdtweaks/lib/disarm.tph | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index 45f77f44..c07c3a9e 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -29,35 +29,17 @@ BEGIN // LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END // - /*LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 7 END // SEQ_READY - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 321 "target" = 1 STR_VAR "resource" = "%DEST_RES%" END // Remove effects by resource - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua*/ + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua BUT_ONLY // EFF - CREATE "eff" "%ROGUE_DISARM%b" - COPY_EXISTING "%ROGUE_DISARM%b.eff" "override" + CREATE "eff" "%ROGUE_DISARM%" + COPY_EXISTING "%ROGUE_DISARM%.eff" "override" WRITE_LONG 0x10 146 // Cast spell WRITE_LONG 0x14 2 // Projectile target WRITE_LONG 0x20 1 // Mode: instant/ignore level WRITE_SHORT 0x2C 100 // prob1 WRITE_ASCII 0x30 "%DEST_RES%" #8 // spl file BUT_ONLY - // Disarm (auxiliary spl file) - CREATE "spl" "%ROGUE_DISARM%b" - COPY_EXISTING "%ROGUE_DISARM%b.spl" "override" - WRITE_LONG NAME1 RESOLVE_STR_REF (@0) - WRITE_LONG NAME2 "-1" - WRITE_LONG UNIDENTIFIED_DESC "-1" - WRITE_LONG DESC "-1" - WRITE_LONG 0x18 (BIT14 BOR BIT25) // ignore dead/wild magic, castable when silenced - WRITE_SHORT 0x1C 4 // innate - WRITE_LONG 0x34 1 // level - WRITE_ASCII 0x3A "%DEST_RES%" #8 // icon - // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%" END - // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%ROGUE_DISARM%" END // Invoke lua - BUT_ONLY // icon COPY "cdtweaks\luke\bam\class\disarm\spl_icon.bam" "override\%ROGUE_DISARM%b.bam" END From 55457250f709862a3dd4a9e187c22505cb1d07ed Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Thu, 24 Oct 2024 12:52:02 +0200 Subject: [PATCH 21/33] Update disarm.lua --- cdtweaks/luke/lua/class/disarm.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index e03e1bfc..b896a89a 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -1,8 +1,10 @@ --[[ - *************************************************************************************************************************** ++---------------------------------------------+ +| cdtweaks, NWN-ish Disarm ability for Rogues | ++---------------------------------------------+ --]] --- cdtweaks, NWN-ish Disarm ability. Small / Medium / Large weapons -- +-- NWN-ish Disarm ability. Small / Medium / Large weapons -- local cdtweaks_Disarm_WeaponSize = { ["small"] = {"", "CL", "DD", "F2", "M2", "MC", "SL", "SS"}, @@ -21,7 +23,7 @@ local function cdtweaks_Disarm_CheckWeaponSize(animationType) return "none" -- should not happen end --- cdtweaks, NWN-ish Disarm ability -- +-- NWN-ish Disarm ability (main) -- function %ROGUE_DISARM%(CGameEffect, CGameSprite) local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite @@ -171,7 +173,7 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) inventoryFull:free() end --- cdtweaks, NWN-ish Disarm ability. Make sure one and only one attack roll is performed -- +-- NWN-ish Disarm ability. Make sure one and only one attack roll is performed -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -213,7 +215,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) isWeaponRanged:free() end) --- cdtweaks, NWN-ish Disarm ability. Morph the spell action into an attack action -- +-- NWN-ish Disarm ability. Morph the spell action into an attack action -- EEex_Action_AddSpriteStartedActionListener(function(sprite, action) local ea = GT_Resource_SymbolToIDS["ea"] @@ -225,7 +227,7 @@ EEex_Action_AddSpriteStartedActionListener(function(sprite, action) {["op"] = 321, ["res"] = "%ROGUE_DISARM%"}, -- remove effects by resource {["op"] = 284, ["p1"] = -6}, -- melee thac0 bonus {["op"] = 142, ["p2"] = %feedback_icon_can_disarm%}, -- feedback icon - {["op"] = 248, ["res"] = "%ROGUE_DISARM%B"}, -- melee hit effect + {["op"] = 248, ["res"] = "%ROGUE_DISARM%"}, -- melee hit effect } -- for _, attributes in ipairs(effectCodes) do From 24b849ae57911e3e81f4559561c1bb34557da69d Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Thu, 24 Oct 2024 12:58:33 +0200 Subject: [PATCH 22/33] Update disarm.lua --- cdtweaks/luke/lua/class/disarm.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index b896a89a..3c0ffd2b 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -184,7 +184,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") -- if sprite:getLocalInt("cdtweaksDisarm") == 1 then - if GT_Utility_EffectCheck(sprite, {["op"] = 0xF8, ["res"] = "%ROGUE_DISARM%B"}) then + if GT_Utility_EffectCheck(sprite, {["op"] = 0xF8, ["res"] = "%ROGUE_DISARM%"}) then if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtDisarmSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then sprite:setLocalInt("gtDisarmSwing", 1) elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtDisarmSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then From 5303c86e9e12aecdace1c0c4dc1d7a10f1b6ae6d Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Wed, 18 Dec 2024 17:27:33 +0100 Subject: [PATCH 23/33] Yet another implementation - Add missing `["durationType"] = 1` to op122. - Make sure to unequip ammo (apparently, if you disarm a launcher, the corresponding ammo is still equipped). --- cdtweaks/languages/english/disarm.tra | 8 +- cdtweaks/languages/italian/disarm.tra | 8 +- cdtweaks/lib/disarm.tph | 26 +-- cdtweaks/luke/lua/class/disarm.lua | 226 ++++++++++++++------------ cdtweaks/readme-cdtweaks.html | 5 +- 5 files changed, 135 insertions(+), 138 deletions(-) diff --git a/cdtweaks/languages/english/disarm.tra b/cdtweaks/languages/english/disarm.tra index 3bdf5c96..a3ee28d6 100644 --- a/cdtweaks/languages/english/disarm.tra +++ b/cdtweaks/languages/english/disarm.tra @@ -2,12 +2,12 @@ @1 = "Disarm -The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands." +The character can attempt to disarm an opponent in melee combat. The combatant with the larger weapon gains a +2 bonus per size category of difference. If the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands." -@100 = "The selected target is out of range" +//@100 = "The selected target is out of range" @101 = "Disarm Canceled: Inventory full" @102 = "Disarm: Resisted" @103 = "Disarm: Hit" @104 = "This feat cannot be used while wielding a ranged weapon" -@105 = "The character cannot perform more than one action per round" -@106 = "Unaffected by effects from Disarm" \ No newline at end of file +@105 = "The targeted creature cannot be disarmed" +//@106 = "Unaffected by effects from Disarm" \ No newline at end of file diff --git a/cdtweaks/languages/italian/disarm.tra b/cdtweaks/languages/italian/disarm.tra index 8a6f9c87..038db712 100644 --- a/cdtweaks/languages/italian/disarm.tra +++ b/cdtweaks/languages/italian/disarm.tra @@ -2,12 +2,12 @@ @1 = "Disarmare -Il personaggio può tentare di disarmare un avversario durante un combattimento in mischia. Il tentativo di disarmare applica una penalità di -6 al tiro per colpire del personaggio, e il combattente con l'arma più grande ottiene un bonus di +2 per ogni categoria di taglia di differenza. Un colpo andato a segno infligge danni normalmente e, se l'avversario fallisce un tiro-salvezza contro Soffio, l'arma gli vola via dalle mani." +Il personaggio può tentare di disarmare un avversario durante un combattimento in mischia. Il combattente con l'arma più grande ottiene un bonus di +2 per ogni categoria di taglia di differenza. Se l'avversario fallisce un tiro-salvezza contro Soffio, l'arma gli vola via dalle mani." -@100 = "Il bersaglio selezionato è fuori portata" +//@100 = "Il bersaglio selezionato è fuori portata" @101 = "Disarmare Annullato: Inventario pieno" @102 = "Disarmare: Resistito" @103 = "Disarmare: Colpito" @104 = "Questa abilità non può essere usata mentre si brandisce un'arma a distanza" -@105 = "Il personaggio non può compiere più di un'azione per round" -@106 = "Non soggetto agli effetti di Disarmare" \ No newline at end of file +@105 = "La creatura selezionata non può essere disarmata" +//@106 = "Non soggetto agli effetti di Disarmare" \ No newline at end of file diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index c07c3a9e..458e46ed 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -11,8 +11,6 @@ BEGIN "ROGUE_DISARM" = "resName" END // - //LAF "ADD_EXTENDED_STAT" INT_VAR "max" = 25 STR_VAR "identifier" = "GT_IGNORE_ACTION_ADD_SPRITE_STARTED_ACTION_LISTENER" END - // WITH_SCOPE BEGIN ACTION_TO_LOWER "ROGUE_DISARM" // Disarm (main spl file) @@ -27,18 +25,9 @@ BEGIN WRITE_LONG 0x34 1 // level WRITE_ASCII 0x3A "%DEST_RES%B" #8 // icon // - LPF "ADD_SPELL_HEADER" INT_VAR "range" = 30 STR_VAR "icon" = "%DEST_RES%B" END + LPF "ADD_SPELL_HEADER" INT_VAR "range" = 0 STR_VAR "icon" = "%DEST_RES%B" END // - LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 402 "target" = 2 STR_VAR "resource" = "%DEST_RES%" END // Invoke lua - BUT_ONLY - // EFF - CREATE "eff" "%ROGUE_DISARM%" - COPY_EXISTING "%ROGUE_DISARM%.eff" "override" - WRITE_LONG 0x10 146 // Cast spell - WRITE_LONG 0x14 2 // Projectile target - WRITE_LONG 0x20 1 // Mode: instant/ignore level - WRITE_SHORT 0x2C 100 // prob1 - WRITE_ASCII 0x30 "%DEST_RES%" #8 // spl file + LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 0 END // SEQ_ATTACK BUT_ONLY // icon COPY "cdtweaks\luke\bam\class\disarm\spl_icon.bam" "override\%ROGUE_DISARM%b.bam" @@ -49,20 +38,11 @@ BEGIN OUTER_SET "feedback_strref_resisted" = RESOLVE_STR_REF (@102) OUTER_SET "feedback_strref_hit" = RESOLVE_STR_REF (@103) OUTER_SET "feedback_strref_melee_only" = RESOLVE_STR_REF (@104) - OUTER_SET "feedback_strref_aura_free" = RESOLVE_STR_REF (@105) - // - LAF "ADD_STATDESC_ENTRY" INT_VAR "description" = RESOLVE_STR_REF (@0) STR_VAR "bam_file" = "%ROGUE_DISARM%D" RET "feedback_icon_can_disarm" = "index" END - WITH_SCOPE BEGIN - ACTION_TO_LOWER "ROGUE_DISARM" - COPY "cdtweaks\luke\bam\class\disarm\portrait_icon.bam" "override\%ROGUE_DISARM%d.bam" - END + OUTER_SET "feedback_strref_cannot_be_disarmed" = RESOLVE_STR_REF (@105) // LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Class/Kit Abilities" "sourceFileSpec" = "cdtweaks\luke\lua\class\disarm.lua" "destRes" = "m_gtspcl" END END // - //LAF "APPEND_LUA_FUNCTION" STR_VAR "description" = "Lua Tools" "sourceFileSpec" = "cdtweaks\luke\lua\tools\key_exists.lua" "destRes" = "m_gttool" 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 diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index 3c0ffd2b..b2aa8d97 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -94,6 +94,7 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) -- sourceSprite:applyEffect({ ["effectID"] = 122, -- create inventory item + ["durationType"] = 1, ["effectAmount"] = targetSelectedWeapon.m_useCount1, ["m_effectAmount2"] = targetSelectedWeapon.m_useCount2, ["m_effectAmount3"] = targetSelectedWeapon.m_useCount3, @@ -102,18 +103,20 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) ["sourceTarget"] = sourceSprite.m_id, }) -- restore ``CItem`` flags - local sourceItems = sourceEquipment.m_items -- Array - for i = 18, 33 do -- inventory slots - local item = sourceItems:get(i) -- CItem - if item then - local resref = item.pRes.resref:get() - if resref == targetSelectedWeaponResRef then - if item.m_flags == 0 then - if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then - if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then - if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then - item.m_flags = targetSelectedWeapon.m_flags - break + do + local sourceItems = sourceEquipment.m_items -- Array + for i = 18, 33 do -- inventory slots + local item = sourceItems:get(i) -- CItem + if item then + local resref = item.pRes.resref:get() + if resref == targetSelectedWeaponResRef then + if item.m_flags == 0 then + if item.m_useCount1 == targetSelectedWeapon.m_useCount1 then + if item.m_useCount2 == targetSelectedWeapon.m_useCount2 then + if item.m_useCount3 == targetSelectedWeapon.m_useCount3 then + item.m_flags = targetSelectedWeapon.m_flags + break + end end end end @@ -128,52 +131,122 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) + -- make sure to unequip ammo (apparently, if you disarm a launcher, the corresponding ammo is still equipped) + do + local targetItems = CGameSprite.m_equipment.m_items -- Array + for i = 11, 13 do -- ammo slots + local item = targetItems:get(i) -- CItem + if item then + local resref = item.pRes.resref:get() + -- + local unequip = EEex_Action_ParseResponseString(string.format('XEquipItem("%s",Myself,%d,UNEQUIP)', resref, i)) + unequip:executeResponseAsAIBaseInstantly(CGameSprite) + -- + unequip:free() + end + end + end end else CGameSprite:applyEffect({ - ["effectID"] = 324, -- immunity to resource and message - ["res"] = CGameEffect.m_sourceRes:get(), + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_cannot_be_disarmed%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 324, -- immunity to resource and message - ["res"] = CGameEffect.m_sourceRes:get(), + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_cannot_be_disarmed%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 324, -- immunity to resource and message - ["res"] = CGameEffect.m_sourceRes:get(), + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_cannot_be_disarmed%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else CGameSprite:applyEffect({ - ["effectID"] = 324, -- immunity to resource and message - ["res"] = CGameEffect.m_sourceRes:get(), + ["effectID"] = 139, -- display string + ["effectAmount"] = %feedback_strref_cannot_be_disarmed%, ["sourceID"] = CGameEffect.m_sourceId, ["sourceTarget"] = CGameEffect.m_sourceTarget, }) end else - CGameSprite:applyEffect({ + sourceSprite:applyEffect({ ["effectID"] = 139, -- display string ["effectAmount"] = %feedback_strref_inventory_full%, - ["sourceID"] = CGameEffect.m_sourceId, - ["sourceTarget"] = CGameEffect.m_sourceTarget, + ["sourceID"] = sourceSprite.m_id, + ["sourceTarget"] = sourceSprite.m_id, }) end -- inventoryFull:free() end --- NWN-ish Disarm ability. Make sure one and only one attack roll is performed -- +-- Make it castable at will. Prevent spell disruption. Check if melee weapon equipped -- + +EEex_Sprite_AddQuickListsCheckedListener(function(sprite, resref, changeAmount) + local curAction = sprite.m_curAction + local spriteAux = EEex_GetUDAux(sprite) + + if not (curAction.m_actionID == 31 and resref == "%ROGUE_DISARM%" and changeAmount < 0) then + return + end + + -- nuke current action + curAction.m_actionID = 0 + + local spellHeader = EEex_Resource_Demand(resref, "SPL") + local spellLevelMemListArray = sprite.m_memorizedSpellsInnate + local memList = spellLevelMemListArray:getReference(spellHeader.spellLevel - 1) -- !!!count starts from 0!!! + + -- restore memorization bit + EEex_Utility_IterateCPtrList(memList, function(memInstance) + local memInstanceResref = memInstance.m_spellId:get() + if memInstanceResref == resref then + local memFlags = memInstance.m_flags + if EEex_IsBitUnset(memFlags, 0x0) then + memInstance.m_flags = EEex_SetBit(memFlags, 0x0) + end + end + end) + + -- make sure the creature is equipped with a melee weapon + local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") + if not isWeaponRanged:evalConditionalAsAIBase(sprite) then + -- store target id + spriteAux["gtDisarmTargetID"] = curAction.m_acteeID.m_Instance + -- initialize the attack frame counter + sprite.m_attackFrame = 0 + -- recast the ability as "ForceSpell()" + local targetSprite = EEex_GameObject_Get(curAction.m_acteeID.m_Instance) + targetSprite:applyEffect({ + ["effectID"] = 146, -- Cast spell + ["res"] = resref, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = targetSprite.m_id, + }) + else + sprite:applyEffect({ + ["effectID"] = 139, -- Display string + ["effectAmount"] = %feedback_strref_melee_only%, + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = sprite.m_id, + }) + end + + isWeaponRanged:free() +end) + +-- Cast the "real" spl (ability) when the attack frame counter is 6 -- EEex_Opcode_AddListsResolvedListener(function(sprite) -- Sanity check @@ -181,31 +254,29 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) return end -- + local spriteAux = EEex_GetUDAux(sprite) + -- local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") -- if sprite:getLocalInt("cdtweaksDisarm") == 1 then - if GT_Utility_EffectCheck(sprite, {["op"] = 0xF8, ["res"] = "%ROGUE_DISARM%"}) then - if sprite.m_startedSwing == 1 and sprite:getLocalInt("gtDisarmSwing") == 0 and not isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtDisarmSwing", 1) - elseif (sprite.m_startedSwing == 0 and sprite:getLocalInt("gtDisarmSwing") == 1) or isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:setLocalInt("gtDisarmSwing", 0) - -- - sprite.m_curAction.m_actionID = 0 -- nuke current action - -- - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%ROGUE_DISARM%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - -- - if isWeaponRanged:evalConditionalAsAIBase(sprite) then - sprite:applyEffect({ - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_melee_only%, + if not isWeaponRanged:evalConditionalAsAIBase(sprite) then + if sprite.m_nSequence == 0 and sprite.m_attackFrame == 6 then -- SetSequence(SEQ_ATTACK) + if spriteAux["gtDisarmTargetID"] then + -- retrieve / forget target sprite + local targetSprite = EEex_GameObject_Get(spriteAux["gtDisarmTargetID"]) + spriteAux["gtDisarmTargetID"] = nil + -- + targetSprite:applyEffect({ + ["effectID"] = 138, -- set animation + ["dwFlags"] = 4, -- SEQ_DAMAGE ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, + ["sourceTarget"] = targetSprite.m_id, + }) + targetSprite:applyEffect({ + ["effectID"] = 402, -- invoke lua + ["res"] = "%ROGUE_DISARM%", + ["sourceID"] = sprite.m_id, + ["sourceTarget"] = targetSprite.m_id, }) end end @@ -215,71 +286,16 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) isWeaponRanged:free() end) --- NWN-ish Disarm ability. Morph the spell action into an attack action -- +-- Forget about ``spriteAux["gtDisarmTargetID"]`` if the player manually interrupts the action -- EEex_Action_AddSpriteStartedActionListener(function(sprite, action) - local ea = GT_Resource_SymbolToIDS["ea"] + local spriteAux = EEex_GetUDAux(sprite) -- if sprite:getLocalInt("cdtweaksDisarm") == 1 then - if action.m_actionID == 31 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%" then - if EEex_Sprite_GetCastTimer(sprite) == -1 then - local effectCodes = { - {["op"] = 321, ["res"] = "%ROGUE_DISARM%"}, -- remove effects by resource - {["op"] = 284, ["p1"] = -6}, -- melee thac0 bonus - {["op"] = 142, ["p2"] = %feedback_icon_can_disarm%}, -- feedback icon - {["op"] = 248, ["res"] = "%ROGUE_DISARM%"}, -- melee hit effect - } - -- - for _, attributes in ipairs(effectCodes) do - sprite: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 "", - ["durationType"] = 1, - ["m_sourceRes"] = "%ROGUE_DISARM%", - ["m_sourceType"] = 1, - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - end - -- - sprite:setLocalInt("gtDisarmSwing", 0) - -- - if sprite.m_typeAI.m_EnemyAlly < ea["GOODCUTOFF"] then - action.m_actionID = 3 -- Attack() - else - action.m_actionID = 134 -- AttackReevaluate() - action.m_specificID = 100 -- ReevaluationPeriod - end - -- - sprite.m_castCounter = 0 - else - action.m_actionID = 0 -- nuke current action - -- - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%ROGUE_DISARM%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 139, -- display string - ["effectAmount"] = %feedback_strref_aura_free%, - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) + if not (action.m_actionID == 113 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%") then + if spriteAux["gtDisarmTargetID"] ~= nil then + spriteAux["gtDisarmTargetID"] = nil end - else - EEex_GameObject_ApplyEffect(sprite, - { - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%ROGUE_DISARM%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) end end end) diff --git a/cdtweaks/readme-cdtweaks.html b/cdtweaks/readme-cdtweaks.html index 6011cb69..919d836f 100644 --- a/cdtweaks/readme-cdtweaks.html +++ b/cdtweaks/readme-cdtweaks.html @@ -1472,13 +1472,14 @@

    NWN-ish Feats Collection Disarm class feat for Rogues [Luke]
    EEex

    -

    This component aims at implementing the NWN feat Disarm.
    - The character can attempt to disarm an opponent in melee combat. Attempting a disarm applies a -6 penalty to the character's attack roll, and the combatant with the larger weapon gains a +2 bonus per size category of difference. A successful hit deals normal damage, and if the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands.
    +

    + The character can attempt to disarm an opponent in melee combat. The combatant with the larger weapon gains a +2 bonus per size category of difference. If the opponent fails a Save vs. Breath, then the weapon flies from the opponent's hands.
    Notes:

    • Use: selected, unlimited uses per day. Only available to Rogues (starting from level 1).
    • When the weapon flies from the opponent's hands, the attacker automatically picks it up (provided its Inventory is not full).
    • This feat cannot be used while wielding a ranged weapon.
    • +
    • The Disarm blow itself automatically hits (no attack roll is required), but deals no damage and applies no on-hit effects (if any).
    • As far as weapon sizes are concerned:
        From c8b3bbe819a411adf7b44c844b72c5334bc9792c Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 10 Jan 2025 18:19:44 +0100 Subject: [PATCH 24/33] Misc tweaks --- cdtweaks/lib/disarm.tph | 12 +++--- .../class/{disarm/spl_icon.bam => disarm.bam} | Bin .../luke/bam/class/disarm/portrait_icon.bam | Bin 381 -> 0 bytes cdtweaks/luke/lua/class/disarm.lua | 36 ++++++++---------- 4 files changed, 21 insertions(+), 27 deletions(-) rename cdtweaks/luke/bam/class/{disarm/spl_icon.bam => disarm.bam} (100%) delete mode 100644 cdtweaks/luke/bam/class/disarm/portrait_icon.bam diff --git a/cdtweaks/lib/disarm.tph b/cdtweaks/lib/disarm.tph index 458e46ed..52c12070 100644 --- a/cdtweaks/lib/disarm.tph +++ b/cdtweaks/lib/disarm.tph @@ -6,16 +6,16 @@ BEGIN "preferredSlot" = 44 "type" = 4 STR_VAR - "idsName" = "ROGUE_DISARM" + "idsName" = "THIEF_DISARM" RET - "ROGUE_DISARM" = "resName" + "THIEF_DISARM" = "resName" END // WITH_SCOPE BEGIN - ACTION_TO_LOWER "ROGUE_DISARM" + ACTION_TO_LOWER "THIEF_DISARM" // Disarm (main spl file) - CREATE "spl" "%ROGUE_DISARM%" - COPY_EXISTING "%ROGUE_DISARM%.spl" "override" + CREATE "spl" "%THIEF_DISARM%" + COPY_EXISTING "%THIEF_DISARM%.spl" "override" WRITE_LONG NAME1 RESOLVE_STR_REF (@0) WRITE_LONG NAME2 "-1" WRITE_LONG UNIDENTIFIED_DESC RESOLVE_STR_REF (@1) @@ -30,7 +30,7 @@ BEGIN LPF "ADD_SPELL_EFFECT" INT_VAR "opcode" = 138 "target" = 1 "parameter2" = 0 END // SEQ_ATTACK BUT_ONLY // icon - COPY "cdtweaks\luke\bam\class\disarm\spl_icon.bam" "override\%ROGUE_DISARM%b.bam" + COPY "cdtweaks\luke\bam\class\disarm.bam" "override\%THIEF_DISARM%b.bam" END // lua WITH_SCOPE BEGIN diff --git a/cdtweaks/luke/bam/class/disarm/spl_icon.bam b/cdtweaks/luke/bam/class/disarm.bam similarity index 100% rename from cdtweaks/luke/bam/class/disarm/spl_icon.bam rename to cdtweaks/luke/bam/class/disarm.bam diff --git a/cdtweaks/luke/bam/class/disarm/portrait_icon.bam b/cdtweaks/luke/bam/class/disarm/portrait_icon.bam deleted file mode 100644 index 1a4b0bb32ef95c14f6d92a9fb7e8b6fe3135f543..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 381 zcmV-@0fPQQK}|zeF(4ps1ONbdoTZaJO9Md=hUX;2v#_xc%amg0Pte}hA9RLPCJ+#W zpb|ujOVWvG`~bONp#&nB_<EM)CZMg#2gJZ#x`S5R*sRi z=9${E>Ztcw7pWXd9p zo_YXY!3y`t#3-m*mcbhR@4&VEJfHt1L(G|7QktV~f)aDw1G}u{O1ft<&wVoaSD1Uv z>P>M#-!-j2`2L2;<%RogzTJlEeTlVYyY=HYo=(e%=Y`^WULbBV$y+Q8#7U)miTl9< b#Px%+xMA53WH^K=FyhdmvW$HLEadSpPl&_x diff --git a/cdtweaks/luke/lua/class/disarm.lua b/cdtweaks/luke/lua/class/disarm.lua index b2aa8d97..3d9ad370 100644 --- a/cdtweaks/luke/lua/class/disarm.lua +++ b/cdtweaks/luke/lua/class/disarm.lua @@ -25,7 +25,7 @@ end -- NWN-ish Disarm ability (main) -- -function %ROGUE_DISARM%(CGameEffect, CGameSprite) +function %THIEF_DISARM%(CGameEffect, CGameSprite) local sourceSprite = EEex_GameObject_Get(CGameEffect.m_sourceId) -- CGameSprite -- local inventoryFull = EEex_Trigger_ParseConditionalString("InventoryFull(Myself)") @@ -38,7 +38,7 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) local targetEquipment = CGameSprite.m_equipment local targetSelectedWeapon = targetEquipment.m_items:get(targetEquipment.m_selectedWeapon) -- CItem -- Get launcher if needed - local targetSelectedWeapon = CGameSprite:getLauncher(targetSelectedWeapon:getAbility(targetEquipment.m_selectedWeaponAbility)) or targetSelectedWeapon + local targetSelectedWeapon = CGameSprite:getLauncher(targetSelectedWeapon:getAbility(targetEquipment.m_selectedWeaponAbility)) or targetSelectedWeapon -- CItem -- local targetSelectedWeaponResRef = targetSelectedWeapon.pRes.resref:get() local targetSelectedWeaponHeader = targetSelectedWeapon.pRes.pHeader -- Item_Header_st @@ -139,10 +139,10 @@ function %ROGUE_DISARM%(CGameEffect, CGameSprite) if item then local resref = item.pRes.resref:get() -- - local unequip = EEex_Action_ParseResponseString(string.format('XEquipItem("%s",Myself,%d,UNEQUIP)', resref, i)) - unequip:executeResponseAsAIBaseInstantly(CGameSprite) + local responseString = EEex_Action_ParseResponseString(string.format('XEquipItem("%s",Myself,%d,UNEQUIP)', resref, i)) + responseString:executeResponseAsAIBaseInstantly(CGameSprite) -- - unequip:free() + responseString:free() end end end @@ -197,7 +197,7 @@ EEex_Sprite_AddQuickListsCheckedListener(function(sprite, resref, changeAmount) local curAction = sprite.m_curAction local spriteAux = EEex_GetUDAux(sprite) - if not (curAction.m_actionID == 31 and resref == "%ROGUE_DISARM%" and changeAmount < 0) then + if not (curAction.m_actionID == 31 and resref == "%THIEF_DISARM%" and changeAmount < 0) then return end @@ -258,7 +258,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- local isWeaponRanged = EEex_Trigger_ParseConditionalString("IsWeaponRanged(Myself)") -- - if sprite:getLocalInt("cdtweaksDisarm") == 1 then + if sprite:getLocalInt("gtThiefDisarm") == 1 then if not isWeaponRanged:evalConditionalAsAIBase(sprite) then if sprite.m_nSequence == 0 and sprite.m_attackFrame == 6 then -- SetSequence(SEQ_ATTACK) if spriteAux["gtDisarmTargetID"] then @@ -274,7 +274,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) }) targetSprite:applyEffect({ ["effectID"] = 402, -- invoke lua - ["res"] = "%ROGUE_DISARM%", + ["res"] = "%THIEF_DISARM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = targetSprite.m_id, }) @@ -291,8 +291,8 @@ end) EEex_Action_AddSpriteStartedActionListener(function(sprite, action) local spriteAux = EEex_GetUDAux(sprite) -- - if sprite:getLocalInt("cdtweaksDisarm") == 1 then - if not (action.m_actionID == 113 and action.m_string1.m_pchData:get() == "%ROGUE_DISARM%") then + if sprite:getLocalInt("gtThiefDisarm") == 1 then + if not (action.m_actionID == 113 and action.m_string1.m_pchData:get() == "%THIEF_DISARM%") then if spriteAux["gtDisarmTargetID"] ~= nil then spriteAux["gtDisarmTargetID"] = nil end @@ -310,7 +310,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- internal function that grants the ability local gain = function() -- Mark the creature as 'feat granted' - sprite:setLocalInt("cdtweaksDisarm", 1) + sprite:setLocalInt("gtThiefDisarm", 1) -- local effectCodes = { {["op"] = 172}, -- remove spell @@ -320,7 +320,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) for _, attributes in ipairs(effectCodes) do sprite:applyEffect({ ["effectID"] = attributes["op"] or EEex_Error("opcode number not specified"), - ["res"] = "%ROGUE_DISARM%", + ["res"] = "%THIEF_DISARM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) @@ -339,7 +339,7 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) or (spriteClassStr == "CLERIC_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) or (spriteClassStr == "FIGHTER_THIEF" and (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2)) -- - if sprite:getLocalInt("cdtweaksDisarm") == 0 then + if sprite:getLocalInt("gtThiefDisarm") == 0 then if gainAbility then gain() end @@ -348,17 +348,11 @@ EEex_Opcode_AddListsResolvedListener(function(sprite) -- do nothing else -- Mark the creature as 'feat removed' - sprite:setLocalInt("cdtweaksDisarm", 0) + sprite:setLocalInt("gtThiefDisarm", 0) -- sprite:applyEffect({ ["effectID"] = 172, -- remove spell - ["res"] = "%ROGUE_DISARM%", - ["sourceID"] = sprite.m_id, - ["sourceTarget"] = sprite.m_id, - }) - sprite:applyEffect({ - ["effectID"] = 321, -- remove effects by resource - ["res"] = "%ROGUE_DISARM%", + ["res"] = "%THIEF_DISARM%", ["sourceID"] = sprite.m_id, ["sourceTarget"] = sprite.m_id, }) From a2de5bb18c2fdea1f55f11c37daa5e78740e6b8d Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:09:03 +0100 Subject: [PATCH 25/33] Delete gtprone.bam --- cdtweaks/luke/bam/gtprone.bam | Bin 1015 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cdtweaks/luke/bam/gtprone.bam diff --git a/cdtweaks/luke/bam/gtprone.bam b/cdtweaks/luke/bam/gtprone.bam deleted file mode 100644 index f64ae14da36cdee2fe3dd64cc3144937de90e623..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1015 zcmVvdLCFs+pn!_pCXEd# z{cFah1_U*9bx1a*gsfoW6FK#POBoD0Vxus#*u^!xY&EgeP_sMj5DT;0UWA3BGIJ6b zMiheF?J(21z3(~id7m@SInT*^W`BIi*7$e@3Sxl77A+hmBrM0m z+?$4sOwc94YAx*4$MM(V3*;BT_8n0A3Upk~=Hd^~bQvZ?HH?RwINT1F8#hQZ)Ql&H#ktlCn=rurq~o^51ZRwackf5Rb>lmDg2v!X~cqKMmz zYM)(TpJ7$`A4DFTMP1@XQ)ow>W@Oz#Cu>V=X!Ac}qhXks9VYbEU$N%sLlLhfBew{L zYXY7dMU`#g;?-f$-$oHzO3IN5sv15ep~wL_;_P%6XmU{GK0vE0gRMTa2?pfXL&!BD zw7FqqV+gY~Ot#+0hwT=0X>G^_f-4#fh7dkq7>lK!*w{F_YTQ`NRzCmaDg{{vtj+zH ztIUj>$C-D`V=~lZ`^JXvz~2%iJx0 zk?@b-yzQ$_8^;&e%67Q9#5+42lS5qnvzCMh(QsPcq1f{!EFz%74J)oo6AR%Xf zwMoL)1LNPxl*#Z#*Fl=!f+AVV%pD6elhD{85t>`c$7j_{-F=Cglh5-=(ERri%+A7Z zzr)X7=>HaMHn?^TE(p1p-hsM$c(odiA4l8?6cXVq7R#QHYp1R4 z45g(djE#-b($XwqAr=-En46mud}l@O41quZuh)yi;b353K=8IY}5g1Cz;w z(P*TyvQqFiP*6~SEZ$77*OQi(Mtpoc8jVKqSMh&&JUGV6;4eWx5y7$UF{i)Vi?Tc5 zzvK;Gw>#aJ{C>aNt@H$Yd#?BP+6P^(L8s8KTj^BV2YXyj_s}iy_YNtYZsGg9DE_p2 ll|#OvF>kk_k{oe From ad5e76a2acfde7990d16a67749dbdabfbe97a24d Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:10:27 +0100 Subject: [PATCH 26/33] Delete portrait_icon.bam --- .../luke/bam/innate/knockdown/portrait_icon.bam | Bin 974 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cdtweaks/luke/bam/innate/knockdown/portrait_icon.bam diff --git a/cdtweaks/luke/bam/innate/knockdown/portrait_icon.bam b/cdtweaks/luke/bam/innate/knockdown/portrait_icon.bam deleted file mode 100644 index b35d38d97c8ed8b4da3ef993db57448a945ae3f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 974 zcmV;<12OzUK}|zeF(4q01ONbdoMn@JOw@H8$6w&@(%J6N=Fg`h&mK6zfR!m?PEK^e z8N`DKKASf@x&tyu%}}Edk&Tm7Zs-QtXget8#R$%Jc{VxoX0ri9V1@@<7Co%=x_m-e zzh7Ubf3)>|_n^evb% zlazcLa#AWx((rw6AAI2AhwG!r2i?RS^|D}N3G z;ooY9EsgMs8RjRzoEUWVH<1&wSiJLuxbGNPJ0V-d#b?2^NTl>iA`Xq9eYKQb7Zj)# zG22{_auAZwuqn^el; zRayA^MxbyAO^%CC&h&^xj*5Nrh&?cZwd!-C3jOegID1_;%t|Dz;12Rj8z5&8d65}Y zt%B*Og1ke;RIT9rR%L0bjiV=B7*^I{Di&`I*J0kTFc?sAwVmV1ry@C4(nqV)P3vc0 zkeXoTwEY|nRww<=VS@g9>@k<&{o2dm`Zi`t5jf(k+%q^Z%Fp98ZAWeBVC1x$XoG>5 z7cF9q$;9t#EvP;}-8F|fySoTATgEU=qAD#8)%y|MZ^v=x)E1ntN&H$onLJ}GwgidN zGy`_wGYK-fizNmtV7S@DhGo!Jw+Z`J$V!q4UUL!jKt+Lsa(N0LmutDvn?s2;4dn{_ zBj^+oJpJh$479^Hr@$*{(q0FRV$XdRcrPD{HbVYdQA$CL?A4H&42kiedmJ>6_u+9nf&=l0?9xVW>kA|3J&O%*l-R&!)HiY2Mrr!Pu1-IQ!{B8V*OH44Ww0Hjfnv zGq~KDg7S-vvf?E?xW0?p50e@Ht(Kmyy{LaR6B{!R^=~&fuD22#?L@uXjl0dk#q&;- z`#-XO-@BYV;h^sLG4gVAxi&P!5xX5lQ5YK=_ghC;L!5~+!US(il0KeZ)S63Ha zuNSA&NmEl3_4W0Xm6c($*|1nFn9XJ~GBPlUni-8o;^X7d>-Fe#Iy4#$kJ|Kr&%=~} wPY(AmSt#HCRrr6b$0pPSm=y5&WC1-sVIaK1@H~_grq366s61%@1?mWhMVcbxp#T5? From a4d622c06287de1580ae35c91929b0b65defa311 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:10:37 +0100 Subject: [PATCH 27/33] Delete spl_icon.bam --- cdtweaks/luke/bam/innate/knockdown/spl_icon.bam | Bin 1298 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cdtweaks/luke/bam/innate/knockdown/spl_icon.bam diff --git a/cdtweaks/luke/bam/innate/knockdown/spl_icon.bam b/cdtweaks/luke/bam/innate/knockdown/spl_icon.bam deleted file mode 100644 index 841b7cdd5b51eb4e6c7121e508cbf4449e238db3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1298 zcmV+t1?~DmK}|zeF(4o`3jhFkob8m&cM@k5hkt4kNTQM$n^0?0Xw^VXBUnubo78|t z1q%Ykm|)`v!!(f@A-rQUCNoaR$b^$4JJ}U?W~aMmSC@6C%Pjk^&`Uo2sKPnj_Vk(a zD3l<0h^Kv5S_SX@MDv4jHC@MeSIFUtC>BsMnER1U%Jfu)!bd0q6Bn zIC$I~IJcYPfzR!P$LXXs2QT$5r-ynMoD>(GcWthnaP+ugr)ueR!fCg|O}*3ZfXi!x z&u61+EU?r04x1fzn~g%%ZbL^$2W%EQtkw?LE!11Blnz+w_hH@q1YU1E#{c|Rq5pur zt%E<=I3Idi+k6*Bf|t)mV>nHn(30MgyUE$}h-w zyROenXu6RutiWPz8w#EY2d|7xM+NQh0FzvKS(#V#3|d;xjK)SIg%k1m!TrSQ;-Be&1y%tTSB$)>^~Pt#m6Q2tA6dim~csQS~6C2MWe|m-G`Ty6TLH24^AJE z6ftKQ8O21)o|fTgOyVbwC;PJ5efUtC9tUzw@o1?&GkMo z&E<@aJ;aoH$DeAy2O_&z6p6|^-Cci?{AHzSaPRwS8B_-Q0Kj^)xuuLl2 zy%5)n2KKZEFYoGPvLfWZ>GotL<=By&5|a|Qb)#yaX@pxnKR4s(?CzR+I6KZ1Z}+z| z`qIgjYE?m#uXS~`v#a;$9AmPWmX+n319uX)`wCT^hI`NR8O_i#88$mDX=ZlWG!_?< zOGciaP&h5-lzWnCD6(1A=JR=DId2$w16DD|BK)K3EYpfK)Mx|EG!3++q;S?S1=Y+K zj1^5a49zTJUraXX3Fx#*RWVK4`G9U{I(2#Uf1ts(0(E##jF0(;DIf9)ZQkdT2EC(> zN^i$?jM~|}u2l|iy1wI+-hRMG4u8yBss9as I1BP;&*aY8#Z~y=R From 54991063f3351f269ac808a64eca2202c35e0fb5 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:16:46 +0100 Subject: [PATCH 28/33] Update m_gttbls.lua --- cdtweaks/luke/lua/m_gttbls.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/luke/lua/m_gttbls.lua b/cdtweaks/luke/lua/m_gttbls.lua index bde99f95..6861a6c6 100644 --- a/cdtweaks/luke/lua/m_gttbls.lua +++ b/cdtweaks/luke/lua/m_gttbls.lua @@ -7,7 +7,7 @@ GT_Resource_SymbolToIDS = {} EEex_GameState_AddInitializedListener(function() -- 2DA EEex_Utility_NewScope(function() - local resources = { "STRMOD", "STRMODEX", "DEXMOD", "STYLBONU", "SNEAKATT", "MONKFIST" } + local resources = { "STRMOD", "STRMODEX", "DEXMOD", "STYLBONU", "SNEAKATT" } -- for _, v in ipairs(resources) do local data = EEex_Resource_Load2DA(v) From 0310f190f3ddcd64e811808bde01f19240709ddd Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:28:36 +0100 Subject: [PATCH 29/33] Update misc.tph --- cdtweaks/luke/misc.tph | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index 0ba8ef72..815d946b 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -415,13 +415,17 @@ BEGIN BUT_ONLY UNLESS "%fileContent%" END -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* - -Custom ADD_SPELL - ++-----------------------------------+ +| Custom ADD_SPELL | ++-----------------------------------+ +| Adds a new entry to "gtspell.ids" | +| - "gtwi***" for wizard spells | +| - "gtpr***" for priest spells | +| - "gtin***" for innate spells | +| - "gtcl***" for class/kit spells | ++-----------------------------------+ */ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DEFINE_DIMORPHIC_FUNCTION "GT_ADD_SPELL" INT_VAR @@ -500,11 +504,7 @@ BEGIN END END -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* - -*/ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// auxiliary function // DEFINE_DIMORPHIC_FUNCTION "GT_RES_NUM_OF_SPELL_NAME" STR_VAR @@ -549,11 +549,7 @@ BEGIN BUT_ONLY_IF_IT_CHANGES END -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* - -*/ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// auxiliary function // DEFINE_DIMORPHIC_FUNCTION "GT_NAME_NUM_OF_SPELL_RES" STR_VAR @@ -599,11 +595,12 @@ BEGIN END /* -============================================================================================================== -**SORT_IDS_FILE** -- Sort "%idsFile%" in ascending numerical order -- Do not use without a real reason (it may take up to several seconds... probably not a big deal...) -============================================================================================================== ++------------------------------------------------------------------------------------------------------+ +| SORT_IDS_FILE | ++------------------------------------------------------------------------------------------------------+ +| Sort "%idsFile%" in ascending numerical order | +| - Do not use without a real reason (it may take up to several seconds... probably not a big deal...) | ++------------------------------------------------------------------------------------------------------+ */ DEFINE_DIMORPHIC_FUNCTION "SORT_IDS_FILE" From b3823d9ddc3600f422e65b1ad78fbbbd1145f7e0 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:40:17 +0100 Subject: [PATCH 30/33] Update misc.tph --- cdtweaks/luke/misc.tph | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index 815d946b..4efbc111 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -480,7 +480,7 @@ BEGIN FAIL "GT_ADD_SPELL: invalid spell type (%type%)" END // - ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%preferredSlot%.spl") BEGIN + ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%preferredSlot% ") BEGIN APPEND "GTSPELL.IDS" "%type%%level%%preferredSlot% %idsName%" OUTER_TEXT_SPRINT "resName" "%prefix%%level%%preferredSlot%" END ELSE BEGIN @@ -488,7 +488,7 @@ BEGIN ACTION_IF (STRING_LENGTH "%i%" == 1) BEGIN OUTER_TEXT_SPRINT "i" "0%i%" END - ACTION_IF !(FILE_EXISTS_IN_GAME "%prefix%%level%%i%.spl") BEGIN + ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%i% ") BEGIN APPEND "GTSPELL.IDS" "%type%%level%%i% %idsName%" OUTER_TEXT_SPRINT "resName" "%prefix%%level%%i%" OUTER_SET "i" = "%max%" // kill FOR-loop From a82c955439c79f4251610bcc3a2a93d7a36a5c3c Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 11:42:08 +0100 Subject: [PATCH 31/33] Update misc.tph --- cdtweaks/luke/misc.tph | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdtweaks/luke/misc.tph b/cdtweaks/luke/misc.tph index 4efbc111..ba9b1fab 100644 --- a/cdtweaks/luke/misc.tph +++ b/cdtweaks/luke/misc.tph @@ -480,7 +480,7 @@ BEGIN FAIL "GT_ADD_SPELL: invalid spell type (%type%)" END // - ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%preferredSlot% ") BEGIN + ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%preferredSlot%[ %TAB%]+") BEGIN APPEND "GTSPELL.IDS" "%type%%level%%preferredSlot% %idsName%" OUTER_TEXT_SPRINT "resName" "%prefix%%level%%preferredSlot%" END ELSE BEGIN @@ -488,7 +488,7 @@ BEGIN ACTION_IF (STRING_LENGTH "%i%" == 1) BEGIN OUTER_TEXT_SPRINT "i" "0%i%" END - ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%i% ") BEGIN + ACTION_IF !(RESOURCE_CONTAINS "gtspell.ids" "^%type%%level%%i%[ %TAB%]+") BEGIN APPEND "GTSPELL.IDS" "%type%%level%%i% %idsName%" OUTER_TEXT_SPRINT "resName" "%prefix%%level%%i%" OUTER_SET "i" = "%max%" // kill FOR-loop From afd12299a799406e0938e9ebf4b3978ac12adf85 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 12:05:10 +0100 Subject: [PATCH 32/33] Update weidu.tra --- cdtweaks/languages/english/weidu.tra | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/languages/english/weidu.tra b/cdtweaks/languages/english/weidu.tra index ec251b16..696d49c6 100644 --- a/cdtweaks/languages/english/weidu.tra +++ b/cdtweaks/languages/english/weidu.tra @@ -812,4 +812,4 @@ Use Baldur.lua options: a7_interval_ini /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -@600000 = "Disarm class feat for Rogues [Luke]" \ No newline at end of file +@600000 = "Disarm class feat for Rogues [Luke (EEex)]" \ No newline at end of file From 7e10c52ef4c617c359be31c68c7c4c40dab7afc6 Mon Sep 17 00:00:00 2001 From: 4Luke4 Date: Fri, 17 Jan 2025 12:05:12 +0100 Subject: [PATCH 33/33] Update weidu.tra --- cdtweaks/languages/italian/weidu.tra | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdtweaks/languages/italian/weidu.tra b/cdtweaks/languages/italian/weidu.tra index 03d5c388..ee127463 100644 --- a/cdtweaks/languages/italian/weidu.tra +++ b/cdtweaks/languages/italian/weidu.tra @@ -728,4 +728,4 @@ Usa opzioni di Baldur.lua: a7_interval_ini /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ /////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ -@600000 = "Aggiungi talento di classe Disarmare per i Ladri [Luke]" +@600000 = "Aggiungi talento di classe Disarmare per i Ladri [Luke (EEex)]"