// event handlers and whatnot // preload fonts and stuff Class SWWMPreloader : StaticEventHandler { transient ui Font TewiFont, MPlusFont; transient ui CVar lang; override void OnRegister() { 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'); } // FIXME uncomment this once it's supported /*override void UiTick() { // HACK! Graf, please let us change this in a cleaner way if ( menuDelegate.GetClass() == 'DoomMenuDelegate' ) { 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 ) { 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 UiTick() { if ( (gamestate == GS_LEVEL) || (gamestate == GS_TITLELEVEL) ) { wasinmap = true; timer = 0; } else if ( (gamestate == GS_FULLCONSOLE) && ((wasinmap && !players[consoleplayer].viewheight) || (timer > 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++; } } } // 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; // 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; transient CVar lang; transient String curlang; transient CVar funtags; transient bool curfuntags; // optimization OnFire fires; int fires_cnt; // junk SWWMCasing casings, casings_end; int casings_cnt, oldmaxcasings; SWWMChip chips, chips_end; int chips_cnt, oldmaxdebris; // prevents revived monsters from spawning in more golden shells Array alreadygold; 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 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 ) { let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC); SWWMStats s; while ( s = SWWMStats(ti.Next()) ) s.AddLevelStats(); ClearAllShaders(players[consoleplayer]); } override void WorldLoaded( WorldEvent e ) { if ( level.levelname ~== "Modder Test Map" ) level.ReplaceTextures("-noflat-","kinstile",0); 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= 0) && (casings_cnt > swwm_maxcasings) ) DeQueueCasing(casings); } if ( swwm_maxdebris != oldmaxdebris ) { while ( chips && (swwm_maxdebris >= 0) && (chips_cnt > swwm_maxdebris) ) DeQueueChip(chips); } oldmaxcasings = swwm_maxcasings; oldmaxdebris = swwm_maxdebris; 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--; } // countable item scoring 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 // 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 bool HexenMap40() { if ( level.GetChecksum() ~== "2A6C4235B942467D25FD50D5B313E67A" ) return true; // 1.1 if ( level.GetChecksum() ~== "1C5DE5A921DEE405E98E7E09D9829387" ) return true; // 1.0 if ( level.GetChecksum() ~== "EFAFE59092DE5E613562ACF52B86C37F" ) return true; // beta return false; } override void WorldThingDied( WorldEvent e ) { if ( ((e.Thing.default.bBOSS) || (e.Thing.default.Health >= 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); if ( !Random[GoldDrop](0,2) ) { 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; } } override void WorldThingDamaged( WorldEvent e ) { if ( e.Damage > 0 ) { 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 ForcedFallerDamager.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 ( e.DamageSource && (e.DamageSource != e.Thing) ) { 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) ) 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; if ( (e.DamageSource && e.DamageSource.player && (e.DamageSource != e.Thing)) ) { let s = SWWMStats.Find(e.DamageSource.player); if ( s ) { s.kills++; s.AddWeaponKill(e.Inflictor,e.Thing,e.DamageType); } if ( e.DamageSource == players[consoleplayer].mo ) { highesttic = gametic; if ( !lastcombat || (gametic > lastcombat+40) ) { if ( e.Thing.IsFriend(e.DamageSource) || 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(e.DamageSource) || (!e.Thing.default.bCountKill && !(e.Thing is 'ScriptedMarine')) ) return; int pnum = e.DamageSource.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 ( e.DamageSource.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()) || (e.DamageSource.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageType == 'Extreme')) && !e.DamageSource.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(e.DamageSource.player,score); if ( scr ) scr.score = score; // update final score if ( (level.killed_monsters+1 == level.total_monsters) && !allkills ) { allkills = true; SWWMCredits.Give(e.DamageSource.player,1000); Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),e.DamageSource.player.GetUserName(),1000); SWWMScoreObj.Spawn(1000,e.DamageSource.Vec3Offset(0,0,e.DamageSource.Height/2)); } spreecount[pnum]++; if ( s && (spreecount[pnum] > s.skill) && !tookdamage[pnum] ) s.skill = spreecount[pnum]; } } 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 ) { if ( e.Thing is 'Inventory' ) CopyFloatBob(e.Thing); if ( swwm_doomfall && e.Thing.bISMONSTER && !level.monsterfallingdamage ) ForcedFallerDamager.TrackBody(e.Thing); // alternate form without extra thinker, just needs PR #1153 //if ( swwm_doomfall && e.Thing.bISMONSTER ) // e.Thing.bFALLDAMAGE = true; if ( e.Thing is 'Key' ) { DoKeyTagFix(e.Thing); SWWMInterest.Spawn(thekey:Key(e.Thing)); } else if ( e.Thing.GetClass() == 'BossBrain' ) { e.Thing.SetTag("$FN_BOSSBRAIN"); e.Thing.A_SetSize(20,40); e.Thing.bNOBLOOD = true; } else if ( (e.Thing is 'MBFHelperDog') || ((e.Thing is 'Cacodemon') && !(e.Thing is 'DeadCacodemon')) ) { // you can pet the dog, and you can also pet the caco let hp = Actor.Spawn("HeadpatTracker",e.Thing.pos); hp.target = e.Thing; } if ( !swwm_notrack && (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER) && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') ) SWWMCombatTracker.Spawn(e.Thing); if ( e.Thing.bSHOOTABLE || e.Thing.bISMONSTER || e.Thing.bCORPSE || (e.Thing is 'Inventory') ) { if ( (swwm_shadows == 2) || ((swwm_shadows == 1) && ((e.Thing is 'Demolitionist') || (e.Thing.SpawnState.sprite == e.Thing.GetSpriteIndex('XZW1')))) ) SWWMShadow.Track(e.Thing); } } override void PostUiTick() { if ( (gametic == onelinertic) && (oneliner != "") && (players[consoleplayer].health > 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 2 ) 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'; } 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"}; 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 ) e.Replacement = 'SWWMHangingKeen'; } 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') ) 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.Replacement = 'ExplodiumGun'; else if ( (e.Replacee is 'Shotgun') || (e.Replacee is 'CWeapStaff') ) e.Replacement = 'Spreadgun'; else if ( (e.Replacee is 'SuperShotgun') || (e.Replacee is 'MWeapFrost') ) e.Replacement = 'Wallbuster'; else if ( e.Replacee is 'Crossbow' ) { if ( Random[Replacements](0,2) ) e.Replacement = 'Spreadgun'; else e.Replacement = 'Wallbuster'; } else if ( (e.Replacee is 'Chaingun') || (e.Replacee is 'Blaster') || (e.Replacee is 'FWeapHammer') ) e.Replacement = 'Eviscerator'; else if ( (e.Replacee is 'RocketLauncher') || (e.Replacee is 'PhoenixRod') || (e.Replacee is 'FWeaponPiece3') ) e.Replacement = 'Hellblazer'; else if ( (e.Replacee is 'PlasmaRifle') || (e.Replacee is 'SkullRod') ) { if ( Random[Replacements](0,2) ) e.Replacement = 'Sparkster'; else e.Replacement = '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') ) { if ( Random[Replacements](0,2) ) e.Replacement = 'CandyGun'; else e.Replacement = 'Ynykron'; } else if ( e.Replacee is 'CWeaponPiece2' ) e.Replacement = 'CandyGun'; else if ( e.Replacee is 'MWeaponPiece1' ) e.Replacement = 'Ynykron'; else if ( (e.Replacee == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') ) { switch( Random[Replacement](0,14) ) { case 0: case 1: case 2: e.Replacement = redpool[Random[Replacement](0,1)]; break; case 4: case 5: case 6: e.Replacement = greenpool[Random[Replacement](0,1)]; break; case 7: case 8: e.Replacement = purplepool[0]; break; default: e.Replacement = 'SWWMNothing'; break; } } else if ( (e.Replacee == 'Shell') || (e.Replacee is 'CrossbowAmmo') ) { switch( Random[Replacement](0,13) ) { case 0: case 1: case 2: e.Replacement = redpool[Random[Replacement](0,2)]; break; case 3: case 4: case 5: e.Replacement = greenpool[Random[Replacement](0,2)]; break; case 6: case 7: e.Replacement = whitepool[0]; break; case 8: case 9: case 10: e.Replacement = purplepool[Random[Replacement](0,1)]; break; case 11: case 12: e.Replacement = bluepool[Random[Replacement](0,1)]; break; case 13: e.Replacement = blackpool[0]; break; } } else if ( (e.Replacee == 'ShellBox') || (e.Replacee is 'CrossbowHefty') ) { switch( Random[Replacement](0,14) ) { case 0: case 1: case 2: e.Replacement = redpool[Random[Replacement](1,3)]; break; case 3: case 4: case 5: e.Replacement = greenpool[Random[Replacement](1,2)]; break; case 6: case 7: case 8: e.Replacement = whitepool[Random[Replacement](0,1)]; break; case 9: case 10: case 11: e.Replacement = purplepool[Random[Replacement](0,2)]; break; case 12: case 13: e.Replacement = bluepool[Random[Replacement](0,2)]; break; case 14: e.Replacement = blackpool[Random[Replacement](0,1)]; break; } } else if ( e.Replacee == 'ClipBox' ) { if ( Random[Replacements](0,3) ) e.Replacement = 'EvisceratorShell'; else if ( Random[Replacements](0,4) ) e.Replacement = 'EvisceratorTrioSpawn'; else e.Replacement = 'EvisceratorSixPack'; } else if ( e.Replacee == 'BlasterAmmo' ) e.Replacement = 'EvisceratorShell'; else if ( e.Replacee == 'BlasterHefty' ) { if ( Random[Replacements](0,4) ) e.Replacement = 'EvisceratorTrioSpawn'; else e.Replacement = 'EvisceratorSixPack'; } else if ( (e.Replacee == 'RocketAmmo') || (e.Replacee == 'PhoenixRodAmmo') || (e.Replacee == 'MaceAmmo') ) { switch ( Random[Replacements](0,6) ) { case 0: case 1: case 2: case 3: e.Replacement = 'HellblazerMissiles'; break; case 4: case 5: case 6: e.Replacement = 'HellblazerCrackshots'; break; } } else if ( (e.Replacee == 'RocketBox') || (e.Replacee == 'PhoenixRodHefty') || (e.Replacee == 'MaceHefty') ) { switch ( Random[Replacements](0,11) ) { case 0: case 1: case 2: case 3: case 4: if ( Random[Replacements](0,3) ) e.Replacement = 'HellblazerMissiles'; else if ( Random[Replacements](0,2) ) e.Replacement = 'HellblazerMissileTrioSpawn'; else e.Replacement = 'HellblazerMissileMag'; break; case 5: case 6: case 7: case 8: if ( Random[Replacements](0,4) ) 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 == 'Cell') || (e.Replacee == 'SkullRodAmmo') ) { if ( Random[Replacements](0,3) ) 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 == 'CellPack') || (e.Replacee == '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 == 'Mana1' ) e.Replacement = 'FabricatorTier1'; else if ( e.Replacee == 'Mana2' ) e.Replacement = 'FabricatorTier2'; else if ( e.Replacee == 'Mana3' ) e.Replacement = 'FabricatorTier3'; else if ( e.Replacee == 'ArtiBoostMana' ) e.Replacement = 'FabricatorTier4'; else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'HammerspaceEmbiggener'; else if ( (e.Replacee == 'FWeaponPiece1') || (e.Replacee == 'FWeaponPiece2') || (e.Replacee == 'CWeaponPiece1') || (e.Replacee == 'CWeaponPiece3') || (e.Replacee == 'MWeaponPiece2') || (e.Replacee == '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 == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') || (e.Replacee == 'ArtiBlastRadius') || (e.Replacee is 'ArtiPoisonBag') ) e.Replacement = 'ArmorNuggetItem'; else if ( (e.Replacee == 'HealthBonus') || (e.Replacee == 'CrystalVial') ) e.Replacement = 'HealthNuggetItem'; else if ( e.Replacee == 'Stimpack' ) e.Replacement = 'TetraHealthItem'; else if ( e.Replacee == 'Medikit' ) e.Replacement = 'CubeHealthItem'; else if ( e.Replacee == 'ArtiHealth' ) { if ( gameinfo.gametype&GAME_Heretic && Random[Replacements](0,1) ) e.Replacement = 'CubeHealthItem'; else e.Replacement = 'TetraHealthItem'; } else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) { if ( gameinfo.gametype&GAME_Hexen ) e.Replacement = 'CubeHealthItem'; else e.Replacement = 'RefresherItem'; } else if ( e.Replacee == 'ArtiHealingRadius' ) e.Replacement = 'RefresherItem'; else if ( (e.Replacee == 'Megasphere') || (e.Replacee == 'ArtiEgg') || (e.Replacee == 'PlatinumHelm') ) e.Replacement = 'GrilledCheeseSandwich'; else if ( (e.Replacee == 'Blursphere') || (e.Replacee == 'ArtiInvisibility') || (e.Replacee == 'AmuletOfWarding') ) e.Replacement = 'GhostArtifact'; else if ( e.Replacee == 'Radsuit' ) e.Replacement = 'EBarrier'; else if ( (e.Replacee == 'ArtiFly') ) e.Replacement = 'GravitySuppressor'; else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') || (e.Replacee == 'ArtiInvulnerability2') ) e.Replacement = 'FuckingInvinciball'; else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'Ragekit'; else if ( (e.Replacee == 'AllMap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'Omnisight'; else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') ) e.Replacement = 'SWWMLamp'; else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'SilverShield') || (e.Replacee == 'MeshArmor') ) e.Replacement = 'BlastSuitItem'; else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'FalconShield') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'WarArmorItem'; else if ( (e.Replacee == 'ArtiPork') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') ) e.Replacement = 'ChanceboxSpawner'; } 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; if ( e.Args[0] < 0 ) return; // special gestures can't be manually started SWWMGesture.SetGesture(mo,e.Args[0]); } 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]) ) { players[e.Args[0]].mo.GiveInventory(item,e.Args[2],true); if ( item is 'Weapon' ) { // special case, select dual guns if we bought a second one if ( (item is 'ExplodiumGun') && (players[e.Args[0]].mo.CountInv("ExplodiumGun") > 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",16,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); } // 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() ) { 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); 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); } }