Mortal Rifle fully implemented (oh my).

This commit is contained in:
Marisa the Magician 2022-09-28 21:00:24 +02:00
parent dffee0b43d
commit e571fccc4d
16 changed files with 700 additions and 27 deletions

View File

@ -22,8 +22,8 @@ More weapons, because we need 'em. In addition, all the "easy to implement" mini
- [8] Ray-Khom *(UnSX)*
- The Most Silent Takedown *(Kill 40 enemies with the Ray-Khom primary without alerting them)*
- John Romero's Curse *(Fry yourself by discharging an electric weapon in water)*
- [9] Mortal Rifle *(UnSX 2)*
- Railed Hard *(Shoot through 44 enemies with a single Mortal Rifle overpressure shot)*
- [9] Mortal Rifle *(UnSX 2)*
- ✓ Railed Hard *(Kill 44 enemies with a single Mortal Rifle overpressure shot)*
- [0] Rafan-Kos *(UnSX 4)*
- Blasting Ropes *(Melt a grand total of 5000 enemies with the Rafan-Kos)*
* ☑ **Additional Voice Acting:**

View File

@ -1304,7 +1304,7 @@ SWWM_ACHIEVEMENT_PUZZLE_TXT = "Solve all fractions of \"puzzles\" in the same sa
SWWM_ACHIEVEMENT_RAGE_TAG = "No Talk me Angy";
SWWM_ACHIEVEMENT_RAGE_TXT = "Use %s Ragekits";
SWWM_ACHIEVEMENT_RAIL_TAG = "Railed Hard";
SWWM_ACHIEVEMENT_RAIL_TXT = "Shoot through %s enemies with a single Mortal Rifle overpressure shot";
SWWM_ACHIEVEMENT_RAIL_TXT = "Kill %s enemies with a single Mortal Rifle overpressure shot";
SWWM_ACHIEVEMENT_REFLECT_TAG = "Return to Sender";
SWWM_ACHIEVEMENT_REFLECT_TXT = "Kill %s enemies with parried projectiles";
SWWM_ACHIEVEMENT_REFRESH_TAG = "Stay Fresh";

View File

@ -1151,7 +1151,7 @@ SWWM_ACHIEVEMENT_PUZZLE_TXT = "Resuelve todas las partes de \"puzzles\" en la mi
SWWM_ACHIEVEMENT_RAGE_TAG = "No Hablo me Enfado";
SWWM_ACHIEVEMENT_RAGE_TXT = "Usa %s Ragekits";
SWWM_ACHIEVEMENT_RAIL_TAG = "Metida de Través";
SWWM_ACHIEVEMENT_RAIL_TXT = "Atraviesa %s enemigos con un solo disparo a presión del Rifle Mortal";
SWWM_ACHIEVEMENT_RAIL_TXT = "Mata %s enemigos con un solo disparo a presión del Rifle Mortal";
SWWM_ACHIEVEMENT_REFLECT_TAG = "Devuelto a Remitente";
SWWM_ACHIEVEMENT_REFLECT_TXT = "Mata %s enemigos con proyectiles desviados";
SWWM_ACHIEVEMENT_REFRESH_TAG = "Siempre Fresco";

View File

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r523 \cu(Wed 28 Sep 17:58:30 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r523 \cu(2022-09-28 17:58:30)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r524 \cu(Wed 28 Sep 21:00:24 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r524 \cu(2022-09-28 21:00:24)\c-";

View File

@ -80,6 +80,37 @@ Model "MisterSubGrenade"
FrameIndex XZW1 A 0 0
}
Model "MisterRailBeam"
{
Path "models/extra"
Model 0 "YBeam.obj"
Skin 0 "MRBolt.png"
Scale 1 1 0.6
USEACTORPITCH
USEACTORROLL
DONTCULLBACKFACES
FrameIndex XZW1 A 0 0
Skin 0 "MRBoltS.png"
FrameIndex XZW1 B 0 0
}
Model "MisterRailChildBeam"
{
Path "models/extra"
Model 0 "YBeam.obj"
Skin 0 "MRBolt.png"
Scale 1 1 0.6
USEACTORPITCH
USEACTORROLL
DONTCULLBACKFACES
FrameIndex XZW1 A 0 0
Skin 0 "MRBoltS.png"
FrameIndex XZW1 B 0 0
}
Model "MisterRifle"
{
Path "models"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

View File

@ -163,8 +163,6 @@ extend Class MisterRifle
for ( int i=0; i<clipcount; i++ )
Screen.DrawTexture(BulletTex[0],false,bx-12,(by-27)+2*i,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( gchambered ) Screen.DrawTexture(BulletTex[1+gfired],false,bx-21,by-10,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,gfired?0x80000000:0x00000000);
String str = "THIS WEAPON IS NOT YET FULLY IMPLEMENTED";
Screen.DrawText(NewSmallFont,Font.CR_RED,(Screen.GetWidth()-NewSmallFont.StringWidth(str)*CleanXFac_1)/2,Screen.GetHeight()-(NewSmallFont.GetHeight()*CleanYFac_1+clamp(swwm_hudmargin,0,20)*hs),str,DTA_CleanNoMove_1,true);
}
}

View File

@ -1,16 +1,29 @@
// Plutoni Inc. Mortal Rifle (from UnSX 2)
// Slot 9, spawns shared with Candygun
Class MRHitListEntry : HitListEntry
{
// just needs this
bool bExit;
}
// used for splitting model beam between crossed portals (if any)
Class MRRailSeg
{
Vector3 enter, exit;
}
// like the silver bullet tracer except there's no penetration factor
// just a maximum possible travel distance (which is mainly used for probing through walls)
Class MisterRailTracer : LineTracer
{
Actor ignoreme;
Array<HitListEntry> hitlist;
Array<MRHitListEntry> hitlist;
Array<Line> shootthroughlist;
Array<WaterHit> waterhitlist;
Array<MRRailSeg> portalseg;
double RealMaxDist;
double maxdist;
bool pastwall, fullstop;
Array<WallPenetrate> WallPenetrateList;
@ -34,16 +47,35 @@ Class MisterRailTracer : LineTracer
hl.hitpos = Results.Crossed3DWaterPos;
WaterHitList.Push(hl);
}
if ( Results.HitType == TRACE_HitActor )
if ( Results.HitType == TRACE_CrossingPortal )
{
let seg = new("MRRailSeg");
seg.enter = Results.HitPos;
seg.exit = Results.SrcFromTarget;
portalseg.Push(seg);
}
else if ( Results.HitType == TRACE_HitActor )
{
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
if ( Results.HitActor.bSHOOTABLE )
{
let ent = new("HitListEntry");
let ent = new("MRHitListEntry");
ent.hitactor = Results.HitActor;
ent.hitlocation = Results.HitPos;
ent.x = Results.HitVector;
ent.pastwall = pastwall;
ent.bExit = false;
hitlist.Push(ent);
// also include exit point if we can reach it
Vector3 exit = SWWMUtility.TraceExit(Results.HitActor,Results.HitPos,Results.HitVector);
if ( level.Vec3Diff(Results.HitPos,exit).length() > (maxdist-Results.Distance) )
return TRACE_Skip; // exit point is beyond our max distance
ent = new("MRHitListEntry");
ent.hitactor = Results.HitActor;
ent.hitlocation = exit;
ent.x = Results.HitVector;
ent.pastwall = pastwall;
ent.bExit = true;
hitlist.Push(ent);
return TRACE_Skip;
}
@ -62,7 +94,7 @@ Class MisterRailTracer : LineTracer
if ( (Results.Tier == TIER_Middle) && Results.HitLine.sidedef[1] && !(Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
return TRACE_Skip;
}
int maxstep = int(RealMaxDist-Results.Distance);
int maxstep = int(maxdist-Results.Distance);
for ( int i=1; i<=maxstep; i++ )
{
Vector3 ofs = Results.HitPos+Results.HitVector*i;
@ -144,6 +176,26 @@ Class MisterRailTracer : LineTracer
}
}
Class MisterRailCounter : Thinker
{
PlayerInfo player;
Array<Actor> effectors;
int nkill;
override void Tick()
{
int neff = 0;
for ( int i=0; i<effectors.Size(); i++ )
{
if ( !effectors[i] ) continue;
neff++;
}
if ( neff > 0 ) return;
SWWMUtility.AchievementProgress("rail",nkill,player);
Destroy();
}
}
Class MisterRifle : SWWMWeapon
{
int clipcount;
@ -152,7 +204,7 @@ Class MisterRifle : SWWMWeapon
bool boltlock;
bool waschambered;
bool wasgchambered;
int prefirecnt;
double prefirecnt;
transient int holdtic;
int firemode;
ui int lastfiremode;
@ -165,8 +217,6 @@ Class MisterRifle : SWWMWeapon
Property ClipCount : clipcount;
transient MisterRailTracer mrt; // I pity the fool
override void InitializeWeapon()
{
// no round in the chamber
@ -694,8 +744,15 @@ Class MisterRifle : SWWMWeapon
A_StartSound("mister/cancelover",CHAN_WEAPON,CHANF_OVERLAP);
return ResolveState("FireOverpressureCancel");
}
if ( invoker.prefirecnt == 99 ) invoker.holdtic = gametic;
invoker.prefirecnt = min(100,int(invoker.prefirecnt+1));
if ( invoker.prefirecnt < 100 )
{
invoker.prefirecnt += 1.5;
if ( invoker.prefirecnt >= 100 )
{
invoker.prefirecnt = 100;
invoker.holdtic = gametic;
}
}
A_SoundVolume(CHAN_WEAPONEXTRA,clamp(invoker.prefirecnt*.01,.01,1.));
A_SoundPitch(CHAN_WEAPONEXTRA,clamp(.5+invoker.prefirecnt*.005,.5,1.)**.5);
if ( (invoker.prefirecnt >= 100) && !((gametic-invoker.holdtic)%32) && CheckLocalView() )
@ -719,6 +776,299 @@ Class MisterRifle : SWWMWeapon
A_QuakeEx(8,8,8,12,0,10,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:2.);
A_BumpFOV(.85);
A_AlertMonsters(swwm_uncapalert?0:12000);
for ( int i=0; i<12; i++ )
{
let s = Spawn("SWWMSmoke",origin);
s.scale *= .4;
s.alpha *= .1;
s.vel += vel*.5+x*FRandom[Mister](1.,12.);
s.SetShade(Color(0,3,4)*Random[ExploS](48,63));
}
Vector3 dir, startdir;
startdir = dir = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
let mrt = new("MisterRailTracer"); // I pity the fool
mrt.ignoreme = self;
mrt.hitlist.Clear();
mrt.shootthroughlist.Clear();
mrt.waterhitlist.Clear();
mrt.wallpenetratelist.Clear();
mrt.ffloors.Clear();
mrt.portalseg.Clear();
for ( int i=0; i<level.Sectors.Size(); i++ )
{
Sector s = level.Sectors[i];
for ( int j=0; j<s.Get3DFloorCount(); j++ )
{
F3DFloor ff = s.Get3DFloor(j);
if ( ff.flags&(F3DFloor.FF_EXISTS|F3DFloor.FF_SOLID) )
mrt.ffloors.Push(ff);
}
}
mrt.pastwall = false;
Vector3 norigin = origin;
mrt.maxdist = 10000.;
do
{
mrt.fullstop = true;
mrt.Trace(norigin,level.PointInSector(norigin.xy),dir,mrt.maxdist,TRACE_HitSky|TRACE_ReportPortals);
mrt.maxdist -= (mrt.exitpoint-norigin).length();
norigin = mrt.exitpoint;
dir = mrt.Results.HitVector;
}
while ( !mrt.fullstop );
let mrc = new("MisterRailCounter");
mrc.ChangeStatNum(STAT_USER); // so it can tick
mrc.player = player;
Vector3 sstart = origin;
// beam segments
if ( mrt.portalseg.Size() <= 0 )
{
Vector3 sdir = mrt.Results.HitPos-sstart;
double sdist = sdir.length();
sdir /= sdist;
Actor b;
if ( sdist > 32 )
{
b = Spawn("MisterRailBeam",sstart);
b.frame = 1;
b.scale.y = 32;
b.angle = atan2(sdir.y,sdir.x);
b.pitch = asin(-sdir.z)+90;
MisterRailBeam(b).mrc = mrc;
mrc.effectors.Push(b);
sstart += sdir*32;
sdist -= 32;
b = Spawn("MisterRailBeam",sstart);
}
else
{
b = Spawn("MisterRailBeam",sstart);
b.frame = 1;
}
b.scale.y = sdist;
b.angle = atan2(sdir.y,sdir.x);
b.pitch = asin(-sdir.z)+90;
MisterRailBeam(b).mrc = mrc;
mrc.effectors.Push(b);
}
else for ( int i=0; i<mrt.portalseg.Size(); i++ )
{
Vector3 sdir = mrt.portalseg[i].enter-sstart;
double sdist = sdir.length();
sdir /= sdist;
Actor b;
if ( i == 0 )
{
if ( sdist > 32 )
{
b = Spawn("MisterRailBeam",sstart);
b.target = self;
b.frame = 1;
b.scale.y = 32;
b.angle = atan2(sdir.y,sdir.x);
b.pitch = asin(-sdir.z)+90;
MisterRailBeam(b).mrc = mrc;
mrc.effectors.Push(b);
sstart += sdir*32;
sdist -= 32;
b = Spawn("MisterRailBeam",sstart);
}
else
{
b = Spawn("MisterRailBeam",sstart);
b.frame = 1;
}
}
else b = Spawn("MisterRailBeam",sstart);
b.target = self;
b.scale.y = sdist;
b.angle = atan2(sdir.y,sdir.x);
b.pitch = asin(-sdir.z)+90;
MisterRailBeam(b).mrc = mrc;
mrc.effectors.Push(b);
sstart = mrt.portalseg[i].exit;
if ( i == (mrt.portalseg.Size()-1) )
{
sdir = mrt.Results.HitPos-sstart;
sdist = sdir.length();
sdir /= sdist;
b = Spawn("MisterRailBeam",sstart);
b.target = self;
b.scale.y = sdist;
b.angle = atan2(sdir.y,sdir.x);
b.pitch = asin(-sdir.z)+90;
MisterRailBeam(b).mrc = mrc;
mrc.effectors.Push(b);
}
}
for ( int i=0; i<mrt.ShootThroughList.Size(); i++ )
{
mrt.ShootThroughList[i].Activate(self,0,SPAC_Impact);
mrt.ShootThroughList[i].Activate(self,0,SPAC_PCross);
}
for ( int i=0; i<mrt.WaterHitList.Size(); i++ )
{
let b = Spawn("InvisibleSplasher",mrt.WaterHitList[i].hitpos);
b.target = self;
b.A_CheckTerrain();
}
Array<MisterBulletImpact> bi; // so we can ignite them all at once after main contact damage
for ( int i=0; i<mrt.hitlist.Size(); i++ )
{
if ( mrt.HitList[i].bExit )
{
let b = MisterBulletImpact(Spawn("MisterRailExitImpact",mrt.hitlist[i].HitLocation-mrt.hitlist[i].x*4.));
b.angle = atan2(mrt.HitList[i].x.y,mrt.HitList[i].x.x);
b.pitch = asin(-mrt.HitList[i].x.z);
b.target = self;
b.mrc = mrc;
mrc.effectors.Push(b);
bi.Push(b);
}
else
{
let b = MisterBulletImpact(Spawn("MisterRailEntryImpact",mrt.hitlist[i].HitLocation+mrt.hitlist[i].x*4.));
b.angle = atan2(mrt.HitList[i].x.y,mrt.HitList[i].x.x)+180;
b.pitch = asin(mrt.HitList[i].x.z);
b.target = self;
b.mrc = mrc;
mrc.effectors.Push(b);
bi.Push(b);
}
if ( !mrt.HitList[i].HitActor || mrt.HitList[i].bExit ) continue;
SWWMUtility.DoKnockback(mrt.HitList[i].HitActor,mrt.HitList[i].x+(0,0,0.025),80000);
let p = SWWMPuff.Setup(mrt.HitList[i].HitLocation,mrt.HitList[i].x,invoker,self,mrt.HitList[i].HitActor);
mrt.HitList[i].HitActor.DamageMobj(p,self,4444,'Mortal',DMG_FOILINVUL|DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
if ( !mrt.HitList[i].HitActor || (mrt.HitList[i].HitActor.Health <= 0) )
mrc.nkill++;
}
LineTracer faketracer = new("LineTracer");
for ( int i=0; i<mrt.wallpenetratelist.Size(); i++ )
{
bool bExit = !!(i%2); // odd-numbered entries are exit points
Vector3 hitpos = mrt.WallPenetrateList[i].hitpos;
Vector3 hitnormal = mrt.WallPenetrateList[i].hitnormal;
let b = MisterBulletImpact(Spawn(bExit?"MisterRailExitImpact":"MisterRailEntryImpact",hitpos+hitnormal*4.));
b.angle = atan2(hitnormal.y,hitnormal.x);
b.pitch = asin(-hitnormal.z);
b.target = self;
b.mrc = mrc;
mrc.effectors.Push(b);
bi.Push(b);
if ( mrt.WallPenetrateList[i].hittype == TRACE_HitWall )
mrt.WallPenetrateList[i].hitline.Activate(self,mrt.WallPenetrateList[i].hitside,SPAC_Impact);
if ( swwm_omnibust )
{
faketracer.Results.HitType = mrt.WallPenetrateList[i].HitType;
faketracer.Results.HitSector = mrt.WallPenetrateList[i].HitSector;
faketracer.Results.HitLine = mrt.WallPenetrateList[i].HitLine;
faketracer.Results.ffloor = mrt.WallPenetrateList[i].HitFFloor;
faketracer.Results.Side = mrt.WallPenetrateList[i].HitSide;
faketracer.Results.Tier = mrt.WallPenetrateList[i].HitTier;
BusterWall.Bust(faketracer.Results,444,self,mrt.WallPenetrateList[i].BustDir,mrt.WallPenetrateList[i].HitPos.z);
}
}
if ( (mrt.Results.HitType != TRACE_HitNone) && (mrt.Results.HitType != TRACE_HasHitSky) && (mrt.Results.HitType != TRACE_HitActor) )
{
Vector3 hitnormal = -mrt.Results.HitVector;
if ( mrt.Results.HitType == TRACE_HitFloor )
{
if ( mrt.Results.FFloor ) hitnormal = -mrt.Results.FFloor.top.Normal;
else hitnormal = mrt.Results.HitSector.floorplane.Normal;
}
else if ( mrt.Results.HitType == TRACE_HitCeiling )
{
if ( mrt.Results.FFloor ) hitnormal = -mrt.Results.FFloor.bottom.Normal;
else hitnormal = mrt.Results.HitSector.ceilingplane.Normal;
}
else if ( mrt.Results.HitType == TRACE_HitWall )
{
hitnormal = (-mrt.Results.HitLine.delta.y,mrt.Results.HitLine.delta.x,0).unit();
if ( !mrt.Results.Side ) hitnormal *= -1;
}
let b = MisterBulletImpact(Spawn("MisterRailEntryImpact",mrt.Results.HitPos+hitnormal*4.));
b.angle = atan2(hitnormal.y,hitnormal.x);
b.pitch = asin(-hitnormal.z);
b.target = self;
b.mrc = mrc;
mrc.effectors.Push(b);
bi.Push(b);
if ( mrt.Results.HitType == TRACE_HitWall ) mrt.Results.HitLine.RemoteActivate(self,mrt.Results.Side,SPAC_Impact,mrt.Results.HitPos);
if ( swwm_omnibust ) BusterWall.Bust(mrt.Results,444,self,mrt.Results.HitVector,mrt.Results.HitPos.z);
}
for ( int i=0; i<bi.Size(); i++ ) bi[i].A_BulletExplode();
double dist = level.Vec3Diff(origin,mrt.Results.HitPos).length();
for ( double d=0.; d<=dist; d+=200. )
{
Vector3 p = level.Vec3Offset(origin,startdir*d);
if ( !level.IsPointInlevel(p) ) continue;
Spawn("MisterRailLight",p);
}
int numpt = Random[ExploS](50,100);
double dv = max(16.,dist/numpt);
for ( double d=32.; d<=dist; d+=dv )
{
Vector3 np = level.Vec3Offset(origin,startdir*d);
np = level.Vec3Offset(np,SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](4,12));
if ( !level.IsPointInLevel(np) ) continue;
let p = Spawn("MisterPop",np);
p.target = self;
MisterPop(p).mrc = mrc;
mrc.effectors.Push(p);
}
if ( mrt.wallpenetratelist.Size() > 0 )
{
Vector3 start = origin;
Vector3 end = mrt.WallPenetrateList[0].hitpos;
Vector3 tdir = level.Vec3Diff(start,end);
double dist = tdir.length();
tdir /= dist;
for ( double d=4.; d<=dist; d+=8. )
{
if ( !Random[ExploS](0,1) ) continue;
Vector3 ofs = level.Vec3Offset(start,tdir*d);
if ( !level.IsPointInLevel(ofs) ) continue;
let b = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[ExploS](.7,1.4);
b.alpha *= .2;
b.special1 = Random[ExploS](1,3);
b.SetShade(Color(2,3,4)*Random[ExploS](48,63));
}
for ( int i=1; i<mrt.WallPenetrateList.Size(); i+=2 )
{
start = mrt.WallPenetrateList[i].hitpos;
if ( i >= mrt.WallPenetrateList.Size()-1 ) end = mrt.Results.HitPos;
else end = mrt.WallPenetrateList[i+1].hitpos;
tdir = level.Vec3Diff(start,end);
dist = tdir.length();
tdir /= dist;
for ( double d=4.; d<=dist; d+=8. )
{
if ( !Random[ExploS](0,1) ) continue;
Vector3 ofs = level.Vec3Offset(start,tdir*d);
if ( !level.IsPointInLevel(ofs) ) continue;
let b = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[ExploS](.7,1.4);
b.alpha *= .2;
b.special1 = Random[ExploS](1,3);
b.SetShade(Color(2,3,4)*Random[ExploS](48,63));
}
}
}
else
{
for ( double d=4.; d<=mrt.Results.Distance; d+=8. )
{
if ( !Random[ExploS](0,1) ) continue;
Vector3 ofs = level.Vec3Offset(origin,startdir*d);
if ( !level.IsPointInLevel(ofs) ) continue;
let b = Spawn("SWWMHalfSmoke",ofs);
b.Scale *= FRandom[ExploS](.7,1.4);
b.alpha *= .2;
b.special1 = Random[ExploS](1,3);
b.SetShade(Color(2,3,4)*Random[ExploS](48,63));
}
}
}
action void A_MisterFireGrenade()

View File

@ -191,6 +191,7 @@ Class MisterBulletImpactPop : Actor
Class MisterFuzzy : Actor
{
MisterRailCounter mrc;
Default
{
Obituary "$O_MORTALRIFLE";
@ -215,7 +216,9 @@ Class MisterFuzzy : Actor
override void Tick()
{
if ( isFrozen() ) return;
SWWMUtility.DoExplosion(self,(special2<0)?4:44,3000,80,80,DE_EXTRAZTHRUST);
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,(special2<0)?4:44,3000,80,80,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
special1--;
if ( special1 <= 0 )
{
@ -332,6 +335,7 @@ Class MisterFuzzyTrail : Actor
Class MisterPop : Actor
{
MisterRailCounter mrc;
Default
{
Obituary "$O_MORTALRIFLE";
@ -368,13 +372,18 @@ Class MisterPop : Actor
Spawn:
TNT1 A 1 NoDelay
{
A_SetTics(Random[ExploS](1,5));
A_SetTics(Random[ExploS](1,15));
Scale *= FRandom[ExploS](.5,1.5);
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
roll = FRandom[ExploS](0,360);
}
BLPF C 2 Bright { SWWMUtility.DoExplosion(self,4,2000,50,50,DE_EXTRAZTHRUST); }
BLPF C 2 Bright
{
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,4,2000,50,50,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
}
TNT1 A 1
{
let p = Spawn("MisterFuzzyTrail",pos);
@ -387,6 +396,7 @@ Class MisterPop : Actor
Class MisterBulletImpact : Actor
{
MisterRailCounter mrc; // simplify code by putting this here
Default
{
Obituary "$O_MORTALRIFLE";
@ -648,6 +658,280 @@ Class MisterStreamImpact : MisterBulletImpact
}
}
Class MisterRailEntryImpact : MisterBulletImpact
{
Default
{
Scale 1.2;
}
override void A_BulletExplode()
{
A_AlertMonsters(swwm_uncapalert?0:4000);
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,444,200000,100,100,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
A_QuakeEx(6,6,6,10,0,400,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:150,rollintensity:.8);
A_StartSound("mister/hitover",CHAN_VOICE,attenuation:.35);
A_SprayDecal("SmallRocketBlast",-172);
Scale *= FRandom[ExploS](0.8,1.1);
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
int numpt = Random[ExploS](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,10);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(0,3,4)*Random[ExploS](48,63));
s.special1 = Random[ExploS](0,2);
s.scale *= 3.5;
s.alpha *= .4;
}
numpt = Random[ExploS](4,6);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](8,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](3,6);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](4,16);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
numpt = Random[ExploS](4,6);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("MisterFuzzy",pos);
s.angle = FRandom[ExploS](0,360);
s.pitch = FRandom[ExploS](-90,90);
s.target = target;
s.special1 -= 2;
if ( !mrc ) continue;
MisterFuzzy(s).mrc = mrc;
mrc.effectors.Push(s);
}
Spawn("MisterExLightTiny",pos);
let p = Spawn("MisterBulletImpactPop",pos);
p.A_SetScale(4.);
}
override void A_BulletSubExplode()
{
if ( special1 && (special1 <= 10) )
{
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,44,3000+special1*50,80+special1*4,80+special1*4,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
int numpt = Random[ExploS](0,special1/2);
for ( int i=0; i<numpt; i++ )
{
Vector3 np = level.Vec3Offset(pos,SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,16)*special1);
if ( !level.IsPointInLevel(np) ) continue;
let p = Spawn("MisterPop",np);
p.target = target;
if ( !mrc ) continue;
MisterPop(p).mrc = mrc;
mrc.effectors.Push(p);
}
}
special1++;
}
States
{
Spawn:
TNT1 A 0;
XEX7 ACEGIKMOQSUWY[] 1 Bright A_BulletSubExplode();
Stop;
}
}
Class MisterRailExitImpact : MisterBulletImpact
{
Default
{
Scale 1.8;
}
override void A_BulletExplode()
{
A_AlertMonsters(swwm_uncapalert?0:4000);
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,444,80000,200,200,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
A_QuakeEx(8,8,8,15,0,600,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:250,rollintensity:1.2);
A_StartSound("mister/hitover",CHAN_WEAPON,attenuation:.2);
A_SprayDecal("BigRocketBlast",-172);
Scale *= FRandom[ExploS](0.8,1.1);
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
int numpt = Random[ExploS](15,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,12);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(0,3,4)*Random[ExploS](48,63));
s.special1 = Random[ExploS](1,3);
s.scale *= 3.5;
s.alpha *= .4;
}
numpt = Random[ExploS](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](8,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](6,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](4,16);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("MisterFuzzy",pos);
s.angle = FRandom[ExploS](0,360);
s.pitch = FRandom[ExploS](-90,90);
s.target = target;
if ( !mrc ) continue;
MisterFuzzy(s).mrc = mrc;
mrc.effectors.Push(s);
}
Spawn("MisterExLightBig",pos);
let p = Spawn("MisterBulletImpactPop",pos);
p.A_SetScale(8.);
}
override void A_BulletSubExplode()
{
if ( special1 && (special1 <= 20) )
{
int nhit, nkill;
[nhit, nkill] = SWWMUtility.DoExplosion(self,44,6000+special1*100,150+special1*5,150+special1*5,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
if ( mrc ) mrc.nkill += nkill;
int numpt = Random[ExploS](0,special1/2);
for ( int i=0; i<numpt; i++ )
{
Vector3 np = level.Vec3Offset(pos,SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,16)*special1);
if ( !level.IsPointInLevel(np) ) continue;
let p = Spawn("MisterPop",np);
p.target = target;
if ( !mrc ) continue;
MisterPop(p).mrc = mrc;
mrc.effectors.Push(p);
}
}
special1++;
}
States
{
Spawn:
TNT1 A 0;
XEX7 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright A_BulletSubExplode();
Stop;
}
}
Class MisterRailLight : PaletteLight
{
Default
{
Tag "Cyanblu,1";
ReactionTime 50;
Args 0,0,0,250;
}
}
Class MisterRailBeam : Actor
{
MisterRailCounter mrc;
transient CandyBeamTracer cbt; // from wikipedia
Default
{
Obituary "$O_MORTALRIFLE";
RenderStyle "Add";
Radius .1;
Height 0.;
RenderRadius 10000.;
+FORCEXYBILLBOARD;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
+FOILINVUL;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let b = Spawn("MisterRailChildBeam",pos);
b.frame = frame;
b.scale.y = scale.y;
b.angle = angle;
b.pitch = pitch;
}
override void Tick()
{
if ( isFrozen() ) return;
A_SetScale(scale.x*.85,scale.y);
A_FadeOut(.05);
if ( frame == 1 ) return;
if ( !cbt ) cbt = new("CandyBeamTracer");
cbt.hitlist.Clear();
Vector3 dir = SWWMUtility.Vec3FromAngles(angle,pitch-90);
cbt.ShootThroughList.Clear();
cbt.Trace(pos,CurSector,dir,scale.y,0);
for ( int i=0; i<cbt.hitlist.Size(); i++ )
{
if ( !cbt.hitlist[i].hitactor ) continue;
SWWMUtility.DoKnockback(cbt.hitlist[i].hitactor,cbt.hitlist[i].x,12000);
let p = SWWMPuff.Setup(cbt.hitlist[i].hitlocation,cbt.hitlist[i].x,self,target,cbt.hitlist[i].hitactor);
cbt.hitlist[i].hitactor.DamageMobj(p,target,44,'Mortal',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
if ( mrc && (!cbt.hitlist[i].hitactor || (cbt.hitlist[i].hitactor.Health <= 0)) )
mrc.nkill++;
}
}
States
{
Spawn:
XZW1 A -1 Bright;
Stop;
}
}
Class MisterRailChildBeam : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
Alpha .5;
RenderRadius 10000.;
+FORCEXYBILLBOARD;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
}
override void Tick()
{
if ( isFrozen() ) return;
A_SetScale(scale.x*1.05,scale.y);
A_FadeOut(.01);
}
States
{
Spawn:
XZW1 A -1 Bright;
Stop;
}
}
Class MisterGrenadeFlare : Actor
{
Default
@ -1147,3 +1431,4 @@ Class MisterSubGrenade : MisterGrenade
Stop;
}
}

View File

@ -322,7 +322,7 @@ extend Class SWWMHandler
let a = beams[i];
if ( !a ) continue;
Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy;
double rad = a.speed*cos(a.pitch);
double rad = SWWMUtility.IsYBeam(a)?(a.scale.y*cos(a.pitch-90)):(a.speed*cos(a.pitch));
if ( max(abs(rv.x)-rad,abs(rv.y)-rad) > viewdist )
continue;
if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
@ -380,7 +380,7 @@ extend Class SWWMHandler
let a = beams[i];
if ( !a ) continue;
Vector2 rv = a.pos.xy-relpos;
double rad = a.speed*cos(a.pitch);
double rad = SWWMUtility.IsYBeam(a)?(a.scale.y*cos(a.pitch-90)):(a.speed*cos(a.pitch));
if ( max(abs(rv.x)-rad,abs(rv.y)-rad) > viewdist )
continue;
if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )

View File

@ -2198,7 +2198,7 @@ Class SWWMStatusBar : BaseStatusBar
{
pos = SWWMUtility.LerpVector2(t.target.prev.xy,t.target.pos.xy,FracTic);
angle = t.target.angle;
radius = t.isbeam?(t.target.speed*cos(t.target.pitch)):t.target.radius;
radius = t.isybeam?(t.target.scale.y*cos(t.target.pitch-90)):t.isbeam?(t.target.speed*cos(t.target.pitch)):t.target.radius;
}
else
{

View File

@ -265,7 +265,7 @@ Class SWWMSimpleTracker play
bool vipitem;
bool expired;
bool ismissile;
bool isbeam;
bool isbeam, isybeam;
int lastupdate;
ui double smoothalpha; // smoothened alpha, for ui
SWWMSimpleTracker next;
@ -274,7 +274,8 @@ Class SWWMSimpleTracker play
{
if ( !target ) return;
isbeam = SWWMUtility.IsBeamProj(target);
radius = isbeam?(target.speed*cos(target.pitch)):target.radius;
isybeam = isbeam&&SWWMUtility.IsYBeam(target);
radius = isybeam?(target.scale.y*cos(target.pitch+90)):isbeam?(target.speed*cos(target.pitch)):target.radius;
angle = target.angle;
pos = target.pos;
isplayer = target.player;

View File

@ -939,7 +939,7 @@ Class SWWMTeleportLine : Actor
override void Tick()
{
if ( !tline )
if ( !tline || !tline.special )
{
Destroy();
return;

View File

@ -1466,6 +1466,13 @@ Class SWWMUtility
if ( a is 'YnykronLightningArc' ) return true;
if ( a is 'YnykronAltBeam' ) return true;
if ( a is 'MykradvoTendril' ) return true;
if ( a is 'MisterRailBeam' ) return true;
return false;
}
// is this a YBeam type? (real pitch is pitch-90, scale.y == length)
static play bool IsYBeam( Actor a )
{
if ( a is 'MisterRailBeam' ) return true;
return false;
}

View File

@ -674,6 +674,7 @@ Class SilverBullet : SWWMWeapon
sst.Trace(norigin,level.PointInSector(norigin.xy),x2,maxdist,TRACE_HitSky);
maxdist -= (sst.exitpoint-norigin).length();
norigin = sst.exitpoint;
x2 = sst.Results.HitVector;
}
while ( !sst.fullstop );
invoker.nkills = 0;