561 lines
14 KiB
Text
561 lines
14 KiB
Text
// Explodium Gun projectiles and effects
|
|
|
|
Class ExplodiumCasing : SWWMCasing {}
|
|
|
|
Class ExplodiumMag : SWWMCasing
|
|
{
|
|
Default
|
|
{
|
|
Mass 10;
|
|
BounceFactor 0.4;
|
|
WallBounceFactor 0.4;
|
|
BounceSound "explodium/mag";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
heat = 0;
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
XZW1 BC -1
|
|
{
|
|
pitch = roll = 0;
|
|
angle = FRandom[Junk](0,360);
|
|
frame = RandomPick[Junk](1,2);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumMagArm : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_EXPLODIUM";
|
|
PROJECTILE;
|
|
+THRUACTORS;
|
|
+BOUNCEONWALLS;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+CANBOUNCEWATER;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
-NOGRAVITY;
|
|
Gravity 0.35;
|
|
BounceFactor 1.0;
|
|
Radius 2;
|
|
Height 4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
reactiontime = Random[ExploS](10,15);
|
|
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
|
|
{
|
|
Spawn("ExplodiumMagTrail",pos);
|
|
if ( !(ReactionTime%2) )
|
|
{
|
|
int nhit, nkill;
|
|
[nhit, nkill] = SWWMUtility.DoExplosion(self,2+reactiontime/2,3000+500*reactiontime,40+3*reactiontime,20,DE_COUNTENEMIES);
|
|
if ( target && special1 ) SWWMUtility.AchievementProgressInc("grenade",nkill,target.player);
|
|
}
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel+vel*.2;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,3);
|
|
s.scale *= 2.4;
|
|
s.alpha *= 0.1+.4*(ReactionTime/15.);
|
|
A_CountDown();
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumMagTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 1.1;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX1 ADGJMPSVY\ 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumMagProj : Actor
|
|
{
|
|
double pitchvel, anglevel;
|
|
Vector3 cvel;
|
|
|
|
Default
|
|
{
|
|
Obituary "$O_EXPLODIUM";
|
|
DamageType "Explodium";
|
|
Radius 2;
|
|
Height 4;
|
|
Gravity 0.5;
|
|
Speed 30;
|
|
PROJECTILE;
|
|
-NOGRAVITY;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+INTERPOLATEANGLES;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
+FORCEXYBILLBOARD;
|
|
+BOUNCEONFLOORS;
|
|
+BOUNCEONCEILINGS;
|
|
+BOUNCEONWALLS;
|
|
+CANBOUNCEWATER;
|
|
+DONTBOUNCEONSKY;
|
|
+USEBOUNCESTATE;
|
|
BounceFactor 0.4;
|
|
WallBounceFactor 0.4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
}
|
|
void A_BlowUp()
|
|
{
|
|
bool isplanted = (self is 'ExplodiumMagAttach');
|
|
angle = atan2(cvel.y,cvel.x);
|
|
pitch = asin(-cvel.z);
|
|
bNOGRAVITY = true;
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
Scale *= 2.+.2*special1;
|
|
A_AlertMonsters(swwm_uncapalert?0:6000);
|
|
int nhit, nkill;
|
|
[nhit, nkill] = SWWMUtility.DoExplosion(self,10+20*special1,80000+8000*special1,90+10*special1,60,DE_EXTRAZTHRUST|DE_COUNTENEMIES);
|
|
if ( target && isplanted ) SWWMUtility.AchievementProgressInc("grenade",nkill,target.player);
|
|
A_QuakeEx(9,9,9,30,0,400+80*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollintensity:2.);
|
|
A_StartSound("explodium/maghit",CHAN_VOICE,attenuation:.35);
|
|
A_StartSound("explodium/maghit",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](16,24);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,6);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,4);
|
|
s.scale *= 2.8;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](15,25);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = int(Random[ExploS](2,3)+(.6*special1));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("ExplodiumMagArm",pos);
|
|
s.target = target;
|
|
s.special1 = isplanted;
|
|
}
|
|
Spawn("ExploLight2",pos);
|
|
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,20+15*special1,cvel);
|
|
}
|
|
void A_CheckBounce()
|
|
{
|
|
if ( (vel.length() > 4) && (vel.unit() dot cvel > .5) )
|
|
{
|
|
bHITOWNER = true;
|
|
A_StartSound("explodium/mag");
|
|
return;
|
|
}
|
|
ExplodeMissile();
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1
|
|
{
|
|
pitch += pitchvel;
|
|
angle += anglevel;
|
|
if ( vel.length() > 0. ) cvel = vel.unit();
|
|
}
|
|
Wait;
|
|
Bounce:
|
|
XZW1 A 0 A_CheckBounce();
|
|
Goto Spawn;
|
|
Death:
|
|
TNT1 A 0 A_BlowUp();
|
|
XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumMagHitbox : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 2;
|
|
Height 4;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
+SHOOTABLE;
|
|
+NOBLOOD;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || target.bKILLED )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.Vec3Offset(0,0,-height*.5),false);
|
|
let bt = BlockThingsIterator.Create(self,128);
|
|
while ( bt.Next() )
|
|
{
|
|
if ( !bt.Thing || (bt.Thing == self) || !bt.Thing.bSHOOTABLE || (bt.Thing == target.target) || bt.Thing.IsFriend(target.target) || !SWWMUtility.BoxIntersect(self,bt.Thing) )
|
|
continue;
|
|
target.bKILLED = true;
|
|
target.SetStateLabel("Detonate");
|
|
Destroy();
|
|
break;
|
|
}
|
|
}
|
|
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
|
{
|
|
if ( target && !target.bKILLED )
|
|
{
|
|
target.bKILLED = true;
|
|
target.SetStateLabel("Detonate");
|
|
Destroy();
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumMagAttach : ExplodiumMagProj
|
|
{
|
|
Line atline;
|
|
int atside;
|
|
int atpart;
|
|
int atplane;
|
|
Sector atsector;
|
|
double atz;
|
|
Vector3 normal;
|
|
Actor hitbox;
|
|
|
|
default
|
|
{
|
|
+MOVEWITHSECTOR;
|
|
+EXPLODEONWATER;
|
|
-BOUNCEONFLOORS;
|
|
-BOUNCEONCEILINGS;
|
|
-BOUNCEONWALLS;
|
|
-CANBOUNCEWATER;
|
|
-USEBOUNCESTATE;
|
|
Speed 15;
|
|
}
|
|
|
|
override int SpecialMissileHit( Actor victim )
|
|
{
|
|
if ( victim is 'ExplodiumMagHitbox' ) return 1;
|
|
return -1;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( isFrozen() ) return;
|
|
if ( bKILLED ) return;
|
|
if ( atline ) // attempt to follow the movement of the line
|
|
{
|
|
if ( atpart == 1 )
|
|
{
|
|
if ( atline.flags&Line.ML_DONTPEGTOP ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true);
|
|
else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(1)),true);
|
|
}
|
|
else if ( atpart == -1 )
|
|
{
|
|
if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true);
|
|
else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(0)),true);
|
|
}
|
|
else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true);
|
|
else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true);
|
|
if ( (pos.z > ceilingz) || (pos.z < floorz) ) bKILLED = true;
|
|
}
|
|
else if ( atsector ) // attempt to follow the movement of the plane
|
|
{
|
|
SetOrigin(Vec2OffsetZ(0,0,atz+atsector.GetPlaneTexZ(atplane)),true);
|
|
if ( ceilingz-floorz <= 2 ) bKILLED = true;
|
|
}
|
|
if ( bKILLED ) SetStateLabel("Detonate");
|
|
}
|
|
void A_Attach()
|
|
{
|
|
F3DFloor ff;
|
|
A_NoGravity();
|
|
A_Stop();
|
|
if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = BlockingFloor.Get3DFLoor(i);
|
|
break;
|
|
}
|
|
if ( ff )
|
|
{
|
|
normal = -ff.top.Normal;
|
|
atsector = ff.model;
|
|
atplane = 1;
|
|
SWWMUtility.SetToSlopeSpecific(self,angle,ff.top,true);
|
|
}
|
|
else
|
|
{
|
|
normal = BlockingFloor.floorplane.Normal;
|
|
atsector = BlockingFloor;
|
|
atplane = 0;
|
|
SWWMUtility.SetToSlopeSpecific(self,angle,BlockingFloor.floorplane,false);
|
|
}
|
|
frame = 1; // on floor
|
|
SetOrigin((pos.x,pos.y,floorz)+normal*.75,true);
|
|
atz = pos.z-atsector.GetPlaneTexZ(atplane);
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = BlockingCeiling.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff )
|
|
{
|
|
normal = -ff.bottom.Normal;
|
|
atsector = ff.model;
|
|
atplane = 0;
|
|
SWWMUtility.SetToSlopeSpecific(self,angle,ff.bottom,false);
|
|
}
|
|
else
|
|
{
|
|
normal = BlockingCeiling.ceilingplane.Normal;
|
|
atsector = BlockingCeiling;
|
|
atplane = 1;
|
|
SWWMUtility.SetToSlopeSpecific(self,angle,BlockingCeiling.ceilingplane,true);
|
|
}
|
|
frame = 2; // on ceiling
|
|
SetOrigin((pos.x,pos.y,ceilingz)+normal*.75,true);
|
|
atz = pos.z-atsector.GetPlaneTexZ(atplane);
|
|
}
|
|
else if ( BlockingLine )
|
|
{
|
|
atline = BlockingLine;
|
|
normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
atside = SWWMUtility.PointOnLineSide(pos.xy,BlockingLine);
|
|
if ( !atside ) normal *= -1;
|
|
Vector3 orig = (BlockingLine.v1.p.x,BlockingLine.v1.p.y,0);
|
|
Vector3 onwall = pos-(normal dot (pos-orig))*normal;
|
|
SetOrigin(onwall+normal*.75,true);
|
|
// attempt to guess line part (upper/mid/lower)
|
|
if ( !atline.sidedef[1] ) atpart = 0; // mid
|
|
else if ( atline.sidedef[!atside].sector.ceilingplane.ZAtPoint(pos.xy) < pos.z ) atpart = 1; // upper
|
|
else if ( atline.sidedef[!atside].sector.floorplane.ZAtPoint(pos.xy) > (pos.z+height) ) atpart = -1; // lower
|
|
else
|
|
{
|
|
atpart = 0;
|
|
// check if we're touching a 3d floor line
|
|
Sector backsector = atline.sidedef[!atside].sector;
|
|
for ( int i=0; i<backsector.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( backsector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) > (pos.z+height) ) continue;
|
|
if ( backsector.Get3DFloor(i).top.ZAtPoint(pos.xy) < pos.z ) continue;
|
|
ff = backsector.Get3DFloor(i);
|
|
break;
|
|
}
|
|
// attach to it
|
|
if ( ff )
|
|
{
|
|
atline = ff.master;
|
|
atside = 0;
|
|
}
|
|
}
|
|
if ( atpart == 1 )
|
|
{
|
|
if ( atline.flags&Line.ML_DONTPEGTOP ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1);
|
|
else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(1);
|
|
}
|
|
else if ( atpart == -1 )
|
|
{
|
|
if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0);
|
|
else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(0);
|
|
}
|
|
else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0);
|
|
else atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1);
|
|
angle = atan2(normal.y,normal.x)+180;
|
|
pitch = 0;
|
|
}
|
|
else
|
|
{
|
|
bKILLED = true;
|
|
SetStateLabel("Detonate");
|
|
return;
|
|
}
|
|
let b = Spawn("ExplodiumMagHitbox",pos);
|
|
b.target = self;
|
|
A_StartSound("explodium/jamitin",CHAN_BODY,CHANF_DEFAULT,.65,2.5);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
Death:
|
|
XZW1 A -1 A_Attach();
|
|
Stop;
|
|
Detonate:
|
|
XZW1 # 2;
|
|
TNT1 A 0
|
|
{
|
|
cvel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
A_BlowUp();
|
|
}
|
|
XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ExploLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 15;
|
|
}
|
|
}
|
|
Class ExploLight2 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 30;
|
|
Args 0,0,0,120;
|
|
}
|
|
}
|
|
|
|
Class ExplodiumBulletImpact : Actor
|
|
{
|
|
Default
|
|
{
|
|
Obituary "$O_EXPLODIUM";
|
|
DamageType "Explodium";
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
Scale 1.2;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+NODAMAGETHRUST;
|
|
+FORCERADIUSDMG;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_AlertMonsters(swwm_uncapalert?0:3000);
|
|
SWWMUtility.DoExplosion(self,20,40000,70,40,DE_EXTRAZTHRUST);
|
|
A_QuakeEx(4,4,4,10,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:150,rollintensity:0.2);
|
|
A_StartSound("explodium/hit",CHAN_VOICE,attenuation:.6);
|
|
A_StartSound("explodium/hit",CHAN_WEAPON,attenuation:.3);
|
|
A_SprayDecal("RocketBlast",-172);
|
|
Scale *= FRandom[ExploS](0.8,1.1);
|
|
Scale.x *= RandomPick[ExploS](-1,1);
|
|
Scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,3);
|
|
let s = Spawn("SWWMSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
|
|
s.special1 = Random[ExploS](1,2);
|
|
s.scale *= 2.4;
|
|
s.alpha *= .4;
|
|
}
|
|
numpt = Random[ExploS](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
|
|
let s = Spawn("SWWMSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](6,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("SWWMChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
Spawn("ExploLight",pos);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX1 ACEGIKMOQSUWY[] 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|