818 lines
21 KiB
Text
818 lines
21 KiB
Text
Class BioAmmo : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "Biosludge Ammo";
|
|
Inventory.PickupMessage "You picked up the Biosludge Ammo.";
|
|
Inventory.Amount 25;
|
|
Inventory.MaxAmount 100;
|
|
Ammo.BackpackAmount 50;
|
|
Ammo.BackpackMaxAmount 200;
|
|
Ammo.DropAmount 10;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BIOA A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BioAmmo2 : BioAmmo // small variant
|
|
{
|
|
Default
|
|
{
|
|
Tag "Biosludge Ammo";
|
|
Inventory.PickupMessage "You picked up the Small Biosludge Ammo.";
|
|
Inventory.Amount 10;
|
|
Ammo.DropAmount 5;
|
|
Scale 0.5;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BIOA A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BioSpark : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 2;
|
|
Height 2;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+MISSILE;
|
|
+MOVEWITHSECTOR;
|
|
+THRUACTORS;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
-BOUNCEAUTOOFF;
|
|
+BOUNCEAUTOOFFFLOORONLY;
|
|
BounceType "Doom";
|
|
BounceFactor 0.5;
|
|
WallBounceFactor 0.5;
|
|
Gravity 0.2;
|
|
Scale 0.06;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
frame = Random[GES](0,4);
|
|
roll = FRandom[GES](0,360);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
GBLB # 1 Bright A_FadeOut(FRandom[GES](0.005,0.015));
|
|
Wait;
|
|
Death:
|
|
GBLB # 1 Bright A_FadeOut(FRandom[GES](0.04,0.06));
|
|
Wait;
|
|
Dummy:
|
|
GBLB ABCDE -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BioHitbox : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 3;
|
|
Height 6;
|
|
+SHOOTABLE;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOBLOOD;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
if ( target ) A_SetSize(1.5*target.scale.x,3*target.scale.y);
|
|
}
|
|
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
|
{
|
|
if ( inflictor == target ) return 0;
|
|
if ( target && !target.InStateSequence(target.CurState,target.ResolveState("XDeath")) )
|
|
{
|
|
target.bAMBUSH = true;
|
|
target.ExplodeMissile(null,inflictor);
|
|
}
|
|
return 0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos-(0,0,height*0.5),true);
|
|
}
|
|
override bool CanCollideWith( Actor other, bool passive )
|
|
{
|
|
return !target.bNoGravity; // don't "intercept" while flying (doesn't seem to work, but at least I tried)
|
|
}
|
|
}
|
|
|
|
Class BioLight : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
Args 64,255,48,8;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
args[LIGHT_INTENSITY] = int(8*target.Scale.x);
|
|
}
|
|
}
|
|
|
|
Class BioXLight : DynamicLight
|
|
{
|
|
double lifetime;
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
Args 64,255,48,30;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
lifetime = 1.0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( globalfreeze || level.frozen ) return;
|
|
args[LIGHT_RED] = int(64*lifetime);
|
|
args[LIGHT_GREEN] = int(255*lifetime);
|
|
args[LIGHT_BLUE] = int(48*lifetime);
|
|
lifetime -= 0.05;
|
|
if ( lifetime <= 0 ) Destroy();
|
|
}
|
|
}
|
|
|
|
Class BioGel : Actor
|
|
{
|
|
Actor l, b;
|
|
enum EHitType
|
|
{
|
|
HIT_NONE,
|
|
HIT_WALL,
|
|
HIT_CEILING,
|
|
HIT_FLOOR
|
|
};
|
|
int hittype;
|
|
int deadtimer, dttimer;
|
|
Line atline;
|
|
int atside;
|
|
int atpart;
|
|
int atplane;
|
|
Sector atsector;
|
|
double atz;
|
|
double rollvel, pitchvel, yawvel;
|
|
Vector3 normal;
|
|
Actor atbridge;
|
|
bool onbridge;
|
|
Vector3 atbridgeofs;
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
vel.z += 3;
|
|
deadtimer = -1;
|
|
l = Spawn("BioLight",pos);
|
|
l.target = self;
|
|
rollvel = FRandom[GES](10,30)*RandomPick[GES](-1,1);
|
|
pitchvel = FRandom[GES](10,30)*RandomPick[GES](-1,1);
|
|
yawvel = FRandom[GES](10,30)*RandomPick[GES](-1,1);
|
|
}
|
|
override int SpecialMissileHit( Actor victim )
|
|
{
|
|
if ( victim == b ) return 1;
|
|
if ( (victim is 'BioHitbox') && ((victim.target == master) || (victim.target.master == master)) ) return 1;
|
|
return -1;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( globalfreeze || level.frozen ) return;
|
|
if ( !bNOGRAVITY )
|
|
{
|
|
roll += rollvel;
|
|
pitch += pitchvel;
|
|
pitch += yawvel;
|
|
if ( waterlevel > 0 )
|
|
{
|
|
vel.xy *= 0.98;
|
|
rollvel *= 0.98;
|
|
pitchvel *= 0.98;
|
|
yawvel *= 0.98;
|
|
}
|
|
}
|
|
if ( deadtimer > -2 )
|
|
{
|
|
if ( onbridge ) // attempt to follow the movement of the bridge (if it's moving)
|
|
{
|
|
if ( atbridge )
|
|
{
|
|
if ( !Warp(atbridge,atbridgeofs.x,atbridgeofs.y,atbridgeofs.z,0,WARPF_ABSOLUTEOFFSET|WARPF_USECALLERANGLE|WARPF_COPYINTERPOLATION) )
|
|
deadtimer = min(deadtimer,0);
|
|
}
|
|
else deadtimer = min(deadtimer,0);
|
|
}
|
|
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?0:1].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?0:1].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) ) deadtimer = min(deadtimer,0);
|
|
}
|
|
else if ( atsector ) // attempt to follow the movement of the plane
|
|
{
|
|
SetOrigin(Vec2OffsetZ(0,0,atz+cursector.GetPlaneTexZ(atplane)),true);
|
|
if ( ceilingz-floorz <= 2 ) deadtimer = min(deadtimer,0);
|
|
}
|
|
}
|
|
if ( !InStateSequence(CurState,FindState("XDeath")) && ((!bNOGRAVITY && !Random[GES](0,2)) || !Random[GES](0,10)) )
|
|
{
|
|
int numpt = Min(20,int(Scale.x*2))+Random[GES](-1,1);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[GES](-1,1),FRandom[GES](-1,1),FRandom[GES](-1,1)).unit()*FRandom[GES](1,3);
|
|
Vector3 spos = pos;
|
|
if ( atplane == 1 ) spos += Normal*2;
|
|
let s = Spawn("BioSpark",spos);
|
|
s.vel = pvel;
|
|
}
|
|
}
|
|
if ( deadtimer <= -1 ) return;
|
|
let bi = BlockThingsIterator.Create(self,4*Scale.x);
|
|
while ( bi.Next() )
|
|
{
|
|
if ( !bi.Thing || !bi.Thing.bSHOOTABLE || (bi.Thing == b) || ((bi.Thing is 'BioHitbox') && ((bi.Thing.target.master == self) || (bi.Thing.target == master))) ) continue;
|
|
if ( (Distance2D(bi.Thing)-bi.Thing.radius <= 4*Scale.x) && ((bi.Thing.pos.z <= pos.z+4*Scale.x) && (bi.Thing.pos.z+bi.Thing.height >= pos.z-4*Scale.x)) ) deadtimer = 0;
|
|
}
|
|
if ( deadtimer-- <= 0 )
|
|
{
|
|
deadtimer = -1;
|
|
SetStateLabel("XDeath");
|
|
}
|
|
}
|
|
// align self to what surface was hit, currently does not support 3d floors + slopes properly
|
|
virtual void AlignSelf()
|
|
{
|
|
bINTERPOLATEANGLES = false;
|
|
bHITOWNER = true;
|
|
A_NoGravity();
|
|
A_Stop();
|
|
if ( bAMBUSH )
|
|
{
|
|
SetStateLabel("XDeath");
|
|
return;
|
|
}
|
|
A_SetSize(0.1,0);
|
|
if ( tracer && tracer.bACTLIKEBRIDGE )
|
|
{
|
|
atbridge = tracer;
|
|
onbridge = true;
|
|
if ( (pos.x+radius) <= (atbridge.pos.x-atbridge.radius) )
|
|
{
|
|
// west side
|
|
normal = (-1,0,0);
|
|
SetOrigin((atbridge.pos.x-atbridge.radius,pos.y,pos.z),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
angle = 180;
|
|
pitch = 0;
|
|
roll = 180; // otherwise it slides upwards (UT changes roll like this too)
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_WALL;
|
|
}
|
|
else if ( (pos.x-radius) >= (atbridge.pos.x+atbridge.radius) )
|
|
{
|
|
// east side
|
|
normal = (1,0,0);
|
|
SetOrigin((atbridge.pos.x+atbridge.radius,pos.y,pos.z),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
angle = 0;
|
|
pitch = 0;
|
|
roll = 180; // otherwise it slides upwards (UT changes roll like this too)
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_WALL;
|
|
}
|
|
else if ( (pos.y+radius) <= (atbridge.pos.y-atbridge.radius) )
|
|
{
|
|
// north side
|
|
normal = (0,-1,0);
|
|
SetOrigin((pos.x,atbridge.pos.y-atbridge.radius,pos.z),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
angle = 270;
|
|
pitch = 0;
|
|
roll = 180; // otherwise it slides upwards (UT changes roll like this too)
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_WALL;
|
|
}
|
|
else if ( (pos.y-radius) >= (atbridge.pos.y+atbridge.radius) )
|
|
{
|
|
// south side
|
|
normal = (0,1,0);
|
|
SetOrigin((pos.x,atbridge.pos.y+atbridge.radius,pos.z),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
angle = 90;
|
|
pitch = 0;
|
|
roll = 180; // otherwise it slides upwards (UT changes roll like this too)
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_WALL;
|
|
}
|
|
else if ( pos.z >= (atbridge.pos.z+atbridge.height) )
|
|
{
|
|
// top of actor
|
|
normal = (0,0,1);
|
|
SetOrigin((pos.x,pos.y,atbridge.pos.z+atbridge.height),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
pitch = -90;
|
|
angle = 0;
|
|
roll = FRandom[GES](0,360);
|
|
hittype = HIT_FLOOR;
|
|
}
|
|
else if ( (pos.z+height) <= atbridge.pos.z )
|
|
{
|
|
// bottom of actor
|
|
normal = (0,0,-1);
|
|
SetOrigin((pos.x,pos.y,atbridge.pos.z),false);
|
|
pitch = 90;
|
|
angle = 0;
|
|
roll = FRandom[GES](0,360);
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_CEILING;
|
|
}
|
|
else
|
|
{
|
|
// inside of actor, just shove to the top or bottom based on our Z velocity
|
|
if ( vel.z <= 0 )
|
|
{
|
|
normal = (0,0,1);
|
|
SetOrigin((pos.x,pos.y,atbridge.pos.z+atbridge.height),false);
|
|
atbridgeofs = pos-atbridge.pos;
|
|
pitch = -90;
|
|
angle = 0;
|
|
roll = FRandom[GES](0,360);
|
|
hittype = HIT_FLOOR;
|
|
}
|
|
else
|
|
{
|
|
normal = (0,0,-1);
|
|
SetOrigin((pos.x,pos.y,atbridge.pos.z),false);
|
|
pitch = 90;
|
|
angle = 0;
|
|
roll = FRandom[GES](0,360);
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_CEILING;
|
|
}
|
|
}
|
|
}
|
|
else if ( BlockingFloor )
|
|
{
|
|
atsector = BlockingFloor;
|
|
atplane = 0;
|
|
normal = BlockingFloor.floorplane.Normal;
|
|
pitch = asin(-normal.z);
|
|
angle = atan2(normal.y,normal.x);
|
|
roll = FRandom[GES](0,360);
|
|
SetOrigin((pos.x,pos.y,floorz)+normal*0.5,false);
|
|
atz = pos.z-BlockingFloor.GetPlaneTexZ(0);
|
|
hittype = HIT_FLOOR;
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
atsector = BlockingCeiling;
|
|
atplane = 1;
|
|
normal = BlockingCeiling.ceilingplane.Normal;
|
|
pitch = asin(-normal.z);
|
|
angle = atan2(normal.y,normal.x);
|
|
roll = FRandom[GES](0,360);
|
|
SetOrigin((pos.x,pos.y,ceilingz)+normal*0.5,false);
|
|
atz = pos.z-BlockingCeiling.GetPlaneTexZ(1);
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else if ( normal dot (0,0,-1) > 0.7 )
|
|
hittype = HIT_CEILING;
|
|
else hittype = HIT_FLOOR;
|
|
}
|
|
else if ( BlockingLine )
|
|
{
|
|
atline = BlockingLine;
|
|
normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
atside = 1;
|
|
if ( !BlockingLine.sidedef[1] || (CurSector == BlockingLine.frontsector) )
|
|
{
|
|
atside = 0;
|
|
normal *= -1;
|
|
}
|
|
Vector3 orig = (BlockingLine.v1.p.x,BlockingLine.v1.p.y,0);
|
|
Vector3 onwall = pos-(normal dot (pos-orig))*normal;
|
|
SetOrigin(onwall+normal*0.5,false);
|
|
// attempt to guess line part (upper/mid/lower)
|
|
if ( !atline.sidedef[1] ) atpart = 0; // mid
|
|
else if ( atline.sidedef[atside?0:1].sector.ceilingplane.ZAtPoint(pos.xy) < pos.z ) atpart = 1; // upper
|
|
else if ( atline.sidedef[atside?0:1].sector.floorplane.ZAtPoint(pos.xy) > pos.z ) atpart = -1; // lower
|
|
else atpart = 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?0:1].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?0:1].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);
|
|
pitch = 0;
|
|
roll = 180; // otherwise it slides upwards (UT changes roll like this too)
|
|
if ( waterlevel > 0 ) hittype = HIT_FLOOR;
|
|
else hittype = HIT_WALL;
|
|
}
|
|
else
|
|
{
|
|
SetStateLabel("XDeath");
|
|
return;
|
|
}
|
|
b = Spawn("BioHitbox",pos);
|
|
b.target = self;
|
|
A_PlaySound("ges/hit");
|
|
A_SprayDecal("BioSplat",-172);
|
|
int numpt = Min(100,int(Scale.x*10))+Random[GES](-5,5);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (normal+(FRandom[GES](-.8,.8),FRandom[GES](-.8,.8),FRandom[GES](-.8,.8))).unit()*FRandom[GES](3,6);
|
|
let s = Spawn("BioSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
}
|
|
action void A_DropDrip()
|
|
{
|
|
let d = Spawn("BioSplash",pos+invoker.normal*2*scale.x);
|
|
d.target = target;
|
|
d.angle = angle;
|
|
d.pitch = pitch;
|
|
d.roll = roll;
|
|
d.master = self;
|
|
d.scale = scale*0.5;
|
|
d.vel.z -= 6;
|
|
}
|
|
action void A_GelExplode()
|
|
{
|
|
A_NoGravity();
|
|
A_Stop();
|
|
if ( invoker.l ) invoker.l.Destroy();
|
|
if ( invoker.b ) invoker.b.Destroy();
|
|
let s = Spawn("BioXLight",pos);
|
|
s.args[3] = int(s.args[3]*Scale.x);
|
|
invoker.deadtimer = -2;
|
|
if ( invoker.atline ) invoker.atline.RemoteActivate(target,invoker.atside,SPAC_Impact,pos);
|
|
UTMainHandler.DoBlast(self,Min(175,int(Scale.x*50)),20000*Scale.x);
|
|
A_Explode(int(Random[GES](18,26)*Scale.x),Min(175,int(Scale.x*50)));
|
|
A_PlaySound("ges/explode",CHAN_VOICE);
|
|
int numpt = Min(300,int(Scale.x*30))+Random[GES](-10,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[GES](-1,1),FRandom[GES](-1,1),FRandom[GES](-1,1)).unit()*FRandom[GES](3,12);
|
|
let s = Spawn("BioSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Min(100,int(Scale.x*10))+Random[GES](-4,4);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[GES](-1,1),FRandom[GES](-1,1),FRandom[GES](-1,1)).unit()*FRandom[GES](1.2,2.4);
|
|
let s = Spawn("UTSmoke",pos+invoker.normal*4);
|
|
s.vel = pvel;
|
|
s.scale *= 2;
|
|
s.A_SetRenderStyle(0.5,STYLE_AddShaded);
|
|
if ( Random[GES](0,1) ) s.SetShade("40FF60");
|
|
else s.SetShade("60FF40");
|
|
}
|
|
Scale *= 0.5;
|
|
}
|
|
Default
|
|
{
|
|
Obituary "%o drank a glass of %k's dripping green load.";
|
|
DamageType 'Slime';
|
|
RenderStyle "Add";
|
|
Radius 3;
|
|
Height 3;
|
|
Scale 2;
|
|
Speed 11;
|
|
Gravity 0.25;
|
|
PROJECTILE;
|
|
-NOGRAVITY;
|
|
+SKYEXPLODE;
|
|
+EXPLODEONWATER;
|
|
+FORCERADIUSDMG;
|
|
+FORCEXYBILLBOARD;
|
|
+MOVEWITHSECTOR;
|
|
+NODAMAGETHRUST;
|
|
+HITTRACER;
|
|
+INTERPOLATEANGLES;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
GELF ABCDEFGHIJKLM 1 Bright;
|
|
Loop;
|
|
Death:
|
|
GELH A 1 Bright AlignSelf();
|
|
GELH BCDEFGHIJ 1 Bright;
|
|
GELH J 1 Bright A_SetTics(Random[GES](10,30));
|
|
GELH J -1 Bright
|
|
{
|
|
invoker.deadtimer = Random[GES](250,300);
|
|
if ( invoker.hittype == HIT_WALL ) return ResolveState("Slide");
|
|
else if ( invoker.hittype == HIT_CEILING ) return ResolveState("Drip");
|
|
return ResolveState(null);
|
|
}
|
|
Stop;
|
|
Drip:
|
|
GELD ABCDEFGH 4 Bright;
|
|
GELD I 4 Bright A_DropDrip();
|
|
GELD JKLM 4 Bright;
|
|
GELH J -1 Bright;
|
|
Stop;
|
|
Slide:
|
|
GELS ABCDEF 3 Bright;
|
|
GELS G -1 Bright;
|
|
Stop;
|
|
Crash:
|
|
XDeath:
|
|
TNT1 A 0 A_JumpIf(invoker.HitType==HIT_NONE,"Explode");
|
|
TNT1 A 0 A_JumpIf(invoker.HitType==HIT_WALL,2);
|
|
GELH J 1 Bright A_SetTics(Random[GES](1,3));
|
|
Goto Explode;
|
|
GELS G 1 Bright A_SetTics(Random[GES](1,3));
|
|
Goto Explode;
|
|
Explode:
|
|
TNT1 A 0 A_Jump(255,"Explode1","Explode2","Explode3");
|
|
Explode1:
|
|
GEX1 A 1 Bright A_GelExplode();
|
|
GEX1 BCDEFGHIJK 3 Bright;
|
|
Stop;
|
|
Explode2:
|
|
GEX2 A 1 Bright A_GelExplode();
|
|
GEX2 BCDEFGHIJK 3 Bright;
|
|
Stop;
|
|
Explode3:
|
|
GEX3 A 1 Bright A_GelExplode();
|
|
GEX3 BCDEFGHIJK 3 Bright;
|
|
Stop;
|
|
Shrivel:
|
|
GELX ABCDEFGHIJKL 1 Bright; // UNUSED
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BioGlob : BioGel
|
|
{
|
|
int numsplash;
|
|
|
|
override void AlignSelf()
|
|
{
|
|
Super.AlignSelf();
|
|
if ( !bAMBUSH && (Scale.x > 1) ) numsplash = int(2*Scale.x)-1;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( globalfreeze || level.frozen ) return;
|
|
Vector3 ofs = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
if ( numsplash-- <= 0 ) return;
|
|
Vector3 dir = (ofs+(FRandom[GES](-.8,.8),FRandom[GES](-.8,.8),FRandom[GES](-.8,.8))).unit();
|
|
A_SetScale(scale.x-0.15);
|
|
let d = Spawn("BioSplash",pos+ofs*4);
|
|
d.target = target;
|
|
d.master = self;
|
|
d.scale *= FRandom[GES](0.5,0.7);
|
|
d.angle = atan2(dir.y,dir.x);
|
|
d.pitch = -asin(dir.z);
|
|
d.vel = (cos(d.angle)*cos(d.pitch),sin(d.angle)*cos(d.pitch),-sin(d.pitch))*d.speed*FRandom[GES](0.4,0.6);
|
|
d.vel.z -= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
Class BioSplash : BioGel
|
|
{
|
|
override void AlignSelf()
|
|
{
|
|
Super.AlignSelf();
|
|
if ( hittype == HIT_CEILING ) hittype = HIT_FLOOR;
|
|
}
|
|
}
|
|
|
|
Class BioRifle : UTWeapon
|
|
{
|
|
double charge;
|
|
bool bCharging;
|
|
|
|
action void A_BioFire( bool alt = false )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( !alt )
|
|
{
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
}
|
|
A_PlaySound("ges/fire",CHAN_WEAPON);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(48,0,255,0),1);
|
|
A_AlertMonsters();
|
|
if ( alt ) A_QuakeEx(1+int(0.5*invoker.charge),1+int(0.5*invoker.charge),1+int(0.5*invoker.charge),5+int(1.2*invoker.charge),0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05+0.01*invoker.charge);
|
|
else A_QuakeEx(1,1,1,5,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05);
|
|
Vector3 x, y, z;
|
|
double a, s;
|
|
[x, y, z] = dt_Matrix4.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+8.0*y-5.0*z;
|
|
Actor p;
|
|
if ( alt )
|
|
{
|
|
p = Spawn("BioGlob",origin);
|
|
p.A_SetScale(1.0+invoker.charge*0.8);
|
|
UTMainHandler.DoSwing(self,(FRandom[GES](-0.6,-1.3),FRandom[GES](-0.9,-0.2)),1+invoker.charge*0.3,-0.1,3,SWING_Spring,3,2);
|
|
}
|
|
else
|
|
{
|
|
p = Spawn("BioGel",origin);
|
|
UTMainHandler.DoSwing(self,(FRandom[GES](-0.6,-1.3),FRandom[GES](-0.9,-0.2)),2,-0.5,2,SWING_Spring,2,2);
|
|
}
|
|
p.angle = angle;
|
|
p.pitch = BulletSlope();
|
|
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
|
p.target = self;
|
|
for ( int i=0; i<12; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,4,-3);
|
|
s.scale *= 2.0;
|
|
s.target = self;
|
|
if ( Random[GES](0,1) ) s.SetShade("40FF60");
|
|
else s.SetShade("60FF40");
|
|
s.A_SetRenderStyle(0.5,STYLE_AddShaded);
|
|
UTViewSmoke(s).vvel += (FRandom[GES](0.8,1.6),FRandom[GES](-0.5,0.5),FRandom[GES](-0.5,0.5));
|
|
}
|
|
}
|
|
action void A_BeginCharge()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
invoker.charge = 0;
|
|
A_PlaySound("ges/charge",CHAN_WEAPON);
|
|
invoker.bCharging = true;
|
|
}
|
|
action void A_ChargeUp()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
UTMainHandler.DoSwing(self,(FRandom[GES](-1,1),FRandom[GES](-1,1)),0.02*invoker.charge,0,5,SWING_Spring,0,2);
|
|
if ( invoker.charge >= 5.1 ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
invoker.charge = min(5.1,invoker.charge+0.5);
|
|
}
|
|
override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount )
|
|
{
|
|
if ( bCharging ) return true;
|
|
return Super.CheckAmmo(fireMode,autoSwitch,requireAmmo,ammocount);
|
|
}
|
|
Default
|
|
{
|
|
Tag "GES Bio Rifle";
|
|
Inventory.PickupMessage "You got the GES BioRifle.";
|
|
Weapon.UpSound "ges/select";
|
|
Weapon.SlotNumber 3;
|
|
Weapon.SelectionOrder 7;
|
|
Weapon.AmmoType "BioAmmo";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "BioAmmo";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 25;
|
|
UTWeapon.DropAmmo 5;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BIOP A -1;
|
|
Stop;
|
|
BIOP B -1;
|
|
Stop;
|
|
Ready:
|
|
BIOS ABCDEFGHIJKLMNOPQRSTUV 1 A_WeaponReady(WRF_NOFIRE);
|
|
Idle:
|
|
BIOI A 1
|
|
{
|
|
invoker.bCharging = false;
|
|
A_CheckReload();
|
|
A_WeaponReady();
|
|
}
|
|
Goto Idle;
|
|
Fire:
|
|
BIOF A 1 A_BioFire();
|
|
BIOF BCDEFGHI 1;
|
|
Goto Idle;
|
|
AltCheck:
|
|
TNT1 A 1;
|
|
TNT1 A 0 A_JumpIf(player.cmd.buttons&BT_ALTATTACK,"AltCheck");
|
|
TNT1 A 0 A_Overlay(PSP_WEAPON,"AltRelease");
|
|
TNT1 A 1;
|
|
Wait;
|
|
AltFire:
|
|
BIOC A 0 A_Overlay(-9999,"AltCheck");
|
|
BIOC A 4 A_BeginCharge();
|
|
BIOC B 5 A_ChargeUp();
|
|
BIOC CD 5;
|
|
BIOC E 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC E 5 A_ChargeUp();
|
|
BIOC FG 5;
|
|
BIOC H 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC H 5 A_ChargeUp();
|
|
BIOC IJ 5;
|
|
BIOC K 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC K 5 A_ChargeUp();
|
|
BIOC LM 5;
|
|
BIOC N 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC N 5 A_ChargeUp();
|
|
BIOC OP 5;
|
|
BIOC Q 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC Q 5 A_ChargeUp();
|
|
BIOC RS 5;
|
|
BIOC T 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC T 5 A_ChargeUp();
|
|
BIOC UV 5;
|
|
BIOC W 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC W 5 A_ChargeUp();
|
|
BIOC XY 5;
|
|
BIOC Z 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIOC Z 5 A_ChargeUp();
|
|
BIC2 AB 5;
|
|
BIC2 C 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
BIC2 C 5 A_ChargeUp();
|
|
BIC2 DE 5;
|
|
BIOM A 0 A_Refire(1);
|
|
Goto AltRelease;
|
|
AltHeld:
|
|
BIOM A 1;
|
|
BIOM A 0 A_Refire("AltHeld");
|
|
AltRelease:
|
|
BIOE A 1
|
|
{
|
|
invoker.charge = min(5.1,invoker.charge+0.1);
|
|
A_Overlay(-9999,null);
|
|
A_WeaponOffset(0,32); // fix sudden psprite lowering
|
|
}
|
|
BIOF A 2 A_BioFire(true);
|
|
BIOF BCDEFGHI 2;
|
|
Goto Idle;
|
|
Select:
|
|
BIOS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Deselect:
|
|
BIOD ABCDEFGHIJ 1;
|
|
BIOD J 1 A_Lower(int.max);
|
|
Wait;
|
|
}
|
|
}
|