// event handlers and whatnot // save version holder Class SWWMSaveVerData : Thinker { 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; bool mptaint[MAXPLAYERS]; String mpver[MAXPLAYERS]; int checktic; 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; checktic = gametic+5; let ti = ThinkerIterator.Create("SWWMSaveVerData",Thinker.STAT_STATIC); let svd = SWWMSaveVerData(ti.Next()); if ( !svd ) { tainted = true; taintver = "\cg(no version information)\c-"; return; } String cver = StringTable.Localize("$SWWM_MODVER"); if ( svd.ver != cver ) { tainted = true; taintver = svd.ver; } } override void PlayerEntered( PlayerEvent e ) { if ( multiplayer && (e.playernumber == consoleplayer) ) EventHandler.SendNetworkEvent("swwmversion."..StringTable.Localize("$SWWM_MODVER")); } override void OnRegister() { // preload various fonts Font.GetFont('k6x8'); Font.GetFont('k6x8Shaded'); Font.GetFont('k6x8ShadedInverse'); Font.GetFont('Miniwi'); Font.GetFont('MiniwiShaded'); Font.GetFont('MiniwiShadedInverse'); Font.GetFont('MPlus'); Font.GetFont('MPlusShaded'); Font.GetFont('MPlusShadedInverse'); Font.GetFont('Tewi'); Font.GetFont('TewiShaded'); Font.GetFont('TewiShadedInverse'); Font.GetFont('SWWMBigFont'); } override void NetworkProcess( ConsoleEvent e ) { if ( e.IsManual ) return; if ( e.Name.Left(12) ~== "swwmversion." ) { String verstr = e.Name.Mid(12); mpver[e.Player] = verstr; if ( verstr != StringTable.Localize("$SWWM_MODVER") ) mptaint[e.Player] = true; } } override void PostUiTick() { // TODO achievement update code would go in here if ( gametic != checktic ) return; String cver = StringTable.Localize("$SWWM_MODVER"); if ( tainted ) { let ti = ThinkerIterator.Create("SWWMSaveVerData",Thinker.STAT_STATIC); let svd = SWWMSaveVerData(ti.Next()); if ( !svd ) Console.Printf("\cgWARNING: \cjLoaded save contains no version data. Issues may happen."); else { 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); } } if ( multiplayer ) { bool found = false; for ( int i=0; i 0)) ) { wasinmap = false; if ( timer == 1 ) { Console.Printf("\cfOopsie Woopsie!"); let hnd = SWWMBrutalHandler(StaticEventHandler.Find("SWWMBrutalHandler")); if ( hnd && hnd.detected ) { S_StartSound("crash/glass",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); S_StartSound("crash/glass",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); } else S_StartSound("crash/crash",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); } else if ( timer == 140 ) { Console.Printf("\cfLooks like GZDoom made a fucky wucky! owo"); S_StartSound("crash/curb",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); } else if ( timer == 350 ) { let hnd = SWWMBrutalHandler(StaticEventHandler.Find("SWWMBrutalHandler")); if ( hnd && hnd.detected ) Console.Printf("\cfDon't blame me. Shouldn't have tried running this with Brutal Doom."); else Console.Printf("\cfIf you didn't trigger it manually, it's best if you take a screenshot and show it to Marisa."); Console.Printf("\cfLoaded Version: \cj%s",StringTable.Localize("$SWWM_MODVER")); if ( tainted ) Console.Printf("\cfSavegame Version: \cj%s",taintver); } timer++; } } } // fuck Class DontDuplicate : Inventory {} Class DontDuplicate2 : Inventory {} Class HOLYCOWIMTOTALLYGOINGSOFASTOHFUCK : Inventory { override void DoEffect() { Super.DoEffect(); if ( !Owner || (Owner.Health <= 0) ) return; if ( (Owner.tics > 1) && (Owner.tics > max(1,Owner.CurState.tics/2)) ) Owner.tics = max(1,Owner.CurState.tics/2); } } // Handler responsible for item replacements and whatever else Class SWWMHandler : EventHandler { transient String oneliner, onelinersnd; transient int onelinertic, onelinerspan, onelinerlevel; transient int lastlock, lastcombat; transient Array combatactors; transient Array combattics; transient int highesttic; transient Array flashes; transient Array lastlines; transient int lastpickuptic[MAXPLAYERS]; SWWMCombatTracker trackers; SWWMScoreObj scorenums, damnums; SWWMInterest intpoints; int trackers_cnt, scorenums_cnt, damnums_cnt, intpoints_cnt; bool tookdamage[MAXPLAYERS]; int spreecount[MAXPLAYERS]; int lastkill[MAXPLAYERS]; int multilevel[MAXPLAYERS]; int lastitemcount[MAXPLAYERS]; bool allkills, allitems, allsecrets; bool mapclear; bool mnotify; // for custom cheats transient ui int kcode; transient ui String kstr; // heal/armor flashes need to be handled here so they don't stack transient int hflash[MAXPLAYERS], aflash[MAXPLAYERS]; // for menu events transient Array checklist; transient CVar mutevoice, accdamage; transient ui CVar useshaders, altrage; transient CVar lang; transient String curlang; transient CVar funtags; transient bool curfuntags; transient int slotstrictwarn; // optimization OnFire fires; int fires_cnt; // junk SWWMCasing casings, casings_end; 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; // attempt to optimize Ynykron singularity suction Array suckableactors; // vanilla boss stuff String bosstag; Array bossactors; Actor bossbrainactor; Actor bossviewactor; TextureID facetex[5]; bool initialized; ui bool ui_initialized; ui TextureID bbar_f, bbar_r, bbar_d; ui double bossalpha; ui DynamicValueInterpolator ihealth, ihealthr; ui int thealth, hmax; ui int oldhealth[30]; ui int cummdamage, lastcummtic; // please do not misread transient ui CVar dodrawbossbar; enum EVanillaMap { MAP_NONE, MAP_DE1M8, MAP_DE2M8, MAP_DE3M8, MAP_DE4M8, MAP_HE1M8_HE4M8, MAP_HE2M8_HE5M8, MAP_HE3M8, MAP_DMAP07, MAP_DMAP30, MAP_HMAP12, MAP_HMAP23_HMAP27, MAP_HMAP36, MAP_HMAP37, MAP_HMAP38, MAP_HMAP40, MAP_EVMAP30 // eviternity }; private int WhichVanillaBossMap() { String mapsum = level.GetChecksum(); if ( (mapsum ~== "94500F4B006B316FE03AC46865AEABF8") || (mapsum ~== "97079958C7E89C1908890730B8B9FEB7") || (mapsum ~== "058FB092EA1B70DA1E3CBF501C4A91A1") ) return MAP_DE1M8; if ( mapsum ~== "EFFE91DF41AD41F6973C06F0AD67DDB9" ) return MAP_DE2M8; if ( mapsum ~== "EF128313112110ED6C1549AF96AF26C9" ) return MAP_DE3M8; if ( mapsum ~== "2DC939E508AB8EB68AF79D5B60568711" ) return MAP_DE4M8; if ( (mapsum ~== "27639D04F8090D57A47D354992435893") || (mapsum ~== "30D1480A6D4F3A3153739D4CCF659C4E") ) return MAP_HE1M8_HE4M8; if ( (mapsum ~== "5158C22A0F30CE5E558FD2A05D67685E") || (mapsum ~== "85AC7D20D18F9BC49B9696CC2E67F029") ) return MAP_HE2M8_HE5M8; if ( mapsum ~== "4719C2C71EF28F52310B889DD5A9778B" ) return MAP_HE3M8; if ( mapsum ~== "291F24417FB3DD411339AE82EF9B3597" ) return MAP_DMAP07; if ( mapsum ~== "5EECD88F4491F516D590CE4BBF45F532" ) return MAP_DMAP30; if ( (mapsum ~== "89C4CD26EF05E2577B10CAFE56226662") || (mapsum ~== "441BF111747671066A10A146C03EEFC4") || (mapsum ~== "55E321849F3699655D7E062C90682F63") ) return MAP_HMAP12; if ( (mapsum ~== "E3B06F44DBF6F7E7754D7B1DAEF707E4") || (mapsum ~== "FC832437D7A2B7094A9B56C3909773D9") || (mapsum ~== "91AD797F95CC4C6D6AE33B21F664C60B") || (mapsum ~== "188B1B4244BD8DA501D8532696EC8654") || (mapsum ~== "5B29D0889DF09A8250D62FA09EB2B452") || (mapsum ~== "D3C5FA777BA52264546E6569F167AF0D") ) return MAP_HMAP23_HMAP27; if ( (mapsum ~== "4444C95C2029DA6EECAC92DAA31CE665") || (mapsum ~== "33752742BCA8E539A6EE3E5D0FDA8744") || (mapsum ~== "3FFAF2F624C1B4BB6F581DCF7B99CBA7") ) return MAP_HMAP36; if ( (mapsum ~== "78979A583B1E30D94C9DAE2BCFA9A18D") || (mapsum ~== "FDC90F44C65A71E0901C1B9FFFCF3D02") || (mapsum ~== "088ECE0E0F3E68448FA1D901001A0084") ) return MAP_HMAP37; if ( (mapsum ~== "3BF62E4F9FB3CF9AF267421CE2D5F348") || (mapsum ~== "4799E1FDB5A3C0E3AD650B5AC215A737") || (mapsum ~== "5C63A02B0B04D9AE95CA51687DC3406F") ) return MAP_HMAP38; if ( (mapsum ~== "EFAFE59092DE5E613562ACF52B86C37F") || (mapsum ~== "1C5DE5A921DEE405E98E7E09D9829387") || (mapsum ~== "2A6C4235B942467D25FD50D5B313E67A") ) return MAP_HMAP40; if ( mapsum ~== "5C5E5C08AF3572F31CF27318679F2B4E" ) return MAP_EVMAP30; return MAP_NONE; } static void QueueCasing( SWWMCasing c ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd ) return; hnd.casings_cnt++; if ( !hnd.casings ) { // this is the initial one hnd.casings = c; hnd.casings_end = c; } else { hnd.casings_end.nextcasing = c; c.prevcasing = hnd.casings_end; hnd.casings_end = c; } while ( hnd.casings && (swwm_maxcasings >= 0) && (hnd.casings_cnt > swwm_maxcasings) ) DeQueueCasing(hnd.casings); } static void DeQueueCasing( SWWMCasing c ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd || !hnd.casings ) return; if ( (hnd.casings != c) && !c.prevcasing && !c.nextcasing ) return; hnd.casings_cnt--; if ( !c.prevcasing ) hnd.casings = c.nextcasing; else c.prevcasing.nextcasing = c.nextcasing; if ( c == hnd.casings_end ) hnd.casings_end = c.prevcasing; if ( c.nextcasing ) c.nextcasing.prevcasing = c.prevcasing; c.killme = true; c.prevcasing = null; c.nextcasing = null; } static void QueueChip( SWWMChip c ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd ) return; hnd.chips_cnt++; if ( !hnd.chips ) { // this is the initial one hnd.chips = c; hnd.chips_end = c; } else { hnd.chips_end.nextchip = c; c.prevchip = hnd.chips_end; hnd.chips_end = c; } while ( hnd.chips && (swwm_maxdebris >= 0) && (hnd.chips_cnt > swwm_maxdebris) ) DeQueueChip(hnd.chips); } static void DeQueueChip( SWWMChip c ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd || !hnd.chips ) return; if ( (hnd.chips != c) && !c.prevchip && !c.nextchip ) return; hnd.chips_cnt--; if ( !c.prevchip ) hnd.chips = c.nextchip; else c.prevchip.nextchip = c.nextchip; if ( c == hnd.chips_end ) hnd.chips_end = c.prevchip; if ( c.nextchip ) c.nextchip.prevchip = c.prevchip; c.killme = true; 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 ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd || (p == -1) ) return; hnd.hflash[p] = gametic+5; } static void ArmorFlash( int p ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd || (p == -1) ) return; hnd.aflash[p] = gametic+5; } static int AddOneliner( String type, int level, int delay = 5 ) { // only Demolitionist can play voice lines if ( !(players[consoleplayer].mo is 'Demolitionist') ) return 0; let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd ) return 0; String voicetype = CVar.GetCVar('swwm_voicetype',players[consoleplayer]).GetString(); // suppress non-rage comments when ragekit is active, only screaming allowed if ( players[consoleplayer].mo.FindInventory("RagekitPower") && (type != "ragekit") ) return 0; int whichline; String testme = String.Format("SWWM_SUBS_%s_N%s",voicetype.MakeUpper(),type.MakeUpper()); String locme = StringTable.Localize(testme,false); int countem; if ( testme == locme ) countem = 0; else countem = locme.ToInt(); if ( countem == 0 ) return 0; // voicepack doesn't have this // check last line so we don't repeat int last = 0, ent; for ( int i=0; i 0 ) { whichline = Random[DemoLines](1,countem-1); if ( whichline >= last ) whichline++; hnd.lastlines[ent].lineno = whichline; } else { whichline = Random[DemoLines](1,countem); let lst = new("LastLine"); lst.type = type; lst.lineno = whichline; hnd.lastlines.Push(lst); } hnd.oneliner = String.Format("$SWWM_SUBS_%s_%s%d",voicetype.MakeUpper(),type.MakeUpper(),whichline); hnd.onelinersnd = String.Format("voice/%s/%s%d",voicetype,type,whichline); hnd.onelinertic = gametic+delay; hnd.onelinerspan = int(S_GetLength(hnd.onelinersnd)*Thinker.TICRATE); hnd.onelinerlevel = level; return hnd.onelinertic+hnd.onelinerspan; } override void OnRegister() { // oneliner RNG must be relative to consoleplayer SetRandomSeed[DemoLines](Random[DemoLines]()+consoleplayer+MSTime()); } private static Vector3 UseLinePos( Line l ) { Vector3 al, ah, bl, bh; if ( !l.sidedef[1] ) { // just the whole line al = (l.v1.p,l.frontsector.floorplane.ZatPoint(l.v1.p)); ah = (l.v1.p,l.frontsector.ceilingplane.ZatPoint(l.v1.p)); bl = (l.v2.p,l.frontsector.floorplane.ZatPoint(l.v2.p)); bh = (l.v2.p,l.frontsector.ceilingplane.ZatPoint(l.v2.p)); return (al+ah+bl+bh)*.25; } SecPlane highestfloor, lowestfloor, lowestceiling, highestceiling; if ( (l.frontsector.floorplane.ZatPoint(l.v1.p) > l.backsector.floorplane.ZatPoint(l.v1.p)) && (l.frontsector.floorplane.ZatPoint(l.v2.p) > l.backsector.floorplane.ZatPoint(l.v2.p)) ) { highestfloor = l.frontsector.floorplane; lowestfloor = l.backsector.floorplane; } else { highestfloor = l.backsector.floorplane; lowestfloor = l.frontsector.floorplane; } if ( (l.frontsector.ceilingplane.ZatPoint(l.v1.p) < l.backsector.ceilingplane.ZatPoint(l.v1.p)) && (l.frontsector.ceilingplane.ZatPoint(l.v2.p) < l.backsector.ceilingplane.ZatPoint(l.v2.p)) ) { lowestceiling = l.frontsector.ceilingplane; highestceiling = l.backsector.ceilingplane; } else { lowestceiling = l.backsector.ceilingplane; highestceiling = l.frontsector.ceilingplane; } // try to guess what the part that triggers this is if ( l.Activation&SPAC_Cross ) { // pick the "intersection" al = (l.v1.p,highestfloor.ZatPoint(l.v1.p)); ah = (l.v1.p,lowestceiling.ZatPoint(l.v1.p)); bl = (l.v2.p,highestfloor.ZatPoint(l.v2.p)); bh = (l.v2.p,lowestceiling.ZatPoint(l.v2.p)); return (al+ah+bl+bh)*.25; } // check if lower part available al = (l.v1.p,lowestfloor.ZatPoint(l.v1.p)); ah = (l.v1.p,highestfloor.ZatPoint(l.v1.p)); bl = (l.v2.p,lowestfloor.ZatPoint(l.v2.p)); bh = (l.v2.p,highestfloor.ZatPoint(l.v2.p)); if ( ((al-ah).length() > 0) && ((bl-bh).length() > 0) ) return (al+ah+bl+bh)*.25; // check if upper part available al = (l.v1.p,lowestceiling.ZatPoint(l.v1.p)); ah = (l.v1.p,highestceiling.ZatPoint(l.v1.p)); bl = (l.v2.p,lowestceiling.ZatPoint(l.v2.p)); bh = (l.v2.p,highestceiling.ZatPoint(l.v2.p)); if ( ((al-ah).length() > 0) && ((bl-bh).length() > 0) ) return (al+ah+bl+bh)*.25; // check for 3d floors bool floorfound = false; Vector3 fal, fah, fbl, fbh; for ( int i=0; i ah.z) && (fbh.z > bh.z) && (fal.z > al.z) && (fbl.z > bl.z) ) continue; al = fal; ah = fah; bl = fbl; bh = fbh; floorfound = true; } if ( floorfound ) return (al+ah+bl+bh)*.25; for ( int i=0; i ah.z) && (fbh.z > bh.z) && (fal.z > al.z) && (fbl.z > bl.z) ) continue; al = fal; ah = fah; bl = fbl; bh = fbh; floorfound = true; } if ( floorfound ) return (al+ah+bl+bh)*.25; // check for midtex if ( !l.sidedef[0].GetTexture(1).IsNull() ) { double ofs = l.sidedef[0].GetTextureYOffset(1); Vector2 siz = TexMan.GetScaledSize(l.sidedef[0].GetTexture(1)); Vector2 tofs = TexMan.GetScaledOffset(l.sidedef[0].GetTexture(1)); ofs += tofs.y; ofs *= l.sidedef[0].GetTextureYScale(1); siz.y *= l.sidedef[0].GetTextureYScale(1); if ( l.flags&Line.ML_DONTPEGBOTTOM ) { al = (l.v1.p,highestfloor.ZAtPoint(l.v1.p)+ofs); bl = (l.v2.p,highestfloor.ZAtPoint(l.v2.p)+ofs); ah = al+(0,0,siz.y); bh = bl+(0,0,siz.y); } else { ah = (l.v1.p,lowestceiling.ZAtPoint(l.v1.p)+ofs); bh = (l.v2.p,lowestceiling.ZAtPoint(l.v2.p)+ofs); al = ah-(0,0,siz.y); bl = bh-(0,0,siz.y); } return (al+ah+bl+bh)*.25; } if ( !l.sidedef[1].GetTexture(1).IsNull() ) { double ofs = l.sidedef[1].GetTextureYOffset(1); Vector2 siz = TexMan.GetScaledSize(l.sidedef[1].GetTexture(1)); Vector2 tofs = TexMan.GetScaledOffset(l.sidedef[1].GetTexture(1)); ofs += tofs.y; ofs *= l.sidedef[1].GetTextureYScale(1); siz.y *= l.sidedef[1].GetTextureYScale(1); if ( l.flags&Line.ML_DONTPEGBOTTOM ) { al = (l.v1.p,highestfloor.ZAtPoint(l.v1.p)+ofs); bl = (l.v2.p,highestfloor.ZAtPoint(l.v2.p)+ofs); ah = al+(0,0,siz.y); bh = bl+(0,0,siz.y); } else { ah = (l.v1.p,lowestceiling.ZAtPoint(l.v1.p)+ofs); bh = (l.v2.p,lowestceiling.ZAtPoint(l.v2.p)+ofs); al = ah-(0,0,siz.y); bl = bh-(0,0,siz.y); } return (al+ah+bl+bh)*.25; } // just use the intersection al = (l.v1.p,highestfloor.ZatPoint(l.v1.p)); ah = (l.v1.p,lowestceiling.ZatPoint(l.v1.p)); bl = (l.v2.p,highestfloor.ZatPoint(l.v2.p)); bh = (l.v2.p,lowestceiling.ZatPoint(l.v2.p)); return (al+ah+bl+bh)*.25; } static clearscope void ClearAllShaders( PlayerInfo p ) { Shader.SetEnabled(p,"WaterWarp",false); Shader.SetEnabled(p,"LavaWarp",false); Shader.SetEnabled(p,"SlimeWarp",false); Shader.SetEnabled(p,"ZoomBlur",false); Shader.SetEnabled(p,"RagekitShader",false); Shader.SetEnabled(p,"GhostShader",false); Shader.SetEnabled(p,"InvinciShader",false); Shader.SetEnabled(p,"Glitch",false); Shader.SetEnabled(p,"Grain",false); } // level end stats override void WorldUnloaded( WorldEvent e ) { if ( !(gameinfo.gametype&GAME_STRIFE) ) { let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC); SWWMStats s; while ( s = SWWMStats(ti.Next()) ) { int clust = 0; bool secret = false; if ( SWWMUtility.IsEviternity() ) { // we have to do some heavy lifting here because episodes don't match clusters if ( level.levelnum <= 5 ) clust = 1; else if ( level.levelnum <= 10 ) clust = 2; else if ( level.levelnum <= 15 ) clust = 3; else if ( level.levelnum <= 20 ) clust = 4; else if ( level.levelnum <= 25 ) clust = 5; else if ( level.levelnum <= 30 ) clust = 6; else if ( level.levelnum <= 32 ) { secret = true; if ( level.levelnum <= 31 ) clust = 7; else clust = 8; } } else { if ( (gameinfo.gametype&GAME_DOOM) && ((level.cluster == 9) || (level.cluster == 10)) ) secret = true; clust = level.cluster; } int csiz = s.clustervisit.Size(); if ( csiz == 0 ) { s.clustervisit.Push(clust); s.secretdone.Push(secret); } else if ( s.clustervisit[csiz-1] != clust ) { s.clustervisit.Push(clust); s.secretdone.Push(secret|s.secretdone[csiz-1]); } s.AddLevelStats(); } } ClearAllShaders(players[consoleplayer]); // reset score on dead players (death exitâ„¢) for ( int i=0; i 0) ) continue; let c = SWWMCredits.Find(players[i]); if ( c ) c.credits = c.hcredits = 0; } } override void WorldLoaded( WorldEvent e ) { if ( level.levelname ~== "Modder Test Map" ) { level.ReplaceTextures("-noflat-","kinstile",0); S_ChangeMusic("music/CARDISH1.XM"); } if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]); if ( !e.IsSaveGame && !e.IsReopen && (gamestate != GS_TITLELEVEL) ) AddOneliner("mapstart",3); if ( !e.IsSaveGame && !e.IsReopen ) { // for skipping over merged exit lines (sharing vertices) Array skipme; skipme.Clear(); // find exit lines, and use lines that aren't exits for ( int i=0; i 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 ) { let s = SWWMStats.Find(players[e.playernumber]); if ( s ) s.deaths++; } override void PlayerEntered( PlayerEvent e ) { PlayerInfo p = players[e.playernumber]; // override KEYCONF-forced player classes when run with other gameplay mods (wish this was easier) if ( !(p.mo is 'Demolitionist') ) { // make sure it's defined here, so special purpose classes (player chunks, scripted overrides) are respected for ( int i=0; i= 0) && (casings_cnt > swwm_maxcasings) ) DeQueueCasing(casings); } if ( swwm_maxdebris != oldmaxdebris ) { 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; } // countable item scoring private void ItemCountTrack() { for ( int i=0; i lastitemcount[i] ) { int score = 10*(players[i].itemcount-lastitemcount[i]); if ( (level.total_items == level.found_items) && !allitems ) { allitems = true; Console.Printf(StringTable.Localize("$SWWM_LASTITEM"),players[i].GetUserName(),500); score += 490; } SWWMCredits.Give(players[i],score); SWWMScoreObj.Spawn(score,players[i].mo.Vec3Offset(0,0,players[i].mo.Height/2)); lastitemcount[i] = players[i].itemcount; let s = SWWMStats.Find(players[i]); s.items++; } } } // combat tracking private void CombatTrack() { // prune old entries for ( int i=0; i highesttic ) highesttic = combattics[i]; if ( combatactors[i] && (combatactors[i].Health > 0) && !combatactors[i].bKILLED && !combatactors[i].bCORPSE && (combatactors[i].target == players[consoleplayer].mo) && (combattics[i]+2000 > gametic) ) continue; combatactors.Delete(i); combattics.Delete(i); i--; } bool enteredcombat = false; // add new entries let ti = ThinkerIterator.Create("Actor"); Actor a; while ( a = Actor(ti.Next()) ) { if ( !a.player && !a.bISMONSTER ) continue; // ignore the dead if ( (a.Health <= 0) || a.bKILLED || a.bCORPSE ) continue; // ignore friends if ( a.IsFriend(players[consoleplayer].mo) ) continue; // [Strife] ignore if not in combat if ( (gameinfo.gametype&GAME_Strife) && !a.bINCOMBAT && !a.bJUSTATTACKED ) continue; // [Strife] ignore certain classes if ( (a is 'RatBuddy') || (a is 'Peasant') || (a is 'Beggar') ) continue; // [Strife] ignore Oracle's spectre while it's inactive if ( (a is 'AlienSpectre3') && a.InStateSequence(a.CurState,a.FindState("Spawn")) ) continue; // ignore if not targetted or player can't see it if ( (a.target != players[consoleplayer].mo) || !SWWMUtility.InPlayerFOV(players[consoleplayer],a) ) continue; // [HDoom] ignore cute girls if ( SWWMHDoomHandler.IsCuteGirl(a.target) ) continue; // is it already in? bool addme = true; for ( int i=0; i highesttic+700)) ) lastcombat = AddOneliner("fightstart",1,10); } private void OneHundredPercentCheck() { // ignore levels that have NOTHING if ( (level.total_secrets <= 0) && (level.total_items <= 0) && (level.total_monsters <= 0) ) return; if ( mapclear ) return; if ( (level.found_secrets < level.total_secrets) || (level.found_items < level.total_items) || (level.killed_monsters < level.total_monsters) ) return; mapclear = true; Console.Printf(StringTable.Localize("$SWWM_ALLCLEAR"),5000); S_StartSound("misc/wow",CHAN_VOICE,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); if ( swwm_silencemap == 1 ) S_ChangeMusic("",force:true); else if ( swwm_silencemap > 1 ) S_ChangeMusic("music/olg.ogg",force:true); for ( int i=0; i= 5) ) { mnotify = true; let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC); SWWMStats s; while ( s = SWWMStats(ti.Next()) ) { if ( !SWWMUtility.IsKnownMap() ) break; if ( s.myplayer != players[consoleplayer] ) continue; int clust = level.cluster; if ( SWWMUtility.IsEviternity() ) { // we have to do some heavy lifting here because episodes don't match clusters if ( level.levelnum <= 5 ) clust = 1; else if ( level.levelnum <= 10 ) clust = 2; else if ( level.levelnum <= 15 ) clust = 3; else if ( level.levelnum <= 20 ) clust = 4; else if ( level.levelnum <= 25 ) clust = 5; else if ( level.levelnum <= 30 ) clust = 6; else if ( level.levelnum <= 31 ) clust = 7; else if ( level.levelnum <= 32 ) clust = 8; } int csiz = s.clustervisit.Size(); if ( (csiz > 0) && (s.clustervisit[csiz-1] != clust) ) Console.Printf(StringTable.Localize("$SWWM_NEWMISSION")); } } if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]); if ( onelinertic && (onelinertic < gametic) ) { if ( players[consoleplayer].health > 0 ) { if ( onelinerlevel > mutevoice.GetInt() ) players[consoleplayer].mo.A_StartSound(onelinersnd,CHAN_DEMOVOICE,CHANF_DEFAULT,1.,ATTN_NONE); SendNetworkEvent("swwmremoteliner."..onelinersnd,consoleplayer,onelinerlevel); } onelinertic = 0; onelinerspan = 0; } for ( int i=0; i= gametic ) continue; flashes.Delete(i); i--; } ItemCountTrack(); CombatTrack(); OneHundredPercentCheck(); if ( initialized ) return; // wait until bosses are active for ( int i=0; i 0); } override void WorldThingDied( WorldEvent e ) { if ( e.Thing.default.bISMONSTER && ((e.Thing.default.bBOSS) || (e.Thing.GetSpawnHealth() >= 1000)) && (alreadygold.Find(e.Thing) == alreadygold.Size()) ) { // make sure we can't farm drops from revivable enemies // (or cause some things to spam-spawn gold shells) // (*cough* Touhou Doom *cough*) alreadygold.Push(e.Thing); // weight drop chance based on total count of this monster type // guarantees that maps that get a bit slaughtery won't become easy farms for drops int dropweight = 0; let ti = ThinkerIterator.Create(e.Thing.GetClass()); while ( ti.Next() ) dropweight++; int minchance = max(1,6-(e.Thing.GetSpawnHealth()/1000)); dropweight = max(minchance,dropweight/4); // make sure the gold shell is "worth spawning", too if ( !Random[GoldDrop](0,dropweight) && ShouldSpawnGold() ) { let g = Actor.Spawn("GoldShell",e.Thing.Vec3Offset(0,0,e.Thing.Height/2)); double ang = FRandom[SpareShells](0,360); g.vel.xy = (cos(ang),sin(ang))*FRandom[SpareShells](.4,.8); g.vel.z = FRandom[SpareShells](2.,4.); } } // Korax instakill if ( (e.Thing is 'Korax') && !e.Thing.special2 && HexenMap40() ) { e.Thing.special2 = 1; // terminate the monster closet scripts, open all the // doors ourselves level.ExecuteSpecial(ACS_Terminate,e.Thing,null,false,220); level.ExecuteSpecial(ACS_Terminate,e.Thing,null,false,220); level.ExecuteSpecial(ACS_Terminate,e.Thing,null,false,221); level.ExecuteSpecial(ACS_Terminate,e.Thing,null,false,255); level.ExecuteSpecial(Door_Open,e.Thing,null,false,10,16); level.ExecuteSpecial(Door_Open,e.Thing,null,false,11,16); level.ExecuteSpecial(Door_Open,e.Thing,null,false,12,16); level.ExecuteSpecial(Door_Open,e.Thing,null,false,13,16); level.ExecuteSpecial(Door_Open,e.Thing,null,false,14,16); level.ExecuteSpecial(Door_Open,e.Thing,null,false,10,16); // keep the portal closed, you can't leave unless you // kill everyone else let t = new("UglyBoyGetsFuckedUp"); t.ChangeStatNum(Thinker.STAT_USER); } if ( swwm_partytime ) { 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"); } // gibbing private void DoGibThing( WorldEvent e ) { // 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); } 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 ) { 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; } } // 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?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) ) lastcombat = AddOneliner("hitfriend",1,10); highesttic = gametic; } } } // 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)) ) return; 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?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.GetSpawnHealth()*.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; } } spreecount[pnum]++; if ( s && (spreecount[pnum] > s.skill) && !tookdamage[pnum] ) s.skill = spreecount[pnum]; 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]; 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)); } } 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'); // voodoo doll telefragging barrel hax (eviternity death exits) if ( (e.Thing is 'ExplosiveBarrel') && (e.DamageType == 'Telefrag') && e.DamageSource.player && (e.DamageSource.player.mo != e.DamageSource) ) 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 ) { if ( a is 'SWWMKey' ) return; // mod's custom keys are fine if ( a is 'RedCard' ) a.SetTag("$T_REDCARD"); else if ( a is 'BlueCard' ) a.SetTag("$T_BLUECARD"); else if ( a is 'YellowCard' ) a.SetTag("$T_YELLOWCARD"); else if ( a is 'RedSkull' ) a.SetTag("$T_REDSKULL"); else if ( a is 'BlueSkull' ) a.SetTag("$T_BLUESKULL"); else if ( a is 'YellowSkull' ) a.SetTag("$T_YELLOWSKULL"); else if ( a is 'KeyYellow' ) a.SetTag("$T_YELLOWKEY"); else if ( a is 'KeyGreen' ) a.SetTag("$T_GREENKEY"); else if ( a is 'KeyBlue' ) a.SetTag("$T_BLUEKEY"); else if ( a.GetClassName() == 'KeyRed' ) a.SetTag("$T_REDKEY"); else if ( a is 'KeySteel' ) a.SetTag("$T_KEYSTEEL"); else if ( a is 'KeyCave' ) a.SetTag("$T_KEYCAVE"); else if ( a is 'KeyAxe' ) a.SetTag("$T_KEYAXE"); else if ( a is 'KeyFire' ) a.SetTag("$T_KEYFIRE"); else if ( a is 'KeyEmerald' ) a.SetTag("$T_KEYEMERALD"); else if ( a is 'KeyDungeon' ) a.SetTag("$T_KEYDUNGEON"); else if ( a is 'KeySilver' ) a.SetTag("$T_KEYSILVER"); else if ( a is 'KeyRusted' ) a.SetTag("$T_KEYRUSTED"); else if ( a is 'KeyHorn' ) a.SetTag("$T_KEYHORN"); else if ( a is 'KeySwamp' ) a.SetTag("$T_KEYSWAMP"); else if ( a is 'KeyCastle' ) a.SetTag("$T_KEYCASTLE"); } // tempfix keys have no tags static void KeyTagFix( Actor a ) { let hnd = SWWMHandler(Find("SWWMHandler")); if ( hnd ) hnd.DoKeyTagFix(a); } // copies the floatbob of overlapping identical items, so it doesn't look weird private void CopyFloatBob( Actor a ) { let bt = BlockThingsIterator.Create(a,16); while ( bt.Next() ) { let t = bt.Thing; if ( !t || (t == a) || !(t is 'Inventory') || !(t.spawnpoint ~== a.spawnpoint) ) continue; a.floatbobphase = t.floatbobphase; break; } } override void WorldThingSpawned( WorldEvent e ) { // I WANT DIE if ( G_SkillName() == StringTable.Localize("$SWWM_SKLUNATIC") ) { if ( e.Thing.bMISSILE && !e.Thing.FindInventory("DontDuplicate") && !e.Thing.IsZeroDamage() && (e.Thing.target && e.Thing.target.bISMONSTER && !e.Thing.target.player) ) { e.Thing.speed *= 2; e.Thing.vel *= 2; Vector3 x, y, z; [x, y, z] = swwm_CoordUtil.GetAxes(e.Thing.pitch,e.Thing.angle,e.Thing.roll); int numpt = Random[ExtraMissiles](1,2); for ( int i=0; i 0) ) { int mute; if ( mutevoice ) mute = mutevoice.GetInt(); else mute = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt(); // we can't assign the variable here since it's play scope if ( onelinerlevel > mute ) { let l = SWWMOneLiner.Make(oneliner,onelinerspan); StatusBar.AttachMessage(l,-3473); } SendNetworkEvent("swwmremotelinertxt."..oneliner,consoleplayer,onelinerlevel); } for ( int i=0; i 0 ) { cummdamage += curcumm; lastcummtic = gametic; } else if ( gametic > lastcummtic+150 ) cummdamage = 0; thealth = newhealth; ihealthr.Update(thealth); if ( thealth > oldhealth[29] ) for ( int i=29; i>0; i-- ) oldhealth[i] = thealth; ihealth.Update(oldhealth[29]); for ( int i=29; i>0; i-- ) oldhealth[i] = oldhealth[i-1]; if ( thealth > 0 ) bossalpha = min(3.,bossalpha+1./30.); else bossalpha = max(0,bossalpha-1./50.); } override bool InputProcess( InputEvent e ) { if ( (e.Type == InputEvent.TYPE_KeyDown) && (e.KeyChar >= 0x61) && (e.KeyChar <= 0x7A) ) { // cheat code handling String cht[] = { "swwmlodsofemone", "swwmdeeplore", // SWWM Platinum cheats "swwmimstuck", "swwmarmojumbo", "swwmdangimhealthy", "swwmwarriorofzaemonath", "swwmpowerparp", "swwmcannotseemyhands", "swwmreflectonme", "swwmgunzmeneeds", "swwmbloodrainsfromheaven", "swwmnotwannaboom", "swwmverywrappyoatmeal", "swwmflaggerybingo", "swwmheadsball", "swwmsmarties", "swwmnocilla", "swwmmarioisaweenie", "swwmpunish", "swwmboingball", "swwmgassy", "swwmiamsuperman", "swwmtouchstone" }; String cmd[] = { "swwmmoneycheat", "swwmlorecheat", // SWWM Platinum cheats "swwmsafecheat", "swwmweaponcheat", "swwmhealcheat", "swwmynykroncheat", "swwmgravcheat", "swwminvischeat", "swwmbarriercheat", "swwmammocheat", "swwmbloodcheat", "swwmexplocheat", "swwmallcheat", "swwmflagcheat", "swwmballcheat", "swwmsmartcheat", "swwmnutcheat", "swwmweeniecheat", "swwmpunishcheat", "swwmball2cheat", "swwmfartcheat", "swwmsupercheat", "swwmstonecheat" }; bool matchany = false; kstr.AppendCharacter(e.KeyChar); if ( kstr.Length() > 0 ) { for ( int i=0; i 4 ) return true; // eat keypresses from this point } } // F if ( e.KeyChar == 0x66 ) { let demo = Demolitionist(players[consoleplayer].mo); let gone = PlayerGone(players[consoleplayer].mo); if ( (demo && (demo.Health <= 0) && (demo.deadtimer > 40)) || (gone && (gone.Health <= 0) && (gone.deadtimer > 40)) ) { // pay respects int numf = Random[FInTheChat](1,6); for ( int i=0; i 255) ) return; if ( e.Thing.CheckLocalView() && !e.Thing.CheckKeys(locknum,false,true) ) { if ( !lastlock || (gametic > lastlock+20) ) { if ( SWWMUtility.IsValidLockNum(locknum) ) lastlock = AddOneliner("locked",2); else lastlock = AddOneliner("jammed",2); } } } override void WorldLineActivated( WorldEvent e ) { if ( !(e.ActivationType&SPAC_Use) ) return; if ( !e.Thing || !e.Thing.player ) return; let w = SWWMWeapon(e.Thing.player.ReadyWeapon); if ( !w || !w.wallponch ) return; let s = SWWMStats.Find(e.Thing.player); if ( s ) s.wponch++; } override void CheckReplacee( ReplacedEvent e ) { if ( e.Replacement is 'DSparilHax' ) e.Replacee = 'Sorcerer2'; } // do any players not own dual guns yet private bool ShouldSpawnDualExpl() { int np = 0, ng = 0; // check travelling items, in case this was called mid-transition let ti = ThinkerIterator.Create("ExplodiumGun",Thinker.STAT_TRAVELLING); ExplodiumGun g; while ( g = ExplodiumGun(ti.Next()) ) { np++; if ( g.Amount > 1 ) ng++; } if ( np > 0 ) return (ng < np); for ( int i=0; i 1 ) ng++; } return (ng < np); } override void CheckReplacement( ReplaceEvent e ) { // respect final replacements if ( e.IsFinal ) return; // shell types (sorted by rarity static const Class redpool[] = {"RedShell","RedShell2","RedShell4","RedShell8"}; static const Class greenpool[] = {"GreenShell","GreenShell2","GreenShell4"}; static const Class whitepool[] = {"WhiteShell","WhiteShell2"}; static const Class purplepool[] = {"PurpleShell","PurpleShell2","PurpleShell4"}; static const Class bluepool[] = {"BlueShell","BlueShell2","BlueShell4"}; static const Class blackpool[] = {"BlackShell","BlackShell2"}; // 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')) ) { let def = GetDefaultByType(e.Replacee); bool dehackery = false; for ( State s=def.SpawnState; s; s=s.NextState ) { if ( s.bDEHACKED ) dehackery = true; if ( s.NextState == s ) break; } if ( dehackery ) return; e.Replacement = 'SWWMHangingKeen'; } else if ( (e.Replacee is 'BossBrain') && (!e.Replacement || (e.Replacement == 'BossBrain')) ) { let def = GetDefaultByType(e.Replacee); bool dehackery = false; for ( State s=def.SpawnState; s; s=s.NextState ) { if ( s.bDEHACKED ) dehackery = true; if ( s.NextState == s ) break; } if ( dehackery ) return; e.Replacement = 'SWWMBossBrain'; } else if ( e.Replacee is 'RedCard' ) { if ( level.GetChecksum() ~== "3805A661D5C4523AFF7BF86991071043" ) return; // don't replace red key in Equinox MAP13 e.Replacement = 'SWWMRedCard'; } else if ( e.Replacee is 'BlueCard' ) e.Replacement = 'SWWMBlueCard'; else if ( e.Replacee is 'YellowCard' ) e.Replacement = 'SWWMYellowCard'; else if ( e.Replacee.GetClassName() == 'KDiZDSilverKey' ) e.Replacement = 'SWWMSilverCardKDiZD'; else if ( e.Replacee.GetClassName() == 'KDiZDGreenKey' ) e.Replacement = 'SWWMGreenCardKDiZD'; else if ( e.Replacee.GetClassName() == 'KDiZDOrangeKey' ) e.Replacement = 'SWWMOrangeCardKDiZD'; else if ( e.Replacee.GetClassName() == 'GreenCard' ) e.Replacement = 'SWWMGreenCard'; else if ( e.Replacee is 'RedSkull' ) e.Replacement = 'SWWMRedSkull'; else if ( e.Replacee is 'BlueSkull' ) e.Replacement = 'SWWMBlueSkull'; else if ( e.Replacee is 'YellowSkull' ) e.Replacement = 'SWWMYellowSkull'; else if ( e.Replacee is 'KeyGreen' ) e.Replacement = 'SWWMKeyGreen'; else if ( e.Replacee is 'KeyBlue' ) e.Replacement = 'SWWMKeyBlue'; else if ( e.Replacee is 'KeyYellow' ) e.Replacement = 'SWWMKeyYellow'; else if ( e.Replacee.GetClassName() == 'KeyRed' ) e.Replacement = 'SWWMKeyRed'; else if ( (e.Replacee is 'Chainsaw') || (e.Replacee is 'Gauntlets') || (e.Replacee is 'FWeapAxe') ) { if ( ShouldSpawnDualExpl() ) e.Replacement = Random[Replacements](0,1)?'ExplodiumGun':'PusherWeapon'; else e.Replacement = 'PusherWeapon'; } else if ( (e.Replacee is 'Fist') || (e.Replacee is 'Staff') ) e.Replacement = 'DeepImpact'; else if ( (e.Replacee is 'Pistol') || (e.Replacee is 'GoldWand') || (e.Replacee is 'FWeapFist') || (e.Replacee is 'CWeapMace') || (e.Replacee is 'MWeapWand') || (e.Replacee.GetClassName() == 'TangoPistol') ) e.Replacement = 'ExplodiumGun'; else if ( (e.Replacee is 'Shotgun') || (e.Replacee is 'CWeapStaff') || (e.Replacee.GetClassName() == 'TangoShotgun') ) e.Replacement = 'Spreadgun'; else if ( (e.Replacee is 'SuperShotgun') || (e.Replacee is 'MWeapFrost') || (e.Replacee.GetClassName() == 'TangoSuperShotgun') ) e.Replacement = 'Wallbuster'; else if ( (e.Replacee is 'Crossbow') || (e.Replacee.GetClassName() == 'TangoScrapGun') ) e.Replacement = Random[Replacements](0,2)?'Spreadgun':'Wallbuster'; else if ( (e.Replacee is 'Chaingun') || (e.Replacee is 'Blaster') || (e.Replacee is 'FWeaponPiece3') || (e.Replacee.GetClassName() == 'TangoAssaultRifle') || (e.Replacee.GetClassName() == 'TangoChaingun') ) e.Replacement = 'Eviscerator'; else if ( (e.Replacee is 'RocketLauncher') || (e.Replacee is 'PhoenixRod') || (e.Replacee is 'FWeapHammer') || (e.Replacee.GetClassName() == 'TangoStomper') ) e.Replacement = 'Hellblazer'; else if ( (e.Replacee is 'PlasmaRifle') || (e.Replacee is 'SkullRod') ) e.Replacement = Random[Replacements](0,2)?'Sparkster':'SilverBullet'; else if ( e.Replacee is 'CWeapFlame' ) e.Replacement = 'Sparkster'; else if ( e.Replacee is 'MWeapLightning' ) e.Replacement = 'SilverBullet'; else if ( (e.Replacee is 'BFG9000') || (e.Replacee is 'Mace') ) e.Replacement = Random[Replacements](0,2)?'CandyGun':'Ynykron'; else if ( e.Replacee is 'CWeaponPiece2' ) e.Replacement = 'CandyGun'; else if ( e.Replacee is 'MWeaponPiece1' ) e.Replacement = 'Ynykron'; else if ( (e.Replacee is 'ShellBox') || (e.Replacee is 'CrossbowHefty') || (e.Replacee.GetClassName() == 'TangoShellBox') || (e.Replacee.GetClassName() == 'TangoScrapDrumPack') ) { switch( Random[Replacements](0,14) ) { case 0: case 1: case 2: e.Replacement = redpool[Random[Replacements](1,2)]; break; case 3: case 4: case 5: e.Replacement = greenpool[Random[Replacements](1,2)]; break; case 6: case 7: case 8: e.Replacement = whitepool[Random[Replacements](0,1)]; break; case 9: case 10: case 11: e.Replacement = purplepool[Random[Replacements](0,2)]; break; case 12: case 13: e.Replacement = bluepool[Random[Replacements](0,2)]; break; case 14: e.Replacement = blackpool[Random[Replacements](0,1)]; break; } } else if ( (e.Replacee is 'Shell') || (e.Replacee is 'CrossbowAmmo') || (e.Replacee.GetClassName() == 'TangoShell') || (e.Replacee.GetClassName() == 'TangoScrapDrum') ) { switch( Random[Replacements](0,13) ) { case 0: case 1: case 2: e.Replacement = redpool[Random[Replacements](0,2)]; break; case 3: case 4: case 5: e.Replacement = greenpool[Random[Replacements](0,2)]; break; case 6: case 7: e.Replacement = whitepool[0]; break; case 8: case 9: case 10: e.Replacement = purplepool[Random[Replacements](0,1)]; break; case 11: case 12: e.Replacement = bluepool[Random[Replacements](0,1)]; break; case 13: e.Replacement = blackpool[0]; break; } } else if ( e.Replacee is 'ClipBox' ) e.Replacement = Random[Replacements](0,4)?'EvisceratorShell':Random[Replacements](0,6)?'EvisceratorTrioSpawn':'EvisceratorSixPack'; else if ( (e.Replacee is 'Clip') || (e.Replacee is 'GoldWandAmmo') ) e.Replacement = 'SWWMNothing'; else if ( e.Replacee is 'BlasterHefty' ) e.Replacement = Random[Replacements](0,6)?'EvisceratorTrioSpawn':'EvisceratorSixPack'; else if ( (e.Replacee is 'BlasterAmmo') || (e.Replacee.GetClassName() == 'TangoBulletClipHalf') ) e.Replacement = 'EvisceratorShell'; else if ( (e.Replacee is 'RocketBox') || (e.Replacee is 'PhoenixRodHefty') || (e.Replacee is 'MaceHefty')|| (e.Replacee.GetClassName() == 'TangoStomperBox') ) { switch ( Random[Replacements](0,11) ) { case 0: case 1: case 2: case 3: case 4: if ( Random[Replacements](0,5) ) e.Replacement = 'HellblazerMissiles'; else if ( Random[Replacements](0,4) ) e.Replacement = 'HellblazerMissileTrioSpawn'; else e.Replacement = 'HellblazerMissileMag'; break; case 5: case 6: case 7: case 8: if ( Random[Replacements](0,6) ) e.Replacement = 'HellblazerCrackshots'; else e.Replacement = 'HellblazerCrackshotMag'; break; case 9: case 10: if ( Random[Replacements](0,8) ) e.Replacement = 'HellblazerRavagers'; else e.Replacement = 'HellblazerRavagerMag'; break; case 11: if ( Random[Replacements](0,10) ) e.Replacement = 'HellblazerWarheads'; else e.Replacement = 'HellblazerWarheadMag'; break; } } else if ( (e.Replacee is 'RocketAmmo') || (e.Replacee is 'PhoenixRodAmmo') || (e.Replacee is 'MaceAmmo') || (e.Replacee.GetClassName() == 'TangoStomperAmmo') ) e.Replacement = Random[Replacements](0,2)?'HellblazerMissiles':'HellblazerCrackshots'; else if ( (e.Replacee is 'CellPack') || (e.Replacee is 'SkullRodHefty') ) { if ( !Random[Replacements](0,2) ) { if ( Random[Replacements](0,3) ) e.Replacement = Random[Replacements](0,2)?'SilverBulletsBundleSpawn':'SilverBullets2BundleSpawn'; else e.Replacement = Random[Replacements](0,2)?'SilverBulletAmmo':'SilverBulletAmmo2'; } else if ( Random[Replacements](0,2) ) e.Replacement = 'CandyGunBulletsBundleSpawn'; else e.Replacement = 'CandyGunAmmo'; } else if ( (e.Replacee is 'Cell') || (e.Replacee is 'SkullRodAmmo') ) { if ( !Random[Replacements](0,2) ) e.Replacement = Random[Replacements](0,2)?'HellblazerRavagers':'HellblazerWarheads'; else if ( Random[Replacements](0,2) ) e.Replacement = 'SparkUnit'; else if ( !Random[Replacements](0,3) ) e.Replacement = 'CandyGunBullets'; else e.Replacement = Random[Replacements](0,2)?'SilverBullets':'SilverBullets2'; } else if ( e.Replacee is 'Mana1' ) e.Replacement = 'FabricatorTier1'; else if ( e.Replacee is 'Mana2' ) e.Replacement = 'FabricatorTier2'; else if ( e.Replacee is 'Mana3' ) e.Replacement = 'FabricatorTier3'; else if ( e.Replacee is 'ArtiBoostMana' ) e.Replacement = 'FabricatorTier4'; else if ( (e.Replacee is 'Backpack') || (e.Replacee is 'BagOfHolding') || (e.Replacee is 'ArtiBoostArmor') ) e.Replacement = 'HammerspaceEmbiggener'; else if ( (e.Replacee is 'FWeaponPiece1') || (e.Replacee is 'FWeaponPiece2') || (e.Replacee is 'CWeaponPiece1') || (e.Replacee is 'CWeaponPiece3') || (e.Replacee is 'MWeaponPiece2') || (e.Replacee is 'MWeaponPiece3') ) { if ( Random[Replacements](0,1) ) e.Replacement = 'SWWMNothing'; else if ( Random[Replacements](0,5) ) e.Replacement = 'HammerspaceEmbiggener'; else e.Replacement = 'GoldShell'; } else if ( (e.Replacee is 'ArmorBonus') || (e.Replacee is 'ArtiTimeBomb') || (e.Replacee is 'ArtiBlastRadius') || (e.Replacee is 'ArtiPoisonBag') ) e.Replacement = 'ArmorNuggetItem'; else if ( (e.Replacee is 'HealthBonus') || (e.Replacee is 'CrystalVial') ) e.Replacement = 'HealthNuggetItem'; else if ( e.Replacee is 'Stimpack' ) e.Replacement = 'TetraHealthItem'; else if ( e.Replacee is 'Medikit' ) e.Replacement = 'CubeHealthItem'; else if ( e.Replacee is 'ArtiHealth' ) e.Replacement = Random[Replacements](0,1)?'CubeHealthItem':'TetraHealthItem'; else if ( (e.Replacee is 'Soulsphere') || (e.Replacee is 'ArtiSuperHealth') ) e.Replacement = 'RefresherItem'; else if ( e.Replacee is 'ArtiHealingRadius' ) e.Replacement = 'SWWMNothing'; else if ( (e.Replacee is 'Megasphere') || (e.Replacee is 'ArtiEgg') || (e.Replacee is 'PlatinumHelm') ) e.Replacement = 'GrilledCheeseSandwich'; else if ( (e.Replacee is 'Blursphere') || (e.Replacee is 'ArtiInvisibility') || (e.Replacee is 'AmuletOfWarding') ) e.Replacement = 'GhostArtifact'; else if ( e.Replacee is 'Radsuit' ) e.Replacement = 'EBarrier'; else if ( (e.Replacee is 'ArtiFly') ) e.Replacement = 'GravitySuppressor'; else if ( (e.Replacee is 'InvulnerabilitySphere') || (e.Replacee is 'ArtiInvulnerability') || (e.Replacee is 'ArtiInvulnerability2') ) e.Replacement = 'FuckingInvinciball'; else if ( (e.Replacee is 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'Ragekit'; else if ( (e.Replacee is 'AllMap') || (e.Replacee is 'SuperMap') ) e.Replacement = 'Omnisight'; else if ( (e.Replacee is 'Infrared') || (e.Replacee is 'ArtiTorch') ) e.Replacement = 'SWWMLamp'; else if ( (e.Replacee is 'GreenArmor') || (e.Replacee is 'SilverShield') || (e.Replacee is 'MeshArmor') ) e.Replacement = 'BlastSuitItem'; else if ( (e.Replacee is 'BlueArmor') || (e.Replacee is 'FalconShield') || (e.Replacee is 'EnchantedShield') ) e.Replacement = 'WarArmorItem'; else if ( (e.Replacee is 'ArtiPork') || (e.Replacee is 'ArtiDarkServant') || (e.Replacee is 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') ) e.Replacement = 'ChanceboxSpawner'; else return; // this last part is kind of ugly, but it works // guarantees that OUR replacements are all final e.IsFinal = true; } override void ConsoleProcess( ConsoleEvent e ) { // doing it with an event because this way we can control WHEN it should be openable if ( e.Name ~== "swwmdemomenu" ) { if ( (gamestate != GS_LEVEL) || (players[consoleplayer].Health <= 0) || !(players[consoleplayer].mo is 'Demolitionist') ) return; Menu.SetMenu('DemolitionistMenu'); } } override void NetworkProcess( ConsoleEvent e ) { static const Class cbttypes[] = {"RedShell","GreenShell","BlueShell","PurpleShell"}; if ( e.Name ~== "swwmgesture" ) { if ( (e.player == -1) || !playeringame[e.player] || !players[e.player].mo ) return; let mo = players[e.player].mo; switch( e.Args[0] ) { case 0: SWWMGesture.SetGesture(mo,GS_Wave); break; case 1: SWWMGesture.SetGesture(mo,GS_ThumbsUp); break; case 2: SWWMGesture.SetGesture(mo,GS_Victory); break; case 3: SWWMGesture.SetGesture(mo,GS_BlowKiss); break; } } else if ( e.Name ~== "swwmdebugdumprng" ) { // dump the values of all mod RNGs (might help someday to track down what desyncs) Console.Printf("\cxSWWM GZ RNG dump for player %d (\c-%s\cx):\c-",consoleplayer,players[consoleplayer].GetUserName()); Console.Printf("bdscreen: %d",Random2[bdscreen]()); Console.Printf("Blood: %d",Random2[Blood]()); Console.Printf("Boolet: %d",Random2[Boolet]()); Console.Printf("BrainExplode: %d",Random2[BrainExplode]()); Console.Printf("Bundle: %d",Random2[Bundle]()); Console.Printf("Candy: %d",Random2[Candy]()); Console.Printf("Chancebox: %d",Random2[Chancebox]()); Console.Printf("DemoLines: %d",Random2[DemoLines]()); Console.Printf("DoBlast: %d",Random2[DoBlast]()); Console.Printf("Eviscerator: %d",Random2[Eviscerator]()); Console.Printf("Explos: %d",Random2[Explos]()); Console.Printf("FInTheChat: %d",Random2[FInTheChat]()); Console.Printf("FlameT: %d",Random2[FlameT]()); Console.Printf("Flicker: %d",Random2[Flicker]()); Console.Printf("FunTags: %d",Random2[FunTags]()); Console.Printf("Gibs: %d",Random2[Gibs]()); Console.Printf("GoldDrop: %d",Random2[GoldDrop]()); Console.Printf("Goldy: %d",Random2[Goldy]()); Console.Printf("GunFlash: %d",Random2[GunFlash]()); Console.Printf("hdscreen: %d",Random2[hdscreen]()); Console.Printf("Hellblazer: %d",Random2[Hellblazer]()); Console.Printf("HudStuff: %d",Random2[HudStuff]()); Console.Printf("Impact: %d",Random2[Impact]()); Console.Printf("InterArt: %d",Random2[InterArt]()); Console.Printf("Invinciball: %d",Random2[Invinciball]()); Console.Printf("Junk: %d",Random2[Junk]()); Console.Printf("Moth: %d",Random2[Moth]()); Console.Printf("Nugget: %d",Random2[Nugget]()); Console.Printf("Parry: %d",Random2[Parry]()); Console.Printf("Ponch: %d",Random2[Ponch]()); Console.Printf("Puff: %d",Random2[Puff]()); Console.Printf("Pusher: %d",Random2[Pusher]()); Console.Printf("Rage: %d",Random2[Rage]()); Console.Printf("Replacements: %d",Random2[Replacements]()); Console.Printf("ScoreBits: %d",Random2[ScoreBits]()); Console.Printf("ShellDrop: %d",Random2[ShellDrop]()); Console.Printf("Shivers: %d",Random2[Shivers]()); Console.Printf("Silverbullet: %d",Random2[Silverbullet]()); Console.Printf("SpareShells: %d",Random2[SpareShells]()); Console.Printf("Sparkster: %d",Random2[Sparkster]()); Console.Printf("Spread: %d",Random2[Spread]()); Console.Printf("Spreadgun: %d",Random2[Spreadgun]()); Console.Printf("TUID: %d",Random2[TUID]()); Console.Printf("Wallbuster: %d",Random2[Wallbuster]()); Console.Printf("WallbusterMenu: %d",Random2[WallbusterMenu]()); Console.Printf("Ynykron: %d",Random2[Ynykron]()); } if ( e.IsManual ) return; if ( e.Name.Left(14) ~== "swwmstoregive." ) { Class item = e.Name.Mid(14); if ( !item ) return; if ( SWWMCredits.Take(players[e.Args[0]],e.Args[1]) ) { let def = GetDefaultByType(item); SWWMWeapon sw; // drop the swapweapon if we own it first if ( swwm_swapweapons && (item is 'SWWMWeapon') && (sw = SWWMWeapon(def).HasSwapWeapon(players[e.Args[0]].mo)) ) { bool swapto = (sw == players[e.Args[0]].ReadyWeapon) || (sw.SisterWeapon && (sw.Sisterweapon == players[e.Args[0]].ReadyWeapon)); int ngun = sw.Amount; double ang = -15*(ngun-1); for ( int i=0; i 1) ) players[e.Args[0]].mo.A_SelectWeapon("DualExplodiumGun"); else players[e.Args[0]].mo.A_SelectWeapon((Class)(item)); } } } else if ( e.Name.Left(10) ~== "swwmtrade." ) { Class item = e.Name.Mid(10); if ( !item ) return; let def = GetDefaultByType(item); int amt = def.Amount; // if it's an ammo, check the largest unit givable if ( item is 'Ammo' ) { for ( int i=0; i)(AllActorClasses[i]); if ( !a || (a.GetParentClass() != item) || (GetDefaultByType(a).Amount < amt) ) continue; amt = GetDefaultByType(a).Amount; } } Inventory ritm = players[e.Args[1]].mo.FindInventory(item); if ( ritm ) { int maxgive = ritm.MaxAmount-ritm.Amount; if ( amt > maxgive ) amt = maxgive; } else if ( amt > def.MaxAmount ) amt = def.MaxAmount; bool rslt = false; if ( (amt > 0) && players[e.Args[1]].mo.GiveInventory(item,amt,true) ) { players[e.Args[0]].mo.TakeInventory(item,amt); // add to history SWWMTradeHistory.RegisterSend(players[e.Args[0]],players[e.Args[1]],item,amt); SWWMTradeHistory.RegisterReceive(players[e.Args[1]],players[e.Args[0]],item,amt); // add messages if ( e.Args[0] == consoleplayer ) Console.Printf(StringTable.Localize("$SWWM_MSGSENT"),amt,def.GetTag(),players[e.Args[1]].GetUserName()); if ( e.Args[1] == consoleplayer ) Console.Printf(StringTable.Localize("$SWWM_MSGRECV"),players[e.Args[0]].GetUserName(),amt,def.GetTag()); rslt = true; } if ( e.Args[0] == consoleplayer ) { let t = new("MenuTransaction"); t.uid = e.Args[2]; t.type = MenuTransaction.TT_ITEMSEND; t.result = rslt; t.used = item; t.usedup = (players[e.Args[1]].mo.CountInv(item)<=0); checklist.Push(t); } } else if ( e.Name.Left(17) ~== "swwmmarkloreread." ) { let l = SWWMLoreLibrary.Find(players[e.Args[0]]); let idx = l.FindEntry(e.Name.Mid(17)); l.MarkRead(idx); } else if ( e.Name.Left(12) ~== "swwmuseitem." ) { Class item = e.Name.Mid(12); if ( !item ) return; let i = players[e.Args[0]].mo.FindInventory(item); if ( !i ) return; bool rslt = players[e.Args[0]].mo.UseInventory(i); if ( e.Args[0] == consoleplayer ) { let t = new("MenuTransaction"); t.uid = e.Args[1]; t.type = MenuTransaction.TT_ITEMUSE; let w = (Class)(item); if ( w ) { t.result = (players[e.Args[0]].PendingWeapon==Weapon(i)); // dual wield gun support if ( (i is 'ExplodiumGun') && (players[e.Args[0]].PendingWeapon==Weapon(i).SisterWeapon) ) t.result = true; } else t.result = rslt; t.used = item; t.usedup = (!i||(i.Amount<=0)); checklist.Push(t); } } else if ( e.Name.Left(13) ~== "swwmdropitem." ) { Class item = e.Name.Mid(13); if ( !item ) return; let i = players[e.Args[0]].mo.FindInventory(item); if ( !i ) return; int amt = i.default.Amount; // if it's an ammo, check the largest unit givable if ( i is 'Ammo' ) { for ( int i=0; i)(AllActorClasses[i]); if ( !a || (a.GetParentClass() != item) || (GetDefaultByType(a).Amount < amt) ) continue; amt = GetDefaultByType(a).Amount; } } if ( amt > i.Amount ) amt = i.Amount; let drop = players[e.Args[0]].mo.DropInventory(i,amt); // add some random velocity so multiple drops don't get bunched together if ( drop ) drop.vel += (Actor.RotateVector((FRandom[Junk](-1.5,.5),FRandom[Junk](-2.5,2.5)),players[e.Args[0]].mo.angle),FRandom[Junk](2.,5.)); if ( e.Args[0] == consoleplayer ) { let t = new("MenuTransaction"); t.uid = e.Args[1]; t.type = MenuTransaction.TT_ITEMDROP; t.used = item; t.result = drop; t.usedup = (!i||(i.Amount<=0)); checklist.Push(t); } } else if ( e.Name ~== "swwmkoraxline" ) { if ( consoleplayer != e.Args[1] ) return; switch ( e.Args[0] ) { case 0: AddOneliner("koraxgreet",3,60); break; case 1: AddOneliner("koraxblood",3,150); break; case 2: AddOneliner("koraxgame",3,120); break; case 3: AddOneliner("koraxworship",3,80); break; case 4: AddOneliner("koraxmasters",3,90); break; } } else if ( e.Name.Left(16) ~== "swwmremoteliner." ) { if ( consoleplayer == e.Args[0] ) return; if ( !CVar.GetCVar('swwm_othervoice',players[consoleplayer]).GetBool() ) return; if ( CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() >= e.Args[1] ) return; players[e.Args[0]].mo.A_StartSound(e.Name.Mid(16),CHAN_DEMOVOICE,attenuation:.5); } else if ( e.Name.Left(19) ~== "swwmremotelinertxt." ) { if ( consoleplayer == e.Args[0] ) return; if ( !CVar.GetCVar('swwm_othervoice',players[consoleplayer]).GetBool() ) return; if ( CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() >= e.Args[1] ) return; double dist = players[consoleplayer].Camera.Distance3D(players[e.Args[0]].mo); if ( dist < 2000 ) Console.Printf("\cx%s\cx: %s\c-",players[e.Args[0]].GetUserName(),StringTable.Localize(e.Name.Mid(19))); } else if ( e.Name.Left(8) ~== "swwmcbt." ) { // from wikipedia, the free encyclopedia if ( !playeringame[e.Args[0]] || !players[e.Args[0]].mo ) return; let cbt = Wallbuster(players[e.Args[0]].mo.FindInventory("Wallbuster")); if ( !cbt ) return; cbt.reloadqueue.Clear(); Array qs; qs.Clear(); String rite = e.Name.Mid(8); rite.Split(qs,",",TOK_SKIPEMPTY); for ( int i=0; i 3) ) continue; cbt.reloadqueue.Push(cbttypes[qi]); } cbt.waitreload = false; } else if ( e.Name ~== "swwmcleartransaction" ) { if ( e.Args[1] != consoleplayer ) return; for ( int i=0; i)(AllActorClasses[i]); if ( !w || (w == 'SWWMWeapon') ) continue; let def = GetDefaultByType(w); if ( def.bCHEATNOTWEAPON ) continue; let ow = players[e.Args[0]].mo.FindInventory(w); if ( ow && (ow.Amount >= ow.MaxAmount) ) continue; if ( ow ) ow.Amount = ow.MaxAmount; else players[e.Args[0]].mo.GiveInventory(w,def.MaxAmount); } } else if ( e.Name ~== "swwmhealcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyRemember to stay fit.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/health_pkup",CHAN_VOICE,CHANF_UI); } players[e.Args[0]].health = players[e.Args[0]].mo.health = 1000; } else if ( e.Name ~== "swwmynykroncheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyYou're still crazy.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/w_pkup",CHAN_VOICE,CHANF_UI); } players[e.Args[0]].mo.GiveInventory("Ynykron",1); } else if ( e.Name ~== "swwmgravcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyGot something floatier.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/p_pkup",CHAN_VOICE,CHANF_UI); } let g = GravityPower(players[e.Args[0]].mo.FindInventory("GravityPower")); if ( g ) g.EffectTics += g.default.EffectTics; else players[e.Args[0]].mo.GiveInventory("GravityPower",1); } else if ( e.Name ~== "swwminvischeat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyProbably because you're invisible.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/p_pkup",CHAN_VOICE,CHANF_UI); } let g = GhostPower(players[e.Args[0]].mo.FindInventory("GhostPower")); if ( g ) g.EffectTics += g.default.EffectTics; else players[e.Args[0]].mo.GiveInventory("GhostPower",1); } else if ( e.Name ~== "swwmbarriercheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cySafe from those pesky elements.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/p_pkup",CHAN_VOICE,CHANF_UI); } let b = BarrierPower(players[e.Args[0]].mo.FindInventory("BarrierPower")); if ( b ) b.EffectTics += b.default.EffectTics; else players[e.Args[0]].mo.GiveInventory("BarrierPower",1); } else if ( e.Name ~== "swwmammocheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyDon't squander it.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/ammo_pkup",CHAN_VOICE,CHANF_UI); } players[e.Args[0]].mo.GiveInventory("HammerspaceEmbiggener",8,true); for ( Inventory i=players[e.Args[0]].mo.inv; i; i=i.inv ) { if ( !(i is 'Ammo') ) continue; i.Amount = i.MaxAmount; } } else if ( e.Name ~== "swwmbloodcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyEdgy...\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmexplocheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyThat cheat's not needed anymore.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmallcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyStill as wrappy as it's always been.\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("fabricator/use",CHAN_VOICE,CHANF_UI); } players[e.Args[0]].mo.CheatGive("all",0); } else if ( e.Name ~== "swwmflagcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyThere are no flags here.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmballcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cy\"Balls on your head\"? What was I even thinking...\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmsmartcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cySkittles are better anyway.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmnutcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyI'm way past that, it was bad for my health.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmweeniecheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyAlways has been.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmpunishcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyThis is a bulli free zone.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmball2cheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cy\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmfartcheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyI'd rather not reimplement that one.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmsupercheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyNo, you're the Demolitionist.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } else if ( e.Name ~== "swwmstonecheat" ) { if ( SWWMUtility.CheatsDisabled(e.Args[0]) ) return; if ( consoleplayer == e.Args[0] ) { Console.Printf("\cyThe pinnacle of... wait, I misread that.\c-"); S_StartSound("misc/nocheat",CHAN_ITEM,CHANF_UI); } } } // stuff for hud override void RenderUnderlay( RenderEvent e ) { // armor/health flashes int camplayer = players[consoleplayer].Camera.PlayerNumber(); if ( camplayer != -1 ) { if ( gametic < hflash[camplayer] ) { double fstr = (hflash[camplayer]-(gametic+e.FracTic))/5.; Screen.Dim(Color(64,128,255),.1875*fstr,0,0,Screen.GetWidth(),Screen.GetHeight()); } if ( gametic < aflash[camplayer] ) { double fstr = (aflash[camplayer]-(gametic+e.FracTic))/5.; Screen.Dim(Color(96,255,64),.1875*fstr,0,0,Screen.GetWidth(),Screen.GetHeight()); } } // weapon underlays if ( players[consoleplayer].ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(players[consoleplayer].ReadyWeapon).RenderUnderlay(e); if ( !statusbar || !(statusbar is 'SWWMStatusBar') ) return; SWWMStatusBar(statusbar).viewpos = e.viewpos; SWWMStatusBar(statusbar).viewrot = (e.viewangle,e.viewpitch,e.viewroll); if ( slotstrictwarn && (gametic < slotstrictwarn) ) { String str = StringTable.Localize("$SWWM_SETSLOTSTRICT"); double t = (slotstrictwarn-(gametic+e.FracTic))/20.; double alph = clamp(t,0.,1.); BrokenLines l = newsmallfont.BreakLines(str,300); double yy = (200-l.Count()*newsmallfont.GetHeight())/2; for ( int i=0; i 0) && (gametic < lastcummtic+150) ) { double calph = clamp(((lastcummtic+150)-gametic)/50.,0.,1.); string dnum = String.Format("%d",cummdamage); Screen.DrawText(dmgfnt,Font.CR_RED,vpos.x+300-dmgfnt.StringWidth(dnum),vpos.y-(dmgfnt.GetHeight()+2),dnum,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha*calph); } Screen.DrawText(barfnt,Font.CR_WHITE,vpos.x,vpos.y-(barfnt.GetHeight()+2),StringTable.Localize((funtags&&funtags.GetBool())?(bosstag.."_FUN"):bosstag),DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha); } // various shaders override void RenderOverlay( RenderEvent e ) { PlayerInfo p = players[consoleplayer]; if ( !useshaders ) useshaders = CVar.GetCVar('swwm_shaders',p); let mo = p.mo; if ( !mo ) return; bool pc = (p.camera == mo); let rage = RagekitPower(mo.FindInventory("RagekitPower")); if ( pc && rage && useshaders.GetBool() ) { if ( !altrage ) altrage = CVar.GetCVar('swwm_rageshader',p); if ( altrage.GetBool() ) { Shader.SetEnabled(p,"RagekitShader",false); Shader.SetEnabled(p,"RagekitAltShader",true); Shader.SetUniform1f(p,"RagekitAltShader","timer",(gametic+e.FracTic)/Thinker.TICRATE); double xstrastr = 1.+max(0,rage.lastpulse-(gametic+e.Fractic))/35.; Shader.SetUniform1f(p,"RagekitAltShader","xtrastr",xstrastr**2.); } else { Shader.SetEnabled(p,"RagekitAltShader",false); Shader.SetEnabled(p,"RagekitShader",true); Shader.SetUniform1f(p,"RagekitShader","timer",(gametic+e.FracTic)/Thinker.TICRATE); double xstrastr = 1.+max(0,rage.lastpulse-(gametic+e.Fractic))/35.; Shader.SetUniform1f(p,"RagekitShader","xtrastr",xstrastr**2.); } } else { Shader.SetEnabled(p,"RagekitShader",false); Shader.SetEnabled(p,"RagekitAltShader",false); } let ghost = GhostPower(mo.FindInventory("GhostPower")); if ( pc && ghost && useshaders.GetBool() ) Shader.SetEnabled(p,"GhostShader",true); else Shader.SetEnabled(p,"GhostShader",false); let sunny = InvinciballPower(mo.FindInventory("InvinciballPower")); if ( pc && sunny && useshaders.GetBool() ) { Shader.SetEnabled(p,"InvinciShader",true); double str = max(0,sunny.lastpulse-(gametic+e.Fractic))/35.; Shader.SetUniform1f(p,"InvinciShader","str",str); } else Shader.SetEnabled(p,"InvinciShader",false); let coat = BarrierPower(mo.FindInventory("BarrierPower")); if ( pc && coat && useshaders.GetBool() ) { Shader.SetEnabled(p,"BarrierShader",true); Shader.SetUniform1f(p,"BarrierShader","timer",(gametic+e.FracTic)/Thinker.TICRATE); } else Shader.SetEnabled(p,"BarrierShader",false); if ( pc && (mo is 'Demolitionist') && useshaders.GetBool() ) { let demo = Demolitionist(mo); if ( demo.lastunder == Demolitionist.UNDER_WATER ) { Shader.SetEnabled(p,"WaterWarp",true); Shader.SetUniform1f(p,"WaterWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"WaterWarp","dfact",coat?.25:1.); Shader.SetUniform3f(p,"WaterWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.)); } else Shader.SetEnabled(p,"WaterWarp",false); if ( demo.lastunder == Demolitionist.UNDER_LAVA ) { Shader.SetEnabled(p,"LavaWarp",true); Shader.SetUniform1f(p,"LavaWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"LavaWarp","dfact",coat?.25:1.); Shader.SetUniform3f(p,"LavaWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.)); } else Shader.SetEnabled(p,"LavaWarp",false); if ( demo.lastunder == Demolitionist.UNDER_SLIME ) { Shader.SetEnabled(p,"SlimeWarp",true); Shader.SetUniform1f(p,"SlimeWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"SlimeWarp","dfact",coat?.25:1.); Shader.SetUniform3f(p,"SlimeWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.)); } else Shader.SetEnabled(p,"SlimeWarp",false); int lastdmg = (demo.Health>0)?demo.lastdamage:Random[Flicker](60,80); int lastdmgtic = (demo.Health>0)?demo.lastdamagetic:(gametic+Random[Flicker](30,20)); double noiz = min(lastdmg*.09*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),.5); Shader.SetEnabled(p,"Glitch",noiz>0); Shader.SetEnabled(p,"Grain",noiz>0); if ( noiz > 0 ) { Shader.SetUniform1f(p,"Glitch","Timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"Grain","Timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"Grain","ni",noiz); noiz = min(lastdmg*.08*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),.8); Shader.SetUniform1f(p,"Glitch","str1",noiz); noiz = min(lastdmg*.03*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),3.5); Shader.SetUniform1f(p,"Glitch","str2",noiz); } if ( !demo.InStateSequence(demo.CurState,demo.FindState("Dash")) ) { Shader.SetEnabled(p,"ZoomBlur",false); return; } Shader.SetEnabled(p,"ZoomBlur",true); Vector3 vel = demo.vel+demo.dashdir*demo.dashboost; double baumpu = max(0.,(demo.bumptic-(gametic+e.Fractic))/35.); vel += demo.dashdir*baumpu; double spd = vel.length(); Vector3 worlddir = vel/spd; Shader.SetUniform1f(p,"ZoomBlur","Fade",clamp((spd-20.)/60.,0.,1.)); double str = min(spd/40.,15.); Vector3 x, y, z; [x, y, z] = swwm_CoordUtil.GetAxes(e.ViewPitch,e.ViewAngle,e.ViewRoll); Vector3 reldir = (worlddir dot y, worlddir dot z, worlddir dot x); Vector2 centerspot = (.5+reldir.x*.5,.5+reldir.y*.5); if ( reldir.z < 0 ) { centerspot.x = 1.-centerspot.x; centerspot.y = 1.-centerspot.y; str *= -1; } Shader.SetUniform1f(p,"ZoomBlur","Str",str); Shader.SetUniform2f(p,"ZoomBlur","CenterSpot",centerspot); } else { Shader.SetEnabled(p,"WaterWarp",false); Shader.SetEnabled(p,"LavaWarp",false); Shader.SetEnabled(p,"SlimeWarp",false); Shader.SetEnabled(p,"Glitch",false); Shader.SetEnabled(p,"Grain",false); Shader.SetEnabled(p,"ZoomBlur",false); } } static void DoFlash( Actor camera, Color c, int duration ) { // don't flash when paused if ( menuactive && (menuactive != Menu.OnNoPause) ) return; QueuedFlash qf = new("QueuedFlash"); qf.duration = duration; qf.c = c; qf.tic = gametic; qf.cam = camera; let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( !hnd ) return; // not supposed to happen hnd.flashes.push(qf); } // can't use this until I actually figure out how to make those walls damageable /*override void WorldLineDamaged( WorldEvent e ) { // allow boss brain to take (reduced) damage from the facewall being shot if ( level.mapname ~== "MAP30" ) { if ( !SWWMUtility.IsIOSWall(e.DamageLine) ) return; if ( bossbrainactor ) bossbrainactor.DamageMobj(e.Inflictor,e.DamageSource,e.Damage/3,e.DamageType,e.DamageFlags,e.DamageAngle); e.NewDamage = 0; } }*/ }