flak_m/zscript/ripper.zsc
Marisa Kirisame fb96c7523e Portal awareness adjustments to various vector operations.
Got rid of the deprecated Matrix4.GetAxes method. Next step is to get rid of more stuff by migrating to libeye.
Mirrored Translocator model so it shows the actually detailed side. At some point in UT's development it got flipped around for some reason.
Weapon code cleanup (most noticeable on states).
Backported scope shader from Doomreal.
Added optional "dummied out" Sniper zoom sounds from a dubious source.
2019-09-28 20:06:51 +02:00

307 lines
6.9 KiB
Text

Class RipperAmmo : Ammo
{
Default
{
Tag "$T_RIPPERAMO";
Inventory.PickupMessage "$I_RIPPERAMMO";
Inventory.Amount 10;
Inventory.MaxAmount 40;
Ammo.BackpackAmount 20;
Ammo.BackpackMaxAmount 80;
Ammo.DropAmount 5;
}
States
{
Spawn:
BHOP A -1;
Stop;
}
}
Class Razor2Trail : 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")) )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
angle = target.angle;
pitch = target.pitch;
alpha = target.vel.length()/target.speed;
}
States
{
Spawn:
RAZB A -1 Bright;
Stop;
}
}
Class Razor2 : Actor
{
Default
{
Radius 2;
Height 2;
Speed 25;
DamageFunction (int(30*((DamageType=='Decapitated')?3.5:1.0)));
DamageType 'Shredded';
Obituary "$O_RIPPER";
BounceType "Hexen";
ReactionTime 7;
BounceFactor 1.0;
WallBounceFactor 1.0;
PROJECTILE;
+USEBOUNCESTATE;
+SKYEXPLODE;
+CANBOUNCEWATER;
+NODAMAGETHRUST;
+DONTBOUNCEONSHOOTABLES;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let t = Spawn("Razor2Trail",pos);
t.target = self;
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));
}
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;
}
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 A -1;
Stop;
Bounce:
RAZB A 0
{
bHITOWNER = true; // technically the UT 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 Razor2AltLight : PaletteLight
{
Default
{
Args 0,0,0,90;
ReactionTime 20;
}
}
Class Razor2Alt : Razor2
{
Default
{
BounceType "None";
-CANBOUNCEWATER;
+EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
}
action void A_RazorExplode()
{
A_SetRenderStyle(1.0,STYLE_Add);
bFORCEXYBILLBOARD = true;
Scale *= 0.65;
A_StopSound(CHAN_VOICE);
A_PlaySound("ripper/althit");
Spawn("Razor2AltLight",pos);
A_AlertMonsters();
A_SprayDecal("RazorBlast",20);
UTMainHandler.DoBlast(self,90,87000);
A_Explode(34,90,damagetype:'RipperAltDeath');
A_QuakeEx(3,3,3,10,0,140,"",QF_RELATIVE|QF_SCALEDOWN,falloff:90,rollIntensity:0.1);
int numpt = Random[Ripper](10,20);
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](8,16);
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](8,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("UTChip",pos);
s.vel = pvel;
}
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
return damage;
}
override int SpecialMissileHit( Actor victim )
{
return -1;
}
States
{
Death:
XDeath:
TNT1 A 0 A_RazorExplode();
RIPX ABCDEFG 2 Bright;
Stop;
}
}
Class Ripper2 : UTWeapon
{
Default
{
Tag "$T_RIPPER";
Inventory.PickupMessage "$I_RIPPER";
Weapon.UpSound "ripper/select";
Weapon.SlotNumber 6;
Weapon.SelectionOrder 4;
Weapon.AmmoType "RipperAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "RipperAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 10;
UTWeapon.DropAmmo 5;
}
action void A_RazorFire( bool alt = false )
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
if ( alt ) A_PlaySound("ripper/altfire",CHAN_WEAPON);
else A_PlaySound("ripper/fire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(8,0,255,255),1);
A_AlertMonsters();
if ( alt )
{
A_QuakeEx(3,3,3,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
UTMainHandler.DoSwing(self,(FRandom[Ripper](-0.3,-0.6),FRandom[Ripper](0.2,0.6)),3,-0.5,3,SWING_Spring,5,4);
}
else
{
A_QuakeEx(1,1,1,5,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
UTMainHandler.DoSwing(self,(FRandom[Ripper](-0.3,-0.6),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 = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+6*y-4*z);
Actor p;
if ( alt ) p = Spawn("Razor2Alt",origin);
else p = Spawn("Razor2",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;
}
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 ABCDEFGHIJKLMNOPQRS 2
{
A_CheckReload();
A_WeaponReady();
}
Loop;
Fire:
RZRF A 0 A_RazorFire();
RZRF ABCDEFGHIJKLMNO 1;
Goto Idle;
AltFire:
RZRF A 0 A_RazorFire(true);
RZRF ABCDEFG 3;
RZRF HIJKLMNO 1;
Goto Idle;
Deselect:
RZRD ABCDEF 1;
RZRD F 1 A_Lower(int.max);
Wait;
}
}