// common code goes here enum ESWWMGZChannels { CHAN_YOUDONEFUCKEDUP = 63200, // exception handler CHAN_DEMOVOICE = 63201, // demolitionist voices CHAN_FOOTSTEP = 63202, // footstep sounds and others CHAN_WEAPONEXTRA = 63203, // additional weapon sounds (usually loops) CHAN_POWERUP = 63204, // powerup sounds CHAN_POWERUPEXTRA = 63205, // additional powerup sounds CHAN_JETPACK = 63206, // jetpack sound CHAN_ITEMEXTRA = 63207, // additional item sounds CHAN_AMBEXTRA = 63208 // player ambience when submerged }; // Misc. Utility code Class SWWMUtility { static void StripColor( out String str ) { int len = str.CodePointCount(); for ( int i=0; i double.epsilon); } // not portal aware, will have to fix that later static bool SphereIntersect( Actor a, Vector3 p, double radius ) { Vector3 amin = a.pos+(-a.radius,-a.radius,0), amax = a.pos+(a.radius,a.radius,a.height); double distsq = 0.; if ( p.x < amin.x ) distsq += (amin.x-p.x)**2; if ( p.x > amax.x ) distsq += (p.x-amax.x)**2; if ( p.y < amin.y ) distsq += (amin.y-p.y)**2; if ( p.y > amax.y ) distsq += (p.y-amax.y)**2; if ( p.z < amin.z ) distsq += (amin.z-p.z)**2; if ( p.z > amax.z ) distsq += (p.z-amax.z)**2; return (distsq <= (radius**2)); } } // Stats Class WeaponUsage { Class w; int kills; } Class SWWMStats : Thinker { PlayerInfo myplayer; int lastspawn, dashcount, boostcount, stompcount, airtime, kills, deaths, damagedealt, damagetaken, mkill, hiscore, topdealt, toptaken, skill; double grounddist, airdist, fuelusage, topspeed; Array wstats; Array > alreadygot; int favweapon; bool GotWeapon( Class which ) { for ( int i=0; i which ) { for ( int i=0; i 999999999) ) c.credits = 999999999; else c.credits += amount; let s = SWWMStats.Find(p); if ( s && (c.credits > s.hiscore) ) s.hiscore = c.credits; } static clearscope bool CanTake( PlayerInfo p, int amount ) { let c = Find(p); if ( !c ) return false; // too much! if ( (c.credits-amount < 0) || (c.credits-amount > c.credits) ) return false; return true; } static bool Take( PlayerInfo p, int amount ) { let c = Find(p); if ( !c ) return false; // too much! if ( (c.credits-amount < 0) || (c.credits-amount > c.credits) ) return false; c.credits -= amount; return true; } static clearscope int Get( PlayerInfo p ) { let c = Find(p); if ( !c ) return 0; return c.credits; } static clearscope SWWMCredits Find( PlayerInfo p ) { let ti = ThinkerIterator.Create("SWWMCredits",STAT_STATIC); SWWMCredits t; while ( t = SWWMCredits(ti.Next()) ) { if ( t.myplayer != p ) continue; return t; } return null; } } // Trading history between players Class SWWMTrade { int timestamp, type, amt; String other; Class what; } Class SWWMTradeHistory : Thinker { PlayerInfo myplayer; Array ent; static void RegisterSend( PlayerInfo p, PlayerInfo other, Class what, int amt ) { let th = Find(p); if ( !th ) return; SWWMTrade t = new("SWWMTrade"); t.timestamp = level.totaltime; t.type = 0; t.other = other.GetUserName(); t.what = what; t.amt = amt; th.ent.Push(t); } static void RegisterReceive( PlayerInfo p, PlayerInfo other, Class what, int amt ) { let th = Find(p); if ( !th ) return; SWWMTrade t = new("SWWMTrade"); t.timestamp = level.totaltime; t.type = 1; t.other = other.GetUserName(); t.what = what; t.amt = amt; th.ent.Push(t); } static clearscope SWWMTradeHistory Find( PlayerInfo p ) { let ti = ThinkerIterator.Create("SWWMTradeHistory",STAT_STATIC); SWWMTradeHistory th; while ( th = SWWMTradeHistory(ti.Next()) ) { if ( th.myplayer != p ) continue; return th; } return Null; } } // Lore holder enum ELoreTab { LORE_ITEM, LORE_PEOPLE, LORE_LORE // lol }; Class SWWMLore { String tag, text, assoc; int tab; bool read; } Class SWWMLoreLibrary : Thinker { PlayerInfo myplayer; Array ent; int lastaddtic; bool DirectAdd( String ref ) { // restrictions if ( !(gameinfo.gametype&GAME_Hexen) ) { if ( ref ~== "Kirin" ) return true; // not met } ref = ref.MakeUpper(); String tag = String.Format("SWWM_LORETAG_%s",ref); String tab = String.Format("SWWM_LORETAB_%s",ref); String text = String.Format("SWWM_LORETXT_%s",ref); String assoc = String.Format("SWWM_LOREREL_%s",ref); // redirects if ( gameinfo.gametype&GAME_Raven ) { if ( text ~== "SWWM_LORETXT_UAC" ) text = "SWWM_LORETXT_UAC2"; // uac "reformed" else if ( text ~== "SWWM_LORETXT_HELL" ) text = "SWWM_LORETXT_HELL2"; // invasion was a thing of the past else if ( text ~== "SWWM_LORETXT_NANA" ) text = "SWWM_LORETXT_NANA2"; // demo met nana else if ( text ~== "SWWM_LORETXT_ZANAVETH3" ) text = "SWWM_LORETXT_ZANAVETH32"; // iagb happened } if ( gameinfo.gametype&GAME_Hexen ) { if ( text ~== "SWWM_LORETXT_SAYA" ) text = "SWWM_LORETXT_SAYA2"; // married kirin else if ( text ~== "SWWM_LORETXT_ANARUKON" ) text = "SWWM_LORETXT_ANARUKON2"; // comments from miyamoto-xanai wedding } // check that it's valid if ( StringTable.Localize(tag,false) == tag ) return false; if ( StringTable.Localize(tab,false) == tab ) return false; if ( StringTable.Localize(text,false) == text ) return false; // check if existing for ( int i=0; i 0) && (gametic > lastaddtic) && (myplayer == players[consoleplayer]) && (!menuactive || (menuactive == Menu.OnNoPause)) ) Console.Printf(StringTable.Localize("$SWWM_NEWLORE")); lastaddtic = gametic; // sorted add String loca = StringTable.Localize(e.tag), locb; int cpa, cpb; for ( int i=0; i= ent.Size()) ) return; if ( !ent[idx].read ) { ent[idx].read = true; // add associated entries Array rel; rel.Clear(); String assocstr = StringTable.Localize(ent[idx].assoc); assocstr.Split(rel,";",0); for ( int i=0; i level.maptime ) updated = level.maptime; lasthealth = 0; intp.Update(lasthealth); if ( level.maptime > updated+35 ) Destroy(); return; } tcnt++; if ( tcnt == 1 ) { // post-spawn health inflation check if ( lasthealth > maxhealth ) maxhealth = lasthealth; } if ( tcnt == 6 ) { // legendoom check for ( Inventory i=mytarget.inv; i; i=i.inv ) { if ( i.GetClassName() != "LDLegendaryMonsterToken" ) continue; legged = true; // adjust for health inflation if ( lasthealth > maxhealth ) maxhealth = lasthealth; } } if ( mytarget.player || mytarget.bISMONSTER ) mytag = mytarget.player?mytarget.player.GetUserName():mytarget.GetTag(); else mytag = ""; int newhealth = mytarget.Health; //if ( newhealth != lasthealth ) updated = level.maptime+35; if ( (mytarget.bISMONSTER || mytarget.player) && !mytarget.bINVISIBLE ) { // enemies within 2000mu that have us as target if ( mytarget.target && (mytarget.target.Health > 0) && (mytarget.target.player == players[consoleplayer]) && mytarget.CheckSight(mytarget.target) && (mytarget.Vec3To(mytarget.target).length() < 2000) ) updated = level.maptime+70; // players (but not voodoo dolls), always visible in sp/coop if ( !deathmatch && mytarget.player && (mytarget.player.mo == mytarget) ) updated = level.maptime+35; // enemies we're directly aiming at within 600mu if ( players[consoleplayer].mo.CheckSight(mytarget) && ((mytarget.Vec3To(players[consoleplayer].mo).length() < 600) || (players[consoleplayer].mo.AimTarget() == mytarget)) ) updated = level.maptime; } lasthealth = newhealth; intp.Update(lasthealth); } } // Press F to Pay Respects Class PayRespects : HUDMessageBase { Vector2 basepos; int lifespan, initialspan, starttic; transient Font TewiFont; double scale; Vector2 hs, ss; int seed, seed2; static PayRespects PressF() { let f = new("PayRespects"); f.basepos = (FRandom[FInTheChat](0.,1.),FRandom[FInTheChat](1.02,1.05)); f.scale = FRandom[FInTheChat](.5,2.); f.lifespan = f.initialspan = Random[FInTheChat](20,80); f.starttic = level.maptime; f.seed = Random[FInTheChat](); f.seed2 = Random[FInTheChat](); f.ScreenSizeChanged(); return f; } override bool Tick() { lifespan--; return (lifespan<=0); } override void ScreenSizeChanged() { hs = StatusBar.GetHUDScale()*scale; ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y); } override void Draw( int bottom, int visibility ) { Vector2 realpos = (basepos.x*ss.x,basepos.y*ss.y); if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded'); Vector2 fo = (TewiFont.StringWidth("F")/2.,-TewiFont.GetHeight()); // F rise up int initspd = (128-seed); if ( (initspd >= 0) && (initspd < 32) ) initspd = 32; if ( (initspd < 0) && (initspd > -32) ) initspd = -32; int boostup = 32+(seed2/4); double fractic = SWWMStatusBar(statusbar)?SWWMStatusBar(statusbar).fractic:0; fo.x += (.15*initspd)*((initialspan-(lifespan-fractic))**.6); fo.y += ((initialspan-(lifespan-fractic))**1.6)-boostup*sin((90./initialspan)*(level.maptime+fractic-starttic)); double alph = clamp((lifespan+fractic)/double(initialspan),0.,1.); Screen.DrawText(TewiFont,Font.CR_GREEN,realpos.x-fo.x,realpos.y-fo.y,"F",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); } } // One-liners Class SWWMOneLiner : HUDMessageBase { String whichline; int lifespan, curtime; transient Font TewiFont, MPlusFont; transient CVar safezone, lang; static SWWMOneLiner Make( String whichline, int lifespan ) { let l = new("SWWMOneLiner"); l.whichline = whichline; l.curtime = l.lifespan = lifespan; return l; } override bool Tick() { if ( players[consoleplayer].Health <= 0 ) curtime = int.min; curtime--; return (curtime<-20); } override void Draw( int bottom, int visibility ) { if ( !safezone ) safezone = CVar.GetCVar('swwm_hudmargin',players[consoleplayer]); if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]); if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded'); if ( !MPlusFont ) MPlusFont = Font.GetFont('MPlusShaded'); int margin = safezone.GetInt(); Vector2 hs = StatusBar.GetHUDScale(); Vector2 ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y); String loc = StringTable.Localize(whichline); if ( loc.Length() <= 0 ) return; // don't draw empty strings String locs = StringTable.Localize("$SWWM_LQUOTE")..loc..StringTable.Localize("$SWWM_RQUOTE"); Font fnt = TewiFont; if ( lang.GetString() ~== "jp" ) fnt = MPlusFont; // split so it can fit BrokenLines l = fnt.BreakLines(locs,int(ss.x*.5)); int maxlen = 0; for ( int i=0; i maxlen ) maxlen = len; } int h = fnt.GetHeight(); int fh = h*l.Count(); double alph = clamp((curtime/20.)+1.,0.,1.); alph *= clamp((lifespan-curtime)/10.,0.,1.); Screen.Dim("Black",alph*.8,int((Screen.GetWidth()-(maxlen+12)*hs.x)/2.),int(bottom-(margin+2+fh)*hs.y),int((maxlen+12)*hs.x),int((fh+4)*hs.y)); int yy = margin+fh; for ( int i=0; i 0 ) { let b = Spawn("SWWMBubble",pos); b.scale *= abs(scale.x); b.vel = vel; Destroy(); } } States { Spawn: XSMK ABCDEFGHIJKLMNOPQRST 1 A_SetTics(1+special1); Stop; } } Class SWWMHalfSmoke : SWWMSmoke { States { Spawn: XSMK ACEGIKMOQS 1 A_SetTics(1+special1); Stop; } } Class SWWMSmallSmoke : SWWMSmoke { override void PostBeginPlay() { Actor.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16); } } Class SWWMViewSmoke : SWWMSmoke { Vector3 ofs, vvel; override void PostBeginPlay() { Actor.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vvel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16); } override void Tick() { Actor.Tick(); if ( !target || !target.player ) { Destroy(); return; } Vector3 x, y, z; [x, y, z] = swwm_CoordUtil.GetAxes(target.pitch,target.angle,target.roll); Vector3 origin = level.Vec3Offset(target.Vec2OffsetZ(0,0,target.player.viewz),x*ofs.x+y*ofs.y+z*ofs.z); SetOrigin(origin,true); bInvisible = (players[consoleplayer].camera != target); if ( isFrozen() ) return; ofs += vvel; vvel *= 0.96; vvel.z += 0.01; if ( waterlevel > 0 ) Destroy(); } } Class SWWMBubble : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; +NOTELEPORT; Scale 0.5; } override void PostBeginPlay() { Super.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8); if ( waterlevel <= 0 ) Destroy(); SetState(ResolveState("Spawn")+Random[Puff](0,19)); } override void Tick() { Super.Tick(); if ( isFrozen() ) return; vel *= 0.96; vel.z += 0.05; if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy(); } States { Spawn: XBUB ABCDEFGHIJKLMNOPQRST 1; Loop; } } Class SWWMSpark : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +FORCEXYBILLBOARD; +MISSILE; +MOVEWITHSECTOR; +THRUACTORS; +NOTELEPORT; +DONTSPLASH; BounceType "Doom"; BounceFactor 0.4; Gravity 0.2; Scale 0.05; } override void Tick() { Super.Tick(); if ( waterlevel > 0 ) { let b = Spawn("SWWMBubble",pos); b.vel = vel; b.scale *= 0.3; Destroy(); } } States { Spawn: BLPF A 1 Bright A_FadeOut(0.01); Wait; Death: BLPF A 1 Bright A_FadeOut(0.05); Wait; } } Class SWWMChip : Actor { int deadtimer; double rollvel; Default { Radius 2; Height 2; +NOBLOCKMAP; +MISSILE; +MOVEWITHSECTOR; +THRUACTORS; +NOTELEPORT; +DONTSPLASH; +INTERPOLATEANGLES; +ROLLSPRITE; +ROLLCENTER; +FORCEXYBILLBOARD; BounceType "Doom"; BounceFactor 0.3; Gravity 0.35; Scale 0.2; } override void PostBeginPlay() { Super.PostBeginPlay(); deadtimer = 0; rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); frame = Random[Junk](0,5); scale *= Frandom[Junk](0.8,1.2); } override void Tick() { Super.Tick(); if ( isFrozen() ) return; if ( InStateSequence(CurState,ResolveState("Death")) ) { deadtimer++; if ( deadtimer > 300 ) A_FadeOut(0.05); return; } } States { Spawn: JUNK # 1 { roll += rollvel; } Loop; Bounce: JUNK # 0 { rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); } Goto Spawn; Death: JUNK # -1; Stop; Dummy: JUNK ABCDEF -1; Stop; } } Class SWWMNothing : Actor { States { Spawn: TNT1 A 1; Stop; } } Class PoofLight : PaletteLight { Default { Tag "Yellow"; ReactionTime 5; Args 0,0,0,60; } } Class PoofLight2 : PaletteLight { Default { Tag "Yellow"; ReactionTime 20; Args 0,0,0,90; } } Class SWWMItemFog : Actor { Default { RenderStyle "Add"; +NOGRAVITY; +NOBLOCKMAP; +DONTSPLASH; +ROLLSPRITE; +ROLLCENTER; } States { Spawn: BLPF A 2 Bright NoDelay { // offset up SetOrigin(Vec3Offset(0,0,16),false); roll = FRandom[ExploS](0,360); scale *= FRandom[ExploS](0.9,1.1); scale.x *= RandomPick[ExploS](-1,1); scale.y *= RandomPick[ExploS](-1,1); int numpt = Random[ExploS](16,32); if ( bAMBUSH ) numpt *= 2; for ( int i=0; i WaterHitList; Array ShootThroughList; Actor ignoreme; static play void DoTrail( Actor target, Vector3 pos, Vector3 dir, int dist, int bubblechance, bool smoky = false ) { let t = new("SWWMBulletTrail"); t.ignoreme = target; t.WaterHitList.Clear(); t.ShootThroughList.Clear(); t.Trace(pos,level.PointInSector(pos.xy),dir,dist,0); for ( int i=0; i= steps ) { cnt = 0; str = tstr/steps; cstate = (mode==SWING_Straight)?(-1):(delay>0)?STATE_Wait:STATE_Return; } else tstr += str; break; case STATE_Wait: if ( ++cnt >= delay ) { cnt = 0; cstate = STATE_Return; } break; case STATE_Return: target.A_SetAngle(target.angle-dir.x*(str/rmul),SPF_INTERPOLATE); target.A_SetPitch(target.pitch-dir.y*(str/rmul),SPF_INTERPOLATE); if ( ++cnt >= steps*rmul ) { cnt = 0; cstate = -1; } break; default: Destroy(); return; } } } // Screen flashes from DT Class GenericFlash : HUDMessageBase { Color col; int duration; double alpha; Actor cam; transient CVar str; GenericFlash Setup( Actor camera, Color c, int d ) { alpha = 1.0; col = c; duration = d; cam = camera; return self; } override bool Tick() { if ( duration > 0 ) alpha -= 1./duration; return (alpha<=0)||(!cam); } override void Draw( int bottom, int visibility ) { if ( automapactive || (visibility != BaseStatusBar.HUDMSGLayer_UnderHUD) ) return; if ( cam && (players[consoleplayer].camera != cam) ) return; if ( !str ) str = CVar.GetCVar('swwm_flashstrength',players[consoleplayer]); Screen.Dim(col,(col.a/255.)*alpha*str.GetFloat(),0,0,Screen.GetWidth(),Screen.GetHeight()); } } Class QueuedFlash { Color c; int duration; int tic; Actor cam; } Class LastLine { String type; int lineno; } // Korax instakill handler Class UglyBoyGetsFuckedUp : Thinker { bool wedone; override void Tick() { if ( wedone ) return; if ( level.killed_monsters < level.total_monsters ) { // stop portal door int sidx = level.CreateSectorTagIterator(145).Next(); if ( sidx == -1 ) return; Sector door = level.Sectors[sidx]; let ti = ThinkerIterator.Create("SectorEffect"); SectorEffect se; while ( se = SectorEffect(ti.Next()) ) { if ( se.GetSector() != door ) continue; se.Destroy(); door.StopSoundSequence(CHAN_VOICE); } return; } wedone = true; level.ExecuteSpecial(Door_Open,null,null,false,145,8); Destroy(); } } // 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; 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 money cheat transient ui int kcode; // heal/armor flashes need to be handled here so they don't stack transient int hflash[MAXPLAYERS], aflash[MAXPLAYERS]; transient CVar mutevoice; transient ui CVar useshaders; 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 ) { 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 ) { if ( voicetype ~== "default" ) return 0; // retry with the default voicetype voicetype = "default"; testme = String.Format("SWWM_SUBS_DEFAULT_N%s",type.MakeUpper()); locme = StringTable.Localize(testme,false); if ( testme == locme ) countem = 0; else countem = locme.ToInt(); if ( countem == 0 ) return 0; } // 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; // TODO check for any 3d floors for ( int i=0; i skipme; skipme.Clear(); // find exit lines, and use lines that aren't exits for ( int i=0; i 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 = 25*(players[i].itemcount-lastitemcount[i]); if ( (level.total_items == level.found_items) && !allitems ) { allitems = true; Console.Printf(StringTable.Localize("$SWWM_LASTITEM"),players[i].GetUserName(),2500); score += 2475; } SWWMCredits.Give(players[i],score); lastitemcount[i] = players[i].itemcount; } } // 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 && !a.bCountKill ) continue; // ignore the dead if ( (a.Health <= 0) || a.bKILLED || a.bCORPSE ) continue; // ignore if not targetted or either actor can't see the other if ( (a.target != players[consoleplayer].mo) || !a.CheckSight(players[consoleplayer].mo) || !players[consoleplayer].mo.CheckSight(a) ) continue; // is it already in? bool addme = true; for ( int i=0; i highesttic+100)) ) 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 && !Random[GoldDrop](0,2)) || (e.Thing.default.bBOSSDEATH && !Random[GoldDrop](0,6)) ) { 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); } } override void WorldThingDamaged( WorldEvent e ) { if ( e.Damage > 0 ) 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); if ( e.Thing.player ) { tookdamage[e.Thing.PlayerNumber()] = true; let s = SWWMStats.Find(e.Thing.player); s.damagetaken += 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.damagedealt += 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.Thing == players[consoleplayer].mo) && (e.Thing.Health > 0) ) { if ( !lastcombat || (gametic > lastcombat+20) ) lastcombat = AddOneliner(e.Thing.IsFriend(e.DamageSource)?"friendhit":"gethit",1,15); highesttic = gametic; } if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player) ) { // 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) && !(e.Thing is 'LampMoth') ) { if ( !lastcombat || (gametic > lastcombat+20) ) lastcombat = AddOneliner("hitfriend",1,15); highesttic = gametic; } } } if ( (e.Thing.Health > 0) || e.Thing.bKilled || e.Thing.bCorpse ) return; if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill ) return; if ( (e.DamageSource && e.DamageSource.player && (e.DamageSource != e.Thing)) ) { let s = SWWMStats.Find(e.DamageSource.player); if ( s ) { s.kills++; if ( e.DamageSource.player.ReadyWeapon ) s.AddWeaponKill(e.DamageSource.player.ReadyWeapon.GetClass()); } if ( e.DamageSource == players[consoleplayer].mo ) { highesttic = gametic; if ( !lastcombat || (gametic > lastcombat+20) ) lastcombat = AddOneliner("scorekill",1,15); } if ( !e.Thing.default.bCountKill ) // no credits 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(2000,int(ceil(e.Thing.SpawnHealth()*.5)*10)); int ofs = 0; if ( ((e.Thing.Health <= e.Thing.GetGibHealth()) || (e.DamageSource.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH)) && !e.DamageSource.bNOEXTREMEDEATH && !(e.Inflictor && e.Inflictor.bNOEXTREMEDEATH) ) { score = int(score*1.25); if ( e.DamageSource.player == players[consoleplayer] ) SWWMScoreObj.Spawn(0,e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_OVERKILL",++ofs); } score = int(score*(1.+.5*min(multilevel[pnum],16))); if ( (multilevel[pnum] > 0) && (e.DamageSource.player == players[consoleplayer]) ) SWWMScoreObj.Spawn((multilevel[pnum]>=16)?int.max:(multilevel[pnum]+1),e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_MULTIKILL",++ofs); if ( !tookdamage[pnum] ) { score += 100+50*spreecount[pnum]; if ( (spreecount[pnum] > 0) && (e.DamageSource.player == players[consoleplayer]) ) SWWMScoreObj.Spawn(spreecount[pnum]+1,e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_SPREEKILL",++ofs); } if ( e.Thing.bBOSS ) { score += 10000; if ( e.DamageSource.player == players[consoleplayer] ) SWWMScoreObj.Spawn(0,e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_BOSSKILL",++ofs); } SWWMCredits.Give(e.DamageSource.player,score); if ( e.DamageSource.player == players[consoleplayer] ) SWWMScoreObj.Spawn(score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2)); if ( (level.killed_monsters+1 == level.total_monsters) && !allkills ) { allkills = true; SWWMCredits.Give(e.DamageSource.player,5000); Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),e.DamageSource.player.GetUserName(),5000); } spreecount[pnum]++; if ( s && spreecount[pnum] > s.skill ) s.skill = spreecount[pnum]; } } private void DoKeyTagFix( Actor a ) { 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); } override void WorldThingSpawned( WorldEvent e ) { if ( e.Thing is 'Key' ) { DoKeyTagFix(e.Thing); SWWMInterest.Spawn(thekey:Key(e.Thing)); } else if ( e.Thing is 'BossBrain' ) e.Thing.SetTag("$FN_BOSSBRAIN"); else if ( e.Thing is 'CommanderKeen' ) e.Thing.SetTag("$FN_KEEN"); if ( (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER) && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') ) SWWMCombatTracker.Spawn(e.Thing); } override void PostUiTick() { if ( (gametic == onelinertic) && (oneliner != "") && (players[consoleplayer].health > 0) ) { let l = SWWMOneLiner.Make(oneliner,onelinerspan); StatusBar.AttachMessage(l,-3473); SendNetworkEvent("swwmremotelinertxt."..oneliner,consoleplayer,onelinerlevel); } for ( int i=0; i= 11 ) { SendNetworkEvent("swwmmoneycheat",consoleplayer); kcode = 0; } } else kcode = 0; if ( e.KeyScan == 33 ) { let demo = Demolitionist(players[consoleplayer].mo); if ( demo && (demo.Health <= 0) && (demo.deadtimer > 40) ) { // pay respects int numf = Random[FInTheChat](1,6); for ( int i=0; i lastlock+20) ) lastlock = AddOneliner("locked",2); } } override void CheckReplacement( ReplaceEvent e ) { // shell types (sorted by rarity static const Class redpool[] = {"RedShell","RedShell2","RedShell4","RedShell8","RedShell12","RedShell16"}; static const Class greenpool[] = {"GreenShell","GreenShell2","GreenShell4","GreenShell8","GreenShell12"}; static const Class whitepool[] = {"WhiteShell","WhiteShell2","WhiteShell4","WhiteShell8"}; static const Class purplepool[] = {"PurpleShell","PurpleShell2","PurpleShell4"}; static const Class bluepool[] = {"BlueShell","BlueShell2","BlueShell4","BlueShell8"}; static const Class blackpool[] = {"BlackShell","BlackShell2","BlackShell4"}; if ( e.Replacee is 'ItemFog' ) e.Replacement = 'SWWMItemFog'; if ( e.Replacee is 'TeleportFog' ) e.Replacement = 'SWWMTeleportFog'; 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 'CWeapFlame') ) 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 'MWeapLightning' ) e.Replacement = 'Sparkster'; else if ( e.Replacee is 'FWeaponPiece3' ) e.Replacement = 'SilverBullet'; else if ( (e.Replacee is 'BFG9000') || (e.Replacee is 'Mace') ) { if ( !Random[Replacements](0,2) ) e.Replacement = 'Ynykron'; else e.Replacement = 'CandyGun'; } 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') || (e.Replacee is 'ArtiPoisonBag') ) { 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[Random[Replacement](0,1)]; 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,2)]; 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,5)]; break; case 3: case 4: case 5: e.Replacement = greenpool[Random[Replacement](1,4)]; break; case 6: case 7: case 8: e.Replacement = whitepool[Random[Replacement](0,3)]; break; case 9: case 10: case 11: e.Replacement = purplepool[Random[Replacement](1,2)]; break; case 12: case 13: e.Replacement = bluepool[Random[Replacement](1,3)]; break; case 14: e.Replacement = blackpool[Random[Replacement](0,2)]; break; } } else if ( e.Replacee == 'ClipBox' ) { if ( Random[Replacements](0,3) ) e.Replacement = 'EvisceratorShell'; else e.Replacement = 'EvisceratorSixPack'; } else if ( e.Replacee == 'BlasterAmmo' ) e.Replacement = 'EvisceratorShell'; else if ( e.Replacee == 'BlasterHefty' ) e.Replacement = 'EvisceratorSixPack'; else if ( (e.Replacee == 'RocketAmmo') || (e.Replacee == 'PhoenixRodAmmo') || (e.Replacee == 'MaceAmmo') ) { switch ( Random[Replacements](0,9) ) { case 0: case 1: case 2: case 3: e.Replacement = 'HellblazerMissiles'; break; case 4: case 5: case 6: e.Replacement = 'HellblazerCrackshots'; break; case 7: case 8: e.Replacement = 'HellblazerRavagers'; break; case 9: e.Replacement = 'HellblazerWarheads'; break; } } else if ( (e.Replacee == 'RocketBox') || (e.Replacee == 'PhoenixRodHefty') || (e.Replacee == 'MaceHefty') ) { switch ( Random[Replacements](0,9) ) { case 0: case 1: case 2: case 3: if ( Random[Replacements](0,1) ) e.Replacement = 'HellblazerMissiles'; else e.Replacement = 'HellblazerMissileMag'; break; case 4: case 5: case 6: if ( Random[Replacements](0,2) ) e.Replacement = 'HellblazerCrackshots'; else e.Replacement = 'HellblazerCrackshotMag'; break; case 7: case 8: if ( Random[Replacements](0,3) ) e.Replacement = 'HellblazerRavagers'; else e.Replacement = 'HellblazerRavagerMag'; break; case 9: if ( Random[Replacements](0,4) ) 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 e.Replacement = 'SilverBulletAmmo'; } else if ( (e.Replacee == 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') ) { if ( Random[Replacements](0,3) ) e.Replacement = 'SWWMNothing'; else e.Replacement = 'GoldShell'; } else if ( (e.Replacee == 'CellPack') || (e.Replacee == 'SkullRodHefty') ) { if ( Random[Replacements](0,2) ) e.Replacement = 'SilverBulletAmmo'; 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 == 'ArtiPork') ) 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,7) ) e.Replacement = 'SWWMNothing'; else if ( Random[Replacements](0,3) ) e.Replacement = 'HammerspaceEmbiggener'; else e.Replacement = 'GoldShell'; } else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') || (e.Replacee == 'ArtiBlastRadius') ) 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.Replacee == 'ArtiFly') || (e.Replacee == 'ArtiSpeedBoots') ) 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 == 'ArtiDarkServant') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'Ragekit'; else if ( (e.Replacee == 'AllMap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'Omnisight'; else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiBoostArmor') ) 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'; } override void NetworkProcess( ConsoleEvent e ) { if ( e.Name ~== "swwmgesture" ) { if ( (e.player == -1) || !playeringame[e.player] || !players[e.player].mo ) return; let mo = players[e.player].mo; if ( (mo.Health <= 0) || !(mo is 'Demolitionist') ) return; // TODO redo these as fake weapons switch ( e.Args[0] ) { case 1: if ( mo.FindState("Approve") ) mo.SetStateLabel("Approve"); break; case 2: if ( mo.FindState("Victory") ) mo.SetStateLabel("Victory"); break; default: if ( mo.FindState("Taunt") ) mo.SetStateLabel("Taunt"); break; } } 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]); if ( item is 'Weapon' ) 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; if ( (amt > 0) && players[e.Args[1]].mo.GiveInventory(item,amt) ) { 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()); } } 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; players[e.Args[0]].mo.UseInventory(i); } 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.)); } 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 ~== "swwmmoneycheat" ) { if ( consoleplayer == e.Args[0] ) { Console.Printf("\cfLOADSAMONEY!\c-"); S_StartSound("menu/buyinv",CHAN_ITEM,CHANF_UI); S_StartSound("misc/emone",CHAN_VOICE,CHANF_UI); } SWWMCredits.Give(players[e.Args[0]],999999999); } } // 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()); } } 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); if ( pc && (mo is 'Demolitionist') ) { let demo = Demolitionist(mo); Shader.SetEnabled(p,"Glitch",true); Shader.SetEnabled(p,"Grain",true); Shader.SetUniform1f(p,"Glitch","Timer",(gametic+e.FracTic)/Thinker.TICRATE); Shader.SetUniform1f(p,"Grain","Timer",(gametic+e.FracTic)/Thinker.TICRATE); 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.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); } else { Shader.SetEnabled(p,"Glitch",false); Shader.SetEnabled(p,"Grain",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); } // Doom's explosions aren't fully 3D static void DoBlast( Actor Source, double ExplosionRadius, double MomentumTransfer, Actor ignoreme = null ) { BlockThingsIterator bi = BlockThingsIterator.Create(Source,ExplosionRadius); while ( bi.Next() ) { Actor a = bi.Thing; if ( !a || (a == ignoreme) || !a.bSHOOTABLE || !Source.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) || (a == Source) || (Source.Distance3D(a) > ExplosionRadius) || a.bCANNOTPUSH || (a.Mass >= 10000000) ) continue; Vector3 midpoint = a.Vec3Offset(0,0,a.height*0.5); Vector3 dir = Level.Vec3Diff(Source.pos,midpoint); double dist = max(1,dir.length()); double damagescale = 1-max(0,(dist-a.radius)/ExplosionRadius); dir = dir/dist; a.vel += dir*damagescale*(MomentumTransfer/(Thinker.TICRATE*max(50,a.mass))); } } // Same for this static void DoKnockback( Actor Victim, Vector3 HitDirection, double MomentumTransfer ) { if ( !Victim || !Victim.bSHOOTABLE || Victim.bCANNOTPUSH || (Victim.Mass >= 10000000) ) return; Victim.vel += HitDirection*(MomentumTransfer/(Thinker.TICRATE*max(50,Victim.Mass))); } static void DoSwing( Actor target, Vector2 dir, double initial, double inc, int steps, int mode = 0, int delay = 0, double rmul = 1.0 ) { let s = new("Swinger"); s.ChangeStatNum(Thinker.STAT_USER); s.target = target; s.dir = dir; s.inc = inc; s.rmul = rmul; s.steps = steps; s.mode = mode; s.delay = delay; s.cnt = 0; s.cstate = 0; s.str = initial; s.tstr = initial; } } // Fancy crash effect Class SWWMCrashHandler : StaticEventHandler { ui bool wasinmap; ui int timer; override void UiTick() { if ( (gamestate == GS_LEVEL) || (gamestate == GS_TITLELEVEL) ) { wasinmap = true; timer = 0; } else if ( (gamestate == GS_FULLCONSOLE) && (wasinmap || (timer > 0)) ) { wasinmap = false; if ( timer == 1 ) { Console.Printf(TEXTCOLOR_GOLD.."Oopsie Woopsie!"..TEXTCOLOR_NORMAL); 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 if ( timer == 140 ) { Console.Printf(TEXTCOLOR_GOLD.."Looks like GZDoom made a fucky wucky! owo"..TEXTCOLOR_NORMAL); 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(TEXTCOLOR_GOLD.."Don't blame me. Shouldn't have tried running this with Brutal Doom."..TEXTCOLOR_NORMAL); else Console.Printf(TEXTCOLOR_GOLD.."If you didn't trigger it manually, it's best if you take a screenshot and show it to Marisa."..TEXTCOLOR_NORMAL); } timer++; } } } // >loading brutal doom with this Class SWWMBrutalHandler : StaticEventHandler { ui int timer; ui TextureID scr; bool detected; override void OnRegister() { for ( int i=0; iBrutal Doom"); timer++; } else timer = 0; } override void WorldTick() { if ( !detected ) return; for ( int i=0; i