stinger_m/zscript/napalm.zsc

547 lines
12 KiB
Text

Class FlameAmmo : Ammo
{
Default
{
Tag "$T_FLAMEAMMO";
Inventory.Icon "I_Napalm";
Inventory.PickupMessage "$I_FLAMEAMMO";
Inventory.Amount 75;
Inventory.MaxAmount 450;
Ammo.BackpackAmount 0;
Ammo.BackpackMaxAmount 900;
Ammo.DropAmount 30;
}
States
{
Spawn:
FLMA A -1;
Stop;
}
}
Class OnFireLight : DynamicLight
{
OnFire of;
override void Tick()
{
Super.Tick();
if ( !of || !of.victim )
{
Destroy();
return;
}
Args[0] = clamp(of.Amount*4,0,255);
Args[1] = clamp(of.Amount*2,0,128);
Args[3] = int(max(of.victim.radius,of.victim.height))+60+clamp(of.amount/8,0,80);
SetOrigin(of.Victim.Vec3Offset(0,0,of.Victim.Height/2),true);
}
}
Class OnFire : Thinker
{
Actor victim, instigator, lite;
int amount, cnt, delay;
bool forcespread;
override void Tick()
{
if ( !victim )
{
Destroy();
return;
}
if ( victim.waterlevel > 0 )
{
if ( lite ) lite.Destroy();
amount -= int(victim.waterlevel**2);
}
if ( victim.Health <= 0 ) amount = min(amount,100);
if ( !(level.maptime%3) )
amount -= ((victim.Health>0)?1:2);
if ( amount < -10 )
{
Destroy();
return;
}
if ( amount <= 0 ) return;
if ( cnt > 0 ) cnt--;
else
{
cnt = 10;
if ( victim.bSHOOTABLE && (victim.Health > 0) )
victim.DamageMobj(instigator.FindInventory("UFlamethrower"),instigator,max(1,int(amount*(victim.bBOSS?0.05:0.15))),'Fire',DMG_THRUSTLESS);
if ( !victim )
{
Destroy();
return;
}
}
if ( delay > 0 ) delay--;
if ( level.maptime%5 ) return;
int numpt = clamp(int(Random[FlameT](2,4)*amount*0.02),1,4);
double mult = max(victim.radius,victim.height)/30.;
numpt = int(max(1,numpt*mult));
for ( int i=0; i<numpt; i++ )
{
Vector3 pos = victim.Vec3Offset(FRandom[FlameT](-victim.radius,victim.radius)*0.8,FRandom[FlameT](-victim.radius,victim.radius)*0.8,FRandom[FlameT](victim.height*0.2,victim.height*0.8));
double ang = FRandom[FlameT](0,360);
double pt = FRandom[FlameT](-90,90);
let c = victim.Spawn("UFlameTrail",pos);
c.scale *= max(1.,mult*0.35);
c.vel = victim.vel*0.5+(cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[FlameT](.5,2);
}
if ( !sting_flametspread && !forcespread ) return;
// spread to nearby actors
let bt = BlockThingsIterator.Create(victim);
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || (t.Health <= 0) || (t == victim) || ((t == instigator) && (delay > 0)) || (victim.Distance3D(t) > victim.radius+t.radius+20) || !victim.CheckSight(t) ) continue;
int amt = max(1,amount/10);
if ( IsOnFire(t) ) amt = min(5,amt);
Apply(t,instigator,amt);
}
}
static void Apply( Actor victim, Actor instigator, int amount, bool forcespread = false, int delay = 0 )
{
if ( amount <= 0 ) return;
if ( victim is 'ShredCorpseHitbox' ) return;
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
OnFire t;
while ( t = OnFire(ti.Next()) )
{
if ( t.victim != victim ) continue;
if ( instigator ) t.instigator = instigator;
t.amount = min(500,t.amount+amount);
t.cnt = min(t.cnt,3);
return;
}
t = new("ONFire");
t.ChangeStatNum(STAT_USER);
t.victim = victim;
t.instigator = instigator;
t.amount = amount;
t.cnt = 1;
// for napalm gel
t.forcespread = forcespread;
t.delay = delay;
t.lite = Actor.Spawn("OnFireLight",victim.pos);
OnFireLight(t.lite).of = t;
}
static bool IsOnFire( Actor victim )
{
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
OnFire t;
while ( t = OnFire(ti.Next()) )
{
if ( t.victim != victim ) continue;
return (t.amount>0);
}
return false;
}
}
Class UFlameLight : PaletteLight
{
Default
{
Tag "Ampd";
Args 0,0,0,40;
ReactionTime 40;
}
override void Tick()
{
Super.Tick();
Args[0] /= 5;
Args[1] /= 5;
Args[2] /= 5;
Args[3] += 4;
if ( !target || (target.waterlevel > 0) )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
}
}
Class UFlame : Actor
{
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( waterlevel <= 0 )
{
let l = Spawn("UFlameLight",pos);
l.target = self;
}
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
}
action void A_Flame()
{
if ( waterlevel > 0 )
vel *= 0.9;
else
{
vel *= 0.98;
vel.z += 0.2;
}
if ( waterlevel > 0 ) bINVISIBLE = true;
if ( !Random[FlameT](0,int(30*(0.4-alpha))) && (!bINVISIBLE || (waterlevel > 0)) )
{
let s = Spawn("UTSmoke",pos+vel);
s.vel = (FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2));
s.vel += vel*0.2;
s.alpha *= 0.4;
s.scale *= 2.5;
}
if ( bAMBUSH ) return;
if ( Random[FlameT](0,int(12*(0.5-alpha))) ) return;
double rad = 60+80*int(0.4-alpha);
let bt = BlockThingsIterator.Create(self,rad);
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || (t.Health <= 0) || (t == tracer) || ((t == master) && (GetAge() < 6)) || (Distance3D(t) > rad+t.radius) ) continue;
int amt = max(1,int(alpha*15));
OnFire.Apply(t,master,amt);
}
}
Default
{
RenderStyle "Add";
Speed 20;
Radius 4;
Height 4;
Alpha 0.4;
Scale 0.1;
+NOBLOCKMAP;
+NOGRAVITY;
+NOFRICTION;
+SLIDESONWALLS;
+ACTIVATEPCROSS;
+ACTIVATEIMPACT;
+NOTELEPORT;
+FORCEXYBILLBOARD;
+DROPOFF;
+NOBLOCKMONST;
}
States
{
Spawn:
SEXP AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTT 1 Bright
{
A_Flame();
A_SetScale(scale.x*1.08);
A_FadeOut(0.01);
}
Stop;
}
}
Class UFlameTrail : UFlame
{
override void PostBeginPlay()
{
Actor.PostBeginPlay();
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
}
Default
{
Speed 2;
Alpha 0.3;
Scale 0.6;
+AMBUSH;
}
States
{
Spawn:
SEXP AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTT 1 Bright
{
A_Flame();
A_SetScale(scale.x*0.98);
A_FadeOut(0.01);
}
Stop;
}
}
Class UNapalm : Actor
{
}
Class UFlamethrower : UnrealWeapon
{
bool bCharging;
double ChargeSize, Count;
override Inventory CreateTossable( int amt )
{
if ( Owner.player && (Owner.player.ReadyWeapon == self) )
Owner.A_PlaySound("flamet/down",CHAN_6,Dampener.Active(self)?.1:1.);
return Super.CreateTossable(amt);
}
override void OwnerDied()
{
if ( Owner.player && (Owner.player.ReadyWeapon == self) )
Owner.A_PlaySound("flamet/down",CHAN_6,Dampener.Active(self)?.1:1.);
Super.OwnerDied();
}
override void DoEffect()
{
Super.DoEffect();
if ( Owner.player.ReadyWeapon != self ) return;
let psp = Owner.player.FindPSprite(-2);
if ( psp ) psp.alpha = (Owner.waterlevel>2)?.0:1.;
}
action void A_FireFlame()
{
let weap = Weapon(invoker);
if ( (weap.Ammo1.Amount <= 0) || !(player.cmd.buttons&BT_ATTACK) )
{
player.SetPSPrite(PSP_WEAPON,invoker.FindState("Release"));
return;
}
invoker.count += 10./TICRATE;
while ( invoker.count > 1. )
{
weap.DepleteAmmo(weap.bAltFire,true,1);
invoker.count -= 1.;
}
invoker.FireEffect();
A_AlertMonsters();
UTMainHandler.DoFlash(self,Color(32,255,128,0),1);
Vector3 x, y, z, x2, y2, z2;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2.5*y-2*z);
Actor p = Spawn("UFlame",origin);
double a = FRandom[FlameT](0,360), s = FRandom[FlameT](0,.05);
[x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
p.angle = atan2(dir.y,dir.x);
p.pitch = asin(-dir.z);
p.vel = vel*0.5+(cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed*FRandom[FlameT](0.8,1.4);
p.master = self;
}
action void A_BeginFlame()
{
let weap = Weapon(invoker);
weap.DepleteAmmo(weap.bAltFire,true,1);
invoker.count = 0;
invoker.special1 = 0;
A_PlaySound("flamet/fire",CHAN_WEAPON,Dampener.Active(self)?.1:1.,true);
A_Overlay(-9999,"Dummy2");
}
action void A_BeginCharge()
{
let weap = Weapon(invoker);
weap.DepleteAmmo(weap.bAltFire,true,1);
invoker.count = invoker.chargesize = 0;
A_PlaySound("flamet/charge",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
A_Overlay(-9999,"Dummy3");
}
action void A_ChargeUp()
{
let weap = Weapon(invoker);
if ( (invoker.chargesize < 4.9) && (weap.Ammo1.Amount > 0) )
{
invoker.count += 40./TICRATE;
while ( invoker.count > 1. )
{
invoker.chargesize += 0.05;
weap.DepleteAmmo(weap.bAltFire,true,1);
invoker.count -= 1.;
}
}
double ox = FRandom[Flamet](-1,1)*invoker.chargesize*0.3;
double oy = FRandom[Flamet](-1,1)*invoker.chargesize*0.3;
A_WeaponOffset(ox,32+oy);
A_OverlayOffset(-2,-ox,-oy);
A_SoundVolume(CHAN_WEAPON,Dampener.Active(self)?.1:1.);
if ( (weap.Ammo1.Amount <= 0) || (invoker.chargesize >= 4.9) || !(player.cmd.buttons&BT_ALTATTACK) )
player.SetPSPrite(PSP_WEAPON,invoker.FindState("AltRelease"));
}
action void A_FireNapalm()
{
A_Overlay(-9999,"Null");
A_WeaponOffset(0,32);
A_OverlayOffset(-2,0,0);
invoker.bCharging = false;
A_PlaySound("flamet/altfire",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3();
}
Default
{
Tag "$T_FLAMETHROWER";
Inventory.PickupMessage "$I_FLAMETHROWER";
Weapon.UpSound "flamet/select";
Weapon.SlotNumber 6;
Weapon.SelectionOrder 4;
Weapon.SlotPriority 0.9;
Weapon.AmmoType "FlameAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "FlameAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 100;
UTWeapon.DropAmmo 50;
+NOEXTREMEDEATH;
}
States
{
Spawn:
FLMP A -1;
Stop;
FLMP B -1;
Stop;
Select:
FLMS A 1 A_Raise(int.max);
Wait;
Ready:
FLMS ABCDEF 2 A_WeaponReady(WRF_NOFIRE);
FLMS G 0
{
A_PlaySound("flamet/idle",CHAN_6,Dampener.Active(self)?.1:1.,true);
A_Overlay(-2,"FlameReady");
A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE|PSPF_ALPHA|PSPF_FORCEALPHA,true);
A_OverlayRenderStyle(-2,STYLE_Add);
}
FLMS GHIJ 2 A_WeaponReady(WRF_NOFIRE);
Goto Idle;
Dummy:
TNT1 A 1
{
A_CheckReload();
A_WeaponReady();
}
Wait;
Idle:
FLMI A 0 A_Overlay(-9999,"Dummy");
FLMI ABCDEFG 12 A_SoundVolume(CHAN_6,Dampener.Active(self)?.1:1.);
FLMI A 0 A_Jump(20,"Twiddle");
Goto Idle+1;
Twiddle:
#### # 2
{
A_SoundVolume(CHAN_6,Dampener.Active(self)?.1:1.);
player.SetPSprite(-2,ResolveState("FlameTwiddle"));
}
FLMT ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 2 A_SoundVolume(CHAN_6,Dampener.Active(self)?.1:1.);
FLT2 ABCDEF 2 A_SoundVolume(CHAN_6,Dampener.Active(self)?.1:1.);
Goto Idle+1;
Fire:
#### # 2
{
A_Overlay(-9999,"Null");
player.SetPSprite(-2,ResolveState("FlameFire"));
}
FLMF ABCDE 2;
FLMF F 0 A_BeginFlame();
Goto Hold;
Dummy2:
TNT1 A 1 A_FireFlame();
Wait;
Hold:
FLMF FGHIJK 2 A_SoundVolume(CHAN_WEAPON,Dampener.Active(self)?.1:1.);
Loop;
Release:
#### # 2
{
A_Overlay(-9999,"Null");
player.SetPSprite(-2,ResolveState("FlameRelease"));
A_PlaySound("flamet/fireend",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
A_ClearRefire();
}
FLMF MNOP 2;
Goto Idle;
AltFire:
#### # 2
{
A_Overlay(-9999,"Null");
player.SetPSprite(-2,ResolveState("FlameAltFire"));
invoker.bCharging = true;
}
FLMA ABCDE 2;
FLMA F 0 A_BeginCharge();
Goto AltHold;
Dummy3:
TNT1 A 1 A_ChargeUp();
Wait;
AltHold:
FLMA FIGHLKGJHLGFHJGILHFKGFKHIGKGHL 10;
Loop;
AltRelease:
FLMA M 0
{
A_FireNapalm();
player.SetPSprite(-2,ResolveState("FlameAltRelease"));
}
FLMA MNOPQRSTUVWX 2;
FLMA Y 0
{
if ( invoker.CheckAmmo(1,false,true) )
A_Refire("GotoAltHold");
}
FLMA Y 0 A_ClearRefire();
FLMA YZ[\] 2;
FLA2 ABCD 2;
Goto Idle;
GotoAltHold:
FLMA Y 0
{
player.SetPSprite(-2,ResolveState("FlameAltHold"));
}
Goto AltHold;
Deselect:
#### # 1
{
A_Overlay(-9999,"Null");
A_PlaySound("flamet/down",CHAN_6,Dampener.Active(self)?.1:1.);
player.SetPSprite(-2,ResolveState("FlameDeselect"));
}
FLMD ABCDEFHIJ 1;
FLMD J 1 A_Lower(int.max);
Wait;
FlameReady:
FLFS ABCD 2 Bright;
Goto FlameIdle;
FlameIdle:
FLFI ABCDEFG 12 Bright;
Loop;
FlameTwiddle:
#### # 2 Bright;
FLFT ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 2 Bright;
FFT2 ABCDEF 2 Bright;
Goto FlameIdle;
FlameFire:
#### # 1 Bright;
FLFF ABCDE 2 Bright;
Goto FlameHold;
FlameHold:
FLFF FGHIJK 2 Bright;
Loop;
FlameRelease:
#### # 2 Bright;
FLFF MNOP 2 Bright;
Goto FlameIdle;
FlameAltFire:
#### # 2 Bright;
FLFA ABCDE 2 Bright;
Goto FlameAltHold;
FlameAltHold:
FLFA FIGHLKGJHLGFHJGILHFKGFKHIGKGHL 10 Bright;
Loop;
FlameAltRelease:
FLFA MNOPQRSTUVWXYZ[\] 2 Bright;
FFA2 ABCD 2 Bright;
Goto FlameIdle;
FlameDeselect:
#### # 1 Bright;
FLFD ABCD 2 Bright;
Stop;
}
}