diff --git a/language.version b/language.version index 558d62de6..97b5e908d 100644 --- a/language.version +++ b/language.version @@ -1,2 +1,2 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r602 \cu(Wed 4 Nov 20:50:09 CET 2020)"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r603 \cu(Wed 4 Nov 22:47:48 CET 2020)"; diff --git a/zmapinfo.txt b/zmapinfo.txt index d0bacd6bb..f7449bb12 100644 --- a/zmapinfo.txt +++ b/zmapinfo.txt @@ -1,6 +1,6 @@ GameInfo { - AddEventHandlers = "SWWMCrashHandler", "SWWMBrutalHandler", "SWWMHDoomHandler", "SWWMVanillaBossHandler", "SWWMHandler", "SWWMGoreHandler", "CBTHandler", "SWWMPreloader", "SWWMReadThisHijacker" + AddEventHandlers = "SWWMStaticHandler", "SWWMHandler", "SWWMBrutalHandler", "SWWMHDoomHandler", "SWWMVanillaBossHandler" PlayerClasses = "Demolitionist" StatusBarClass = "SWWMStatusBar" BackpackType = "HammerspaceEmbiggener" diff --git a/zscript/swwm_blod.zsc b/zscript/swwm_blod.zsc index 9c06a87d9..ac865edf7 100644 --- a/zscript/swwm_blod.zsc +++ b/zscript/swwm_blod.zsc @@ -313,14 +313,14 @@ Class mkBloodDrop : Actor override void PostBeginPlay() { Super.PostBeginPlay(); - SWWMGoreHandler.QueueBlod(self); + SWWMHandler.QueueBlod(self); int jumps = Random[Blood](0,3); state dest = ResolveState("Spawn"); SetState(dest+jumps); } override void OnDestroy() { - SWWMGoreHandler.DeQueueBlod(self); + SWWMHandler.DeQueueBlod(self); Super.OnDestroy(); } States @@ -413,12 +413,12 @@ Class mkFlyingGib : Actor else shadecol = Color(80,0,0); bleeding = true; if ( Random[Blood](0,1) ) bXFlip = true; - SWWMGoreHandler.QueueMeat(self); + SWWMHandler.QueueMeat(self); } override void OnDestroy() { - SWWMGoreHandler.DeQueueMeat(self); + SWWMHandler.DeQueueMeat(self); Super.OnDestroy(); } @@ -737,205 +737,3 @@ Class CorpseFallTracker : Thinker Destroy(); } } - -Class SWWMGoreHandler : EventHandler -{ - mkBloodDrop blods, blods_end; - int blods_cnt, oldmaxblood; - mkFlyingGib meats, meats_end; - int meats_cnt, oldmaxgibs; - - override void WorldLoaded( WorldEvent e ) - { - // recheck queues in case limits changed - while ( blods && (blods_cnt > swwm_maxblood) ) - DeQueueBlod(blods); - while ( meats && (meats_cnt > swwm_maxgibs) ) - DeQueueMeat(meats); - } - - static void QueueBlod( mkBloodDrop b ) - { - let hnd = SWWMGoreHandler(EventHandler.Find("SWWMGoreHandler")); - if ( !hnd ) return; - hnd.blods_cnt++; - if ( !hnd.blods ) - { - // this is the initial one - hnd.blods = b; - hnd.blods_end = b; - } - else - { - hnd.blods_end.nextblod = b; - b.prevblod = hnd.blods_end; - hnd.blods_end = b; - } - while ( hnd.blods && (swwm_maxblood >= 0) && (hnd.blods_cnt > swwm_maxblood) ) - DeQueueBlod(hnd.blods); - } - static void DeQueueBlod( mkBloodDrop b ) - { - let hnd = SWWMGoreHandler(EventHandler.Find("SWWMGoreHandler")); - if ( !hnd || !hnd.blods ) return; - if ( (hnd.blods != b) && !b.prevblod && !b.nextblod ) return; - hnd.blods_cnt--; - if ( !b.prevblod ) hnd.blods = b.nextblod; - else b.prevblod.nextblod = b.nextblod; - if ( b == hnd.blods_end ) hnd.blods_end = b.prevblod; - if ( b.nextblod ) b.nextblod.prevblod = b.prevblod; - b.killme = true; - b.prevblod = null; - b.nextblod = null; - } - static void QueueMeat( mkFlyingGib m ) - { - let hnd = SWWMGoreHandler(EventHandler.Find("SWWMGoreHandler")); - if ( !hnd ) return; - hnd.meats_cnt++; - if ( !hnd.meats ) - { - // this is the initial one - hnd.meats = m; - hnd.meats_end = m; - } - else - { - hnd.meats_end.nextmeat = m; - m.prevmeat = hnd.meats_end; - hnd.meats_end = m; - } - while ( hnd.meats && (swwm_maxgibs >= 0) && (hnd.meats_cnt > swwm_maxgibs) ) - DeQueueMeat(hnd.meats); - } - static void DeQueueMeat( mkFlyingGib m ) - { - let hnd = SWWMGoreHandler(EventHandler.Find("SWWMGoreHandler")); - if ( !hnd || !hnd.meats ) return; - if ( (hnd.meats != m) && !m.prevmeat && !m.nextmeat ) return; - hnd.meats_cnt--; - if ( !m.prevmeat ) hnd.meats = m.nextmeat; - else m.prevmeat.nextmeat = m.nextmeat; - if ( m == hnd.meats_end ) hnd.meats_end = m.prevmeat; - if ( m.nextmeat ) m.nextmeat.prevmeat = m.prevmeat; - m.killme = true; - m.prevmeat = null; - m.nextmeat = null; - } - - override void WorldTick() - { - if ( swwm_maxblood != oldmaxblood ) - { - while ( blods && (swwm_maxblood >= 0) && (blods_cnt > swwm_maxblood) ) - DeQueueBlod(blods); - } - if ( swwm_maxgibs != oldmaxgibs ) - { - while ( meats && (swwm_maxgibs >= 0) && (meats_cnt > swwm_maxgibs) ) - DeQueueMeat(meats); - } - oldmaxblood = swwm_maxblood; - oldmaxgibs = swwm_maxgibs; - } - - override void CheckReplacement( ReplaceEvent e ) - { - // only replace vanilla blood if no other gore mod is doing it - if ( (e.Replacee == "Blood") && (!e.Replacement || e.Replacement == "Blood") && swwm_blood ) - e.Replacement = "mkBlood"; - } - - override void WorldThingSpawned( WorldEvent e ) - { - // vanilla blood color changes - if ( (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "Bishop") || (e.Thing.GetClass() == "Korax") ) - { - let gb = Actor.Spawn("GreenBloodReference"); - e.Thing.CopyBloodColor(gb); - gb.Destroy(); - } - else if ( e.Thing.GetClass() == "Cacodemon" ) - { - let bb = Actor.Spawn("BlueBloodReference"); - e.Thing.CopyBloodColor(bb); - bb.Destroy(); - } - else if ( (e.Thing.GetClass() == "Wizard") || (e.Thing.GetClass() == "Heresiarch") || (e.Thing.GetClass() == "Sorcerer2") ) - { - let pb = Actor.Spawn("PurpleBloodReference"); - e.Thing.CopyBloodColor(pb); - pb.Destroy(); - } - else if ( e.Thing.GetClass() == "LostSoul" ) - e.Thing.bNOBLOOD = true; - } - - override void WorldThingDied( WorldEvent e ) - { - // force insert gib animations on some vanilla Doom monsters - int gibhealth = e.Thing.GetGibHealth(); - bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH)); - if ( !gotgibbed ) return; - if ( (e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") ) - ExtraGibDeaths.GibThis(e.Thing,"DemonXDeath"); - else if ( e.Thing.GetClass() == "HellKnight" ) - ExtraGibDeaths.GibThis(e.Thing,"KnightXDeath"); - else if ( e.Thing.GetClass() == "BaronOfHell" ) - ExtraGibDeaths.GibThis(e.Thing,"BaronXDeath"); - else if ( e.Thing.GetClass() == "Cacodemon" ) - ExtraGibDeaths.GibThis(e.Thing,"CacoXDeath"); - else if ( e.Thing.GetClass() == "Revenant" ) - ExtraGibDeaths.GibThis(e.Thing,"BonerXDeath"); - else if ( e.Thing.GetClass() == "Archvile" ) - ExtraGibDeaths.GibThis(e.Thing,"VileXDeath"); - } - - override void WorldThingDamaged( WorldEvent e ) - { - if ( e.Thing.Health > 0 ) return; - // no gib if it was erased - if ( e.DamageType == 'Ynykron' ) return; - int gibhealth = e.Thing.GetGibHealth(); - bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH)); - bool forcegibbed = false; - // force gib availability for some vanilla Doom monsters - if ( gotgibbed && ((e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "Cacodemon") || (e.Thing.GetClass() == "Revenant") || (e.Thing.GetClass() == "Archvile")) ) - forcegibbed = true; - if ( !e.Thing.FindState("XDeath",true) && !e.Thing.FindState("Death.Extreme",true) && !forcegibbed ) - gotgibbed = false; - // only do special handling if they use our blood - if ( (e.Thing.GetBloodType(0) != "mkBlood") || e.Thing.bNOBLOOD ) - return; - CorpseFallTracker.TrackBody(e.Thing); - bool b; - Actor a; - // special handling of some monsters - if ( e.Thing.GetClass() == "Cyberdemon" ) - { - [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); - if ( !b ) return; - mkGibber(a).gibbed = e.Thing; - mkGibber(a).delay = 40; - a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); - return; - } - else if ( e.Thing.GetClass() == "SpiderMastermind" ) - { - [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); - if ( !b ) return; - mkGibber(a).gibbed = e.Thing; - mkGibber(a).delay = 60; - a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); - return; - } - // override gibbing - if ( gotgibbed ) - { - [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); - if ( !b ) return; - mkGibber(a).gibbed = e.Thing; - a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); - } - } -} diff --git a/zscript/swwm_cbt.zsc b/zscript/swwm_cbt.zsc index a4b7ec9f8..aae18522a 100644 --- a/zscript/swwm_cbt.zsc +++ b/zscript/swwm_cbt.zsc @@ -362,49 +362,6 @@ Class WallbusterReloadMenu : GenericMenu } } -Class CBTHandler : StaticEventHandler -{ - bool initme; - double cbtvol; - transient CVar cbtme; - - override void WorldTick() - { - if ( !cbtme ) cbtme = CVar.GetCVar('swwm_cbtmeme',players[consoleplayer]); - if ( !players[consoleplayer].mo ) return; - let cbt = players[consoleplayer].mo.FindInventory("Wallbuster"); - if ( !cbt ) return; - if ( cbt == players[consoleplayer].ReadyWeapon ) - { - if ( !initme && (cbtme.GetInt() > 0) ) - { - initme = true; - cbtvol = .6; - } - cbtvol = min(.6,cbtvol+.1); - if ( (cbtme.GetInt() >= 1) && !cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) - cbt.A_StartSound("wallbuster/olddays",CHAN_AMBEXTRA+1,CHANF_UI|CHANF_LOOP,cbtvol,0.); - else if ( (cbtme.GetInt() < 1) && cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) - cbt.A_StopSound(CHAN_AMBEXTRA+1); - if ( (cbtme.GetInt() >= 2) && !cbt.IsActorPlayingSound(CHAN_AMBEXTRA+2) ) - { - // restart the music - if ( cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) - { - cbt.A_StopSound(CHAN_AMBEXTRA+1); - cbt.A_StartSound("wallbuster/olddays",CHAN_AMBEXTRA+1,CHANF_UI|CHANF_LOOP,cbtvol,0.); - } - cbt.A_StartSound("wallbuster/cbt",CHAN_AMBEXTRA+2,CHANF_UI,cbtvol,0.); - } - else if ( (cbtme.GetInt() < 2) && cbt.IsActorPlayingSound(CHAN_AMBEXTRA+2) ) - cbt.A_StopSound(CHAN_AMBEXTRA+2); - } - else cbtvol = max(0.,cbtvol-.1); - cbt.A_SoundVolume(CHAN_AMBEXTRA+1,cbtvol*((cbtme.GetInt()>=2)?.8:1.)); - cbt.A_SoundVolume(CHAN_AMBEXTRA+2,cbtvol); - } -} - Class BustedQuake : Actor { Default diff --git a/zscript/swwm_handler.zsc b/zscript/swwm_handler.zsc index cd881b588..72bfdc474 100644 --- a/zscript/swwm_handler.zsc +++ b/zscript/swwm_handler.zsc @@ -1,13 +1,60 @@ // event handlers and whatnot -// preload fonts and stuff -Class SWWMPreloader : StaticEventHandler +// save version holder +Class SWWMSaveVerData : Thinker { - transient ui Font TewiFont, MPlusFont; - transient ui CVar lang; + String ver; +} + +// Static handler responsible for some special stuff +Class SWWMStaticHandler : StaticEventHandler +{ + // crash handler + ui bool wasinmap; + ui int timer; + // versioning + bool tainted; + String taintver; + // CBT easter egg + bool initme; + double cbtvol; + transient CVar cbtme; + + override void NewGame() + { + // set save version every new session + let svd = new("SWWMSaveVerData"); + svd.ChangeStatNum(Thinker.STAT_STATIC); + svd.ver = StringTable.Localize("$SWWM_MODVER"); + } + + override void WorldLoaded( WorldEvent e ) + { + // save version checker + if ( !e.IsSaveGame ) return; + let ti = ThinkerIterator.Create("SWWMSaveVerData",Thinker.STAT_STATIC); + let svd = SWWMSaveVerData(ti.Next()); + if ( !svd ) + { + tainted = true; + taintver = "\cg(no version information)\c-"; + Console.Printf("\cgWARNING: \cjLoaded save contains no version data. Issues may happen."); + return; + } + String cver = StringTable.Localize("$SWWM_MODVER"); + if ( svd.ver != cver ) + { + tainted = true; + taintver = svd.ver; + Console.Printf("\cgWARNING: \cjThis savegame is from a different version of SWWM GZ. Issues may happen."); + Console.Printf("\cgSaved: \cj"..svd.ver); + Console.Printf("\cgCurrent: \cj"..cver); + } + } override void OnRegister() { + // preload various fonts Font.GetFont('k6x8'); Font.GetFont('k6x8Shaded'); Font.GetFont('k6x8ShadedInverse'); @@ -31,55 +78,16 @@ Class SWWMPreloader : StaticEventHandler menuDelegate.Destroy(); menuDelegate = new("SWWMMenuDelegate"); } - } -} - -// save version holder -Class SWWMSaveVerData : Thinker -{ - String ver; -} - -// Fancy crash effect / also handles save version stuff, for the sake of debugging -Class SWWMCrashHandler : StaticEventHandler -{ - ui bool wasinmap; - ui int timer; - bool tainted; - String taintver; - - override void NewGame() - { - let svd = new("SWWMSaveVerData"); - svd.ChangeStatNum(Thinker.STAT_STATIC); - svd.ver = StringTable.Localize("$SWWM_MODVER"); - } - - override void WorldLoaded( WorldEvent e ) - { - if ( !e.IsSaveGame ) return; - let ti = ThinkerIterator.Create("SWWMSaveVerData",Thinker.STAT_STATIC); - let svd = SWWMSaveVerData(ti.Next()); - if ( !svd ) + // Hey Graf how about you let us replace the class used for the + // "Read This!" menu in mapinfo/gameinfo or something so I + // don't have to do this hack here? + Menu cur = Menu.GetCurrentMenu(); + if ( cur is 'ReadThisMenu' ) { - tainted = true; - taintver = "\cg(no version information)\c-"; - Console.Printf("\cgWARNING: \cjLoaded save contains no version data. Issues may happen."); - return; + cur.Close(); + Menu.SetMenu('SWWMHelpMenu'); } - String cver = StringTable.Localize("$SWWM_MODVER"); - if ( svd.ver != cver ) - { - tainted = true; - taintver = svd.ver; - Console.Printf("\cgWARNING: \cjThis savegame is from a different version of SWWM GZ. Issues may happen."); - Console.Printf("\cgSaved: \cj"..svd.ver); - Console.Printf("\cgCurrent: \cj"..cver); - } - } - - override void UiTick() - { + // Fancy crash effect if ( (gamestate == GS_LEVEL) || (gamestate == GS_TITLELEVEL) ) { wasinmap = true; @@ -115,6 +123,43 @@ Class SWWMCrashHandler : StaticEventHandler timer++; } } + + // from Wikipedia, the free encyclopedia + override void WorldTick() + { + if ( !cbtme ) cbtme = CVar.GetCVar('swwm_cbtmeme',players[consoleplayer]); + if ( !players[consoleplayer].mo ) return; + let cbt = players[consoleplayer].mo.FindInventory("Wallbuster"); + if ( !cbt ) return; + if ( cbt == players[consoleplayer].ReadyWeapon ) + { + if ( !initme && (cbtme.GetInt() > 0) ) + { + initme = true; + cbtvol = .6; + } + cbtvol = min(.6,cbtvol+.1); + if ( (cbtme.GetInt() >= 1) && !cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) + cbt.A_StartSound("wallbuster/olddays",CHAN_AMBEXTRA+1,CHANF_UI|CHANF_LOOP,cbtvol,0.); + else if ( (cbtme.GetInt() < 1) && cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) + cbt.A_StopSound(CHAN_AMBEXTRA+1); + if ( (cbtme.GetInt() >= 2) && !cbt.IsActorPlayingSound(CHAN_AMBEXTRA+2) ) + { + // restart the music + if ( cbt.IsActorPlayingSound(CHAN_AMBEXTRA+1) ) + { + cbt.A_StopSound(CHAN_AMBEXTRA+1); + cbt.A_StartSound("wallbuster/olddays",CHAN_AMBEXTRA+1,CHANF_UI|CHANF_LOOP,cbtvol,0.); + } + cbt.A_StartSound("wallbuster/cbt",CHAN_AMBEXTRA+2,CHANF_UI,cbtvol,0.); + } + else if ( (cbtme.GetInt() < 2) && cbt.IsActorPlayingSound(CHAN_AMBEXTRA+2) ) + cbt.A_StopSound(CHAN_AMBEXTRA+2); + } + else cbtvol = max(0.,cbtvol-.1); + cbt.A_SoundVolume(CHAN_AMBEXTRA+1,cbtvol*((cbtme.GetInt()>=2)?.8:1.)); + cbt.A_SoundVolume(CHAN_AMBEXTRA+2,cbtvol); + } } // Handler responsible for item replacements and whatever else @@ -166,6 +211,11 @@ Class SWWMHandler : EventHandler int casings_cnt, oldmaxcasings; SWWMChip chips, chips_end; int chips_cnt, oldmaxdebris; + // gore + mkBloodDrop blods, blods_end; + int blods_cnt, oldmaxblood; + mkFlyingGib meats, meats_end; + int meats_cnt, oldmaxgibs; // prevents revived monsters from spawning in more golden shells Array alreadygold; @@ -241,6 +291,74 @@ Class SWWMHandler : EventHandler c.prevchip = null; c.nextchip = null; } + static void QueueBlod( mkBloodDrop b ) + { + let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); + if ( !hnd ) return; + hnd.blods_cnt++; + if ( !hnd.blods ) + { + // this is the initial one + hnd.blods = b; + hnd.blods_end = b; + } + else + { + hnd.blods_end.nextblod = b; + b.prevblod = hnd.blods_end; + hnd.blods_end = b; + } + while ( hnd.blods && (swwm_maxblood >= 0) && (hnd.blods_cnt > swwm_maxblood) ) + DeQueueBlod(hnd.blods); + } + static void DeQueueBlod( mkBloodDrop b ) + { + let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); + if ( !hnd || !hnd.blods ) return; + if ( (hnd.blods != b) && !b.prevblod && !b.nextblod ) return; + hnd.blods_cnt--; + if ( !b.prevblod ) hnd.blods = b.nextblod; + else b.prevblod.nextblod = b.nextblod; + if ( b == hnd.blods_end ) hnd.blods_end = b.prevblod; + if ( b.nextblod ) b.nextblod.prevblod = b.prevblod; + b.killme = true; + b.prevblod = null; + b.nextblod = null; + } + static void QueueMeat( mkFlyingGib m ) + { + let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); + if ( !hnd ) return; + hnd.meats_cnt++; + if ( !hnd.meats ) + { + // this is the initial one + hnd.meats = m; + hnd.meats_end = m; + } + else + { + hnd.meats_end.nextmeat = m; + m.prevmeat = hnd.meats_end; + hnd.meats_end = m; + } + while ( hnd.meats && (swwm_maxgibs >= 0) && (hnd.meats_cnt > swwm_maxgibs) ) + DeQueueMeat(hnd.meats); + } + static void DeQueueMeat( mkFlyingGib m ) + { + let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); + if ( !hnd || !hnd.meats ) return; + if ( (hnd.meats != m) && !m.prevmeat && !m.nextmeat ) return; + hnd.meats_cnt--; + if ( !m.prevmeat ) hnd.meats = m.nextmeat; + else m.prevmeat.nextmeat = m.nextmeat; + if ( m == hnd.meats_end ) hnd.meats_end = m.prevmeat; + if ( m.nextmeat ) m.nextmeat.prevmeat = m.prevmeat; + m.killme = true; + m.prevmeat = null; + m.nextmeat = null; + } static void HealthFlash( int p ) { @@ -575,6 +693,15 @@ Class SWWMHandler : EventHandler } } ClearAllShaders(players[consoleplayer]); + // recheck queues in case limits changed + while ( casings && (casings_cnt > swwm_maxcasings) ) + DeQueueCasing(casings); + while ( chips && (chips_cnt > swwm_maxdebris) ) + DeQueueChip(chips); + while ( blods && (blods_cnt > swwm_maxblood) ) + DeQueueBlod(blods); + while ( meats && (meats_cnt > swwm_maxgibs) ) + DeQueueMeat(meats); } override void PlayerDied( PlayerEvent e ) @@ -774,8 +901,20 @@ Class SWWMHandler : EventHandler while ( chips && (swwm_maxdebris >= 0) && (chips_cnt > swwm_maxdebris) ) DeQueueChip(chips); } + if ( swwm_maxblood != oldmaxblood ) + { + while ( blods && (swwm_maxblood >= 0) && (blods_cnt > swwm_maxblood) ) + DeQueueBlod(blods); + } + if ( swwm_maxgibs != oldmaxgibs ) + { + while ( meats && (swwm_maxgibs >= 0) && (meats_cnt > swwm_maxgibs) ) + DeQueueMeat(meats); + } oldmaxcasings = swwm_maxcasings; oldmaxdebris = swwm_maxdebris; + oldmaxblood = swwm_maxblood; + oldmaxgibs = swwm_maxgibs; if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]); if ( onelinertic && (onelinertic < gametic) ) { @@ -924,216 +1063,289 @@ Class SWWMHandler : EventHandler let pt = Actor.Spawn("PartyTime",e.Thing.pos); pt.target = e.Thing; } + // force insert gib animations on some vanilla Doom monsters + int gibhealth = e.Thing.GetGibHealth(); + bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH)); + if ( !gotgibbed ) return; + if ( (e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") ) + ExtraGibDeaths.GibThis(e.Thing,"DemonXDeath"); + else if ( e.Thing.GetClass() == "HellKnight" ) + ExtraGibDeaths.GibThis(e.Thing,"KnightXDeath"); + else if ( e.Thing.GetClass() == "BaronOfHell" ) + ExtraGibDeaths.GibThis(e.Thing,"BaronXDeath"); + else if ( e.Thing.GetClass() == "Cacodemon" ) + ExtraGibDeaths.GibThis(e.Thing,"CacoXDeath"); + else if ( e.Thing.GetClass() == "Revenant" ) + ExtraGibDeaths.GibThis(e.Thing,"BonerXDeath"); + else if ( e.Thing.GetClass() == "Archvile" ) + ExtraGibDeaths.GibThis(e.Thing,"VileXDeath"); } - override void WorldThingDamaged( WorldEvent e ) + // gibbing + private void DoGibThing( WorldEvent e ) { - if ( e.Damage > 0 ) + // no gib if it was erased + if ( e.DamageType == 'Ynykron' ) return; + int gibhealth = e.Thing.GetGibHealth(); + bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH)); + bool forcegibbed = false; + // force gib availability for some vanilla Doom monsters + if ( gotgibbed && ((e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "Cacodemon") || (e.Thing.GetClass() == "Revenant") || (e.Thing.GetClass() == "Archvile")) ) + forcegibbed = true; + if ( !e.Thing.FindState("XDeath",true) && !e.Thing.FindState("Death.Extreme",true) && !forcegibbed ) + gotgibbed = false; + // only do special handling if they use our blood + if ( (e.Thing.GetBloodType(0) != "mkBlood") || e.Thing.bNOBLOOD ) + return; + CorpseFallTracker.TrackBody(e.Thing); + bool b; + Actor a; + // special handling of some monsters + if ( e.Thing.GetClass() == "Cyberdemon" ) { - if ( !accdamage ) accdamage = CVar.GetCVar('swwm_accdamage',players[consoleplayer]); - bool spawnme = true; - if ( accdamage.GetBool() ) + [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); + if ( !b ) return; + mkGibber(a).gibbed = e.Thing; + mkGibber(a).delay = 40; + a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); + return; + } + else if ( e.Thing.GetClass() == "SpiderMastermind" ) + { + [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); + if ( !b ) return; + mkGibber(a).gibbed = e.Thing; + mkGibber(a).delay = 60; + a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); + } + else if ( gotgibbed ) + { + [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); + if ( !b ) return; + mkGibber(a).gibbed = e.Thing; + a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); + } + } + + // damage numbers, combat tracking, etc. + private void DoDamageHandling( WorldEvent e ) + { + if ( !accdamage ) accdamage = CVar.GetCVar('swwm_accdamage',players[consoleplayer]); + bool spawnme = true; + if ( accdamage.GetBool() ) + { + // find existing damage number + for ( SWWMScoreObj d=damnums; d; d=d.next ) { - // find existing damage number - for ( SWWMScoreObj d=damnums; d; d=d.next ) - { - if ( (d.starttic < level.maptime) || (d.acc != e.Thing) ) continue; - if ( d.score-e.Damage > d.score ) d.score = int.min; - else d.score -= e.Damage; - spawnme = false; - break; - } - } - if ( spawnme ) SWWMScoreObj.Spawn(-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),Font.CR_RED,e.Thing); - // update combat tracker for it - if ( !(e.Thing is 'BossBrain') ) - { - for ( SWWMCombatTracker t=trackers; t; t=t.next ) - { - if ( t.mytarget != e.Thing ) continue; - t.updated = level.maptime+35; - break; - } - } - // fall dmg - SWWMWhoPushedMe.SetInstigator(e.Thing,e.DamageSource); - // stats - if ( e.Thing.player ) - { - tookdamage[e.Thing.PlayerNumber()] = true; - let s = SWWMStats.Find(e.Thing.player); - s.AddDamageTaken(e.Damage); - if ( e.Damage > s.toptaken ) s.toptaken = e.Damage; - } - if ( e.DamageSource && e.DamageSource.player ) - { - let s = SWWMStats.Find(e.DamageSource.player); - s.AddDamageDealt(e.Damage); - if ( e.Damage > s.topdealt ) s.topdealt = e.Damage; + if ( (d.starttic < level.maptime) || (d.acc != e.Thing) ) continue; + if ( d.score-e.Damage > d.score ) d.score = int.min; + else d.score -= e.Damage; + spawnme = false; + break; } } - if ( e.DamageSource && (e.DamageSource != e.Thing) ) + if ( spawnme ) SWWMScoreObj.Spawn(-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),Font.CR_RED,e.Thing); + // update combat tracker for it + if ( !(e.Thing is 'BossBrain') ) { - if ( (e.DamageSource.bISMONSTER || e.DamageSource.player || (e.DamageSource is 'ScriptedMarine')) && (e.Thing == players[consoleplayer].mo) && (e.Thing.Health > 0) ) + for ( SWWMCombatTracker t=trackers; t; t=t.next ) + { + if ( t.mytarget != e.Thing ) continue; + t.updated = level.maptime+35; + break; + } + } + // fall dmg + SWWMWhoPushedMe.SetInstigator(e.Thing,e.DamageSource); + // stats + if ( e.Thing.player ) + { + tookdamage[e.Thing.PlayerNumber()] = true; + let s = SWWMStats.Find(e.Thing.player); + s.AddDamageTaken(e.Damage); + if ( e.Damage > s.toptaken ) s.toptaken = e.Damage; + } + if ( e.DamageSource && e.DamageSource.player ) + { + let s = SWWMStats.Find(e.DamageSource.player); + s.AddDamageDealt(e.Damage); + if ( e.Damage > s.topdealt ) s.topdealt = e.Damage; + } + } + + // combat hit chatter + private void DoCombatHit( WorldEvent e ) + { + if ( (e.DamageSource.bISMONSTER || e.DamageSource.player || (e.DamageSource is 'ScriptedMarine')) && (e.Thing == players[consoleplayer].mo) && (e.Thing.Health > 0) ) + { + if ( !lastcombat || (gametic > lastcombat+40) ) + { + if ( (e.Thing.IsFriend(e.DamageSource) || SWWMUtility.IsCivilian(e.DamageSource)) ) + lastcombat = AddOneliner("friendhit",1,10); + else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.DamageSource.bBOSS||e.DamageSource.bBOSSDEATH)?2:4) && !SWWMHDoomHandler.IsCuteGirl(e.DamageSource) ) // [HDoom] don't shout at the girls + lastcombat = AddOneliner("gethit",1,15); + } + highesttic = gametic; + } + // friendly fire lines only fire up if we didn't kill them right away (because then the teamkill line should take priority) + if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player || (e.Thing is 'ScriptedMarine')) && (e.Thing.Health > 0) ) + { + // make sure it's not a moth, because otherwise they won't shut up about accidentally hurting them (it happens a lot) + if ( (e.Thing.IsFriend(e.DamageSource) || SWWMUtility.IsCivilian(e.Thing)) && !(e.Thing is 'LampMoth') ) { if ( !lastcombat || (gametic > lastcombat+40) ) - { - if ( (e.Thing.IsFriend(e.DamageSource) || SWWMUtility.IsCivilian(e.DamageSource)) ) - lastcombat = AddOneliner("friendhit",1,10); - else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.DamageSource.bBOSS||e.DamageSource.bBOSSDEATH)?2:4) && !SWWMHDoomHandler.IsCuteGirl(e.DamageSource) ) // [HDoom] don't shout at the girls - lastcombat = AddOneliner("gethit",1,15); - } + lastcombat = AddOneliner("hitfriend",1,10); highesttic = gametic; } - // friendly fire lines only fire up if we didn't kill them right away (because then the teamkill line should take priority) - if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player || (e.Thing is 'ScriptedMarine')) && (e.Thing.Health > 0) ) - { - // make sure it's not a moth, because otherwise they won't shut up about accidentally hurting them (it happens a lot) - if ( (e.Thing.IsFriend(e.DamageSource) || SWWMUtility.IsCivilian(e.Thing)) && !(e.Thing is 'LampMoth') ) - { - if ( !lastcombat || (gametic > lastcombat+40) ) - lastcombat = AddOneliner("hitfriend",1,10); - highesttic = gametic; - } - } } - if ( (e.Thing.Health > 0) || e.Thing.bKilled || e.Thing.bCorpse ) return; - // romero hax - if ( (e.Thing is 'BossBrain') && (e.DamageType == 'Telefrag') ) - e.DamageSource.DamageMobj(null,null,Actor.TELEFRAG_DAMAGE,'EndLevel'); - if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill && !(e.Thing is 'ScriptedMarine') ) return; + } + + // kill scoring + private void DoKillScoring( WorldEvent e ) + { // fall damage tracking hack let src = e.DamageSource; if ( (e.DamageType == 'Falling') && !e.DamageSource ) src = SWWMWhoPushedMe.RecallInstigator(e.Thing); - if ( (src && src.player && (src != e.Thing)) ) + if ( (!src || !src.player || (src == e.Thing)) ) return; + let s = SWWMStats.Find(src.player); + if ( s ) { - let s = SWWMStats.Find(src.player); - if ( s ) - { - s.kills++; - s.AddWeaponKill(e.Inflictor,e.Thing,e.DamageType); - } - if ( src == players[consoleplayer].mo ) - { - highesttic = gametic; - if ( !lastcombat || (gametic > lastcombat+40) ) - { - if ( e.Thing.IsFriend(src) || SWWMUtility.IsCivilian(e.Thing) ) - lastcombat = AddOneliner("friendkill",1,5); - else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.bBOSSDEATH)?2:5) && !SWWMHDoomHandler.IsCuteGirl(e.Thing) ) // [HDoom] don't shout at the girls - lastcombat = AddOneliner("scorekill",1,15); - } - } - // no credits unless it's a counted kill or marine (that isn't friendly) - if ( e.Thing.IsFriend(src) || (!e.Thing.default.bCountKill && !(e.Thing is 'ScriptedMarine')) ) - return; - int pnum = src.PlayerNumber(); - if ( level.maptime < (lastkill[pnum]+5*Thinker.TICRATE) ) - multilevel[pnum]++; - else multilevel[pnum] = 0; - if ( s && (multilevel[pnum]+1 > s.mkill) ) - s.mkill = multilevel[pnum]+1; - lastkill[pnum] = level.maptime; - // scoring - int score = min(1000,int(ceil(e.Thing.SpawnHealth()*.05)*10)); - SWWMScoreObj scr = null; - if ( src.player == players[consoleplayer] ) - scr = SWWMScoreObj.Spawn(score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2)); - int ofs = 0; - if ( e.DamageType == 'Push' ) - { - score += 500; - if ( scr ) - { - scr.xscore[ofs] = 0; - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_SHAMEFUL"); - scr.xcnt = ++ofs; - } - } - else if ( e.DamageType == 'Buttslam' ) - { - score += 200; - if ( scr ) - { - scr.xscore[ofs] = 0; - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_BUTTSLAM"); - scr.xcnt = ++ofs; - } - } - else if ( e.DamageType == 'Love' ) - { - score += 600; - if ( scr ) - { - scr.xscore[ofs] = 0; - scr.xtcolor[ofs] = Font.FindFontColor('BlushPink'); - scr.xstr[ofs] = StringTable.Localize((e.Thing is 'WolfensteinSS')?"$SWWM_LOVED_ALT":"$SWWM_LOVED"); - scr.xcnt = ++ofs; - } - } - if ( (e.Damage >= e.Thing.GetSpawnHealth()*2) || (((e.Thing.Health <= e.Thing.GetGibHealth()) || (src.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageType == 'Extreme')) && !src.bNOEXTREMEDEATH && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH)) ) - { - score *= 2; - if ( scr ) - { - scr.xscore[ofs] = 0; - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_OVERKILL"); - scr.xcnt = ++ofs; - } - } - score = int(score*(1.+.5*min(multilevel[pnum],16))); - if ( (multilevel[pnum] > 0) && scr ) - { - if ( scr ) - { - scr.xscore[ofs] = (multilevel[pnum]>=16)?int.max:(multilevel[pnum]+1); - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_MULTIKILL"); - scr.xcnt = ++ofs; - } - } - if ( !tookdamage[pnum] ) - { - int spreebonus = 10*spreecount[pnum]; - // taper off after 10x (some people go really far with these, holy fuck) - if ( spreecount[pnum] > 10 ) spreebonus = int(spreebonus*((spreecount[pnum]/10.)**.25)); - score += 100+spreebonus; - if ( (spreecount[pnum] > 0) && scr ) - { - scr.xscore[ofs] = spreecount[pnum]+1; - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_SPREEKILL"); - scr.xcnt = ++ofs; - } - } - if ( e.Thing.bBOSS ) - { - score += 2000; - if ( scr ) - { - scr.xscore[ofs] = 0; - scr.xtcolor[ofs] = Font.CR_FIRE; - scr.xstr[ofs] = StringTable.Localize("$SWWM_BOSSKILL"); - scr.xcnt = ++ofs; - } - } - SWWMCredits.Give(src.player,score); - if ( scr ) scr.score = score; // update final score - if ( (level.killed_monsters+1 == level.total_monsters) && !allkills ) - { - allkills = true; - SWWMCredits.Give(src.player,1000); - Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),src.player.GetUserName(),1000); - SWWMScoreObj.Spawn(1000,src.Vec3Offset(0,0,src.Height/2)); - } - spreecount[pnum]++; - if ( s && (spreecount[pnum] > s.skill) && !tookdamage[pnum] ) - s.skill = spreecount[pnum]; + s.kills++; + s.AddWeaponKill(e.Inflictor,e.Thing,e.DamageType); } + if ( src == players[consoleplayer].mo ) + { + highesttic = gametic; + if ( !lastcombat || (gametic > lastcombat+40) ) + { + if ( e.Thing.IsFriend(src) || SWWMUtility.IsCivilian(e.Thing) ) + lastcombat = AddOneliner("friendkill",1,5); + else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.bBOSSDEATH)?2:5) && !SWWMHDoomHandler.IsCuteGirl(e.Thing) ) // [HDoom] don't shout at the girls + lastcombat = AddOneliner("scorekill",1,15); + } + } + // no credits unless it's a counted kill or marine (that isn't friendly) + if ( e.Thing.IsFriend(src) || (!e.Thing.default.bCountKill && !(e.Thing is 'ScriptedMarine')) ) + return; + int pnum = src.PlayerNumber(); + if ( level.maptime < (lastkill[pnum]+5*Thinker.TICRATE) ) + multilevel[pnum]++; + else multilevel[pnum] = 0; + if ( s && (multilevel[pnum]+1 > s.mkill) ) + s.mkill = multilevel[pnum]+1; + lastkill[pnum] = level.maptime; + // scoring + int score = min(1000,int(ceil(e.Thing.SpawnHealth()*.05)*10)); + SWWMScoreObj scr = null; + if ( src.player == players[consoleplayer] ) + scr = SWWMScoreObj.Spawn(score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2)); + int ofs = 0; + if ( e.DamageType == 'Push' ) + { + score += 500; + if ( scr ) + { + scr.xscore[ofs] = 0; + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_SHAMEFUL"); + scr.xcnt = ++ofs; + } + } + else if ( e.DamageType == 'Buttslam' ) + { + score += 200; + if ( scr ) + { + scr.xscore[ofs] = 0; + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_BUTTSLAM"); + scr.xcnt = ++ofs; + } + } + else if ( e.DamageType == 'Love' ) + { + score += 600; + if ( scr ) + { + scr.xscore[ofs] = 0; + scr.xtcolor[ofs] = Font.FindFontColor('BlushPink'); + scr.xstr[ofs] = StringTable.Localize((e.Thing is 'WolfensteinSS')?"$SWWM_LOVED_ALT":"$SWWM_LOVED"); + scr.xcnt = ++ofs; + } + } + if ( (e.Damage >= e.Thing.GetSpawnHealth()*2) || (((e.Thing.Health <= e.Thing.GetGibHealth()) || (src.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageType == 'Extreme')) && !src.bNOEXTREMEDEATH && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH)) ) + { + score *= 2; + if ( scr ) + { + scr.xscore[ofs] = 0; + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_OVERKILL"); + scr.xcnt = ++ofs; + } + } + score = int(score*(1.+.5*min(multilevel[pnum],16))); + if ( (multilevel[pnum] > 0) && scr ) + { + if ( scr ) + { + scr.xscore[ofs] = (multilevel[pnum]>=16)?int.max:(multilevel[pnum]+1); + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_MULTIKILL"); + scr.xcnt = ++ofs; + } + } + if ( !tookdamage[pnum] ) + { + int spreebonus = 10*spreecount[pnum]; + // taper off after 10x (some people go really far with these, holy fuck) + if ( spreecount[pnum] > 10 ) spreebonus = int(spreebonus*((spreecount[pnum]/10.)**.25)); + score += 100+spreebonus; + if ( (spreecount[pnum] > 0) && scr ) + { + scr.xscore[ofs] = spreecount[pnum]+1; + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_SPREEKILL"); + scr.xcnt = ++ofs; + } + } + if ( e.Thing.bBOSS ) + { + score += 2000; + if ( scr ) + { + scr.xscore[ofs] = 0; + scr.xtcolor[ofs] = Font.CR_FIRE; + scr.xstr[ofs] = StringTable.Localize("$SWWM_BOSSKILL"); + scr.xcnt = ++ofs; + } + } + SWWMCredits.Give(src.player,score); + if ( scr ) scr.score = score; // update final score + if ( (level.killed_monsters+1 == level.total_monsters) && !allkills ) + { + allkills = true; + SWWMCredits.Give(src.player,1000); + Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),src.player.GetUserName(),1000); + SWWMScoreObj.Spawn(1000,src.Vec3Offset(0,0,src.Height/2)); + } + spreecount[pnum]++; + if ( s && (spreecount[pnum] > s.skill) && !tookdamage[pnum] ) + s.skill = spreecount[pnum]; + } + + override void WorldThingDamaged( WorldEvent e ) + { + if ( e.Damage > 0 ) DoDamageHandling(e); + if ( e.DamageSource && (e.DamageSource != e.Thing) ) DoCombatHit(e); + if ( (e.Thing.Health > 0) || e.Thing.bKilled || e.Thing.bCorpse ) return; + DoGibThing(e); + // romero hax + if ( (e.Thing is 'BossBrain') && (e.DamageType == 'Telefrag') ) + e.DamageSource.DamageMobj(null,null,Actor.TELEFRAG_DAMAGE,'EndLevel'); + if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill && !(e.Thing is 'ScriptedMarine') ) return; + DoKillScoring(e); } private void DoKeyTagFix( Actor a ) @@ -1212,8 +1424,30 @@ Class SWWMHandler : EventHandler if ( (swwm_shadows == 2) || ((swwm_shadows == 1) && ((e.Thing is 'Demolitionist') || (e.Thing.SpawnState.sprite == e.Thing.GetSpriteIndex('XZW1')))) ) SWWMShadow.Track(e.Thing); } + // Ynykron vortex optimization if ( e.Thing.bSHOOTABLE || e.Thing.bMISSILE ) SuckableActors.Push(e.Thing); + // vanilla blood color changes + if ( (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "Bishop") || (e.Thing.GetClass() == "Korax") ) + { + let gb = Actor.Spawn("GreenBloodReference"); + e.Thing.CopyBloodColor(gb); + gb.Destroy(); + } + else if ( e.Thing.GetClass() == "Cacodemon" ) + { + let bb = Actor.Spawn("BlueBloodReference"); + e.Thing.CopyBloodColor(bb); + bb.Destroy(); + } + else if ( (e.Thing.GetClass() == "Wizard") || (e.Thing.GetClass() == "Heresiarch") || (e.Thing.GetClass() == "Sorcerer2") ) + { + let pb = Actor.Spawn("PurpleBloodReference"); + e.Thing.CopyBloodColor(pb); + pb.Destroy(); + } + else if ( e.Thing.GetClass() == "LostSoul" ) + e.Thing.bNOBLOOD = true; } override void PostUiTick() @@ -1370,7 +1604,9 @@ Class SWWMHandler : EventHandler static const Class purplepool[] = {"PurpleShell","PurpleShell2","PurpleShell4"}; static const Class bluepool[] = {"BlueShell","BlueShell2","BlueShell4"}; static const Class blackpool[] = {"BlackShell","BlackShell2"}; - if ( e.Replacee is 'ItemFog' ) e.Replacement = 'SWWMItemFog'; + // only replace vanilla blood if no other gore mod is doing it + if ( (e.Replacee == "Blood") && (!e.Replacement || e.Replacement == "Blood") && swwm_blood ) e.Replacement = "mkBlood"; + else if ( e.Replacee is 'ItemFog' ) e.Replacement = 'SWWMItemFog'; else if ( e.Replacee is 'TeleportFog' ) e.Replacement = 'SWWMTeleportFog'; else if ( (e.Replacee is 'CommanderKeen') && (!e.Replacement || (e.Replacement == 'CommanderKeen')) ) { diff --git a/zscript/swwm_hdoom.zsc b/zscript/swwm_hdoom.zsc index bc280ff5b..83019a24a 100644 --- a/zscript/swwm_hdoom.zsc +++ b/zscript/swwm_hdoom.zsc @@ -24,8 +24,13 @@ Class SWWMHDoomHandler : StaticEventHandler detected = true; break; } + if ( !detected ) + { + // get rid of ourselves + Destroy(); + return; + } SetRandomSeed[hdscreen](Random[hdscreen]()+consoleplayer+MSTime()); - if ( !detected ) return; Console.Printf( "\cx┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" "\cx┃ \cfOh my, someone appears to be \cgH \ckO \cdR \cvN \chY \ct♥ \cx┃\n" diff --git a/zscript/swwm_help.zsc b/zscript/swwm_help.zsc index f3d12f43e..36deecee6 100644 --- a/zscript/swwm_help.zsc +++ b/zscript/swwm_help.zsc @@ -1,17 +1,4 @@ -// Hey Graf how about you let us replace the class used for the "Read This!" -// menu in mapinfo/gameinfo or something so I don't have to do this hack here? -Class SWWMReadThisHijacker : StaticEventHandler -{ - override void UiTick() - { - Menu cur = Menu.GetCurrentMenu(); - if ( cur is 'ReadThisMenu' ) - { - cur.Close(); - Menu.SetMenu('SWWMHelpMenu'); - } - } -} +// alternate "Read This!" menu Class SWWMHelpMenu : GenericMenu { diff --git a/zscript/swwm_shame.zsc b/zscript/swwm_shame.zsc index a8b8c24e9..102ff5dbb 100644 --- a/zscript/swwm_shame.zsc +++ b/zscript/swwm_shame.zsc @@ -27,8 +27,13 @@ Class SWWMBrutalHandler : StaticEventHandler detected = true; break; } + if ( !detected ) + { + // get rid of ourselves + Destroy(); + return; + } SetRandomSeed[bdscreen](Random[bdscreen]()+consoleplayer+MSTime()); - if ( !detected ) return; Console.Printf( "\cx┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" "\cx┃ \cfIf you have BD on your autoload you really shouldn't. \cx┃\n"