Download Link
Alternative Mirror
Size of Archive: 1.01MB
Size of Extracted Archive: 68.6MB
DeathHooks
Loosely inspired by the inner workings of @Serious_Stan 's Infinity Chaser mod, DeathHooks is a utility mod one can use to set up similar on-monster-killed effects. By default, DeathHooks changes nothing about vanilla gameplay whatsoever. This is purely a modding baseline from which one can create further mods as needed.
Of course, DeathHooks is open source. Use however you like, though I’d appreciate a holler if you do make use of it!
Under the Hood
DeathHooks attaches an onDie script trigger to almost every enemy in the game:
Exceptions include summoned enemies, enemies spawned in SR, ‘special’ enemies (e.g., Secret Quests), and enemies spawned via waveevents (e.g., the Burrwitch Riftgate spawns).
Most of these scripts, by default, just have a simple print statement which logs the successful trigger of the script in the modding console window.
However, for those enemies that already have a script that would have been triggered in vanilla Grim Dawn, those script calls are preserved in the DeathHooks.lua script so as to preserve vanilla functionality as follows:
function gd.DeathHooks.miltonhart(objectID)
print("gd.DeathHooks.miltonhart")
end
function gd.DeathHooks.mummy_osyr(objectID)
gd.quests.areaGMiscEncounters.mummyOsyrOnKill(objectID)
end
function gd.DeathHooks.obsidiandefiler_chthonicvoid01(objectID)
gd.quests.areaDQuestBaneOfCairn.obsidianThroneBossKilled(objectID)
end
The intent here is to provide a simple and extensible framework to trigger anything needed from scripts on killing any monster without needing to manually import monsters and connect scripts to them by hand.
How DeathHooks Was Made
DeathHooks was generated automatically via the following Python code:
import os
import ModPaths as mp
def dh_attach_script_name(path, name):
scr = ""
with open(path, "r") as fn:
lines = fn.readlines()
for line in lines:
if "onDie,," in line: # no pre-existing script
scr = f"gd.DeathHooks.{name}"
lines = [l.replace(line, f"onDie,{scr},") for l in lines]
elif "onDie," in line: # script exists
scr = line.split(",")[-2]
lines = [l.replace(line, f"onDie,gd.DeathHooks.{name},\n") for l in lines]
if not scr: # never encountered onDie line -> empty pre-pruning, got pruned
scr = f"gd.DeathHooks.{name}"
lines.append(f"onDie,{scr},\n")
lines = sorted(lines)
init = path.replace(mp.GD_DBR, mp.DH_DBR)
os.makedirs(os.path.dirname(init), exist_ok=True)
with open(init, "w") as fn:
fn.write("".join(lines))
return scr
def dh_write_script(old, new):
script = mp.DH_LUA_TEMPLATE
if old == new:
script = script.replace("NAME", old)
script = script.replace("INSERT", 'print("' + new + '")')
else:
script = script.replace("NAME", new)
script = script.replace("INSERT", f"{old}(objectID)")
with open(mp.DH_SCRIPT_PATH, "a") as fn:
fn.write(script)
def dh_master():
files = [
(root, name)
for root, dirs, files in os.walk(mp.GD_ENEMIES)
for name in files
if (
name.endswith(".dbr")
and not any(xr in root for xr in ["special", "waveevents"])
and not any(xn in name for xn in ["anm_", "bio_", "summon"])
)
]
with open(mp.DH_SCRIPT_PATH, "w") as fn:
fn.write(
mp.DH_LUA_OPEN
) # ensure we reset the script file before appending a ton of scripts to it.
for file in files:
fn = file[1].replace(".dbr", "")
scr_name = dh_attach_script_name("\\".join(file), fn)
dh_write_script(scr_name, f"gd.DeathHooks.{fn}")
class DeathHooks:
def __init__(self):
print("DeathHooks Loaded")
This code assumes a ‘ModPaths.py’ file exists which enumerates a number of specific modding paths, and that GDX1/GDX2 DBR files have been merged with vanilla GD DBR files.
# ModPaths.py excerpt
# ...
DH_SCRIPT_PATH = DH_PATH + r"\source\Scripts\Game\DeathHooks\deathhooks.lua"
# recommended to use Util.prune_and_merge_master() prior to utilizing any of the below
GD_ENEMIES = GD_DBR + r"\creatures\enemies"
# not a path, is a lua script template
DH_LUA_OPEN = "gd.DeathHooks = {}\n\n"
DH_LUA_TEMPLATE = "NAME(objectID)\n\tINSERT\nend\n\n"