stinger_m/zscript/peacemaker.zsc

553 lines
13 KiB
Text

Class PeaceAmmo : Ammo
{
Default
{
Inventory.Icon "I_Peace";
Inventory.Amount 1;
Inventory.MaxAmount 1;
Ammo.BackpackAmount 0;
Ammo.BackpackMaxAmount 2;
}
override bool TryPickup( in out Actor toucher )
{
if ( !sting_proto ) return false; // not allowed
return Super.TryPickup(toucher);
}
override void Tick()
{
Super.Tick();
if ( sting_proto ) return;
if ( Owner ) Owner.RemoveInventory(self);
Destroy();
}
}
Class PeaceLight : RocketLight
{
Default
{
Args 255,128,112,32;
}
}
Class PeaceTrail : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+NOTELEPORT;
Scale 0.25;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("PeaceLight",pos);
l.target = self;
}
override void Tick()
{
Super.Tick();
if ( !target || !target.bMISSILE )
{
Destroy();
return;
}
Vector3 dir = dt_Utility.Vec3FromAngle(target.angle,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;
+NOFRICTION;
ReactionTime 9;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("PeaceTrail",pos);
l.target = self;
A_StartSound("peace/fly",CHAN_VOICE,CHANF_LOOPING,1.,2.5,.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;
if ( sting_peacehome && ((bi.Thing == target) || (target && target.IsFriend(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_StartSound("eightball/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:
PEMR 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();
}
// early check
if ( GetAge() == 5 ) A_CheckForTargets();
}
Wait;
Death:
TNT1 A 0 A_PeaceExplode();
SSMX ABCDEFGHIJ 2 Bright;
Stop;
}
}
Class PeaceFragment : SentryFragment
{
Default
{
Scale 0.5;
}
}
Class PeaceBarrel : Actor
{
Mixin UMissileFix;
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_StartSound("uflak/altfire",CHAN_WEAPON,CHANF_OVERLAP);
A_AlertMonsters();
Vector3 x, y, z;
[x, y, z] = dt_Utility.GetAxes(angle,pitch,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_StartSound("sentry/explode",CHAN_VOICE,CHANF_OVERLAP,pitch:.6);
A_StartSound("eightball/explode",CHAN_VOICE,CHANF_OVERLAP,pitch:.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 = dt_Utility.Vec3FromAngle(ang,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:
PEMM A -1;
Stop;
Bounce:
PEMM A 0
{
if ( BlockingFloor ) A_AlignSelf();
else pitch = roll = 0;
if ( vel.length() < 2. ) ClearBounce();
}
Goto Spawn;
Death:
PEMM A 1 A_CheckFloor(1);
Wait;
PEMM A 4 A_AlignSelf();
PEMM A 35
{
A_StartSound((special1<=0)?"eightball/seeklost":"eightball/seeklock",CHAN_VOICE,CHANF_OVERLAP);
A_AlertMonsters();
return A_JumpIf(--special1<0,1);
}
Wait;
PEMM A 0 A_JumpIf(bAMBUSH,"Detonate");
PEMM A 3 A_StartSound("peace/open",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM B 3;
PEMM C 3 A_StartSound("peace/open",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM D 3 A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM E 3 A_StartSound("peace/open",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM F 3
{
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEMM G 3 A_StartSound("peace/open",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM H 3
{
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEMM I 3;
PEMM J 3
{
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.8,pitch:FRandom[Peace](0.8,1.2));
A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEMM K 3 A_StartSound("eightball/rotate",CHAN_BODY,CHANF_OVERLAP,.1);
PEMM L 3 A_StartSound("transloc/bounce",CHAN_BODY,CHANF_OVERLAP,.5,pitch:FRandom[Peace](0.8,1.2));
PEMM M 3;
PEMM N 3 A_StartSound("eightball/rotate",CHAN_BODY,CHANF_OVERLAP,.1);
PEMM OPQ 3;
PEMM R 3 A_StartSound("eightball/rotate",CHAN_BODY,CHANF_OVERLAP,.1);
PEMM STU 3;
PEMM V 3 A_StartSound("eightball/rotate",CHAN_BODY,CHANF_OVERLAP,.1);
PEMM XYZ[\] 3;
PEMM ] 35;
PEMM ] 0 A_FireRocket(0);
PEML A 20;
PEML A 0 A_FireRocket(1);
PEML B 20;
PEML B 0 A_FireRocket(2);
PEML C 20;
PEML C 0 A_FireRocket(3);
PEML D 20;
Detonate:
PEMM A 20;
BlowUp:
TNT1 A 0 A_BlowUp();
SSMX ABCDEFGHIJ 2 Bright;
Stop;
}
}
Class Peacemaker : UnrealWeapon
{
override bool TryPickup( in out Actor toucher )
{
if ( !sting_proto ) return false; // not allowed
return Super.TryPickup(toucher);
}
override void Tick()
{
Super.Tick();
if ( sting_proto ) return;
if ( Owner ) Owner.RemoveInventory(self);
Destroy();
}
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_StartSound("peace/throw",CHAN_WEAPON);
Vector3 origin = dt_Utility.GetFireOffset(self,10,5,-3);
let p = Spawn("PeaceBarrel",origin);
if ( bAlt ) p.bAMBUSH = true;
p.special1 = invoker.special2;
p.angle = angle;
p.pitch = BulletSlope();
p.vel = dt_Utility.Vec3FromAngle(p.angle,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_StartSound("peace/set",CHAN_WEAPONMISC,CHANF_OVERLAP,.4);
}
action void A_CountUp( Statelabel next )
{
invoker.special1++;
if ( invoker.special1 > 20 )
{
invoker.special2++;
if ( invoker.special2 <= 9 )
{
A_StartSound("peace/set",CHAN_WEAPONMISC,CHANF_OVERLAP,.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 1050;
Weapon.SlotPriority 0.9;
Weapon.AmmoType "PeaceAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "PeaceAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 1;
UTWeapon.DropAmmo 1;
}
States
{
Spawn:
PEMP A -1;
Stop;
PEMP B -1;
Stop;
Select:
PEMS A 1 A_Raise(int.max);
Wait;
Ready:
PEMS ABCDEFGHIJ 2 A_WeaponReady(WRF_NOFIRE);
PEMS K 0 A_StartSound("peace/up",CHAN_WEAPONMISC,volume:.4);
PEMS KLMNOPQRST 2 A_WeaponReady(WRF_NOFIRE);
Idle:
PEMI 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:
PEMC A 1 A_StartCount();
PEMC # 1 A_CountUp(1);
Wait;
PEMF ABCD 2;
PEMF E 0 A_StartSound("peace/down",CHAN_WEAPONMISC,volume:.4);
PEMF EFG 2;
PEMF HI 2; // hello
PEMF I -1 A_PeacemakerThrow();
Stop;
AltFire:
PEMC A 1 A_StartCount();
PEMC # 1 A_CountUp(1);
Wait;
PEMF ABCD 2;
PEMF E 0 A_StartSound("peace/down",CHAN_WEAPONMISC,volume:.4);
PEMF EFG 2;
PEMF HI 2; // howdy
PEMF I -1 A_PeacemakerThrow(true);
Stop;
Deselect:
PEMD A 0 A_JumpIfNoAmmo("EmptyDeselect");
PEMD ABCDEFGHI 1;
PEMD J 1 A_Lower(int.max);
EmptyDeselect:
TNT1 A 1 A_Lower(int.max);
Wait;
}
}