stinger_m/zscript/razorjack.zsc
Marisa Kirisame fae4f6d50b Partially implemented Stunner and Impaler (very unfinished).
Switched Impaler fire sound to something more appropriate (proto Skaarj fire).
Add slot priorities to all weapons, final weapons come first.
Adjust hud behavior to properly draw ammo bars by the order of their weapons.
2019-09-16 00:38:38 +02:00

316 lines
7.8 KiB
Text

Class RazorAmmo : Ammo
{
Default
{
Tag "$T_RIPPERAMMO";
Inventory.Icon "I_RazorA";
Inventory.PickupMessage "$I_RIPPERAMMO";
Inventory.Amount 25;
Inventory.MaxAmount 75;
Ammo.BackpackAmount 20;
Ammo.BackpackMaxAmount 150;
Ammo.DropAmount 15;
}
States
{
Spawn:
BHOP A 8 A_CheckProximity(1,"PlayerPawn",80,1,CPXF_ANCESTOR|CPXF_CHECKSIGHT);
Wait;
BHOP AA 16;
BHOP B 8 A_CheckProximity(1,"PlayerPawn",80,0,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_EXACT);
Goto Spawn+3;
BHOP BB 16;
Goto Spawn;
}
}
Class RazorBlade : Actor
{
Vector3 gvel, accel;
double oldgangle, gangle, oldgpitch, gpitch;
Default
{
Radius 2;
Height 2;
Speed 25;
DamageFunction (int((30+special1*5)*((DamageType=='Decapitated')?3.5:1.0)));
DamageType 'Shredded';
Obituary "$O_RAZORJACK";
BounceType "Hexen";
ReactionTime 5;
BounceFactor 1.0;
WallBounceFactor 1.0;
PROJECTILE;
+USEBOUNCESTATE;
+SKYEXPLODE;
+CANBOUNCEWATER;
+NODAMAGETHRUST;
+DONTBOUNCEONSHOOTABLES;
+ROLLSPRITE;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let t = Spawn("RazorBladeTrail",pos);
t.target = self;
frame = special1;
if ( special1 > 0 )
{
vel *= 1.+.06+special1;
A_PlaySound("ripper/hum",CHAN_VOICE,1.0,true,3.0,pitch:3.125+special1*.2);
}
else A_PlaySound("ripper/hum",CHAN_VOICE,1.0,true,3.0,pitch:3.125);
Vector3 dir = vel.unit();
A_SetAngle(atan2(dir.y,dir.x));
A_SetPitch(asin(-dir.z));
frame = 0;
gvel = vel;
oldgangle = gangle = angle;
oldgpitch = gpitch = pitch;
}
override int SpecialMissileHit( Actor victim )
{
if ( pos.z > victim.pos.z+victim.height*0.81 ) DamageType = 'Decapitated';
return -1;
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( !target.bNOBLOOD )
{
target.SpawnBlood(pos,AngleTo(target),damage);
A_PlaySound("ripper/flesh");
A_AlertMonsters();
}
UTMainHandler.DoKnockback(target,vel.unit(),15000);
return damage;
}
void A_RazorAltOrient()
{
if ( !bAMBUSH || !target || !target.player || (target.Health <= 0) ) return;
if ( sting_razoraim )
{
FLineTraceData d;
target.LineTrace(target.angle,10000,target.pitch,0,target.player.viewheight,data:d);
Vector3 SeekingDir = level.Vec3Diff(pos,d.HitLocation).unit();
double MagnitudeVel = Vel.length();
SeekingDir = (SeekingDir*0.1*MagnitudeVel+Vel).unit();
vel = MagnitudeVel * SeekingDir;
accel = SeekingDir * 25.;
vel += accel/TICRATE;
vel = vel.unit()*clamp(MagnitudeVel,10,15);
}
else
{
double dangle, dpitch;
dangle = deltaangle(oldgangle,target.angle);
dpitch = deltaangle(oldgpitch,target.pitch);
gangle += dangle;
gpitch += dpitch;
vel += (cos(gangle)*cos(gpitch),sin(gangle)*cos(gpitch),-sin(gpitch))*15./TICRATE;
double spd = vel.length();
vel = vel*clamp(spd,10,15)/spd;
gvel = vel;
oldgangle = target.angle;
oldgpitch = target.pitch;
}
Vector3 dir = vel.unit();
A_SetAngle(atan2(dir.y,dir.x));
A_SetPitch(asin(-dir.z));
}
action void A_RazorHit()
{
A_PlaySound("ripper/hit");
A_AlertMonsters();
A_SprayDecal("WallCrack",-20);
int numpt = Random[Ripper](5,10);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (-x+(FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8))).unit()*FRandom[Ripper](0.1,1.2);
let s = Spawn("UTSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[Ripper](128,192));
}
numpt = Random[Ripper](4,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[Ripper](4,8);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
let s = Spawn("UTChip",pos);
s.vel = pvel;
}
}
States
{
Spawn:
RAZB # 1 A_RazorAltOrient();
Wait;
Bounce:
RAZB # 0
{
bHITOWNER = true; // technically the Unreal version sets this 0.2 seconds after being fired, but this works better
Vector3 dir = vel.unit();
A_SetAngle(atan2(dir.y,dir.x));
A_SetPitch(asin(-dir.z));
A_RazorHit();
A_CountDown();
}
Goto Spawn;
Death:
TNT1 A 1 A_StopSound(CHAN_VOICE);
Stop;
}
}
Class RazorBladeTrail : Actor
{
Default
{
RenderStyle "Add";
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+NOTELEPORT;
Radius 0.1;
Height 0;
}
override void Tick()
{
if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
{
A_RemoveLight('RazorLight');
Destroy();
return;
}
SetOrigin(target.pos,true);
angle = target.angle;
pitch = target.pitch;
roll = target.roll;
alpha = min(target.vel.length()/target.speed,1.);
A_AttachLight('RazorLight',DynamicLight.PointLight,Color(2,0,3)*int(80*alpha),80,80);
}
States
{
Spawn:
RAZB A -1 Bright;
Stop;
}
}
Class Razorjack : UnrealWeapon
{
action void A_RazorFire( bool bAlt = false )
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
if ( self is 'UTPlayer' )
UTPlayer(self).PlayAttacking3();
A_PlaySound("ripper/fire",CHAN_WEAPON,pitch:bAlt?1.:(1.+invoker.special1*.1));
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(16,255,0,255),1);
A_AlertMonsters();
A_QuakeEx(1,1,1,5,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
if ( bAlt ) UTMainHandler.DoSwing(self,(FRandom[Ripper](-0.6,-0.3),FRandom[Ripper](0.2,0.4)),1,-0.3,2,SWING_Spring,2,2);
else UTMainHandler.DoSwing(self,(FRandom[Ripper](-0.3,0.3),FRandom[Ripper](0.2,0.6)),1,-0.3,2,SWING_Spring,2,2);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = Vec2OffsetZ(0,0,player.viewz);
if ( bAlt ) origin = level.Vec3Offset(origin,x*10-y*4-z*5);
else origin = level.Vec3Offset(origin,x*10-z*9);
Actor p;
p = Spawn("RazorBlade",origin);
if ( bAlt )
{
p.roll = 70;
p.bAMBUSH = true;
}
else p.special1 = invoker.special1;
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;
}
Default
{
Tag "$T_RAZORJACK";
Inventory.PickupMessage "$I_RAZORJACK";
Weapon.UpSound "ripper/select";
Weapon.SlotNumber 7;
Weapon.SelectionOrder 7;
Weapon.SlotPriority 1;
Weapon.AmmoType "RazorAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "RazorAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 15;
UTWeapon.DropAmmo 10;
}
States
{
Spawn:
RZRP A -1;
Stop;
RZRP B -1;
Stop;
Select:
RZRS A 1 A_Raise(int.max);
Wait;
Ready:
RZRS ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_WeaponReady(WRF_NOFIRE);
RZS2 ABCD 1 A_WeaponReady(WRF_NOFIRE);
Idle:
RZRI ABCDEFGHIJKLMNOPQRSUVWXYZ 2
{
A_CheckReload();
A_WeaponReady();
}
RZI2 ABCDE 2
{
A_CheckReload();
A_WeaponReady();
}
Loop;
Fire:
RZRI A 0
{
invoker.special1 = 0;
return A_JumpIf(sting_razor,"ChargeUp");
}
Release:
RZRF A 0 A_RazorFire();
RZRF ABCDEFGH 2;
Goto Idle;
ChargeUp:
RZRI ABCDEFGHIJKLMNOPQRSUVWXYZ 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZI2 ABCDE 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZRI A 0 { invoker.special1 = 1; }
RZRI ACEGIKMOQSVXZ 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZI2 BD 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZRI A 0 { invoker.special1 = 2; }
RZRI ADGJMPSWZ 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZI2 C 1 A_JumpIf(!(player.cmd.buttons&BT_ATTACK),"Release");
RZRI A 0 { invoker.special1 = 3; }
Goto Release;
AltFire:
RZRA ABCDEFGHIJKL 1;
AltHold:
RZRA M 0 A_RazorFire(true);
RZRA MNOP 4;
RZRA Q 0 A_ReFire("AltHold");
RZRA QRSTU 2;
Goto Idle;
Deselect:
RZRD ABCDEF 1;
RZRD F 1 A_Lower(int.max);
Wait;
}
}