Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defensive Roll #76

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions cdtweaks/languages/english/defensive_roll.tra
@@ -0,0 +1 @@
@0 = "Defensive Roll : The character takes only half damage from the blow"
2 changes: 2 additions & 0 deletions cdtweaks/languages/english/weidu.tra
Expand Up @@ -456,6 +456,8 @@ The uninstall messages above are normal and expected.

@267000 = "Dual-Wield feat for Rangers [Luke]"

@270000 = "Defensive Roll feat for Thieves [Luke]"

/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
///// \\\\\
Expand Down
1 change: 1 addition & 0 deletions cdtweaks/languages/italian/defensive_roll.tra
@@ -0,0 +1 @@
@0 = "Tiro Difensivo : Il personaggio subisce solo la metà dei danni inflitti dal colpo"
2 changes: 2 additions & 0 deletions cdtweaks/languages/italian/weidu.tra
Expand Up @@ -409,6 +409,8 @@ o rimpiazzata da - un'altra facente parte di uno dei mods installati.~
// @257000 = ~BGT: Limite di esperienza aggiuntivo mentre sei in BG~
// @257100 = ~BGT: Limite di esperienza aggiuntivo in SoA~

@270000 = "Aggiungi talento Tiro Difensivo per i ladri [Luke]"

/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
///// \\\\\
Expand Down
15 changes: 15 additions & 0 deletions cdtweaks/lib/comp_2700.tpa
@@ -0,0 +1,15 @@
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
///// \\\\\
///// Defensive Roll feat for Thieves \\\\\
///// \\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\

WITH_SCOPE BEGIN
INCLUDE "cdtweaks\luke\misc.tph"
INCLUDE "cdtweaks\lib\defensive_roll.tph"
WITH_TRA "cdtweaks\languages\english\defensive_roll.tra" "cdtweaks\languages\%LANGUAGE%\defensive_roll.tra" BEGIN
LAF "DEFENSIVE_ROLL" END
END
END
32 changes: 32 additions & 0 deletions cdtweaks/lib/defensive_roll.tph
@@ -0,0 +1,32 @@
DEFINE_ACTION_FUNCTION "DEFENSIVE_ROLL"
BEGIN
<<<<<<<< .../cdtweaks-inlined/empty
>>>>>>>>
//
WITH_SCOPE BEGIN
ACTION_IF !(FILE_EXISTS_IN_GAME "m_gt#403.lua") BEGIN
COPY ".../cdtweaks-inlined/empty" "override\m_gt#403.lua"
DELETE_BYTES 0x0 BUFFER_LENGTH
INSERT_BYTES 0x0 STRING_LENGTH "-- Functions to be invoked via op403 --%WNL%%WNL%"
WRITE_ASCII 0x0 "-- Functions to be invoked via op403 --%WNL%%WNL%"
BUT_ONLY_IF_IT_CHANGES
END
COPY_EXISTING "m_gt#403.lua" "override"
SET "feedback_strref" = RESOLVE_STR_REF (@0)
APPEND_FILE_EVALUATE TEXT "cdtweaks\luke\lua\defensive_roll.lua"
BUT_ONLY UNLESS "^function GTDEFRLL"
// Listener: run 'func' each time a sprite has finished evaluating its effects
ACTION_IF !(FILE_EXISTS_IN_GAME "m_gtlstn.lua") BEGIN
COPY ".../cdtweaks-inlined/empty" "override\m_gtlstn.lua"
DELETE_BYTES 0x0 BUFFER_LENGTH
INSERT_BYTES 0x0 STRING_LENGTH "-- Listeners --%WNL%%WNL%"
WRITE_ASCII 0x0 "-- Listeners --%WNL%%WNL%"
BUT_ONLY_IF_IT_CHANGES
END
COPY_EXISTING "m_gtlstn.lua" "override"
APPEND_FILE TEXT "cdtweaks\luke\lua\defensive_roll_apply.lua"
BUT_ONLY UNLESS "cdtweaksDefensiveRoll"
END
//
LAF "ADD_EXTENDED_STAT" STR_VAR "identifier" = "CDTWEAKS_DEFENSIVE_ROLL" END
END
44 changes: 44 additions & 0 deletions cdtweaks/luke/lua/defensive_roll.lua
@@ -0,0 +1,44 @@
-- cdtweaks: Defensive Roll feat for rogues --

function GTDEFRLL(op403CGameEffect, CGameEffect, CGameSprite)
local damageTypeStr = GT_Resource_IDSToSymbol["dmgtype"][CGameEffect.m_dWFlags]
local damageAmount = CGameEffect.m_effectAmount
--
local spriteHP = CGameSprite.m_baseStats.m_hitPoints
--
local spriteState = CGameSprite.m_derivedStats.m_generalState + CGameSprite.m_bonusStats.m_generalState
local state = GT_Resource_SymbolToIDS["state"]
--
local stats = GT_Resource_SymbolToIDS["stats"]
--
local spriteSaveVSBreath = CGameSprite.m_derivedStats.m_nSaveVSBreath + CGameSprite.m_bonusStats.m_nSaveVSBreath
--
local roll = Infinity_RandomNumber(1, 20) -- 1d20
-- If the character is struck by a potentially lethal blow, he makes a save vs. breath. If successful, he takes only half damage from the blow.
if CGameEffect.m_effectId == 0xC and damageTypeStr ~= "STUNNING" and CGameEffect.m_slotNum == -1 and CGameEffect.m_sourceType == 0 and CGameEffect.m_sourceRes:get() == "" -- base weapon damage (all damage types but STUNNING)
and EEex_BAnd(spriteState, state["CD_STATE_NOTVALID"]) == 0
and spriteSaveVSBreath <= roll
and damageAmount >= spriteHP
and EEex_Sprite_GetStat(CGameSprite, stats["CDTWEAKS_DEFENSIVE_ROLL"]) == 0
then
CGameEffect.m_effectAmount = math.floor(damageAmount / 2)
EEex_GameObject_ApplyEffect(CGameSprite,
{
["effectID"] = 139, -- Display string
["durationType"] = 1,
["effectAmount"] = %feedback_strref%,
["sourceID"] = op403CGameEffect.m_sourceId, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it...
["sourceTarget"] = op403CGameEffect.m_sourceTarget, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it...
})
EEex_GameObject_ApplyEffect(CGameSprite,
{
["effectID"] = 401, -- Set extended stat
["duration"] = 7200,
["special"] = stats["CDTWEAKS_DEFENSIVE_ROLL"],
["dwFlags"] = 1, -- set
["effectAmount"] = 1,
["sourceID"] = op403CGameEffect.m_sourceId, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it...
["sourceTarget"] = op403CGameEffect.m_sourceTarget, -- Certain opcodes (see f.i. op326) use this field internally... it's probably a good idea to always specify it...
})
end
end
89 changes: 89 additions & 0 deletions cdtweaks/luke/lua/defensive_roll_apply.lua
@@ -0,0 +1,89 @@
-- cdtweaks: NWN Defensive Roll feat for Rogues --

EEex_Opcode_AddListsResolvedListener(function(sprite)
-- internal function that applies the actual feat
local apply = function()
-- Mark the creature as 'feat applied'
sprite:setLocalInt("cdtweaksDefensiveRoll", 1)
--
sprite:applyEffect({
["effectID"] = 321, -- Remove effects by resource
["durationType"] = 1,
["res"] = "CDDEFRLL",
["sourceID"] = sprite.m_id,
["sourceTarget"] = sprite.m_id,
})
sprite:applyEffect({
["effectID"] = 403, -- Screen effects
["durationType"] = 9,
["res"] = "GTDEFRLL",
["m_sourceRes"] = "CDDEFRLL",
["sourceID"] = sprite.m_id,
["sourceTarget"] = sprite.m_id,
})
end
-- Check creature's class / kit / flags / levels
local spriteClassStr = GT_Resource_IDSToSymbol["class"][sprite.m_typeAI.m_Class]
--
local spriteKitStr = GT_Resource_IDSToSymbol["kit"][EEex_BOr(EEex_LShift(sprite.m_baseStats.m_mageSpecUpperWord, 16), sprite.m_baseStats.m_mageSpecialization)]
--
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 spriteLevel3 = sprite.m_derivedStats.m_nLevel3
-- KIT == SHADOWDANCER => Level 5+ ; KIT != SHADOWDANCER => Level 10+
local applyAbility = false
if spriteKitStr == "SHADOWDANCER" then
if spriteClassStr == "THIEF" then
if spriteLevel1 >= 5 then
applyAbility = true
end
elseif spriteClassStr == "FIGHTER_THIEF" or spriteClassStr == "MAGE_THIEF" or spriteClassStr == "CLERIC_THIEF" then
-- incomplete dual-class characters are not supposed to benefit from this feat
if (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2) and spriteLevel2 >= 5 then
applyAbility = true
end
elseif spriteClassStr = "FIGHTER_MAGE_THIEF" then
if spriteLevel3 >= 5 then
applyAbility = true
end
end
else
if spriteClassStr == "THIEF" then
if spriteLevel1 >= 10 then
applyAbility = true
end
elseif spriteClassStr == "FIGHTER_THIEF" or spriteClassStr == "MAGE_THIEF" or spriteClassStr == "CLERIC_THIEF" then
-- incomplete dual-class characters are not supposed to benefit from this feat
if (EEex_IsBitUnset(spriteFlags, 0x6) or spriteLevel1 > spriteLevel2) and spriteLevel2 >= 10 then
applyAbility = true
end
elseif spriteClassStr = "FIGHTER_MAGE_THIEF" then
if spriteLevel3 >= 10 then
applyAbility = true
end
end
end
--
if sprite:getLocalInt("cdtweaksDefensiveRoll") == 0 then
if applyAbility then
apply()
end
else
if applyAbility then
-- do nothing
else
-- Mark the creature as 'feat removed'
sprite:setLocalInt("cdtweaksDefensiveRoll", 0)
--
sprite:applyEffect({
["effectID"] = 321, -- Remove effects by resource
["durationType"] = 1,
["res"] = "CDDEFRLL",
["sourceID"] = sprite.m_id,
["sourceTarget"] = sprite.m_id,
})
end
end
end)
88 changes: 88 additions & 0 deletions cdtweaks/luke/misc.tph
Expand Up @@ -187,6 +187,7 @@ BEGIN

END

////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\
// Get the clab files of all kits whose base class is "%class%" \\
////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\

Expand Down Expand Up @@ -221,4 +222,91 @@ BEGIN
END
BUT_ONLY

END

////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\
// Add the specified ability to the current clab file \\
////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\////\\\\

DEFINE_PATCH_FUNCTION "ADD_CLAB_ABILITY"
INT_VAR
"level" = 1
STR_VAR
"type" = "ap" // default: passive ability
"resref" = ""
"identifier" = "GT_EXAMPLE"
BEGIN
// Sanity checks
PATCH_IF ("%level%" <= 0) BEGIN
PATCH_FAIL "ADD_CLAB_ABILITY: level must be strictly greater than 0"
END
PATCH_IF ("%resref%" STRING_EQUAL_CASE "") BEGIN
PATCH_FAIL "ADD_CLAB_ABILITY: resref cannot be empty"
END
//
TO_UPPER "type"
TO_UPPER "resref"
TO_UPPER "identifier"
// Main
TEXT_SPRINT "string" "%identifier%"
FOR ("i" = 1 ; "%i%" <= "%level%" ; "i" += 1) BEGIN
PATCH_IF ("%i%" == "%level%") BEGIN
TEXT_SPRINT "string" "%string% %type%_%resref%"
END ELSE BEGIN
TEXT_SPRINT "string" "%string% ****"
END
END
COUNT_2DA_COLS "cols"
FOR ("i" = "%level%" ; "%i%" < "%cols%" - 1 ; "i" += 1) BEGIN
TEXT_SPRINT "string" "%string% ****"
END
// Add row
COUNT_2DA_ROWS "%cols%" "rows"
INSERT_2DA_ROW "%rows%" "%cols%" "%string%"
// formatting
PRETTY_PRINT_2DA
END

/*
=====================================================================================================
**ADD_EXTENDED_STAT**
- For use with EEex (https://eeex-docs.readthedocs.io/en/latest/EEex%20Opcodes/index.html#opcode-401)
=====================================================================================================
*/

DEFINE_DIMORPHIC_FUNCTION "ADD_EXTENDED_STAT"
INT_VAR
"min" = 0 // for use in "x-stats.2da"
"max" = 1 // for use in "x-stats.2da"
"default" = 0 // for use in "x-stats.2da"
STR_VAR
"identifier" = "" // for use in "stats.ids"
RET
"value"
BEGIN
OUTER_SET "value" = IDS_OF_SYMBOL ("stats" "%identifier%")
//
ACTION_IF ("%value%" == "-1") BEGIN
OUTER_PATCH ~~ BEGIN
FOR ("id" = 203 ; "%id%" <= 0xFFFF + 202 ; "id" += 1) BEGIN
LOOKUP_IDS_SYMBOL_OF_INT "symbol" ~stats~ "%id%"
PATCH_IF (~%symbol%~ STRING_EQUAL ~%id%~) BEGIN
SET "value" = "%id%"
SET "id" = 0xFFFF + 202 + 1 // Kill FOR-loop
END
END
END
//
ACTION_IF ("%value%" != "-1") BEGIN
APPEND "stats.ids" "%value% %identifier%"
//
APPEND "x-stats.2da" "%identifier% %min% %max% %default%"
// Formatting
COPY_EXISTING "x-stats.2da" "override"
PRETTY_PRINT_2DA
BUT_ONLY
END ELSE BEGIN
FAIL "ADD_EXTENDED_STAT: there's no room in ~stats.ids~ for appending ~%identifier%~"
END
END
END
12 changes: 12 additions & 0 deletions cdtweaks/readme-cdtweaks.html
Expand Up @@ -1001,6 +1001,18 @@ <h3> <a id="contents_rules" name="contents_rules"></a>Rule Changes </h3>
<p> <strong>Dual-Wield feat for Rangers [Luke]</strong><br />
<em><abbr title="Enhanced Edition">EEex</abbr></em></p>
<p> This component simply forces Rangers to wield light armors (or no armor) in order to benefit from Two-Weapon Fighting.</p>

<p> <strong>Defensive Roll feat for Thieves [Luke]</strong><br />
<em><abbr title="Enhanced Edition">EEex</abbr></em></p>
<p> This component aims at implementing the NWN feat Defensive Roll. As a result, after installing it, if the character is struck by a potentially lethal blow, he makes a Save vs. Breath. If successful, he takes only half damage from the blow.<br>
Notes:
<ul>
<li>This feat is only available to thieves (level 10) and Shadowdancers (level 5).</li>
<li>A "potentially lethal blow" refers to a standard attack with a weapon that would, if not for this feat, reduce the target below one hit point with just its physical damage.</li>
<li>Use: automatic, but limited to one use per day. Incapacitated characters cannot make a defensive roll.</li>
</ul>
</p>

</div>
<div class="ribbon_rectangle_h3">
<h3> <a id="contents_convenience" name="contents_convenience"></a>Convenience Tweaks and/or Cheats </h3>
Expand Down
14 changes: 14 additions & 0 deletions cdtweaks/setup-cdtweaks.tp2
Expand Up @@ -2764,6 +2764,20 @@ REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29
REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/dual_wield.tra~ @7
LABEL ~cd_tweaks_dual_wield~

/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
///// \\\\\
///// Defensive Roll feat for Thieves \\\\\
///// \\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\

BEGIN @270000 DESIGNATED 2700
GROUP @9
REQUIRE_PREDICATE MOD_IS_INSTALLED ~EEex.tp2~ 0 @29
REQUIRE_PREDICATE FILE_EXISTS ~cdtweaks/languages/%LANGUAGE%/defensive_roll.tra~ @7
LABEL ~cd_tweaks_defensive_roll~

/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\
///// \\\\\
Expand Down