flak_m/zscript/ripper.zsc
Marisa Kirisame 1c0f7d08a5 Various rebalances. Corrected some things that weren't 1:1 with UT.
Restored original flak chunk damage function (no longer falls off with distance).
Fixed the minigun altfire shooting bullets at the same speed as the primary fire.
Small hackaround for janky player movement while moving down slopes.
[WIP] The very beginning of an UT gore system (toggleable).
2018-09-05 18:56:04 +02:00

323 lines
7.2 KiB
Text

Class RipperAmmo : Ammo
{
Default
{
Tag "Razor Blades";
Inventory.PickupMessage "You picked up Razor Blades.";
Inventory.Amount 25;
Inventory.MaxAmount 75;
Ammo.BackpackAmount 50;
Ammo.BackpackMaxAmount 150;
Ammo.DropAmount 10;
}
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);
A_SetAngle(target.angle,SPF_INTERPOLATE);
A_SetPitch(target.pitch,SPF_INTERPOLATE);
A_SetRoll(target.roll,SPF_INTERPOLATE);
alpha = target.vel.length()/target.speed;
}
States
{
Spawn:
RAZB A -1 Bright;
Stop;
}
}
Class Razor2 : Actor
{
Default
{
Radius 2;
Height 2;
Speed 27;
DamageFunction (Random[Ripper](25,35)*((DamageType=='Decapitated')?3.5:1.0));
DamageType 'Shredded';
Obituary "%k ripped a chunk of meat out of %o with the Ripper.";
BounceType "Doom";
ReactionTime 7;
BounceFactor 1.0;
WallBounceFactor 1.0;
PROJECTILE;
+USEBOUNCESTATE;
-BOUNCEAUTOOFF;
+SKYEXPLODE;
+CANBOUNCEWATER;
+NODAMAGETHRUST;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let t = Spawn("Razor2Trail",pos);
t.target = self;
A_PlaySound("ripper/hum",CHAN_VOICE,1.0,true,3.0);
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 0
{
angle += 180;
pitch *= -1;
A_RazorHit();
}
XDeath:
TNT1 A 1 A_StopSound(CHAN_VOICE);
Stop;
}
}
Class Razor2AltLight : DynamicLight
{
double lifetime;
Default
{
DynamicLight.Type "Point";
Args 255,240,224,90;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
lifetime = 1.0;
}
override void Tick()
{
Super.Tick();
if ( globalfreeze || level.frozen ) return;
args[LIGHT_RED] = int(255*lifetime);
args[LIGHT_GREEN] = int(240*lifetime);
args[LIGHT_BLUE] = int(224*lifetime);
lifetime -= 0.05;
if ( lifetime <= 0 ) Destroy();
}
}
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(Random[Ripper](30,50),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 "Ripper";
Inventory.PickupMessage "You got the 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 15;
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);
else A_QuakeEx(1,1,1,5,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
Vector3 x, y, z;
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+6.0*y-4.0*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 ABDEGHIJKLMNO 1;
Goto Idle;
AltFire:
RZRF A 0 A_RazorFire(true);
RZRF ABDEG 3;
RZRF HIJKLMNO 1;
Goto Idle;
Deselect:
RZRD ABCDEF 1;
RZRD F 1 A_Lower(int.max);
Wait;
}
}