stinger_m/zscript/peacemaker.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

533 lines
13 KiB
Text

Class PeaceAmmo : Ammo
{
Default
{
Inventory.Icon "I_Peace";
Inventory.Amount 1;
Inventory.MaxAmount 1;
Ammo.BackpackAmount 0;
Ammo.BackpackMaxAmount 2;
}
}
Class PeaceTrail : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+NOTELEPORT;
Scale 0.25;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_AttachLight('RocketLight',DynamicLight.PointLight,Color(255,128,112),32,32);
}
override void Tick()
{
Super.Tick();
if ( !target || !target.bMISSILE )
{
A_RemoveLight('RocketLight');
Destroy();
return;
}
Vector3 dir = (cos(target.angle)*cos(target.pitch),sin(target.angle)*cos(target.pitch),-sin(target.pitch));
SetOrigin(level.Vec3Offset(target.pos,-dir*3),true);
}
States
{
Spawn:
PFLA A -1 Bright;
Stop;
}
}
Class PeaceRocket : Actor
{
Vector3 Acceleration;
int ticcnt;
Default
{
Obituary "$O_PEACE";
DamageType 'PeaceDeath';
Radius 2;
Height 2;
Speed 3.5;
PROJECTILE;
+SKYEXPLODE;
+EXPLODEONWATER;
+SEEKERMISSILE;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
+INTERPOLATEANGLES;
+HITOWNER;
ReactionTime 9;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("PeaceTrail",pos);
l.target = self;
A_PlaySound("peace/fly",CHAN_VOICE,1.0,true,2.5,pitch:0.8);
Acceleration = vel*1.67;
}
action void A_CheckForTargets()
{
let bi = BlockThingsIterator.Create(self,500);
double mindist = double.infinity;
while ( bi.Next() )
{
if ( !bi.Thing || (!bi.Thing.bISMONSTER && !bi.Thing.player) || (bi.Thing.Health <= 0) || (Distance3D(bi.Thing) > 500) || !CheckSight(bi.Thing) ) continue;
double dist = Distance3D(bi.Thing);
if ( dist > mindist ) break;
tracer = bi.Thing;
mindist = dist;
}
}
action void A_SeekTargets()
{
if ( !tracer || (tracer.Health <= 0) ) return;
double mag = vel.length();
vel = mag*(level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2)).unit()*mag*6./TICRATE+vel).unit();
}
action void A_PeaceExplode()
{
bFORCEXYBILLBOARD = true;
A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("RocketBlast",50);
A_NoGravity();
A_SetScale(1.1);
UTMainHandler.DoBlast(self,200,70000);
A_Explode(100,200);
A_QuakeEx(3,3,3,8,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:0.2);
A_PlaySound("utrl/explode",CHAN_VOICE);
A_AlertMonsters();
Spawn("RocketExplLight",pos);
int numpt = Random[Peace](15,30);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Peace](-1,1),FRandom[Peace](-1,1),FRandom[Peace](-1,1)).unit()*FRandom[Peace](1,3);
let s = Spawn("UTSmoke",pos);
s.vel = pvel;
}
numpt = Random[Peace](10,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Peace](-1,1),FRandom[Peace](-1,1),FRandom[Peace](-1,1)).unit()*FRandom[Peace](2,6);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[Peace](35,70);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Peace](-1,1),FRandom[Peace](-1,1),FRandom[Peace](-1,1)).unit()*FRandom[Peace](2,12);
let s = Spawn("UTChip",pos);
s.vel = pvel;
s.scale *= FRandom[Peace](0.9,2.7);
}
}
States
{
Spawn:
PEAR A 1
{
roll += 5.;
A_SeekTargets();
vel += Acceleration/TICRATE;
double mag = vel.length();
if ( mag > 0. )
{
Vector3 dir = vel/mag;
if ( mag > 16 ) vel = vel.unit()*16;
angle = atan2(dir.y,dir.x);
pitch = asin(-dir.z);
mag = Acceleration.length();
Acceleration = dir*mag;
}
for ( int i=0; i<3; i++ )
{
let s = Spawn("UTSmoke",pos);
s.vel = (FRandom[Peace](-0.2,0.2),FRandom[Peace](-0.2,0.2),FRandom[Peace](-0.2,0.2));
s.vel += vel*0.1;
s.SetShade(Color(1,1,1)*Random[Peace](32,48));
}
special1++;
if ( special1 > 35 )
{
special1 = 0;
A_CheckForTargets();
A_CountDown();
}
}
Wait;
Death:
TNT1 A 0 A_PeaceExplode();
SSMX ABCDEFGHIJ 2 Bright;
Stop;
}
}
Class PeaceFragment : SentryFragment
{
Default
{
Scale 0.5;
}
}
Class PeaceBarrel : Actor
{
action void A_AlignSelf()
{
// find closest 3d floor for its normal
F3DFloor ff = null;
for ( int i=0; i<floorsector.Get3DFloorCount(); i++ )
{
if ( !(floorsector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = floorsector.Get3DFLoor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.top.Normal;
else normal = floorsector.floorplane.Normal;
// bless Gutawer
Vector2 angv = (cos(angle),sin(angle));
Vector3 x;
if ( ff ) x = (angv,ff.top.ZAtPoint(pos.xy+angv)-pos.z).unit();
else x = (angv,floorsector.floorplane.ZAtPoint(pos.xy+angv)-pos.z).unit();
pitch = -asin(x.z);
roll = asin(normal.x*angv.y-normal.y*angv.x);
}
action void A_FireRocket( int n )
{
A_PlaySound("flak/altfire",CHAN_AUTO);
A_AlertMonsters();
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 dir = z*1.3;
Vector3 origin;
switch ( n )
{
case 0:
// front right
dir = (dir+x+y).unit();
origin = level.Vec3Offset(pos,z*4+x*4+y*4);
break;
case 1:
// front left
dir = (dir-x+y).unit();
origin = level.Vec3Offset(pos,z*4-x*4+y*4);
break;
case 2:
// back right
dir = (dir+x-y).unit();
origin = level.Vec3Offset(pos,z*4+x*4-y*4);
break;
case 3:
// back left
dir = (dir-x-y).unit();
origin = level.Vec3Offset(pos,z*4-x*4-y*4);
break;
}
let r = Spawn("PeaceRocket",origin);
r.angle = atan2(dir.y,dir.x);
r.pitch = asin(-dir.z);
r.vel = dir*r.speed;
r.target = target;
}
action void A_BlowUp()
{
bFORCEXYBILLBOARD = true;
SetOrigin(Vec3Offset(0,0,16),false);
A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("RocketBlast",50);
A_NoGravity();
A_SetScale(bAMBUSH?1.8:1.2);
A_Explode(bAMBUSH?500:125,bAMBUSH?200:100);
A_PlaySound("sentry/explode",CHAN_BODY,pitch:0.6);
A_PlaySound("utrl/explode",CHAN_VOICE,pitch:0.8);
A_AlertMonsters();
A_QuakeEx(4,4,4,10,0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:0.2);
UTMainHandler.DoBlast(self,bAMBUSH?200:100,50000);
double ang, pt;
for ( int i=0; i<16; i++ )
{
let f = Spawn("PeaceFragment",Vec3Offset(FRandom[EFrag](-8,8),FRandom[EFrag](-8,8),FRandom[EFrag](4,12)));
ang = FRandom[EFrag](0,360);
pt = FRandom[EFrag](-90,90);
f.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[EFrag](4,20);
f.vel.z += 3.;
}
int numpt = Random[ExploS](20,35);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,9);
let s = Spawn("UTSmoke",pos);
s.vel = pvel;
s.scale *= 2.;
}
numpt = Random[ExploS](10,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](20,30);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
let s = Spawn("UTChip",pos);
s.vel = pvel;
s.scale *= FRandom[ExploS](0.9,2.7);
}
Spawn("FlareXLight",pos);
}
Default
{
Obituary "$O_PEACEMK";
Radius 6;
Height 9;
DamageType 'PeaceBarrelDeath';
PROJECTILE;
-NOGRAVITY;
+SKYEXPLODE;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
+MOVEWITHSECTOR;
+CANBOUNCEWATER;
+BOUNCEAUTOOFF;
+BOUNCEAUTOOFFFLOORONLY;
+USEBOUNCESTATE;
+INTERPOLATEANGLES;
Speed 8;
BounceType "Hexen";
BounceFactor 0.3; // otherwise it's too damn bouncy
BounceSound "transloc/bounce";
WallBounceFactor 0.8;
Gravity 0.35;
}
States
{
Spawn:
PEAM A -1;
Stop;
Bounce:
PEAM A 0
{
if ( BlockingFloor ) A_AlignSelf();
else pitch = roll = 0;
if ( vel.length() < 2. ) ClearBounce();
}
Goto Spawn;
Death:
PEAM A 1 A_CheckFloor(1);
Wait;
PEAM A 4 A_AlignSelf();
PEAM A 35
{
A_PlaySound((special1<=0)?"utrl/seeklost":"utrl/seeklock",CHAN_AUTO);
A_AlertMonsters();
return A_JumpIf(--special1<0,1);
}
Wait;
PEAM A 0 A_JumpIf(bAMBUSH,"Detonate");
PEAM A 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM B 3;
PEAM C 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM D 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM E 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM F 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM G 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM H 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM I 3;
PEAM J 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM K 3 A_PlaySound("utrl/rotate",CHAN_AUTO,.1);
PEAM L 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
PEAM M 3;
PEAM N 3 A_PlaySound("utrl/rotate",CHAN_AUTO,.1);
PEAM OPQ 3;
PEAM R 3 A_PlaySound("utrl/rotate",CHAN_AUTO,.1);
PEAM STU 3;
PEAM V 3 A_PlaySound("utrl/rotate",CHAN_AUTO,.1);
PEAM XYZ[\] 3;
PEAM ] 35;
PEAM ] 0 A_FireRocket(0);
PEAL A 20;
PEAL A 0 A_FireRocket(1);
PEAL B 20;
PEAL B 0 A_FireRocket(2);
PEAL C 20;
PEAL C 0 A_FireRocket(3);
PEAL D 20;
Detonate:
PEAM A 20;
BlowUp:
TNT1 A 0 A_BlowUp();
SSMX ABCDEFGHIJ 2 Bright;
Stop;
}
}
Class Peacemaker : UnrealWeapon
{
action void A_PeacemakerThrow( bool bAlt = false )
{
let weap = Weapon(invoker);
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
invoker.FireEffect();
A_PlaySound("peace/throw",CHAN_WEAPON);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+y*5-z*3);
let p = Spawn("PeaceBarrel",origin);
if ( bAlt ) p.bAMBUSH = true;
p.special1 = invoker.special2;
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.vel.z += 2.;
p.target = self;
if ( weap.Ammo1.Amount <= 0 ) player.SetPSprite(PSP_WEAPON,invoker.FindState("EmptyIdle"));
else
{
invoker.PlayUpSound(self);
player.SetPSprite(PSP_WEAPON,invoker.FindState("Ready"));
}
}
action void A_StartCount()
{
invoker.special1 = invoker.special2 = 0;
A_PlaySound("peace/set",CHAN_ITEM,.4);
}
action void A_CountUp( Statelabel next )
{
invoker.special1++;
if ( invoker.special1 > 20 )
{
invoker.special2++;
if ( invoker.special2 <= 9 )
{
A_PlaySound("peace/set",CHAN_ITEM,.4);
player.FindPSprite(PSP_WEAPON).frame = invoker.special2;
}
invoker.special1 = 0;
}
if ( (invoker.special2 >= 10) || !(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK)) )
{
invoker.special2 = min(9,invoker.special2);
player.SetPSprite(PSP_WEAPON,invoker.FindState(next));
}
}
Default
{
Tag "$T_PEACE";
Inventory.PickupMessage "$I_PEACE";
Weapon.UpSound "peace/select";
Weapon.SlotNumber 8;
Weapon.SelectionOrder 1;
Weapon.SlotPriority 0.9;
Weapon.AmmoType "PeaceAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "PeaceAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 1;
UTWeapon.DropAmmo 1;
}
States
{
Spawn:
PEAP A -1;
Stop;
PEAP B -1;
Stop;
Select:
PEAS A 1 A_Raise(int.max);
Wait;
Ready:
PEAS ABCDEFGHIJ 2 A_WeaponReady(WRF_NOFIRE);
PEAS K 0 A_PlaySound("peace/up",CHAN_ITEM,.4);
PEAS KLMNOPQRST 2 A_WeaponReady(WRF_NOFIRE);
Idle:
PEAI A 1
{
A_CheckReload();
A_WeaponReady();
}
Wait;
EmptyIdle:
TNT1 A 1
{
let weap = Weapon(invoker);
if ( weap.Ammo1.Amount > 0 )
return ResolveState("Ready");
A_CheckReload();
A_WeaponReady(WRF_NOFIRE);
return ResolveState(null);
}
Wait;
Fire:
PEAC A 1 A_StartCount();
PEAC # 1 A_CountUp(1);
Wait;
PEAF ABCD 2;
PEAF E 0
{
A_PlaySound("peace/down",CHAN_ITEM,.4);
UTMainHandler.DoSwing(self,(FRandom[Peace](-0.1,-0.04),FRandom[Peace](0.4,0.6)),3,0,7,SWING_Spring,3,0.8);
}
PEAF EFG 2;
PEAF H 0
{
UTMainHandler.DoSwing(self,(FRandom[Peace](0.08,0.12),FRandom[Peace](-1.2,-0.9)),4,0,6,SWING_Spring,3,1.5);
}
PEAF HI 2; // hello
PEAF I -1 A_PeacemakerThrow();
Stop;
AltFire:
PEAC A 1 A_StartCount();
PEAC # 1 A_CountUp(1);
Wait;
PEAF ABCD 2;
PEAF E 0
{
A_PlaySound("peace/down",CHAN_ITEM,.4);
UTMainHandler.DoSwing(self,(FRandom[Peace](-0.1,-0.04),FRandom[Peace](0.4,0.6)),3,0,7,SWING_Spring,3,0.8);
}
PEAF EFG 2;
PEAF H 0
{
UTMainHandler.DoSwing(self,(FRandom[Peace](0.08,0.12),FRandom[Peace](-1.2,-0.9)),4,0,6,SWING_Spring,3,1.5);
}
PEAF HI 2; // howdy
PEAF I -1 A_PeacemakerThrow(true);
Stop;
Deselect:
PEAD A 0 A_JumpIfNoAmmo("EmptyDeselect");
PEAD ABCDEFGHI 1;
PEAD J 1 A_Lower(int.max);
EmptyDeselect:
TNT1 A 1 A_Lower(int.max);
Wait;
}
}