diff --git a/Roadmap.md b/Roadmap.md index a3b6598d6..471699daa 100644 --- a/Roadmap.md +++ b/Roadmap.md @@ -27,6 +27,11 @@ - Finish writing all those damn side stories. - Make 'em fancy, maybe add some lil' art to them. +**Funny Fellas:** + + - Monster/decoration replacement packs. All of it modelled and tweaked to fit the style and theme of the mod. Expect enhanced enemy behaviour, not gonna keep it "vanilla". + - Porting weapons to Hideous Destructor as a meme. + **Fight for the Front and freedom. Move out!:** - Oh boy, Strife support time. @@ -34,10 +39,6 @@ - Voice acting? Maybe not, I'd need people to re-voice all Strife NPCs. - Oh god I have to do dialogue sprites for all characters. Maybe I can get someone else for the job? -**Funny Fellas:** - - - Monster/decoration replacement packs. All of it modelled and tweaked to fit the style and theme of the mod. Expect enhanced enemy behaviour, not gonna keep it "vanilla". - - Porting weapons to Hideous Destructor as a meme. **At this point I'm just making shit up:** diff --git a/credits.txt b/credits.txt index 5292aa4b0..a186751e7 100644 --- a/credits.txt +++ b/credits.txt @@ -19,17 +19,18 @@ Most of the work here is original, but there are some notable exceptions: - This mod uses libeye, by KeksDose. Big thanks. - Title theme, "Traumatic State", by Teque (which a lot of people just know as "the AS-Golgotha music"). - Intermission theme, "Dragony", also by Teque (very comfy music considering the rest of his repertoire). - - Trailer theme, "Gateways Part II", also by Teque, and Cube (pretty cool track tbh). - The anti-BD feature uses art and music by IOSYS, art was edited into the Doom palette. - The crash handler uses a sound bit from Umineko and a short clip of the Curb Your Enthusiasm theme. - Tewi font by lucy (https://github.com/lucy/tewi-font). Modified to add gradients and drop shadow. - MPlus font by M⁺ FONTS PROJECT (http://mplus-fonts.osdn.jp/mplus-bitmap-fonts). Modified to add gradients and drop shadow. - Miniwi font by Josuah Demangeon (http://josuah.net). Modified to add gradients and drop shadow. - k6x8 font by littlelimit (https://littlelimit.net/k6x8.htm). Modified to add gradients and drop shadow. - - Terrain splashes for Doom by MagicWazard. + - Terrain splashes for Doom by MagicWazard (typical Realm667 stuff that we've all used). - Nashgore footprint texture by Valerie Lavender. - Slope alignment utility code by ZZYZX & Nash. - Intermission fanart: * Substance20 (@S20TBL) * Captain J (@Jho7835) + * Redead-ITA + * Sgt. Shivers (@Sgt_Shivers_) - A certain hidden easter egg / meme uses crappified/bassboosted edits of Old Days and the CBT Wikipedia article. diff --git a/language.def_base b/language.def_base index ddb6ffb5f..6fff57730 100644 --- a/language.def_base +++ b/language.def_base @@ -669,7 +669,7 @@ O_SILVERBULLET = "%o could not ignore the girth of %k's bullets."; O_SILVERBULLET2 = "%o was blasted by %k's girthy bullets."; O_CANDYGUN = "%k made %o taste the sweetness (and death)."; O_YNYKRON = "%o was instantly removed by %k."; -O_YNYKRONALT = "%o was spaghettified by %k."; +O_YNYKRONALT = "%o was furiously obliterated by %k."; O_POUND = "%o was very impressed by %k's landing."; O_DASH = "%o was discombobulated by a very fast moving %k."; O_JUMP = "%o was stepped on %k."; diff --git a/language.es_base b/language.es_base index a986a8525..5aafc8dbd 100644 --- a/language.es_base +++ b/language.es_base @@ -622,7 +622,7 @@ O_SILVERBULLET = "%o no pudo ignorar el grosor de las balas de %k."; O_SILVERBULLET2 = "%o fue reventad@[ao_esp] por las gruesas balas de %k."; O_CANDYGUN = "%k hizo probar a %o un sabor dulce (de muerte)."; O_YNYKRON = "%o fue borrad@[ao_esp] instantáneamente por %k."; -O_YNYKRONALT = "%o fue espaguetificad@[ao_esp] por %k."; +O_YNYKRONALT = "%o fue aniquilad@[ao_esp] furiosamente por %k."; O_POUND = "%o se llevó una gran impresión del aterrizaje de %k."; O_DASH = "%o fue descuajeringad@[ao_esp] a todo gas por %k."; O_JUMP = "%o fue pisotead@[ao_esp] por %k."; diff --git a/language.version b/language.version index b01abc2b2..073c16711 100644 --- a/language.version +++ b/language.version @@ -1,2 +1,2 @@ [default] -SWWM_MODVER="\chSWWM \cwGZ\c- r534 (Fri 11 Sep 16:20:58 CEST 2020)"; +SWWM_MODVER="\chSWWM \cwGZ\c- r535 (Fri 11 Sep 22:29:49 CEST 2020)"; diff --git a/menudef.txt b/menudef.txt index c8fea2ae7..d4c42a71e 100644 --- a/menudef.txt +++ b/menudef.txt @@ -143,9 +143,6 @@ OptionMenu "SWWMCreditsMenu" StaticText "Traumatic State", "White" StaticText "Dragony", "White" StaticText " " - StaticText "Nitro", "Gold" - StaticText "Gateways Part II", "White" - StaticText " " StaticText "$SWWM_CFANART", "Red" StaticText " " StaticText "Substance20 (@S20TBL)", "Gold" diff --git a/modeldef.ynykron b/modeldef.ynykron index 224d3d7ec..83bbb2d6d 100644 --- a/modeldef.ynykron +++ b/modeldef.ynykron @@ -150,6 +150,107 @@ Model "YnykronVoidBeam" Skin 0 "DarkRaysStartEnd.png" FrameIndex XZW1 D 0 0 } +Model "YnykronVoidBeamTail" +{ + Path "models/extra" + + Model 0 "BaseBeam_d.3d" + Scale 0.0625 0.05 0.05 + Offset 8 0 0 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + // starter + Skin 0 "DarkRaysStart.png" + FrameIndex XZW1 A 0 0 + // trailer + Skin 0 "DarkRays.png" + FrameIndex XZW1 B 0 0 + // cap + Skin 0 "DarkRaysEnd.png" + FrameIndex XZW1 C 0 0 + // early cap + Skin 0 "DarkRaysStartEnd.png" + FrameIndex XZW1 D 0 0 +} + +Model "YnykronLightningArc" +{ + Path "models/extra" + + Model 0 "WarpBeam_d.3d" + Scale 0.5 0.8 0.8 + Offset 64 0 0 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + Skin 0 "VortexArcS.png" + FrameIndex XZW1 A 0 1 + FrameIndex XZW1 B 0 2 + FrameIndex XZW1 C 0 3 + FrameIndex XZW1 D 0 4 + FrameIndex XZW1 E 0 5 + FrameIndex XZW1 F 0 6 + FrameIndex XZW1 G 0 7 + FrameIndex XZW1 H 0 8 + FrameIndex XZW1 I 0 9 + FrameIndex XZW1 J 0 10 + FrameIndex XZW1 K 0 11 + FrameIndex XZW1 L 0 12 + Skin 0 "VortexArc.png" + FrameIndex XZW2 A 0 1 + FrameIndex XZW2 B 0 2 + FrameIndex XZW2 C 0 3 + FrameIndex XZW2 D 0 4 + FrameIndex XZW2 E 0 5 + FrameIndex XZW2 F 0 6 + FrameIndex XZW2 G 0 7 + FrameIndex XZW2 H 0 8 + FrameIndex XZW2 I 0 9 + FrameIndex XZW2 J 0 10 + FrameIndex XZW2 K 0 11 + FrameIndex XZW2 L 0 12 +} +Model "YnykronLightningArcSub" +{ + Path "models/extra" + + Model 0 "WarpBeam_d.3d" + Scale 0.125 0.2 0.2 + Offset 16 0 0 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + Skin 0 "VortexArcS.png" + FrameIndex XZW1 A 0 1 + FrameIndex XZW1 B 0 2 + FrameIndex XZW1 C 0 3 + FrameIndex XZW1 D 0 4 + FrameIndex XZW1 E 0 5 + FrameIndex XZW1 F 0 6 + FrameIndex XZW1 G 0 7 + FrameIndex XZW1 H 0 8 + FrameIndex XZW1 I 0 9 + FrameIndex XZW1 J 0 10 + FrameIndex XZW1 K 0 11 + FrameIndex XZW1 L 0 12 + Skin 0 "VortexArc.png" + FrameIndex XZW2 A 0 1 + FrameIndex XZW2 B 0 2 + FrameIndex XZW2 C 0 3 + FrameIndex XZW2 D 0 4 + FrameIndex XZW2 E 0 5 + FrameIndex XZW2 F 0 6 + FrameIndex XZW2 G 0 7 + FrameIndex XZW2 H 0 8 + FrameIndex XZW2 I 0 9 + FrameIndex XZW2 J 0 10 + FrameIndex XZW2 K 0 11 + FrameIndex XZW2 L 0 12 +} Model "YnykronSingularity" { diff --git a/music/GW2.XM b/music/GW2.XM deleted file mode 100644 index ae1bc8a7b..000000000 Binary files a/music/GW2.XM and /dev/null differ diff --git a/sndinfo.txt b/sndinfo.txt index ceddc11f6..a5d0e2ff3 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -814,9 +814,9 @@ ynykron/vortexarc3 sounds/ynykron/mc_vortexarc3.ogg $random ynykron/vortexarc { ynykron/vortexarc1 ynykron/vortexarc2 ynykron/vortexarc3 } ynykron/vortexflash1 sounds/ynykron/mc_vortexflash1.ogg ynykron/vortexflash2 sounds/ynykron/mc_vortexflash2.ogg -ynykron/vortexflash3 sounds/ynykron/mc_vortexflash3.ogg -$random ynykron/vortexflash { ynykron/vortexflash1 ynykron/vortexflash2 ynykron/vortexflash3 } +$random ynykron/vortexflash { ynykron/vortexflash1 ynykron/vortexflash2 } ynykron/vortexend sounds/ynykron/mc_vortexend.ogg +ynykron/wind sounds/ynykron/mc_vortexwind.ogg misc/secret sounds/menu/findsecret.ogg misc/keytry sounds/menu/failuse.ogg diff --git a/sounds/ynykron/mc_vortexflash1.ogg b/sounds/ynykron/mc_vortexflash1.ogg index 98dbf5798..b61eaae10 100644 Binary files a/sounds/ynykron/mc_vortexflash1.ogg and b/sounds/ynykron/mc_vortexflash1.ogg differ diff --git a/sounds/ynykron/mc_vortexflash2.ogg b/sounds/ynykron/mc_vortexflash2.ogg index b61eaae10..29ebfa2c9 100644 Binary files a/sounds/ynykron/mc_vortexflash2.ogg and b/sounds/ynykron/mc_vortexflash2.ogg differ diff --git a/sounds/ynykron/mc_vortexflash3.ogg b/sounds/ynykron/mc_vortexflash3.ogg deleted file mode 100644 index 29ebfa2c9..000000000 Binary files a/sounds/ynykron/mc_vortexflash3.ogg and /dev/null differ diff --git a/sounds/ynykron/mc_vortexwind.ogg b/sounds/ynykron/mc_vortexwind.ogg new file mode 100644 index 000000000..be3f63d2f Binary files /dev/null and b/sounds/ynykron/mc_vortexwind.ogg differ diff --git a/sprites/MHALA0.png b/sprites/MHALA0.png index bf68f503c..0c4323247 100644 Binary files a/sprites/MHALA0.png and b/sprites/MHALA0.png differ diff --git a/zscript/swwm_deathlydeathcannon.zsc b/zscript/swwm_deathlydeathcannon.zsc index e61e13de0..c0befbd41 100644 --- a/zscript/swwm_deathlydeathcannon.zsc +++ b/zscript/swwm_deathlydeathcannon.zsc @@ -316,6 +316,23 @@ Class YnykronImpact : Actor qsort_candidates(a,p+1,h); } + void FlashPlayer( int str, double rad ) + { + double vfov = CVar.GetCVar('fov',players[consoleplayer]).GetFloat()*0.5; + double hfov = atan(Screen.GetAspectRatio()*tan(vfov)); + let mo = players[consoleplayer].camera; + Vector3 pp; + if ( !CheckSight(mo) ) return; + if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz); + else pp = mo.Vec3Offset(0,0,mo.CameraHeight); + Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch)); + if ( (abs(sc.x) < hfov) && (abs(sc.y) < vfov) && (sc.z < rad) ) + { + str = int(str*(1.-(sc.z/rad))); + SWWMHandler.DoFlash(mo,Color(str,255,255,255),2); + SWWMHandler.DoFlash(mo,Color(str/2,255,255,255),10); + } + } override void PostBeginPlay() { Super.PostBeginPlay(); @@ -323,6 +340,7 @@ Class YnykronImpact : Actor if ( swwm_ynykronalert && (!special2 || swwm_extraalert) ) A_AlertMonsters(); rad = args[0]+300+10*clamp(special1/10,0,15); A_QuakeEx(4,4,4,50,0,rad*4,"",QF_RELATIVE|QF_SCALEDOWN,falloff:rad*2,rollintensity:.6); + FlashPlayer(60,1200); if ( tracer ) { // voodoo dolls just get erased (how convenient) @@ -938,10 +956,28 @@ Class YnykronShot : Actor +DONTSPLASH; +NOINTERACTION; } + void FlashPlayer( int str, double rad ) + { + double vfov = CVar.GetCVar('fov',players[consoleplayer]).GetFloat()*0.5; + double hfov = atan(Screen.GetAspectRatio()*tan(vfov)); + let mo = players[consoleplayer].camera; + Vector3 pp; + if ( !CheckSight(mo) ) return; + if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz); + else pp = mo.Vec3Offset(0,0,mo.CameraHeight); + Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch)); + if ( (abs(sc.x) < hfov) && (abs(sc.y) < vfov) && (sc.z < rad) ) + { + str = int(str*(1.-(sc.z/rad))); + SWWMHandler.DoFlash(mo,Color(str,255,255,255),3); + SWWMHandler.DoFlash(mo,Color(str/2,255,255,255),30); + } + } 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.); + FlashPlayer(240,8000); hitlist.Clear(); beamcount = 0; blastcount = 0; @@ -1039,6 +1075,35 @@ Class YnykronAltTracer : LineTracer } } +Class YnykronHaloTail : Actor +{ + Default + { + RenderStyle "Add"; + +NOGRAVITY; + +DONTSPLASH; + +NOTELEPORT; + +NOBLOCKMAP; + +NOINTERACTION; + +FORCEXYBILLBOARD; + Radius .1; + Height 0.; + Scale 1.5; + } + override void Tick() + { + if ( isFrozen() ) return; + A_SetScale(scale.x+.5); + A_FadeOut(.2); + } + States + { + Spawn: + MHAL A -1 Bright; + Stop; + } +} + Class YnykronHalo : Actor { Default @@ -1064,6 +1129,9 @@ Class YnykronHalo : Actor } SetOrigin(target.pos,true); A_SetScale(1.5*target.scale.x); + A_AttachLight('YNYKRONHALOLIGHT',DynamicLight.PointLight,Color(224,32,255),int(900*scale.x),0,DYNAMICLIGHT.LF_ATTENUATE); + let h = Spawn("YnykronHaloTail",pos); + h.scale = scale; } States { @@ -1094,40 +1162,40 @@ Class GatherDust : Actor Scale *= FRandom[ExploS](.75,1.5); Scale.x *= RandomPick[ExploS](-1,1); Scale.y *= RandomPick[ExploS](-1,1); + SetShade(Color(4,3,5)*Random[ExploS](5,20)); } void A_Gravitate() { if ( target && !target.InStateSequence(target.CurState,target.FindState("Death")) ) { - if ( alpha < .02 ) A_FadeIn(FRandom[ExploS](.0002,.001)); + if ( alpha < .08 ) A_FadeIn(FRandom[ExploS](.0002,.004)); Vector3 dirto = level.Vec3Diff(pos,target.pos); double distto = dirto.length(); if ( distto < (32.*target.scale.x) ) { // sucked in - target.specialf2 += 1.; + target.specialf2 += FRandom[ExploS](.1,.4); Destroy(); return; } dirto /= distto; double mxdist = 5000.*target.scale.x; - vel = dirto*16.*(clamp((mxdist-distto)/mxdist,.5,1.)**3.); + vel = dirto*25.*(clamp((mxdist-distto)/mxdist,.5,1.)**4.); vel += target.vel; return; } vel *= .98; - A_FadeOut(.001); + A_FadeOut(.002); } Default { RenderStyle "Shaded"; - StencilColor "f8 a0 ff"; Radius .1; Height 0.; Alpha 0.; - Scale 2.; + Scale 3.; +NOGRAVITY; +NOBLOCKMAP; +DONTSPLASH; @@ -1144,6 +1212,33 @@ Class GatherDust : Actor } } +Class YnykronVoidBeamTail : Actor +{ + Default + { + RenderStyle "Add"; + +NOGRAVITY; + +DONTSPLASH; + +NOTELEPORT; + +NOBLOCKMAP; + +NOINTERACTION; + +FORCEXYBILLBOARD; + Radius .1; + Height 0.; + } + override void Tick() + { + if ( isFrozen() ) return; + A_FadeOut(); + } + States + { + Spawn: + XZW1 # -1 Bright; + Stop; + } +} + Class YnykronVoidBeam : Actor { Actor basebeam, prevbeam, nextbeam; @@ -1306,6 +1401,12 @@ Class YnykronVoidBeam : Actor nextbeam.angle += da*.2; nextbeam.pitch += dp*.2; } + let h = Spawn("YnykronVoidBeamTail",pos); + h.angle = angle; + h.pitch = pitch; + h.alpha = alpha*2.; + h.scale = scale; + h.frame = frame; } override void Tick() @@ -1328,33 +1429,449 @@ Class YnykronVoidBeam : Actor } } +Class YnykronLightningImpact : Actor +{ + Default + { + Obituary "$O_YNYKRONALT"; + DamageType "Electric"; + Radius .1; + Height 0; + +FOILINVUL; + +FORCERADIUSDMG; + +NODAMAGETHRUST; + +NOINTERACTION; + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + SWWMUtility.DoExplosion(self,400,120000,100,40); + A_QuakeEx(3,3,3,12,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.4); + A_SprayDecal("ShockMark",-172); + int numpt = Random[ExploS](8,16); + for ( int i=0; i 10 ) + { + dirto /= dist; + dir = (dir+.8*dirto*(clamp(1.-(dist/1500.),0.,1.)**1.5)).unit(); + } + invoker.nextdir = dir; + } + action void A_Spread( Sound arcsnd ) + { + Vector3 tdir = level.Vec3Diff(pos,invoker.nextpos); + if ( (GetClass() == 'YnykronLightningArc') && !Random[Ynykron](0,3) ) + { + for ( int i=0; i<3; i++ ) + { + let r = Spawn("YnykronLightningArcSub",level.Vec3Offset(pos,tdir*FRandom[Ynykron](0,1))); + Vector3 x, y, z; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + double a = FRandom[Ynykron](0,360), s = FRandom[Sparkster](0.,1.); + Vector3 sdir = (x+y*cos(a)*s+z*sin(a)*s).unit(); + r.angle = atan2(sdir.y,sdir.x); + r.pitch = asin(-sdir.z); + r.target = target; + r.special1 = 1; + YnykronLightningArc(r).destpos = invoker.destpos; + r.ReactionTime += Random[Ynykron](-3,3); + } + } + if ( ((ReactionTime > 0) && (special1 > ReactionTime)) || bAMBUSH ) return; + let b = Spawn(GetClass(),invoker.nextpos); + b.angle = atan2(invoker.nextdir.y,invoker.nextdir.x); + b.pitch = asin(-invoker.nextdir.z); + b.target = target; + b.special1 = special1+1; + YnykronLightningArc(b).destpos = invoker.destpos; + b.SetState(b.FindState("Trailer")); + if ( arcsnd != "" ) A_StartSound(arcsnd,CHAN_WEAPON); + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + frame = Random[Ynykron](0,11); + } + override void Tick() + { + if ( isFrozen() ) return; + if ( !CheckNoDelay() || (tics == -1) ) return; + if ( tics > 0 ) tics--; + while ( !tics ) + { + if ( !SetState(CurState.NextState) ) + return; + } + } + Default + { + Obituary "$O_YNYKRONALT"; + RenderStyle "Add"; + DamageFunction 1000; + Speed 128; + Radius .1; + Height 0; + Alpha 2.; + +NOGRAVITY; + +NOCLIP; + +DONTSPLASH; + +NOTELEPORT; + +FOILINVUL; + +NOINTERACTION; + } + States + { + Spawn: + XZW1 # 0 Bright; + XZW1 # 1 Bright A_Trace(); + XZW1 # 1 Bright A_Spread("ynykron/vortexarc"); + XZW1 # 1 Bright A_FadeOut(); + Wait; + Trailer: + XZW2 # 0 Bright; + XZW2 # 1 Bright A_Trace(); + XZW2 # 1 Bright A_Spread("ynykron/vortexarc"); + XZW2 # 1 Bright A_FadeOut(); + Wait; + } +} + +Class YnykronLightningArcSub : YnykronLightningArc +{ + Default + { + DamageFunction 250; + Speed 32; + ReactionTime 10; + } + States + { + Spawn: + XZW1 # 0 Bright; + XZW1 # 1 Bright A_Trace(); + XZW1 # 1 Bright A_Spread(""); + XZW1 # 1 Bright A_FadeOut(); + Wait; + Trailer: + XZW2 # 0 Bright; + XZW2 # 1 Bright A_Trace(); + XZW2 # 1 Bright A_Spread(""); + XZW2 # 1 Bright A_FadeOut(); + Wait; + } +} + +Class YnykronCloud : Actor +{ + Vector3 gx, gy, gz; + double phase; + Vector3 dirto; + double frightening; // lightning flash + Color basecol; + double rollvel; + + override void Tick() + { + prev = pos; + if ( isFrozen() ) return; + if ( !CheckNoDelay() || (tics == -1) ) return; + if ( tics > 0 ) tics--; + while ( !tics ) + { + if ( !SetState(CurState.NextState) ) + return; + } + } + + void FlashPlayer( int str, double rad ) + { + double vfov = CVar.GetCVar('fov',players[consoleplayer]).GetFloat()*0.5; + double hfov = atan(Screen.GetAspectRatio()*tan(vfov)); + let mo = players[consoleplayer].camera; + Vector3 pp; + if ( !CheckSight(mo) ) return; + if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz); + else pp = mo.Vec3Offset(0,0,mo.CameraHeight); + Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch)); + if ( (abs(sc.x) < hfov) && (abs(sc.y) < vfov) && (sc.z < rad) ) + { + str = int(str*(1.-(sc.z/rad))); + SWWMHandler.DoFlash(mo,Color(str,255,255,255),1); + SWWMHandler.DoFlash(mo,Color(str/2,240,224,255),10); + } + } + + override void PostBeginPlay() + { + SetState(FindState("Spawn")+Random[ExploS](0,19)); + Scale *= FRandom[ExploS](.75,1.5); + Scale.x *= RandomPick[ExploS](-1,1); + Scale.y *= RandomPick[ExploS](-1,1); + if ( master ) Scale *= master.scale.x; + // orbit axes + [gx, gy, gz] = swwm_CoordUtil.GetAxes(FRandom[ExploS](-90,90),FRandom[ExploS](0,360),FRandom[ExploS](-90,90)); + specialf1 = FRandom[ExploS](200,400); + scale *= specialf1/200.; + specialf2 = FRandom[ExploS](3.,8.)*RandomPick[ExploS](-1,1); + special2 = Random[ExploS](10,40); + basecol = Color(4,3,5)*Random[ExploS](5,20); + SetShade(basecol); + rollvel = FRandom[ExploS](.5,3.)*RandomPick[ExploS](-1,1); + } + + void A_Gravitate() + { + if ( frightening > 0. ) + { + alpha = max(frightening,.3); + int str = int(RandomPick[ExploS](255,240,192,254,248,128,160,204)*frightening); + Color litecol = Color(min(255,basecol.r+str),min(255,basecol.g+str),min(255,basecol.b+str)); + SetShade(litecol); + frightening *= .96; + if ( frightening < .1 ) + { + frightening = 0.; + SetShade(basecol); + } + } + roll += rollvel; + if ( master && !master.InStateSequence(master.CurState,master.FindState("Death")) ) + { + if ( special1 == 0 ) + { + A_FadeIn(FRandom[ExploS](.001,.002)); + if ( alpha > .3 ) special1 = 1; + } + else if ( special1 > 0 ) + { + special1++; + if ( special1 >= special2 ) + special1 = -1; + } + else if ( special1 == -1 ) A_FadeOut(FRandom[ExploS](.003,.006)); + dirto = level.Vec3Diff(pos,master.pos); + double distto = dirto.length(); + dirto /= distto; + // orbit + Vector3 orbitdir = (gx*cos(phase)+gy*sin(phase))*(specialf1+32)*master.scale.x; + SetOrigin(level.Vec3Offset(master.pos,orbitdir),true); + phase += FRandom[ExploS](.12,.24)*specialf2*(1.-specialf1/600.); + return; + } + SetOrigin(level.Vec3Offset(pos,-dirto*3.*abs(specialf2)),true); + specialf2 *= .98; + A_FadeOut(.005); + } + + Default + { + DamageType 'YnykronAlt'; + Obituary "$O_YNYKRONALT"; + RenderStyle "Shaded"; + Radius .1; + Height 0.; + Alpha 0.; + Scale 3.; + +NOGRAVITY; + +NOBLOCKMAP; + +DONTSPLASH; + +NOTELEPORT; + +NOINTERACTION; + +FORCEXYBILLBOARD; + +ROLLSPRITE; + +NOCLIP; + } + States + { + Spawn: + DUST ABCDEFGHIJKLMNOPQRST 1 A_Gravitate(); + Wait; + } +} + +Class YnykronLightningLight : PaletteLight +{ + Default + { + Tag "WhiteExpl"; + ReactionTime 12; + Args 0,0,0,900; + } +} +Class YnykronLightningLight2 : PaletteLight +{ + Default + { + Tag "WhiteExpl"; + ReactionTime 10; + Args 0,0,0,500; + } +} + +Class SimpleMoveTracer : LineTracer +{ + override ETraceStatus TraceCallback() + { + if ( Results.HitType == TRACE_HitActor ) return TRACE_Skip; + else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) + { + if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&Line.ML_BLOCKPROJECTILE) ) + return TRACE_Stop; + return TRACE_Skip; + } + return TRACE_Stop; + } +} + Class YnykronSingularity : Actor { - Actor beamers[16]; + const MAXBEAMS = 20; + const MAXCLOUDS = 500; + + Actor beamers[MAXBEAMS]; + Actor clouds[MAXCLOUDS]; const MION_CONST = 48538.; // miön v-force compression constant (approximate) - const YNON_CONST = .063738; // ÿnon v-force field constant (approximate) - const AXAN_CONST = 29.2761; // axan u-force field constant (approximate) + const YNON_CONST = .043738; // ÿnon v-force field constant (approximate) + const AXAN_CONST = 27.2761; // axan u-force field constant (approximate) const GOAL_MASS = 26741.; // mass required to compensate Ynykron altfire negative energy release (-2.4×10¹⁵ J, approximately) double critmass; // actual mass required (cummulative with absorbed vortices) + int litetimer; + + transient SimpleMoveTracer mt; + override void PostBeginPlay() { let g = Spawn("YnykronHalo",pos); g.target = self; - A_StartSound("ynykron/vortex",CHAN_BODY,CHANF_LOOP); + A_StartSound("ynykron/vortex",CHAN_BODY,CHANF_LOOP,1.,.6); + A_StartSound("ynykron/wind",CHAN_ITEM,CHANF_LOOP,1.,.0); + A_StartSound("ynykron/hit",CHAN_VOICE,CHANF_OVERLAP,1.,.0); // initial mass and radius specialf1 = scale.x; specialf2 = scale.x*scale.x*MION_CONST; critmass = GOAL_MASS; + litetimer = level.maptime+Random[Ynykron](180,240); } // lightweight tick, we don't need anything else other than states override void Tick() { if ( isFrozen() ) return; - Vector3 newpos = level.Vec3Offset(pos,vel); + Vector3 newpos; + if ( !mt ) mt = new("SimpleMoveTracer"); + mt.Trace(pos,CurSector,vel,1.,0); + if ( mt.Results.HitType == TRACE_HitNone ) newpos = level.Vec3Offset(pos,vel); + else newpos = level.Vec3Offset(mt.Results.HitPos,-mt.Results.HitVector); if ( level.IsPointInLevel(newpos) ) SetOrigin(newpos,true); if ( !CheckNoDelay() || (tics == -1) ) return; @@ -1375,8 +1892,8 @@ Class YnykronSingularity : Actor void A_SingularityTick() { - // gather dust particles (very minor "background" mass gain) - int numpt = int(max(2,16*scale.x)); + // gather dust particles (minor "background" mass gain) + int numpt = int(max(4,32*scale.x)); for ( int i=0; i -1) ) continue; + clouds[i] = Spawn("YnykronCloud",pos); + clouds[i].target = target; + clouds[i].master = self; + } + // check dense cloud formations for lightning + if ( level.maptime > litetimer ) + { + int which = Random[Ynykron](0,MAXCLOUDS-1); + if ( clouds[which] ) + { + Array contacts; + Array dists; + contacts.Clear(); + dists.Clear(); + for ( int i=0; i (200*scale.x) ) continue; + contacts.Push(clouds[i]); + dists.Push(dist); + } + if ( (contacts.Size() > 12) && !Random[Ynykron](0,5) ) + { + Spawn("YnykronLightningLight",clouds[which].pos); + Spawn("YnykronLightningLight2",clouds[which].pos); + A_StartSound("ynykron/vortexflash",CHAN_WEAPON,CHANF_OVERLAP,1.,0.,FRandom[Ynykron](.9,1.1)); + YnykronCloud(clouds[which]).frightening = 1.; + YnykronCloud(clouds[which]).FlashPlayer(200,3000); + for ( int i=0; i 80 ) { if ( IsActorPlayingSound(CHAN_VOICE) ) return; - for ( int i=0; i<16; i++ ) if ( beamers[i] ) return; + for ( int i=0; i 0 ) tics--; @@ -1773,10 +2366,28 @@ Class YnykronAltShot : Actor +DONTSPLASH; +NOINTERACTION; } + void FlashPlayer( int str, double rad ) + { + double vfov = CVar.GetCVar('fov',players[consoleplayer]).GetFloat()*0.5; + double hfov = atan(Screen.GetAspectRatio()*tan(vfov)); + let mo = players[consoleplayer].camera; + Vector3 pp; + if ( !CheckSight(mo) ) return; + if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz); + else pp = mo.Vec3Offset(0,0,mo.CameraHeight); + Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch)); + if ( (abs(sc.x) < hfov) && (abs(sc.y) < vfov) && (sc.z < rad) ) + { + str = int(str*(1.-(sc.z/rad))); + SWWMHandler.DoFlash(mo,Color(str,255,255,255),5); + SWWMHandler.DoFlash(mo,Color(str/2,0,0,0),15); + } + } override void PostBeginPlay() { A_QuakeEx(4,4,4,80,0,65536,"",QF_RELATIVE|QF_SCALEDOWN,falloff:65536,rollIntensity:.8); A_StartSound("ynykron/altbeam",CHAN_VOICE,CHANF_DEFAULT,1.,0.); + FlashPlayer(240,8000); let b = Spawn("YnykronAltBeam",pos); b.target = target; b.angle = angle; @@ -1890,18 +2501,12 @@ Class Ynykron : SWWMWeapon 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(); - } + Actor s; + if ( invoker.inverted ) s = Spawn("YnykronAltShot",origin); + else s = Spawn("YnykronShot",origin); + s.target = self; + s.angle = angle; + s.pitch = BulletSlope(); invoker.specialf1 = 1.; A_Overlay(PSP_WEAPON+3,"FireBlast"); } diff --git a/zscript/swwm_tastytreat.zsc b/zscript/swwm_tastytreat.zsc index 260c73a98..199843c02 100644 --- a/zscript/swwm_tastytreat.zsc +++ b/zscript/swwm_tastytreat.zsc @@ -234,7 +234,7 @@ Class CandyPop : Actor double hfov = atan(Screen.GetAspectRatio()*tan(vfov)); let mo = players[consoleplayer].camera; Vector3 pp; - if ( !mo.CheckSight(self) ) return; + if ( !CheckSight(mo) ) return; if ( mo is 'PlayerPawn' ) pp = mo.Vec2OffsetZ(0,0,PlayerPawn(mo).player.viewz); else pp = mo.Vec3Offset(0,0,mo.CameraHeight); Vector3 sc = level.SphericalCoords(pp,pos,(mo.angle,mo.pitch)); diff --git a/zscript/swwm_thinkers.zsc b/zscript/swwm_thinkers.zsc index b0476cec8..decf3071d 100644 --- a/zscript/swwm_thinkers.zsc +++ b/zscript/swwm_thinkers.zsc @@ -129,7 +129,7 @@ Class SWWMStats : Thinker else if ( (inflictor is 'HellblazerRavagerArm') || (inflictor is 'HellblazerWarheadArm') ) which = 'Hellblazer'; else if ( (inflictor is 'BigBiospark') || (inflictor is 'BiosparkBall') || (inflictor is 'BiosparkBeamImpact') || (inflictor is 'BiosparkComboImpact') || (inflictor is 'BiosparkComboImpactSub') || (inflictor is 'BiosparkBeam') || (inflictor is 'BiosparkArc') ) which = 'Sparkster'; else if ( (inflictor is 'CandyBeam') || (inflictor is 'CandyPop') || (inflictor is 'CandyMagArm') || (inflictor is 'CandyGunProj') || (inflictor is 'CandyMagProj') || (inflictor is 'CandyBulletImpact') ) which = 'CandyGun'; - else if ( (inflictor is 'YnykronBeam') || (inflictor is 'YnykronImpact') ) which = 'Ynykron'; + else if ( (inflictor is 'YnykronBeam') || (inflictor is 'YnykronImpact') || (inflictor is 'YnykronSingularity') || (inflictor is 'YnykronCloud') || (inflictor is 'YnykronVoidBeam') || (inflictor is 'YnykronLightningArc') || (inflictor is 'YnykronLightningImpact') ) which = 'Ynykron'; else if ( (inflictor is 'Demolitionist') || (inflictor is 'DemolitionistShockwave') || (inflictor is 'DemolitionistRadiusShockwave') ) which = 'SWWMWeapon'; // hack to assume Demolitionist as weapon if ( !which ) return; for ( int i=0; i