- Various fixes for the Combined Patch. - Some safeguards for force field and sentries so they don't bug the hell out if receiving crushing or ice damage.
342 lines
8.1 KiB
Text
342 lines
8.1 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 15;
|
|
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*10)*((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("razorjack/hum",CHAN_VOICE,1.0,true,3.0,pitch:3.125+special1*.2);
|
|
}
|
|
else A_PlaySound("razorjack/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("razorjack/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("razorjack/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 0 A_RazorHit();
|
|
XDeath:
|
|
TNT1 A 1 A_StopSound(CHAN_VOICE);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class RazorLight : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
Args 160, 0, 240, 40;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
Args[0] = int(160*target.alpha);
|
|
Args[2] = int(240*target.alpha);
|
|
SetOrigin(target.pos,true);
|
|
}
|
|
}
|
|
|
|
Class RazorBladeTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
Radius 0.1;
|
|
Height 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
let l = Spawn("RazorLight",pos);
|
|
l.target = self;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
angle = target.angle;
|
|
pitch = target.pitch;
|
|
roll = target.roll;
|
|
alpha = min(target.vel.length()/target.speed,1.);
|
|
}
|
|
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("razorjack/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 "razorjack/select";
|
|
Weapon.SlotNumber 7;
|
|
Weapon.SelectionOrder 1500;
|
|
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;
|
|
}
|
|
}
|