547 lines
12 KiB
Text
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;
|
|
}
|
|
}
|