flak_m/zscript/ripper.zsc
Marisa the Magician e8b9a55378 4.10 support:
- CORRECTPIXELSTRETCH where needed on models.
 - Replace CoordUtil.GetAxes with quaternion version.
2022-12-05 16:57:15 +01:00

303 lines
6.7 KiB
Text

Class RipperAmmo : Ammo
{
Default
{
Tag "$T_RIPPERAMO";
Inventory.PickupMessage "$I_RIPPERAMMO";
Inventory.Amount 10;
Inventory.MaxAmount 40;
Ammo.BackpackAmount 5;
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;
+NOFRICTION;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let t = Spawn("Razor2Trail",pos);
t.target = self;
A_StartSound("ripper/hum",CHAN_VOICE,CHANF_LOOPING,1.,3.,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_StartSound("ripper/flesh");
A_AlertMonsters();
}
UTMainHandler.DoKnockback(target,vel.unit(),15000);
return damage;
}
action void A_RazorHit()
{
A_StartSound("ripper/hit");
A_AlertMonsters();
A_SprayDecal("WallCrack",-20);
int numpt = Random[Ripper](5,10);
Vector3 x = dt_Utility.Vec3FromAngle(angle,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 A_RazorHit();
XDeath:
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_StartSound("ripper/althit",CHAN_VOICE);
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 = dt_Utility.Vec3FromAngle(angle,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;
UTWeapon.NameColor "00 FF FF";
}
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_StartSound("ripper/altfire",CHAN_WEAPON,CHANF_OVERLAP);
else A_StartSound("ripper/fire",CHAN_WEAPON,CHANF_OVERLAP);
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] = dt_Utility.GetAxes(angle,pitch,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 = dt_Utility.Vec3FromAngle(p.angle,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;
}
}