swwmgz_m/zscript/swwm_player_fx.zsc

529 lines
12 KiB
Text

// player effects
// drop from monsters when using "Demoslayer" fun option
// heals up to 100 HP when touched
Class SlayerOrb : Actor abstract
{
Class<Actor> tclass;
Property TrailClass : tclass;
Default
{
RenderStyle "Add";
Radius 4;
Height 8;
Scale .5;
BounceFactor .75;
WallBounceFactor .75;
Gravity .35;
PROJECTILE;
+THRUACTORS;
-NOGRAVITY;
+NOTELEPORT;
+DONTSPLASH;
+BOUNCEONWALLS;
+BOUNCEONFLOORS;
+BOUNCEONCEILINGS;
+CANBOUNCEWATER;
+FORCEXYBILLBOARD;
}
virtual void PickedUp( int np, PlayerPawn mo )
{
}
override void Tick()
{
Vector3 oldp = pos;
Super.Tick();
if ( !isFrozen() )
{
let t = Spawn(tclass,pos);
t.scale *= abs(scale.x);
t.alpha *= alpha;
scale *= .995;
alpha = abs(scale.x)*2.;
if ( abs(scale.x) < .1 )
{
Destroy();
return;
}
}
int np = -1;
double mdist = 1000.;
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || (players[i].Health <= 0) || !players[i].mo || !CheckSight(players[i].mo,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
double dist = Distance3D(players[i].mo);
if ( dist > mdist ) continue;
mdist = dist;
np = i;
}
if ( np == -1 ) return;
let mo = players[np].mo;
if ( (GetAge() > 5) && SWWMUtility.BoxIntersect(self,mo,pad:8) )
{
PickedUp(np,mo);
Destroy();
return;
}
if ( isFrozen() ) return;
Vector3 dirto = level.Vec3Diff(pos,mo.Vec3Offset(0,0,mo.Height/2));
double distto = dirto.length();
dirto /= distto;
double fact = ((1000.-distto)/1000.)**2.;
vel *= 1.-.05*fact;
vel += (dirto+(0,0,.1))*fact*2.;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SpriteOffset = (0,-4);
Scale.x *= RandomPick[Junk](-1,-1);
Scale.y *= RandomPick[Junk](-1,-1);
}
}
Class HealthOrb : SlayerOrb
{
Default
{
SlayerOrb.TrailClass "HealthOrbTrail";
}
override void PickedUp( int np, PlayerPawn mo )
{
int flg = CHANF_OVERLAP|CHANF_MAYBE_LOCAL;
if ( mo.CheckLocalView() ) flg |= CHANF_NOPAUSE;
mo.A_StartSound("misc/health_pkup",CHAN_ITEM,flg);
int hp = int(ceil(abs(scale.x*10)));
mo.GiveBody(hp,100);
SWWMHandler.HealthFlash(np);
SWWMScoreObj.Spawn(hp,mo.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+mo.Height/2),ST_Health);
}
States
{
Spawn:
BLPF E -1 Bright;
Stop;
}
}
Class ArmorOrb : SlayerOrb
{
Default
{
SlayerOrb.TrailClass "ArmorOrbTrail";
}
override void PickedUp( int np, PlayerPawn mo )
{
int flg = CHANF_OVERLAP|CHANF_MAYBE_LOCAL;
if ( mo.CheckLocalView() ) flg |= CHANF_NOPAUSE;
mo.A_StartSound("misc/armor_pkup",CHAN_ITEM,flg);
int hp = int(ceil(abs(scale.x*10)));
let n = mo.FindInventory("ArmorNugget");
if ( !n )
{
n = Inventory(Spawn("ArmorNugget"));
n.AttachToOwner(mo);
SWWMLoreLibrary.Add(mo.player,"Nugget");
n.Amount = 0;
}
if ( n.Amount < 100 ) n.Amount = min(n.Amount+hp,100);
SWWMHandler.ArmorFlash(np);
SWWMScoreObj.Spawn(hp,mo.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+mo.Height/2),ST_Armor);
}
States
{
Spawn:
BLPF D -1 Bright;
Stop;
}
}
Class SlayerOrbTrail : Actor abstract
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
Scale .25;
Alpha .5;
+FORCEXYBILLBOARD;
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
}
override void Tick()
{
if ( isFrozen() ) return;
alpha *= .9;
scale *= 1.05;
if ( alpha < .05 ) Destroy();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SpriteOffset = (0,-4);
}
}
Class HealthOrbTrail : SlayerOrbTrail
{
States
{
Spawn:
BLPS E -1 Bright;
Stop;
}
}
Class ArmorOrbTrail : SlayerOrbTrail
{
States
{
Spawn:
BLPS D -1 Bright;
Stop;
}
}
Class DashTrail : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
Scale 0.3;
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
FloatBobPhase 0;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetState(FindState("Spawn")+Random[ExploS](0,7));
let t = Spawn("DashTrail2",level.Vec3Offset(pos,vel*.3));
t.target = target;
t.vel = vel*1.2;
let s = Spawn("SWWMSmoke",level.Vec3Offset(pos,vel*1.6));
s.vel = vel*.8;
s.SetShade(Color(1,1,1)*Random[ExploS](64,128));
s.special1 = Random[ExploS](2,4);
s.scale *= 1.4;
s.alpha *= .3;
}
override void Tick()
{
Super.Tick();
// hack
if ( target && (players[consoleplayer].Camera == target) ) Warp(target,pos.x,pos.y,pos.z,0,WARPF_ABSOLUTEPOSITION|WARPF_COPYINTERPOLATION);
}
States
{
Spawn:
JFLB ABCDEFGH 1 Bright
{
A_FadeOut(.2);
A_SetScale(scale.x*.95);
}
Loop;
}
}
Class DashTrail2 : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
Scale 0.2;
Alpha 0.4;
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
FloatBobPhase 0;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetState(FindState("Spawn")+Random[ExploS](0,7));
}
override void Tick()
{
Super.Tick();
// hack
if ( target && (players[consoleplayer].Camera == target) ) Warp(target,pos.x,pos.y,pos.z,0,WARPF_ABSOLUTEPOSITION|WARPF_COPYINTERPOLATION);
}
States
{
Spawn:
JFLR ABCDEFGH 1 Bright
{
A_FadeOut(.02);
A_SetScale(scale.x*1.04);
if ( waterlevel > 0 )
{
let b = Spawn("SWWMBubble",pos);
b.vel = vel;
b.scale *= scale.x;
Destroy();
}
}
Loop;
}
}
Class DemolitionistRadiusShockwaveTail : Actor
{
Default
{
RenderStyle "Add";
Radius 16;
Height 8;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
}
States
{
Spawn:
XZW1 A 1
{
pitch = min(85,(pitch+2)*1.05);
A_FadeOut(.02);
A_SetScale(scale.x*1.08,scale.y);
vel *= .98;
}
Wait;
}
}
Class DemolitionistRadiusShockwave : Actor
{
Actor lasthit;
Default
{
RenderStyle "Add";
Speed 15;
DamageFunction int(200*alpha);
DamageType "GroundPound";
Radius 16;
Height 8;
Alpha .4;
XScale .65;
YScale 3.;
PROJECTILE;
+DONTSPLASH;
+STEPMISSILE;
+NOEXPLODEFLOOR;
+FLATSPRITE;
+RIPPER;
+BLOODLESSIMPACT;
-NOGRAVITY;
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( target == lasthit ) return 0;
lasthit = target;
if ( damage <= 0 ) return damage;
if ( (target.mass < LARGE_MASS) && !target.bDONTTHRUST )
{
target.vel.xy += vel.xy.unit()*(30000./max(50,target.mass))*alpha;
if ( (target.pos.z <= floorz) || !target.TestMobjZ() )
target.vel.z += (4000./max(50,target.mass))*alpha;
}
return damage;
}
States
{
Spawn:
XZW1 A 1
{
SetZ(floorz);
pitch = min(85,(pitch+2)*1.05);
if ( !Random[ExploS](0,3) )
Spawn("InvisibleSplasher",Vec3Offset(0,0,2));
let s = Spawn("DemolitionistRadiusShockwaveTail",pos);
s.vel = vel*.35;
s.scale = scale;
s.alpha = alpha*.4;
s.angle = angle;
s.pitch = pitch;
s.roll = roll;
A_FadeOut(.015);
A_SetScale(scale.x*1.08,scale.y);
vel *= .98;
}
Wait;
Death:
XZW1 A 1
{
SetZ(floorz);
A_FadeOut(.05);
A_SetScale(scale.x*1.1,scale.y*.97);
}
Wait;
}
}
Class DemolitionistShockwave : Actor
{
Default
{
+NOGRAVITY;
+NOBLOCKMAP;
+NOTELEPORT;
+NODAMAGETHRUST;
+FORCERADIUSDMG;
+NOINTERACTION;
Radius .1;
Height 0.;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(7,7,7,30,0,300+min(special1,50)*4,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:1.5);
if ( target.player != players[consoleplayer] )
{
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.3);
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.2,pitch:.7);
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.1,pitch:.4);
}
SWWMUtility.DoExplosion(self,40+min(special1,120),100000+min(special1*2000,150000),100+min(special1*2,130),80,DE_BLAST|DE_EXTRAZTHRUST,'GroundPound',target);
for ( int i=0; i<360; i+=5 )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,3);
let s = Spawn("SWWMSmoke",Vec3Angle(4,i,8));
s.vel = pvel+(cos(i),sin(i),0)*7.;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,4);
s.scale *= 1.5;
s.alpha *= .4;
}
if ( pos.z > floorz+16 ) return;
for ( int i=0; i<360; i+=5 )
{
let r = Spawn("DemolitionistRadiusShockwave",Vec3Angle(5,i));
r.target = target;
r.angle = i;
r.vel.xy = (cos(i),sin(i))*(r.speed+min(special1*.15,30));
r.alpha *= .1+min(special1*.03,.9);
}
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](2,12);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
let raging = RagekitPower(target.FindInventory("RagekitPower"));
if ( raging || swwm_omnibust )
{
// bust the floor if we can
let tempme = new("LineTracer"); // gross hack to pass needed data
int dmg = 40+min(special1,120);
if ( raging ) dmg *= 8;
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
if ( ff ) tempme.Results.ffloor = ff;
tempme.Results.HitSector = FloorSector;
tempme.Results.HitType = TRACE_HitFloor;
BusterWall.Bust(tempme.Results,dmg,target,(0,0,-1),pos.z);
if ( raging )
{
let ps = Spawn("BigPunchSplash",pos);
ps.damagetype = 'GroundPound';
ps.target = target;
ps.special1 = dmg;
raging.DoHitFX();
}
}
}
States
{
Spawn:
TNT1 A 140;
Stop;
}
}
// not an actual light, just handles the attach/detach
Class DemolitionistSelfLight : Actor
{
bool oldactive;
bool oldglow;
transient Color tagcolor;
Default
{
Radius .1;
Height 0.;
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+NOINTERACTION;
FloatBobPhase 0;
}
bool activelight()
{
// active all the time except when invisible or in certain
// animation frames
if ( target.bINVISIBLE || (target.alpha <= double.epsilon) ) return false;
if ( target.InStateSequence(target.CurState,target.FindState("Death")) && ((target.frame == 20) || (target.frame == 22) || (target.frame == 23) || (target.frame == 25) || (target.frame == 27) || (target.frame == 28) || (target.frame == 30) || (target.frame == 31) || (target.frame == 32) || (target.frame == 33) || (target.frame == 34)) )
return false;
if ( target.InStateSequence(target.CurState,target.FindState("CrouchDeath")) && ((target.frame == 7) || (target.frame == 10) || (target.frame == 11)) )
return false;
if ( target.InStateSequence(target.CurState,target.FindState("VoodooDeath")) && ((target.frame == 9) || (target.frame == 11) || (target.frame == 12) || (target.frame == 14) || (target.frame == 16) || (target.frame == 18)) )
return false;
return true;
}
override void Tick()
{
if ( !target || !(target is 'Demolitionist') || (Demolitionist(target).selflight != self) )
{
Destroy();
return;
}
if ( tagcolor.a == 0 )
{
let lmp = Wads.FindLump("tagcolor.txt");
if ( lmp != -1 )
{
String str = Wads.ReadLump(lmp);
Array<String> rgb;
str.Split(rgb,",",0);
tagcolor = Color(255,rgb[0].ToInt(),rgb[1].ToInt(),rgb[2].ToInt());
}
else tagcolor = Color(255,32,48,24);
}
bool doselflight = swwm_selflight;
bool curactive = doselflight&&activelight();
// setting the pitch to a value outside [-90,90] makes it auto-update to the actor's own pitch
// this is undocumented and it's very great and nice and fine that such a thing had to be found out purely by chance
// how very wonderful /s
if ( curactive && !oldactive )
target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,Color(112,144,176),200,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE|DynamicLight.LF_SPOT,(5,0,target.player?(target.player.viewz-target.pos.z):(target.height*.93)),0,15,60,180);
else if ( !curactive && oldactive )
target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,0,0,0);
oldactive = curactive;
bool curglow = doselflight&&(!(target.bINVISIBLE||(target.alpha <= double.epsilon)));
if ( curglow && !oldglow ) target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,tagcolor,80,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE,(0,0,target.height/2));
else if ( !curglow && oldglow ) target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,0,0,0);
oldglow = curglow;
}
}