Class UFireLight : PaletteLight { Default { Tag "FlamG"; Args 0,0,0,60; } } Class UFireTrail : Actor { Default { RenderStyle "Add"; Radius 0.1; Height 0; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; +NOTELEPORT; Scale 0.5; Alpha 0.2; } override void Tick() { Super.Tick(); if ( !target || !target.bMISSILE ) { Destroy(); return; } SetOrigin(target.pos,true); } States { Spawn: FGFL A -1 Bright; Stop; } } Class UFireball : Actor { Vector3 Acceleration; double spreadf, maxspeed; int ns, nsp; property SpreadFactor : spreadf; property NumSmokes : ns; property NumSparks : nsp; Default { DamageType 'Fire'; DamageFunction 20; Radius 4; Height 4; Speed 15; PROJECTILE; +SKYEXPLODE; +EXPLODEONWATER; +FORCERADIUSDMG; +NODAMAGETHRUST; +FORCEXYBILLBOARD; +DONTSPLASH; UFireball.SpreadFactor 0.2; UFireball.NumSmokes 1; UFireball.NumSparks 2; DeathSound "flamegun/exp"; } override void PostBeginPlay() { Super.PostBeginPlay(); maxspeed = 30.; if ( bAMBUSH ) return; let l = Spawn("UFireTrail",pos); l.target = self; Acceleration = vel.unit()*50; A_PlaySound("eightball/fly",CHAN_VOICE,.6,true,3.,pitch:1.5); } action void A_Spread() { vel += invoker.Acceleration/TICRATE; vel += (FRandom[EWizFX](-1,1),FRandom[EWizFX](-1,1),FRandom[EWizFX](-1,1))*FRandom[EWizFX](.5,1.)*invoker.spreadf; Vector3 dir = vel.unit(); if ( vel.length() > invoker.maxspeed ) vel = dir*invoker.maxspeed; angle = atan2(dir.y,dir.x); pitch = asin(-dir.z); if ( waterlevel > 0 ) { int numpt = Random[ExploS](10,15); if ( bAMBUSH ) numpt /= 3; for ( int i=0; i=2)?WRF_NOFIRE:0; if ( invoker.Ammo1.Amount < invoker.AmmoUse2 ) flags |= WRF_NOSECONDARY; A_WeaponReady(flags); } Wait; Idle: FGNI A 0 A_Overlay(-9999,"Dummy"); FGNI ABCDEFG 12; FGNI A 0 A_Jump(40,"Twiddle"); Goto Idle+1; Twiddle: #### # 2 A_PlaySound("flamegun/idle",CHAN_6,Dampener.Active(self)?.1:1.); FGNT ABCDEFGHIJKLM 3; Goto Idle+1; Fire: #### # 1 A_Overlay(-9999,"Null"); FGNF A 2 { invoker.special1 = 0; A_PlaySound("flamegun/start",CHAN_6,Dampener.Active(self)?.1:1.); if ( !Dampener.Active(self) ) A_AlertMonsters(); } Hold: FGNF B 1 A_FlameGunFire(); FGNF CDEFG 1; FGNF H 0 { invoker.special1++; if ( invoker.CheckAmmo(0,false,true) && (waterlevel < 2) && (invoker.special1 < 3) ) A_Refire("Refire"); } FGNF H 0 A_ClearRefire(); FGNF HIJ 2; FGNT A 0 { if ( invoker.CheckAmmo(0,false,true) && (waterlevel < 2) && (invoker.special1 < 3) ) A_Refire("Fire"); } FGNT A 0 { invoker.special1 = 0; A_PlaySound("flamegun/end",CHAN_6,Dampener.Active(self)?.1:1.); A_ClearRefire(); } FGNT ABCDEFGHIJKLM 2; Goto Idle; Refire: FGNF H 2 A_PlaySound("flamegun/start",CHAN_6,Dampener.Active(self)?.1:1.); Goto Hold; AltFire: #### # 1 A_Overlay(-9999,"Null"); FGNF A 1 { invoker.special1 = 0; A_PlaySound("flamegun/charge",CHAN_WEAPON,Dampener.Active(self)?.1:1.); if ( !Dampener.Active(self) ) A_AlertMonsters(); } FGNF A 1 { invoker.special1++; A_WeaponOffset(FRandom[FlameGun](-.1,.1)*invoker.special1,32+FRandom[FlameGun](-.1,.1)*invoker.special1); return A_JumpIf(invoker.special1>40,"AltRelease"); } Wait; AltRelease: FGNF B 2 { invoker.special1 = 0; A_WeaponOffset(0,32); A_FlameGunFire(true); } FGNF CDEFGHIJ 2; FGNT ABCDEFGHIJKLM 2; Goto Idle; Deselect: FGND A 1 A_Overlay(-9999,"Null"); FGND BCDEFGHIJ 1; FGND J 1 A_Lower(int.max); Wait; } }