1289 lines
31 KiB
Text
1289 lines
31 KiB
Text
// VIP powerups
|
|
|
|
Class TendrilTracer : LineTracer
|
|
{
|
|
Actor ignore;
|
|
Array<Line> ShootThroughList;
|
|
Array<HitListEntry> HitList;
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
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 )
|
|
{
|
|
ShootThroughList.Push(Results.HitLine);
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Skip;
|
|
}
|
|
}
|
|
|
|
// main heatseeker
|
|
Class MykradvoTendril : SWWMNonInteractiveActor
|
|
{
|
|
Vector3 nextpos, nextdir;
|
|
|
|
void A_Trace()
|
|
{
|
|
tics = bMISSILEMORE?2:1;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = SWWMUtility.GetAxes(angle,pitch,roll);
|
|
if ( !bSTANDSTILL )
|
|
{
|
|
let t = new("TendrilTracer");
|
|
t.ignore = target;
|
|
t.hitlist.Clear();
|
|
t.ShootThroughList.Clear();
|
|
t.Trace(pos,CurSector,x,speed,0);
|
|
foreach ( l:t.ShootThroughList )
|
|
{
|
|
l.Activate(target,0,SPAC_PCross);
|
|
l.Activate(target,0,SPAC_Impact);
|
|
}
|
|
foreach ( hit:t.hitlist )
|
|
{
|
|
if ( hit.hitactor.IsFriend(target) ) continue;
|
|
if ( (hit.hitactor == tracer) && bMISSILEMORE ) bMISSILEEVENMORE = true; // we split
|
|
int dmg = (hit.hitactor.bBOSS||hit.hitactor.FindInventory("BossMarker"))?(GetMissileDamage(0,0)*4):max(hit.hitactor.Health,GetMissileDamage(0,0));
|
|
SWWMUtility.DoKnockback(hit.hitactor,-hit.x+(0,0,.5),((hit.hitactor.Health-dmg)<=0)?60000:8000);
|
|
let p = SWWMPuff.Setup(hit.hitlocation,hit.x,self,target,hit.hitactor);
|
|
hit.hitactor.DamageMobj(p,target,dmg,'Plasma',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
|
|
if ( hit.hitactor && hit.hitactor.bISMONSTER && !Random[Mykradvo](0,3) )
|
|
hit.hitactor.Howl();
|
|
}
|
|
}
|
|
nextpos = level.Vec3Offset(pos,x*speed);
|
|
if ( !bSTANDSTILL && (!tracer || !tracer.bSHOOTABLE || (tracer.Health <= 0) || ((tracer.bBOSS || tracer.FindInventory("BossMarker")) && !bMISSILEMORE)) )
|
|
{
|
|
ReactionTime--;
|
|
if ( ReactionTime <= 0 )
|
|
{
|
|
bAMBUSH = true;
|
|
return;
|
|
}
|
|
}
|
|
double a = FRandom[Mykradvo](0,360), s = FRandom[Mykradvo](0.,bSTANDSTILL?3.:bMISSILEMORE?.75:1.5);
|
|
Vector3 dir = SWWMUtility.ConeSpread(x,y,z,a,s);
|
|
if ( tracer )
|
|
{
|
|
Vector3 destofs = bMISSILEMORE?tracer.Vec3Offset(0,0,tracer.Height/2.):tracer.Vec3Offset(FRandom[Mykradvo](-1.2,1.2)*tracer.Radius,FRandom[Mykradvo](-1.2,1.2)*tracer.Radius,FRandom[Mykradvo](-.1,1.1)*tracer.height);
|
|
Vector3 dirto = level.Vec3Diff(nextpos,destofs);
|
|
double dist = dirto.length();
|
|
if ( dist > 1 )
|
|
{
|
|
dirto /= dist;
|
|
dir = (dir+dirto*(clamp(1.-(dist/4000.),.25,1.)**1.5)).unit();
|
|
}
|
|
// early split
|
|
if ( dist < speed ) bMISSILEEVENMORE = true;
|
|
}
|
|
nextdir = dir;
|
|
}
|
|
void A_Spread()
|
|
{
|
|
if ( bMISSILEMORE && bMISSILEEVENMORE )
|
|
{
|
|
// spread into sub-tendrils
|
|
Vector3 x, y, z;
|
|
[x, y, z] = SWWMUtility.GetAxes(angle,pitch,roll);
|
|
int ntendies = tracer?clamp(tracer.GetSpawnHealth()/400,2,10):2;
|
|
for ( int i=0; i<ntendies; i++ )
|
|
{
|
|
let r = Spawn("MykradvoSmallTendril",nextpos);
|
|
double a = FRandom[Mykradvo](0,360), s = FRandom[Mykradvo](0.,1.);
|
|
Vector3 sdir = SWWMUtility.ConeSpread(x,y,z,a,s);
|
|
r.angle = atan2(sdir.y,sdir.x);
|
|
r.pitch = asin(-sdir.z);
|
|
r.target = target;
|
|
r.tracer = tracer;
|
|
if ( tracer && (tracer.bBOSS || tracer.FindInventory("BossMarker")) ) r.ReactionTime -= Random[ExploS](5,15);
|
|
else r.ReactionTime += Random[ExploS](0,20);
|
|
}
|
|
return;
|
|
}
|
|
if ( bAMBUSH || (bSTANDSTILL && (special1 > ReactionTime)) )
|
|
{
|
|
if ( !bSTANDSTILL )
|
|
{
|
|
int numpt = bMISSILEMORE?9:3;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = SWWMUtility.GetAxes(angle,pitch,roll);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double a = FRandom[ExploS](0,360), s = FRandom[ExploS](0,1.);
|
|
Vector3 sdir = SWWMUtility.ConeSpread(x,y,z,a,s);
|
|
let r = Spawn("MykradvoSmallNullTendril",nextpos);
|
|
r.angle = atan2(sdir.y,sdir.x);
|
|
r.pitch = asin(-sdir.z);
|
|
r.target = target;
|
|
if ( bMISSILEMORE ) r.ReactionTime += Random[ExploS](0,4);
|
|
else r.ReactionTime -= Random[ExploS](0,4);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
let b = Spawn(GetClass(),nextpos);
|
|
b.angle = atan2(nextdir.y,nextdir.x);
|
|
b.pitch = asin(-nextdir.z);
|
|
b.target = target;
|
|
b.tracer = tracer;
|
|
b.special1 = special1+1;
|
|
b.special2 = special2;
|
|
b.ReactionTime = ReactionTime;
|
|
if ( !bSTANDSTILL && !((special1+special2)%4) && !Random[Mykradvo](0,4) )
|
|
A_StartSound(bMISSILEMORE?"mykradvo/arc":"mykradvo/smallarc",CHAN_WEAPON,attenuation:(bMISSILEMORE?.5:1.5),pitch:FRandom[Mykradvo](.75,1.25));
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
if ( !special1 ) special2 = Random[Mykradvo](0,8);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( freezetics > 0 )
|
|
{
|
|
freezetics--;
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
A_FadeOut(bMISSILEMORE?.05:bSTANDSTILL?.2:.1);
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
Obituary "$O_MYKRADVO";
|
|
RenderStyle "Add";
|
|
DamageFunction 100;
|
|
ReactionTime 8;
|
|
Speed 64;
|
|
+INTERPOLATEANGLES;
|
|
+FOILINVUL;
|
|
+MISSILEMORE;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 0 Bright;
|
|
XZW1 A 1 Bright A_Trace();
|
|
XZW1 A 1 Bright
|
|
{
|
|
A_Spread();
|
|
return FindState("Fade")+Random[Mykradvo](0,11)*2;
|
|
}
|
|
Stop;
|
|
Fade:
|
|
#### # 20 Bright;
|
|
XZW1 B -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 C -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 D -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 E -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 F -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 G -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 H -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 I -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 J -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 K -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 L -1 Bright;
|
|
Stop;
|
|
#### # 20 Bright;
|
|
XZW1 M -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// sub seekers
|
|
Class MykradvoSmallTendril : MykradvoTendril
|
|
{
|
|
Default
|
|
{
|
|
Speed 16;
|
|
DamageFunction 10;
|
|
ReactionTime 20;
|
|
-MISSILEMORE;
|
|
}
|
|
States
|
|
{
|
|
Fade:
|
|
#### # 10 Bright;
|
|
XZW1 B -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 C -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 D -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 E -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 F -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 G -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 H -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 I -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 J -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 K -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 L -1 Bright;
|
|
Stop;
|
|
#### # 10 Bright;
|
|
XZW1 M -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// non-hurting non-seekers
|
|
Class MykradvoSmallNullTendril : MykradvoSmallTendril
|
|
{
|
|
Default
|
|
{
|
|
Speed 8;
|
|
ReactionTime 6;
|
|
+STANDSTILL;
|
|
}
|
|
States
|
|
{
|
|
Fade:
|
|
#### # 5 Bright;
|
|
XZW1 B -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 C -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 D -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 E -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 F -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 G -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 H -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 I -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 J -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 K -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 L -1 Bright;
|
|
Stop;
|
|
#### # 5 Bright;
|
|
XZW1 M -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class MykradvoBurstLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "Purple";
|
|
ReactionTime 60;
|
|
Args 0,0,0,400;
|
|
}
|
|
}
|
|
|
|
// 'splode
|
|
Class MykradvoBurst : SWWMNonInteractiveActor
|
|
{
|
|
Array<Actor> targets;
|
|
int nstep;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+FORCEXYBILLBOARD;
|
|
Scale 1.4;
|
|
}
|
|
void FlashPlayer( int str, double rad )
|
|
{
|
|
if ( !SWWMUtility.InPlayerFOV(players[consoleplayer],self,rad) ) return;
|
|
let mo = players[consoleplayer].Camera;
|
|
double dist = Distance3D(mo);
|
|
str = int(str*(1.-(dist/rad)));
|
|
SWWMHandler.DoFlash(mo,Color(str,250,240,255),5);
|
|
SWWMHandler.DoFlash(mo,Color(str,128,0,255),15);
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
nstep = clamp(targets.Size()/10,1,5);
|
|
A_AlertMonsters(swwm_uncapalert?0:8000);
|
|
A_QuakeEx(9,9,9,80,0,3000,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:1000,rollintensity:2.);
|
|
A_StartSound("powerup/mykradvo",CHAN_BODY,CHANF_DEFAULT,1.,.25);
|
|
A_StartSound("powerup/mykradvo",CHAN_VOICE,CHANF_DEFAULT,1.,.25);
|
|
FlashPlayer(100,1500);
|
|
int numpt = Random[ExploS](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](.25,8);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](128,160)+Color(28,0,31));
|
|
s.A_SetRenderStyle(.4,STYLE_AddShaded);
|
|
s.special1 = Random[ExploS](1,5);
|
|
s.scale *= 2.;
|
|
}
|
|
numpt = Random[ExploS](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("MykradvoSmallNullTendril",pos);
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.target = target;
|
|
s.ReactionTime += Random[ExploS](0,8);
|
|
}
|
|
Spawn("MykradvoBurstLight",pos);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( freezetics > 0 )
|
|
{
|
|
freezetics--;
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
if ( (special1++)%3 )
|
|
{
|
|
if ( targets.Size() > 0 )
|
|
{
|
|
int numpt = Random[ExploS](2,4);
|
|
for ( int j=0; j<numpt; j++ )
|
|
{
|
|
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](.25,8);
|
|
let s = Spawn("SWWMHalfSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](128,160)+Color(28,0,31));
|
|
s.A_SetRenderStyle(.4,STYLE_AddShaded);
|
|
s.special1 = Random[ExploS](1,5);
|
|
s.scale *= 2.;
|
|
}
|
|
numpt = Random[ExploS](1,2);
|
|
for ( int j=0; j<numpt; j++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("MykradvoSmallNullTendril",pos);
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.target = target;
|
|
s.ReactionTime += Random[ExploS](0,8);
|
|
}
|
|
}
|
|
for ( int i=0; i<nstep; i++ )
|
|
{
|
|
if ( targets.Size() <= 0 ) break;
|
|
let targ = targets[0];
|
|
if ( targ && targ.bSHOOTABLE && (targ.Health > 0) )
|
|
{
|
|
let t = Spawn("MykradvoTendril",pos);
|
|
t.angle = t.AngleTo(targ);
|
|
t.pitch = t.PitchTo(targ,0,targ.Height/2);
|
|
t.target = target;
|
|
t.tracer = targ;
|
|
}
|
|
else i--;
|
|
targets.Delete(0);
|
|
}
|
|
}
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XEX4 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\ 2 Bright;
|
|
TNT1 A 1 A_JumpIf(!IsActorPlayingSound(CHAN_VOICE,-1)&&!(targets.Size()),1);
|
|
Wait;
|
|
TNT1 A 1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Mykradvo : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
Mixin SWWMRespawn;
|
|
Mixin SWWMPickupGlow;
|
|
|
|
Actor ringa[2];
|
|
|
|
Array<Actor> targets;
|
|
|
|
// quicksort (targets)
|
|
private bool CmpDist( Actor ref, Vector3 a, Vector3 b )
|
|
{
|
|
double dista = level.Vec3Diff(ref.pos,a).length();
|
|
double distb = level.Vec3Diff(ref.pos,b).length();
|
|
return (dista < distb);
|
|
}
|
|
private int partition_targets( Array<Actor> a, int l, int h, Actor ref )
|
|
{
|
|
Actor pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpDist(ref,a[j].pos,pv.pos) )
|
|
{
|
|
i++;
|
|
Actor tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
Actor tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_targets( Array<Actor> a, int l, int h, Actor ref )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_targets(a,l,h,ref);
|
|
qsort_targets(a,l,p-1,ref);
|
|
qsort_targets(a,p+1,h,ref);
|
|
}
|
|
|
|
bool FindTargets( Actor t )
|
|
{
|
|
targets.Clear();
|
|
// search all actively hostile enemies within 50m
|
|
let ti = ThinkerIterator.Create("Actor");
|
|
Actor a;
|
|
while ( a=Actor(ti.Next()) )
|
|
{
|
|
// must be an active, shootable live monster
|
|
if ( !a.bISMONSTER || !a.bSHOOTABLE || a.bDORMANT || (a.Health <= 0) ) continue;
|
|
// skip non-hostiles
|
|
if ( a.IsFriend(t) ) continue;
|
|
// is targetting us and is within 10m
|
|
// or
|
|
// is visible and is within 100m
|
|
if ( ((a.target == t) && SWWMUtility.SphereIntersect(a,t.pos,320))
|
|
|| (t.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) && SWWMUtility.SphereIntersect(a,t.pos,3200)) )
|
|
targets.Push(a);
|
|
}
|
|
// sorted, so the closest take priority
|
|
qsort_targets(targets,0,targets.Size()-1,t);
|
|
return (targets.Size() > 0);
|
|
}
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
Vector3 spawnpos = Owner.Vec3Angle(15,Owner.angle,Owner.Height*.7);
|
|
if ( !FindTargets(Owner) )
|
|
{
|
|
int numpt = Random[ExploS](8,12);
|
|
let f = Spawn("SWWMPurplePickupFlash",spawnpos-(0,0,16));
|
|
f.Scale *= .5;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("MykradvoSmallNullTendril",spawnpos+SWWMUtility.Vec3Fromangles(ang,pt)*FRandom[Mykradvo](2,4));
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[ExploS](0,8);
|
|
}
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= 0.98;
|
|
Owner.A_QuakeEx(1,1,1,4,0,8,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D);
|
|
// don't consume on failure
|
|
Amount++;
|
|
return true;
|
|
}
|
|
if ( (targets.Size() == 1) && targets[0] && !targets[0].bBOSS && !targets[0].FindInventory("BossMarker") )
|
|
SWWMUtility.MarkAchievement("anone",Owner.player);
|
|
let p = Spawn("MykradvoBurst",spawnpos);
|
|
p.target = Owner;
|
|
MykradvoBurst(p).targets.Move(targets);
|
|
targets.Clear();
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= 1.2;
|
|
SWWMUtility.AchievementProgressInc("anom",1,Owner.player);
|
|
return true;
|
|
}
|
|
|
|
void A_Zap()
|
|
{
|
|
int numpt = Random[ExploS](2,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
let s = Spawn("MykradvoSmallNullTendril",pos+(0,0,16+GetBobOffset())+SWWMUtility.Vec3Fromangles(ang,pt)*FRandom[Mykradvo](4,8));
|
|
s.angle = ang;
|
|
s.pitch = pt;
|
|
s.ReactionTime += Random[ExploS](-2,2);
|
|
}
|
|
A_StartSound("mykradvo/smallarc",CHAN_WEAPON,CHANF_OVERLAP,attenuation:3.);
|
|
A_SetTics(Random[Mykradvo](10,50));
|
|
}
|
|
|
|
override bool CanPickup( Actor toucher )
|
|
{
|
|
// in DM, we can't be picked up unless we can be used
|
|
if ( deathmatch && !FindTargets(toucher) )
|
|
return false;
|
|
return Super.CanPickup(toucher);
|
|
}
|
|
|
|
override void PreTravelled()
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
if ( !ringa[i] ) continue;
|
|
ringa[i].Destroy();
|
|
}
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("MykradvoX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
if ( ringa[i] ) continue;
|
|
ringa[i] = Spawn("MykradvoX2",pos);
|
|
ringa[i].angle = angle;
|
|
ringa[i].target = self;
|
|
ringa[i].FloatBobPhase = FloatBobPhase;
|
|
ringa[i].special1 = -1+2*i;
|
|
ringa[i].special2 = -2+4*i;
|
|
ringa[i].frame = i;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("MykradvoX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
ringa[i] = Spawn("MykradvoX2",pos);
|
|
ringa[i].angle = angle;
|
|
ringa[i].target = self;
|
|
ringa[i].FloatBobPhase = FloatBobPhase;
|
|
ringa[i].special1 = -1+2*i;
|
|
ringa[i].special2 = -2+4*i;
|
|
ringa[i].frame = i;
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_MYKRADVO";
|
|
Stamina -1200000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Mykradvo.png";
|
|
Inventory.PickupSound "misc/p_pkup_vip";
|
|
Inventory.UseSound "mykradvo/arc";
|
|
Inventory.PickupMessage "$T_MYKRADVO";
|
|
Inventory.MaxAmount 3;
|
|
Inventory.InterHubAmount 3;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
+DONTGIB;
|
|
FloatBobStrength 0.25;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW0 A 10 A_Zap();
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class MykradvoX : SWWMItemOverlay
|
|
{
|
|
Default
|
|
{
|
|
Scale .16;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/mykradvoamb",CHAN_VOICE,CHANF_LOOP,attenuation:2.);
|
|
WorldOffset = (0,0,16);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
prev = target.prev;
|
|
if ( (target.pos != pos) || (target.vel != (0,0,0)) ) SetOrigin(target.pos+vel,true);
|
|
if ( angle != target.angle ) A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
A_SetScale(.16+.01*sin(GetAge()*4));
|
|
bool bOldInvis = bInvisible;
|
|
bInvisible = target.bInvisible||Inventory(target).Owner;
|
|
if ( bInvisible != bOldInvis )
|
|
{
|
|
SetState(SpawnState+bInvisible);
|
|
A_SoundVolume(CHAN_VOICE,bInvisible?0.:1.);
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MKRV A -1 Bright;
|
|
TNT1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class MykradvoX2 : SWWMItemOverlay
|
|
{
|
|
Default
|
|
{
|
|
+ROLLSPRITE;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
WorldOffset = (0,0,16+special2);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
prev = target.prev;
|
|
if ( (target.pos != pos) || (target.vel != (0,0,0)) ) SetOrigin(target.pos+vel,true);
|
|
if ( angle != target.angle ) A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
A_SetPitch(sin(GetAge()*special1*8)*5,SPF_INTERPOLATE);
|
|
A_SetRoll(cos(GetAge()*special1*8)*5,SPF_INTERPOLATE);
|
|
A_SetScale(1.+.05*cos(GetAge()*4)*special1);
|
|
bool bOldInvis = bInvisible;
|
|
bInvisible = target.bInvisible||Inventory(target).Owner;
|
|
if ( bInvisible != bOldInvis )
|
|
SetState(SpawnState+bInvisible);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # -1 Bright;
|
|
TNT1 # -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// additions from 1.1
|
|
|
|
Class AngeryLight : PointLightAttenuated
|
|
{
|
|
Default
|
|
{
|
|
Args 224,0,255,80;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player ) SetOrigin(SWWMUtility.GetFireOffset(target,10,0,0),true);
|
|
else SetOrigin(target.Vec3Angle(10,target.angle,target.missileheight),true);
|
|
args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*8;
|
|
bDORMANT = Powerup(master).isBlinking();
|
|
}
|
|
}
|
|
Class AngerySnd : SWWMNonInteractiveActor
|
|
{
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.5);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.4);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/devastationact",CHAN_VOICE,CHANF_LOOP,.4,1.5);
|
|
A_StartSound("powerup/devastationact",CHAN_7,CHANF_LOOP,.5,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
Class AngeryPower : Powerup
|
|
{
|
|
Mixin SWWMShadedPowerup;
|
|
|
|
Actor l, snd;
|
|
int lasteffect;
|
|
transient int lastpulse;
|
|
|
|
Default
|
|
{
|
|
Powerup.Duration -50;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Devastation.png";
|
|
Powerup.Color "C0 00 FF", 0.2;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:5000);
|
|
SWWMHandler.DoFlash(Owner,Color(64,224,0,255),30);
|
|
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.);
|
|
lasteffect = int.min;
|
|
lastpulse = max(lastpulse,gametic+35);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= .95;
|
|
l = Spawn("AngeryLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
if ( !snd ) snd = Spawn("AngerySnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
}
|
|
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_StartSound("powerup/devastationend",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
SWWMHandler.DoFlash(Owner,Color(128,224,0,255),30);
|
|
Owner.A_QuakeEx(4,4,4,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.);
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:2000);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= .9;
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_DEVASTATION"));
|
|
}
|
|
|
|
void DoHitFX()
|
|
{
|
|
if ( level.maptime <= lasteffect+5 ) return;
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:5000);
|
|
SWWMHandler.DoFlash(Owner,Color(64,224,0,255),10);
|
|
Owner.A_QuakeEx(8,8,8,Random[Rage](3,8),0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.);
|
|
Owner.A_StartSound("powerup/devastationhit",CHAN_POWERUP,CHANF_OVERLAP);
|
|
lasteffect = level.maptime;
|
|
lastpulse = max(lastpulse,gametic+35);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= .9;
|
|
}
|
|
|
|
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( passive || (damage <= 0) ) return;
|
|
if ( damageType == 'Mortal' ) // can only be in 4s
|
|
{
|
|
// max cap is the closest combination of 4s smaller than (2^31-1)
|
|
if ( damage > 44444444 ) newdamage = 444444444;
|
|
else newdamage = damage*10+4;
|
|
}
|
|
else
|
|
{
|
|
// (2^31-1)/25 : guarantee that it caps rather than overflowing
|
|
if ( damage > 85899345 ) newdamage = int.max;
|
|
else newdamage = damage*25;
|
|
}
|
|
// don't play hit fx for wall busting, as it'll be done manually if the bust goes through
|
|
if ( damageType != 'Wallbust' ) DoHitFX();
|
|
}
|
|
}
|
|
Class AngerySigil : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
Mixin SWWMRespawn;
|
|
Mixin SWWMPickupGlow;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
SWWMUtility.AchievementProgressInc("deva",1,Owner.player);
|
|
let r = AngeryPower(Owner.FindInventory("AngeryPower"));
|
|
if ( r )
|
|
{
|
|
r.EffectTics += r.default.EffectTics;
|
|
SWWMHandler.DoFlash(Owner,Color(64,224,0,255),30);
|
|
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= .95;
|
|
}
|
|
else Owner.GiveInventory("AngeryPower",1);
|
|
return true;
|
|
}
|
|
override void PreTravelled()
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( tracer ) return;
|
|
tracer = Spawn("AngerySigilX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("AngerySigilX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_DEVASTATION";
|
|
Stamina -1500000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Devastation.png";
|
|
Inventory.PickupSound "misc/p_pkup_vip";
|
|
Inventory.UseSound "powerup/devastation";
|
|
Inventory.PickupMessage "$T_DEVASTATION";
|
|
Inventory.MaxAmount 3;
|
|
Inventory.InterHubAmount 3;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
+DONTGIB;
|
|
FloatBobStrength 0.25;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
Class AngerySigilX : SWWMItemOverlay
|
|
{
|
|
Default
|
|
{
|
|
Scale .5;
|
|
Alpha .35;
|
|
RenderStyle "Subtract";
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/devastationamb",CHAN_VOICE,CHANF_LOOP,attenuation:2.);
|
|
WorldOffset = (0,0,20);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
prev = target.prev;
|
|
if ( (target.pos != pos) || (target.vel != (0,0,0)) ) SetOrigin(target.pos+vel,true);
|
|
if ( angle != target.angle ) A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
bool bOldInvis = bInvisible;
|
|
bInvisible = target.bInvisible||Inventory(target).Owner;
|
|
if ( bInvisible != bOldInvis )
|
|
{
|
|
SetState(SpawnState+bInvisible);
|
|
A_SoundVolume(CHAN_VOICE,bInvisible?0.:1.);
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BLPS C -1 Bright;
|
|
TNT1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class DivineSpriteLight : PointLightAttenuated
|
|
{
|
|
Default
|
|
{
|
|
Args 255,255,255,100;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player ) SetOrigin(SWWMUtility.GetFireOffset(target,10,0,0),true);
|
|
else SetOrigin(target.Vec3Angle(10,target.angle,target.missileheight),true);
|
|
double vol = clamp((target.Health-1000)/6000.,0.,1.);
|
|
int lv = clamp(int(vol*255),0,255);
|
|
args[LIGHT_RED] = lv;
|
|
args[LIGHT_GREEN] = lv;
|
|
args[LIGHT_BLUE] = lv;
|
|
args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*10;
|
|
}
|
|
}
|
|
Class DivineSpriteSnd : SWWMNonInteractiveActor
|
|
{
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
double vol = clamp((DivineSpriteEffect(master).AlphInter.GetValue()-1000.)/9000.,0.,1.);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.8*vol);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.4*vol);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/divineact",CHAN_VOICE,CHANF_LOOP,.4,1.5);
|
|
A_StartSound("powerup/divineact",CHAN_7,CHANF_LOOP,.8,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
Class DivineSpriteEffect : Inventory
|
|
{
|
|
int healcnt;
|
|
int healtim;
|
|
bool bHealDone;
|
|
Actor l, snd;
|
|
DynamicValueInterpolator AlphInter;
|
|
FSpawnParticleParams flare;
|
|
|
|
Property HealTimer : healtim;
|
|
|
|
default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Divine.png";
|
|
DivineSpriteEffect.HealTimer 1750;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
}
|
|
|
|
clearscope bool isBlinking() const
|
|
{
|
|
return ( (healtim <= BLINKTHRESHOLD) && (healtim&8) );
|
|
}
|
|
|
|
override Color GetBlend()
|
|
{
|
|
if ( swwm_shaders ) return 0;
|
|
if ( !AlphInter ) AlphInter = DynamicValueInterpolator.Create(Owner.Health,.1,1,100);
|
|
double alph = clamp((AlphInter.GetValue()-1000.)/6000.,0.,1.);
|
|
return Color(int(64*alph),255,255,255);
|
|
}
|
|
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
bHealDone = true;
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !l ) l = Spawn("DivineSpriteLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
if ( !snd ) snd = Spawn("DivineSpriteSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
int numpt = Random[ExploS](5,10);
|
|
if ( !AlphInter ) AlphInter = DynamicValueInterpolator.Create(Owner.Health,.1,1,100);
|
|
AlphInter.Update(Owner.Health);
|
|
double alph = clamp((AlphInter.GetValue()-1000.)/6000.,0.,1.);
|
|
double scl = clamp((AlphInter.GetValue()-1000.)/6000.,2.,4.);
|
|
if ( !flare.texture )
|
|
{
|
|
flare.color1 = "White";
|
|
flare.texture = TexMan.CheckForTexture("graphics/Particles/xflare.png");
|
|
flare.style = STYLE_AddShaded;
|
|
flare.flags = SPF_FULLBRIGHT;
|
|
flare.lifetime = 30;
|
|
flare.fadestep = -1;
|
|
flare.accel = (0,0,.05);
|
|
}
|
|
flare.size = scl;
|
|
flare.sizestep = -scl/30.;
|
|
flare.startalpha = alph;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dst = FRandom[ExploS](.25,.75)*Owner.height;
|
|
Vector3 dir = SWWMUtility.Vec3Fromangles(ang,pt);
|
|
flare.pos = Owner.Vec3Offset(0,0,Owner.height/2)+dir*dst;
|
|
flare.vel = dir*.2;
|
|
level.SpawnParticle(flare);
|
|
}
|
|
if ( bHealDone || (Owner.Health <= 0) )
|
|
{
|
|
if ( AlphInter.GetValue() <= 1000 ) DepleteOrDestroy();
|
|
return;
|
|
}
|
|
healcnt++;
|
|
healtim--;
|
|
if ( (healtim <= 0) || (Owner.Health <= 0) )
|
|
{
|
|
Owner.A_StartSound("powerup/divineend",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
SWWMHandler.DoFlash(Owner,Color(80,255,255,255),40);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= 0.95;
|
|
bHealDone = true;
|
|
if ( (healtim <= 0) && Owner && Owner.CheckLocalView() )
|
|
Console.Printf(StringTable.Localize("$D_SPRITE"));
|
|
}
|
|
else if ( Owner.Health < 1000 )
|
|
{
|
|
healcnt = 0;
|
|
Owner.GiveBody(1000,1000);
|
|
SWWMHandler.DoFlash(Owner,Color(40,255,255,255),20);
|
|
if ( Owner is 'Demolitionist' )
|
|
Demolitionist(Owner).lastbump *= 0.97;
|
|
Owner.A_StartSound("powerup/divinehit",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
}
|
|
else if ( !(healcnt%5) )
|
|
{
|
|
Owner.GiveBody(500,10000);
|
|
Owner.A_StartSound("powerup/divinehit",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
}
|
|
}
|
|
}
|
|
Class DivineSprite : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
Mixin SWWMRespawn;
|
|
Mixin SWWMPickupGlow;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
// never get auto-used on pickup unless we're in deathmatch
|
|
if ( pickup && !deathmatch ) return false;
|
|
let p = Owner.FindInventory("DivineSpriteEffect");
|
|
if ( p ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
|
Owner.GiveInventory("DivineSpriteEffect",1);
|
|
SWWMUtility.AchievementProgressInc("divine",1,Owner.player);
|
|
return true;
|
|
}
|
|
override void PreTravelled()
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
}
|
|
override void Travelled()
|
|
{
|
|
if ( tracer ) return;
|
|
tracer = Spawn("DivineSpriteX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("DivineSpriteX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_DIVINE";
|
|
Stamina -3600000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Divine.png";
|
|
Inventory.PickupSound "misc/p_pkup_vip";
|
|
Inventory.UseSound "powerup/divineuse";
|
|
Inventory.PickupMessage "$T_DIVINE";
|
|
Inventory.MaxAmount 3;
|
|
Inventory.InterHubAmount 3;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
+DONTGIB;
|
|
FloatBobStrength 0.25;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
Class DivineSpriteX : SWWMItemOverlay
|
|
{
|
|
Default
|
|
{
|
|
Scale .5;
|
|
+FORCEXYBILLBOARD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/divineamb",CHAN_VOICE,CHANF_LOOP,attenuation:2.);
|
|
WorldOffset = (0,0,16);
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
prev = target.prev;
|
|
if ( (target.pos != pos) || (target.vel != (0,0,0)) ) SetOrigin(target.pos+vel,true);
|
|
if ( angle != target.angle ) A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
bool bOldInvis = bInvisible;
|
|
bInvisible = target.bInvisible||Inventory(target).Owner;
|
|
if ( bOldInvis != bInvisible )
|
|
{
|
|
SetState(SpawnState+bInvisible);
|
|
A_SoundVolume(CHAN_VOICE,bInvisible?0.:1.);
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
DVSP A -1 Bright;
|
|
TNT1 A -1;
|
|
Stop;
|
|
}
|
|
}
|