diff --git a/decaldef.txt b/decaldef.txt index c0b62151d..c98e75187 100644 --- a/decaldef.txt +++ b/decaldef.txt @@ -147,6 +147,16 @@ decal RipBlast y-scale 0.45 } +decal YnykronBlast +{ + pic mcblast + shade "00 00 00" + x-scale 0.6 + y-scale 0.6 + randomflipx + randomflipy +} + decal HugeScorch { pic SCORCH1 diff --git a/language.version b/language.version index 8cb22f863..733223fa2 100644 --- a/language.version +++ b/language.version @@ -1,2 +1,2 @@ [default] -SWWM_MODVER="\chSWWM \cwGZ\c- r376 (Sun 21 Jun 22:34:04 CEST 2020)"; +SWWM_MODVER="\chSWWM \cwGZ\c- r377 (Mon 22 Jun 22:45:50 CEST 2020)"; diff --git a/modeldef.ynykron b/modeldef.ynykron index b8e2153d8..7f9e9a0d9 100644 --- a/modeldef.ynykron +++ b/modeldef.ynykron @@ -1,3 +1,97 @@ +Model "YnykronBeam" +{ + Path "models/extra" + + Model 0 "WarpBeam_d.3d" + Scale 1.0 2.0 2.0 + Offset 128 0 0 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + // starter + Skin 0 "MCBeamS.png" + + // base + FrameIndex XZW1 A 0 0 + // low deviation + FrameIndex XZW1 B 0 1 + FrameIndex XZW1 C 0 2 + FrameIndex XZW1 D 0 3 + FrameIndex XZW1 E 0 4 + + // other + Skin 0 "MCBeam.png" + + // base + FrameIndex XZW2 A 0 0 + // low deviation + FrameIndex XZW2 B 0 1 + FrameIndex XZW2 C 0 2 + FrameIndex XZW2 D 0 3 + FrameIndex XZW2 E 0 4 +} + +Model "YnykronRing" +{ + Model 0 "models/extra/Flat_d.3d" + RollOffset 90 + AngleOffset 90 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + // boy this is a pain + Skin 0 "sprites/XRG4A0.png" + FrameIndex XRG4 A 0 0 + Skin 0 "sprites/XRG4B0.png" + FrameIndex XRG4 B 0 0 + Skin 0 "sprites/XRG4C0.png" + FrameIndex XRG4 C 0 0 + Skin 0 "sprites/XRG4D0.png" + FrameIndex XRG4 D 0 0 + Skin 0 "sprites/XRG4E0.png" + FrameIndex XRG4 E 0 0 + Skin 0 "sprites/XRG4F0.png" + FrameIndex XRG4 F 0 0 + Skin 0 "sprites/XRG4G0.png" + FrameIndex XRG4 G 0 0 + Skin 0 "sprites/XRG4H0.png" + FrameIndex XRG4 H 0 0 + Skin 0 "sprites/XRG4I0.png" + FrameIndex XRG4 I 0 0 + Skin 0 "sprites/XRG4J0.png" + FrameIndex XRG4 J 0 0 + Skin 0 "sprites/XRG4K0.png" + FrameIndex XRG4 K 0 0 + Skin 0 "sprites/XRG4L0.png" + FrameIndex XRG4 L 0 0 + Skin 0 "sprites/XRG4M0.png" + FrameIndex XRG4 M 0 0 + Skin 0 "sprites/XRG4N0.png" + FrameIndex XRG4 N 0 0 + Skin 0 "sprites/XRG4O0.png" + FrameIndex XRG4 O 0 0 + Skin 0 "sprites/XRG4P0.png" + FrameIndex XRG4 P 0 0 + Skin 0 "sprites/XRG4Q0.png" + FrameIndex XRG4 Q 0 0 + Skin 0 "sprites/XRG4R0.png" + FrameIndex XRG4 R 0 0 + Skin 0 "sprites/XRG4S0.png" + FrameIndex XRG4 S 0 0 + Skin 0 "sprites/XRG4T0.png" + FrameIndex XRG4 T 0 0 + Skin 0 "sprites/XRG4U0.png" + FrameIndex XRG4 U 0 0 + Skin 0 "sprites/XRG4V0.png" + FrameIndex XRG4 V 0 0 + Skin 0 "sprites/XRG4W0.png" + FrameIndex XRG4 W 0 0 + Skin 0 "sprites/XRG4X0.png" + FrameIndex XRG4 X 0 0 +} + Model "Ynykron" { Path "models" diff --git a/palettes/WhiteExpl.pal b/palettes/WhiteExpl.pal new file mode 100644 index 000000000..3898a3dfe Binary files /dev/null and b/palettes/WhiteExpl.pal differ diff --git a/palettes/WhiteExpl2.pal b/palettes/WhiteExpl2.pal new file mode 100644 index 000000000..6b9816a22 Binary files /dev/null and b/palettes/WhiteExpl2.pal differ diff --git a/zscript/swwm_deathlydeathcannon.zsc b/zscript/swwm_deathlydeathcannon.zsc index 4b5db088a..e7678b636 100644 --- a/zscript/swwm_deathlydeathcannon.zsc +++ b/zscript/swwm_deathlydeathcannon.zsc @@ -1,6 +1,768 @@ // Ynykron Artifact (from UnSX Series, featured in SWWM Platinum as a secret weapon) // Slot 0, replaces BFG9000, Firemace, Wraithverge (arc) +// cheap way to let players know they just got fucking erased from existence +Class PlayerGone : PlayerChunk +{ + int deadtimer; + + override void DeathThink() + { + player.damagecount--; + player.poisoncount--; + deadtimer++; + if ( (deadtimer == 60) && (player == players[consoleplayer]) ) + A_StartSound("demolitionist/youdied",CHAN_DEMOVOICE,CHANF_OVERLAP|CHANF_UI); + if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) ) + { + // standard behaviour, respawn normally + if ( (((player.cmd.buttons&BT_USE) && !player.Bot) || ((deathmatch || alwaysapplydmflags) && sv_forcerespawn && (Level.maptime >= player.respawn_time))) && !sv_norespawn ) + { + player.cls = null; + player.playerstate = PST_REBORN; + if ( special1 > 2 ) special1 = 0; + } + } + else if ( (player.cmd.buttons&BT_USE) && (deadtimer > 120) ) + { + // gross hackfix for library "vanishing" + SWWMExcuseMeWhatTheFuckHandler.ThisIsSomeSeriousBullshit(); + // reload save + player.cls = null; + player.playerstate = PST_ENTER; + if ( special1 > 2 ) special1 = 0; + } + // no revive (for obvious reasons) + } + + static void FeckOff( Actor p ) + { + // doesn't affect voodoo dolls (convenient, isn't it?) + if ( !p.player || (p.player.mo != p) ) return; + let c = PlayerGone(Spawn("PlayerGone",(32767,32767,0))); + c.player = p.player; + c.Health = p.Health; + p.player = null; + c.ObtainInventory(p); + if ( c.player ) c.player.mo = c; + for ( int i=0; i 0) || (goner.tics != -1) ) return; + goner.Destroy(); + } +} + +Class YnykronImpactLight : PaletteLight +{ + Default + { + Tag "WhiteExpl2"; + ReactionTime 50; + Args 0,0,0,300; + } +} + +Class YnykronShotLight : PaletteLight +{ + Default + { + Tag "WhiteExpl"; + ReactionTime 100; + Args 0,0,0,1200; + } +} + +Class YnykronBeamLight : PaletteLight +{ + Default + { + Tag "WhiteExpl2"; + ReactionTime 200; + Args 0,0,0,600; + } +} + +Class YnykronImpactArm : Actor +{ + Default + { + PROJECTILE; + +THRUACTORS; + +BOUNCEONWALLS; + +BOUNCEONFLOORS; + +BOUNCEONCEILINGS; + +NODAMAGETHRUST; + +FORCERADIUSDMG; + -NOGRAVITY; + Gravity 0.35; + BounceFactor 1.0; + Radius 4; + Height 4; + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + reactiontime = Random[ExploS](10,20); + double ang, pt; + ang = FRandom[ExploS](0,360); + pt = FRandom[ExploS](-90,90); + vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[ExploS](8.,20.); + } + States + { + Spawn: + TNT1 A 1 + { + A_CountDown(); + Spawn("YnykronImpactTrail",pos); + Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5); + let s = Spawn("SWWMSmoke",pos); + s.vel = pvel+vel*.2; + s.special1 = Random[ExploS](1,3); + s.scale *= 2.4; + s.alpha *= 0.1+.4*(ReactionTime/15.); + } + Wait; + } +} + +Class YnykronImpactTrail : Actor +{ + Default + { + RenderStyle "Add"; + +NOBLOCKMAP; + +NOGRAVITY; + +FORCEXYBILLBOARD; + +NOTELEPORT; + Scale 2.; + } + States + { + Spawn: + MOXP ABCDEFGHIJKLMNOPQRSTUVWXYZ[\ 1 Bright; + Stop; + } +} + +Class YnykronImpact : Actor +{ + Default + { + Obituary "$O_YNYKRON"; + DamageType "Ynykron"; + RenderStyle "Add"; + Scale 4.; + Alpha .4; + +NOGRAVITY; + +NOBLOCKMAP; + +NOTELEPORT; + +DONTSPLASH; + +NODAMAGETHRUST; + +FORCERADIUSDMG; + +FORCEXYBILLBOARD; + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + // only the initial impact plays a sound + if ( !special2 ) + { + // no need to call A_AlertMonsters on this, all monsters on the entire map were already alerted by the initial shot + A_QuakeEx(4,4,4,50,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:600,rollintensity:.6); + A_StartSound("ynykron/hit",CHAN_VOICE,CHANF_DEFAULT,.15,0.); + } + Scale *= FRandom[ExploS](0.8,1.1); + Scale.x *= RandomPick[ExploS](-1,1); + Scale.y *= RandomPick[ExploS](-1,1); + int numpt = Random[ExploS](5,10); + for ( int i=0; i 4 ) continue; + // spawn blast that will propagate + let b = Spawn("YnykronImpact",level.Vec3Offset(pos,dirto*min(250,dist))); + b.target = target; + b.master = master; + b.angle = atan2(dirto.y,dirto.x); + b.pitch = asin(-dirto.z); + b.special2 = special2+1; + if ( YnykronShot(master) ) + YnykronShot(master).blastcount++; + } + } + override void OnDestroy() + { + if ( YnykronShot(master) ) + YnykronShot(master).blastcount--; + Super.OnDestroy(); + } + States + { + Spawn: + MOXP ABCDEFGHIJKLMNOPQRSTUVWXYZ[\ 2 Bright; + Stop; + } +} + +Class YnykronTracer : LineTracer +{ + Actor ignore; + Array ShootThroughList; + Array WaterHitList; + Array HitList; + + override ETraceStatus TraceCallback() + { + // liquid splashes + if ( Results.CrossedWater ) + { + let hl = new("WaterHit"); + hl.sect = Results.CrossedWater; + hl.hitpos = Results.CrossedWaterPos; + WaterHitList.Push(hl); + } + else if ( Results.Crossed3DWater ) + { + let hl = new("WaterHit"); + hl.sect = Results.Crossed3DWater; + hl.hitpos = Results.Crossed3DWaterPos; + WaterHitList.Push(hl); + } + if ( Results.HitType == TRACE_HitActor ) + { + if ( Results.HitActor == ignore ) return TRACE_Skip; + if ( Results.HitActor.bSHOOTABLE ) + { + let ent = new("HitListEntry"); + ent.hitactor = Results.HitActor; + ent.hitlocation = Results.HitPos; + ent.x = Results.HitVector; + hitlist.Push(ent); + } + return TRACE_Skip; + } + else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) + { + if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&Line.ML_BlockHitscan) ) + return TRACE_Stop; + ShootThroughList.Push(Results.HitLine); + return TRACE_Skip; + } + return TRACE_Stop; + } +} + +Class YnykronBeamTrail : Actor +{ + override void PostBeginPlay() + { + Super.PostBeginPlay(); + roll = FRandom[Ynykron](0,360); + SetState(FindState("Spawn")+Random[Ynykron](0,8)); + } + override void Tick() + { + Super.Tick(); + if ( isFrozen() ) return; + A_FadeOut(FRandom[Ynykron](.001,.002)); + } + Default + { + RenderStyle "Add"; + Radius 0.1; + Height 0; + Alpha .2; + +NOGRAVITY; + +NOBLOCKMAP; + +NOTELEPORT; + +DONTSPLASH; + +FORCEXYBILLBOARD; + +ROLLSPRITE; + +ROLLCENTER; + } + States + { + Spawn: + MOTR ABCDEFGHI -1 Bright; + Stop; + } +} + +Class YnykronBeam : Actor +{ + void SpreadOut() + { + Vector3 x, y, z; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + let t = new("YnykronTracer"); + t.ignore = target; + t.ShootThroughList.Clear(); + t.WaterHitList.Clear(); + t.HitList.Clear(); + t.Trace(pos,cursector,x,128,TRACE_HitSky); + for ( int i=0; i= 25600 ) + { + // end of the line, dissipate + int numpt = Random[Ynykron](4,8); + for ( int i=0; i 0 ) return; + let next = Spawn("YnykronBeam",pos); + next.angle = angle; + next.pitch = pitch; + next.roll = roll; + next.target = target; + next.master = master; + next.special1 = special1; + next.bAMBUSH = bAMBUSH; + next.SetStateLabel("TrailSpawn"); + // exit blast + Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); + let b = Spawn("YnykronImpact",level.Vec3Offset(pos,x*4)); + b.target = target; + b.master = master; + b.angle = atan2(x.y,x.x); + b.pitch = asin(-x.z); + b.A_SprayDecal("YnykronBlast",-172); + if ( YnykronShot(master) ) + YnykronShot(master).blastcount++; + // trace back to get the proper "exit surface" so we can trigger lines if needed + let at = new("AuxiliarySilverBulletTracer"); + at.Trace(pos,CurSector,-x,2.,TRACE_NoSky); + if ( at.Results.HitType == TRACE_HitWall ) + { + if ( at.Results.HitLine.sidedef[1] ) + { + at.Results.HitLine.Activate(target,0,SPAC_PCross); + if ( at.Results.HitLine.special == GlassBreak ) // fuck glass + at.Results.HitLine.Activate(target,0,SPAC_Impact); + } + else at.Results.HitLine.Activate(tracer,at.Results.Side,SPAC_Impact); + } + Destroy(); + } +} + +Class YnykronRing : Actor +{ + Default + { + RenderStyle "Add"; + Radius 0.1; + Height 0; + Scale .6; + Alpha .1; + +NOGRAVITY; + +NOBLOCKMAP; + +FORCEXYBILLBOARD; + +NOTELEPORT; + +DONTSPLASH; + +ROLLSPRITE; + +ROLLCENTER; + } + States + { + Spawn: + XRG4 AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXX 1 Bright A_SetScale(scale.x*0.988); + Stop; + } +} + +// non-model version, for impacts +Class YnykronImpactRing : YnykronRing +{ + Default + { + Alpha .8; + } + States + { + Spawn: + XRG4 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.02); + Stop; + } +} + +Class YnykronShot : Actor +{ + Array hitlist; + int beamcount; + int blastcount; + + Default + { + Radius .1; + Height 0; + +NOGRAVITY; + +NOBLOCKMAP; + +NOTELEPORT; + +DONTSPLASH; + } + override void PostBeginPlay() + { + A_QuakeEx(6,6,6,150,0,65536,"",QF_RELATIVE|QF_SCALEDOWN,falloff:65536,rollIntensity:1.); + A_StartSound("ynykron/beam",CHAN_VOICE,CHANF_DEFAULT,1.,0.); + hitlist.Clear(); + beamcount = 0; + blastcount = 0; + int rings = 1; + Vector3 x, y, z, dir; + double a, s; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + for ( double i=0; i<.05; i+=.01 ) + { + for ( int j=0; j<360; j+=(360/rings) ) + { + if ( i==0 ) dir = x; // central beam always precise + else + { + a = j+FRandom[Ynykron](-15.,15.); + s = i+FRandom[Ynykron](-.01,.01); + dir = (x+y*cos(a)*s+z*sin(a)*s).unit(); + } + let b = Spawn("YnykronBeam",pos); + b.target = target; + b.master = self; + b.angle = atan2(dir.y,dir.x); + b.pitch = asin(-dir.z); + b.roll = FRandom[Ynykron](0,360); + b.bAMBUSH = (i==0); // central beam spawns trail sprites, makes cone more "dense" + beamcount++; + } + rings += 4; + } + Spawn("YnykronShotLight",level.Vec3Offset(pos,x*30)); + } + override void Tick() + { + if ( isFrozen() ) return; + // spawn rings + special1++; + if ( !(special1%10) && (special1 <= 30) ) + { + Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); + for ( int i=0; i<8; i++ ) + { + let r = Spawn("YnykronRing",level.Vec3Offset(pos,dir*(special1*16+i*2))); + r.scale *= special1/10.; + r.angle = angle; + r.pitch = pitch; + r.roll = FRandom[Ynykron](0,360); + } + } + // wait until we're no longer needed and all effects are over + if ( IsActorPlayingSound(CHAN_VOICE) || (beamcount > 0) || (blastcount > 0) ) return; + // we're done here, but wait for a while just in case + if ( special1 > 350 ) Destroy(); + } +} + Class Ynykron : SWWMWeapon { transient ui TextureID WeaponBox, ChargeBar[2], BoxSide[2]; @@ -95,6 +857,40 @@ Class Ynykron : SWWMWeapon A_OverlayAlpha(PSP_WEAPON+1,0.); invoker.chargestate = CS_IDLE; invoker.clipcount = 0; + Vector3 x, y, z, origin; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),x*15+y*4); + if ( invoker.inverted ) + { + // TODO altfire + Console.Printf("\cgYNYKRON ALTFIRE NOT DONE, FALLBACK TO PRIMARY\c-"); + } + //else + { + let s = Spawn("YnykronShot",origin); + s.target = self; + s.angle = angle; + s.pitch = BulletSlope(); + } + invoker.specialf1 = 1.; + A_Overlay(PSP_WEAPON+3,"FireBlast"); + } + + action void A_Backblast() + { + Vector3 x, y, z, origin; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),-x*15+y*4); + int numpt = Random[Ynykron](40,80); + for ( int i=0; i CS_IDLE) || ((invoker.clipcount <= 0) && ((invoker.Ammo1.Amount > 1) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true))) ) + if ( (invoker.chargestate > CS_IDLE) || ((invoker.clipcount <= 0) && ((invoker.Ammo1.Amount > 0) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true))) ) flg |= WRF_ALLOWRELOAD; if ( (invoker.clipcount <= 0) || (invoker.chargestate > CS_IDLE) ) flg |= WRF_NOSECONDARY; @@ -228,7 +1024,7 @@ Class Ynykron : SWWMWeapon Fire: XZW2 A 1 { - if ( (invoker.clipcount <= 0) && ((invoker.Ammo1.Amount > 1) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true)) ) + if ( (invoker.clipcount <= 0) && ((invoker.Ammo1.Amount > 0) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true)) ) return ResolveState("Reload"); if ( invoker.chargestate == CS_IDLE ) return ResolveState("Charge"); @@ -241,6 +1037,9 @@ Class Ynykron : SWWMWeapon XZW3 Q 3 A_StartSound("ynykron/ventclose",CHAN_WEAPON,CHANF_OVERLAP); XZW3 R 3; Goto Ready; + FireBlast: + TNT1 AAAAA 1 A_Backblast(); + Stop; FireSmoke: XZWA J 1 { diff --git a/zscript/swwm_hud.zsc b/zscript/swwm_hud.zsc index a83394b26..c8208c745 100644 --- a/zscript/swwm_hud.zsc +++ b/zscript/swwm_hud.zsc @@ -437,6 +437,7 @@ Class SWWMStatusBar : BaseStatusBar // ignore player unless chasecamming if ( (trk.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue; if ( trk.myplayer && deathmatch ) continue; // no players in dm + if ( trk.mytarget is 'PlayerGone' ) continue; // ignore "gone" players int mtime = 35; if ( thesight && (trk.lasthealth > 0) ) mtime += 105; if ( level.maptime > trk.updated+mtime ) continue; @@ -1164,16 +1165,18 @@ Class SWWMStatusBar : BaseStatusBar { // death prompt let demo = Demolitionist(CPlayer.mo); - if ( !demo || (CPlayer.Health > 0) || (CPlayer != players[consoleplayer]) ) return; + let goner = PlayerGone(CPlayer.mo); + if ( (!demo && !goner) || (CPlayer.Health > 0) || (CPlayer != players[consoleplayer]) ) return; String str; double alph; int len; double xx, yy; Font fnt; - if ( demo.player.viewheight <= 6 ) + int deadtimer = goner?goner.deadtimer:demo.deadtimer; + if ( goner || (demo.player.viewheight <= 6) ) { - Screen.Dim("Black",min(demo.deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight()); - if ( demo.revivefail > level.maptime ) + Screen.Dim("Black",goner?1.:min(deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight()); + if ( demo && (demo.revivefail > level.maptime) ) { Screen.Dim("Red",clamp((demo.revivefail-level.maptime)/60.,0.,.2),0,0,Screen.GetWidth(),Screen.GetHeight()); str = StringTable.Localize("$SWWM_REFAIL"); @@ -1184,7 +1187,7 @@ Class SWWMStatusBar : BaseStatusBar if ( ((demo.revivefail-level.maptime)%16) < 8 ) Screen.DrawText(fnt,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } - alph = clamp((demo.deadtimer-60)/60.,0.,1.); + alph = clamp((deadtimer-60)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDED"),CPlayer.GetUserName()); fnt = LangFont(mTewiFont); len = fnt.StringWidth(str); @@ -1194,7 +1197,7 @@ Class SWWMStatusBar : BaseStatusBar if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) ) { if ( sv_norespawn ) return; - alph = clamp((demo.deadtimer-90)/60.,0.,1.); + alph = clamp((deadtimer-90)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDEDMP"),CPlayer.GetUserName()); fnt = LangFont(mTewiFont); len = fnt.StringWidth(str); @@ -1203,16 +1206,16 @@ Class SWWMStatusBar : BaseStatusBar Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); return; } - alph = clamp((demo.deadtimer-140)/60.,0.,1.); + alph = clamp((deadtimer-140)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDED2"),CPlayer.GetUserName()); fnt = LangFont(mTewiFont); len = fnt.StringWidth(str); xx = (ss.x-len)/2.; yy = ss.y/2.; Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); - if ( !swwm_revive ) + if ( goner || !swwm_revive ) return; - alph = clamp((demo.deadtimer-160)/60.,0.,1.); + alph = clamp((deadtimer-160)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDED3"),CPlayer.GetUserName()); fnt = LangFont(mTewiFont); len = fnt.StringWidth(str); diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index 9edcee76a..a36d56641 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -1975,7 +1975,7 @@ Class DemolitionistSelfLight : Actor override void Tick() { Super.Tick(); - if ( !target || !(target is 'Demolitionist') || (Demolitionist(target).selflight != self) ) + if ( !target || !target.player || !(target is 'Demolitionist') || (Demolitionist(target).selflight != self) ) { Destroy(); return; diff --git a/zscript/swwm_powerup.zsc b/zscript/swwm_powerup.zsc index d68d141f2..8d85947ec 100644 --- a/zscript/swwm_powerup.zsc +++ b/zscript/swwm_powerup.zsc @@ -1015,7 +1015,7 @@ Class LampMoth : Actor mindist = dist; lamp = a; master = a.target; - if ( CompanionLamp(lamp).moff.Find(self) == -1 ) + if ( CompanionLamp(lamp).moff.Find(self) == CompanionLamp(lamp).moff.Size() ) CompanionLamp(lamp).moff.Push(self); if ( master && master.player ) SetFriendPlayer(master.player); else bFRIENDLY = false; diff --git a/zscript/swwm_thiccboolet.zsc b/zscript/swwm_thiccboolet.zsc index dea10e872..922e1db66 100644 --- a/zscript/swwm_thiccboolet.zsc +++ b/zscript/swwm_thiccboolet.zsc @@ -204,7 +204,7 @@ Class SilverBulletTracer : SpreadSlugTracer ShootThroughList.Push(Results.HitLine); // trace backwards to find exit surface let at = new("AuxiliarySilverBulletTracer"); - at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_HitSky); + at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky); if ( at.Results.HitType != TRACE_HitNone ) { let wp2 = new("WallPenetrate"); @@ -255,7 +255,7 @@ Class SilverBulletTracer : SpreadSlugTracer WallPenetrateList.Push(wp); // trace backwards to find exit surface let at = new("AuxiliarySilverBulletTracer"); - at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_HitSky); + at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky); if ( at.Results.HitType != TRACE_HitNone ) { let wp2 = new("WallPenetrate");