As shown by the bug in some mods concerning MAP07 and the lack of response on the specific topic I created to fix it for Duke Nukem: War Against the Doomed, it feels like there's no widespread solution to the problem. Having just solved it, without adding any ZScript (which should make the solution Zandronum-compatible), I figured I may as well share it with you guys, as well as going into the technicals (although most of you will be able to figure it out).
So, the replacer code for the Mancubus in the DN mod was originally this :
Code: Select all
Actor FatsoReplacer Replaces Fatso
{
States
{
Spawn:
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==1, "Doomy")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==2, "Nazis")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==3, "Aliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==4, "All")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==5, "DoomNazis")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==6, "DoomAliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==7, "NazisAliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==1, "Doomy")
Stop
Doomy:
TNT1 A 0 A_SpawnItemEX("Fatso1",0,0,0,0,0,0)
Stop
Nazis:
TNT1 A 0 A_SpawnItemEX("SuperSoldierSpawner",0,0,0,0,0,0)
Stop
Aliens:
TNT1 A 0 A_SpawnItemEX("FatCommander",0,0,0,0,0,0)
Stop
DoomNazis:
TNT1 A 0 A_SpawnItemEX("Fatso1Nazis",0,0,0,0,0,0)
Stop
DoomAliens:
TNT1 A 0 A_SpawnItemEX("Fatso1Aliens",0,0,0,0,0,0)
Stop
NazisAliens:
TNT1 A 0 A_SpawnItemEX("Fatso1NazisAliens",0,0,0,0,0,0)
Stop
All:
TNT1 A 0 A_SpawnItemEX("Fatso1All",0,0,0,0,0,0)
Stop
}
}
As stated in my previous topic, the problem here is that the hardcoded tag 666 expects the Mancubus actors to die, but, having delved a bit in the source code, I discovered it does not expect the actors that extend Mancubus to die, but either fatso or anything that REPLACES fatso. The obvious issue with this code, is that the replacer is not a monster, and will never be considered dead in any possible way. Actually, it will even be deleted as soon as reaching any Stop keyword, since the duration of all frames before stop is not -1 !
Through trial and error, I found a way to make this actor killable, and actually be killed by the spawned monster on death, without having it affect the gameplay in any way. The new code is as follow :
Code: Select all
Actor FatsoReplacer Replaces Fatso
{
Monster
-SOLID
+BOSSDEATH
+INVULNERABLE
States
{
Death:
TNT1 A 0 A_BossDeath
Stop
XDeath:
TNT1 A 0 A_BossDeath
Stop
Spawn:
TNT1 A 0 A_NoBlocking
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==1, "Doomy")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==2, "Nazis")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==3, "Aliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==4, "All")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==5, "DoomNazis")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==6, "DoomAliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==7, "NazisAliens")
TNT1 A 0 A_JumpIf(CallACS("callmonsterz")==1, "Doomy")
Goto Death
Doomy:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("Fatso1",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
Nazis:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("SuperSoldierSpawner",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
Aliens:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("FatCommander",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
DoomNazis:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("Fatso1Nazis",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
DoomAliens:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("Fatso1Aliens",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
NazisAliens:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("Fatso1NazisAliens",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
All:
TNT1 A -1 A_JumpIf(!A_SpawnItemEX("Fatso1All",0,0,0,0,0,0,0,SXF_SETMASTER|
SXF_TRANSFERAMBUSHFLAG|SXF_TRANSFERSPECIAL|SXF_CLEARCALLERSPECIAL|
SXF_CLEARCALLERTID,0,tid), "Death")
Stop
}
}
-I added the combo Monster, because anything that's not considered a monster by the game cannot be killed by the A_KillMaster/A_KillChildren directives, so this actor needs to be considered a monster
-I remove the SOLID flag to prevent the player colliding with it (although A_NoBlocking on spawn later is probably enough, if you really want to make your code clean)
-I add the BOSSDEATH flag because it will need to send A_BossDeath signals to alert ZDoom of its death to trigger tag 666 sectors
-I add the INVULNERABLE flag to prevent any possible problems (weapons doing funny stuff that may kill the actor even though it has no physical anchor, we never know)
-I add a Death and XDeath state to properly send A_BossDeath signals
-A_SpawnItemEX gets some extra attributes, namely the flags :
-SXF_SETMASTER : To allow the children to kill its master, the replacer
-SXF_TRANSFERAMBUSHFLAG : To prevent breaking map design behaviours
-SXF_TRANSFERSPECIAL and SXF_CLEARCALLERSPECIAL : To give potential special behaviours to the spawned monster and prevent it to trigger on the replacer
-SXF_CLEARCALLERTID : To prevent any TID-linked event to trigger on the replacer
Then I also added tid at the end to transfer the tid (this is to make any map specific ACS that would trigger events based on TID work properly)
-As a failsafe I embedded A_SpawnItemEX in an A_JumpIf that makes the replacer instantly jump to the Death state if the spawn fails (note I also added such failsafe at the end of the Spawn state, but it's specific to the way the replacer works in DN obviously)
As a result though, monsters must be changed too. In their Death and XDeath state, their second to last frame MUST call
Code: Select all
A_KillMaster("None", KILS_FOILINVUL)
I think most enemy trigger problems would be solved with this solution too, if the enemy in question uses a Decorate Replacer. Mind you, the solution works with RandomSpawner, since RandomSpawner transfers everything to the dropped item, including the master.
I probably went a little in detail for some of the better DECORATE coder, but I think it's useful for those who are a bit less at ease with it and would want to use this in their own mod.
Thanks for reading, tell me what you think, don't hesitate to critique the code, enhance it, optimize it, as I am again no DECORATE expert.
Edit : Typos
Edit 2 : It seems QCDE solves this with some ACS, which is much cleaner, although I don't know how exactly ! So as it shows, this is just one solution amongst others.