flak_m/zscript/biorifle.zsc

684 lines
No EOL
16 KiB
Text

Class Tier3Ammo : RandomSpawner2 replaces Shell
{
Default
{
DropItem "BioAmmo", 255, 1;
DropItem "ShockAmmo", 255, 1;
}
}
Class Tier3Ammo2 : Tier3Ammo replaces ShellBox {}
Class Tier3Weapon : RandomSpawner2 replaces Shotgun
{
Default
{
DropItem "BioRifle", 255, 1;
DropItem "ShockRifle", 255, 1;
}
}
Class Tier3Weapon2 : Tier3Weapon replaces SuperShotgun {}
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 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.04;
}
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] = 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] = 64*lifetime;
args[LIGHT_GREEN] = 255*lifetime;
args[LIGHT_BLUE] = 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;
int rollvel, pitchvel, yawvel;
Vector3 normal;
override void PostBeginPlay()
{
Super.PostBeginPlay();
vel.z += 6;
deadtimer = -1;
l = Spawn("BioLight",pos);
l.target = self;
b = Spawn("BioHitbox",pos);
b.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 )
{
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE);
A_SetPitch(pitch+yawvel,SPF_INTERPOLATE);
if ( waterlevel > 0 )
{
vel.xy *= 0.98;
rollvel *= 0.98;
pitchvel *= 0.98;
yawvel *= 0.98;
}
}
if ( deadtimer > -2 )
{
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,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);
let s = Spawn("BioSpark",pos);
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()
{
A_NoGravity();
A_Stop();
if ( bAMBUSH )
{
SetStateLabel("XDeath");
return;
}
FLineTraceData d;
A_SetSize(0.1,0);
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 if ( pos.z <= floorz+4 )
{
atsector = cursector;
atplane = 0;
normal = cursector.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-cursector.GetPlaneTexZ(0);
hittype = HIT_FLOOR;
}
else if ( pos.z >= ceilingz-8 )
{
atsector = cursector;
atplane = 1;
normal = cursector.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-cursector.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
{
SetStateLabel("XDeath");
return;
}
A_PlaySound("ges/hit");
A_SprayDecal("BioSplat",-172);
int numpt = Min(100,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] *= Scale.x;
invoker.deadtimer = -2;
if ( invoker.atline ) invoker.atline.RemoteActivate(target,invoker.atside,SPAC_Impact,pos);
A_Explode(Random[GES](20,40)*Scale.x,Min(150,Scale.x*25));
A_PlaySound("ges/explode",CHAN_VOICE);
int numpt = Min(300,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,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';
DamageFunction Random[GES](20,40)*Scale.x;
RenderStyle "Add";
Radius 3;
Height 3;
Scale 2;
Speed 18;
ProjectileKickback 220;
PROJECTILE;
-NOGRAVITY;
+SKYEXPLODE;
+EXPLODEONWATER;
+FORCERADIUSDMG;
+FORCEXYBILLBOARD;
+MOVEWITHSECTOR;
}
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 ) numsplash = 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();
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.25,0.35);
d.vel.z -= 3;
}
}
}
Class BioSplash : BioGel
{
override void AlignSelf()
{
Super.AlignSelf();
if ( hittype == HIT_CEILING ) hittype = HIT_FLOOR;
}
}
Class BioRifle : UTWeapon
{
double charge;
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+0.5*invoker.charge,1+0.5*invoker.charge,1+0.5*invoker.charge,5+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] = 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.8*invoker.charge);
}
else p = Spawn("BioGel",origin);
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);
}
action void A_ChargeUp()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
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);
}
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;
}
States
{
Spawn:
BIOP A -1;
Stop;
BIOP B -1;
Stop;
Ready:
BIOS ABCDEFGHIJKLMNOPQRSTUV 1 A_WeaponReady(WRF_NOFIRE);
Idle:
BIOI A 1
{
A_CheckReload();
A_WeaponReady();
}
Goto Idle;
Fire:
BIOF A 1 A_BioFire();
BIOF BCDEFGHI 1;
Goto Idle;
AltFire:
BIOC A 4 A_BeginCharge();
BIOC B 5 A_ChargeUp();
BIOC CD 5;
BIOC E 0 A_Refire("AltFire2");
Goto AltRelease;
AltFire2:
BIOC E 5 A_ChargeUp();
BIOC FG 5;
BIOC H 0 A_Refire("AltFire3");
Goto AltRelease;
AltFire3:
BIOC H 5 A_ChargeUp();
BIOC IJ 5;
BIOC K 0 A_Refire("AltFire4");
Goto AltRelease;
AltFire4:
BIOC K 5 A_ChargeUp();
BIOC LM 5;
BIOC N 0 A_Refire("AltFire5");
Goto AltRelease;
AltFire5:
BIOC N 5 A_ChargeUp();
BIOC OP 5;
BIOC Q 0 A_Refire("AltFire6");
Goto AltRelease;
AltFire6:
BIOC Q 5 A_ChargeUp();
BIOC RS 5;
BIOC T 0 A_Refire("AltFire7");
Goto AltRelease;
AltFire7:
BIOC T 5 A_ChargeUp();
BIOC UV 5;
BIOC W 0 A_Refire("AltFire8");
Goto AltRelease;
AltFire8:
BIOC W 5 A_ChargeUp();
BIOC XY 5;
BIOC Z 0 A_Refire("AltFire9");
Goto AltRelease;
AltFire9:
BIOC Z 5 A_ChargeUp();
BIC2 AB 5;
BIC2 C 0 A_Refire("AltFire10");
Goto AltRelease;
AltFire10:
BIC2 C 5 A_ChargeUp();
BIC2 DE 5;
BIOM A 0 A_Refire("AltHeld");
Goto AltRelease;
AltHeld:
BIOM A 5 { invoker.charge = min(5.1,invoker.charge+0.1); }
BIOM A 0 A_Refire("AltHeld");
AltRelease:
BIOE A 1;
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;
}
}