[Mod][Utility] DeathHooks

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:

image

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"
2 Likes

I’m curious about what it can do. Can you add another download link? For example:

or

Size of Archive: 1.01MB?
You can compress it into a zip file and upload it to this post. The forum supports uploading zip compressed files, with a maximum size of 4MB.

I have added an alternative mirror via MediaFire.

The archive is 10MB when zipped, which is greater than the forum’s upload limit. It’s 1MB when using 7zip, available at https://7-zip.org/.

Edit: Does Dropbox not work for you? It should download automatically (without even taking you to the site). Please let me know, as I’ve hosted all of my mods there.

Yes, I can’t access that website without a VPN here. Thank you for the additional link.

Additionally, if you change the extension from .7z to .zip, can deceive the forum’s restrictions on normal uploads. :wink:

1 Like

Good to know. I’ll be sure to work on migrating my mods elsewhere in that case, thank you.

As to the extension thing, that seems like more trouble than it’s worth explaining it to people. :crazy_face:

DeathHooks.zip (1.0 MB)
No need to explain separately, it is no different from general extraction, you can test it.

7zip can, but by default Windows will get confused by it, which will in turn confuse end-users.

image

Uh, maybe because WinRAR is also installed on my computer.