Edit: Thanks to Danukem for the info above as well! I was writing this while they posted. As I understand, EVENT_GAME is an eDuke addition, correct? I'm trying to override hardcoded behavior in vanilla Duke.
To answer my own questions after looking thru some Duke3D source code, a whole bunch of actors ARE hardcoded in various places in the EXE, and it IS possible to assign custom code to them in game.con (instead of the hardcoded stuff) but it's quite annoying - there aren't any lookup tables for these but rather huge switch statements scattered thoughout. So it's either recompiling the source or hex editing some x86 machine code. I went with the latter and here's an example of how I got toilets to execute custom breaking code in game.con:
As above, I added
useractor notenemy TOILET WEAK state breakobject enda
to my game.con where the breakobject state has some code that I want destroying the toilet to execute. This is normally ignored by the game in favor of a hardcoded sequence - I want to patch this hardcoded sequence out.
Two switch statements are responsible for giving TOILET actor hardcoded behavior:
- GAME.C \ spawn() : Assigns specific tags to the actor. If not patched out, actor is not interactive except thru hardcoded sequences.
- SECTOR.C \ checkhitsprite(): The hardcoded sequence itself. If not patched out, overrides any game.con code.
In DUKE3D.EXE v1.5:
spawn() switching code is somewhere around 0x7e800-0x7f000
checkhitsprite() switching code is somewhere around 0xc2000-0xc2800
In these blocks, we want to look for a comparison opcode followed by the ID of the actor we're interested in. TOILET is sprite #569, or 0x239. So we look for hex 66 3D 39 02 and change it to 66 3D FF FF (now the switch statement is looking for sprite with ID -1 instead of the TOILET). Do this for both functions, and toilets now execute game.con code when broken!
Hopefully someone finds this haxx useful!