Class FlakAmmo : Ammo { Default { Tag "Flak Shells"; Inventory.PickupMessage "You picked up 10 Flak Shells."; Inventory.Amount 10; Inventory.MaxAmount 50; Ammo.BackpackAmount 50; Ammo.BackpackMaxAmount 100; Ammo.DropAmount 10; } States { Spawn: FAMO A -1; Stop; } } Class FlakAmmo2 : FlakAmmo { Default { Tag "Flak Shell"; Inventory.PickupMessage "You picked up a Flak Shell."; Inventory.Amount 1; Ammo.DropAmount 1; } States { Spawn: FSLG A -1; Stop; } } Class ChunkLight : DynamicLight { Default { DynamicLight.Type "Point"; Args 255,224,128,8; } override void PostBeginPlay() { Super.PostBeginPlay(); } override void Tick() { Super.Tick(); if ( !target ) { Destroy(); return; } if ( globalfreeze || level.frozen ) return; args[LIGHT_RED] = 255*target.alpha; args[LIGHT_GREEN] = 224*target.alpha; args[LIGHT_BLUE] = 128*target.alpha; } } Class ChunkTrail : Actor { Default { RenderStyle "Add"; Radius 0.1; Height 0; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; +INVISIBLE; // temporarily until clipping screwery is fixed Scale 0.2; } override void PostBeginPlay() { Super.PostBeginPlay(); let l = Spawn("ChunkLight",pos); l.target = self; } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; A_SpawnParticle("FFFF00",SPF_FULLBRIGHT,1,8,startalphaf:alpha); A_SpawnParticle("E0A000",SPF_FULLBRIGHT,1,16,startalphaf:alpha*0.6); A_SpawnParticle("804000",SPF_FULLBRIGHT,1,32,startalphaf:alpha*0.3); if ( InStateSequence(CurState,FindState("Death")) ) return; if ( !target ) { SetStateLabel("Death"); return; } SetOrigin(target.pos+(0,0,speed),true); } States { Spawn: FGLO A 1 Bright; Wait; Death: FGLO A 1 Bright A_FadeOut(0.1); Wait; } } Class FlakChunk : Actor { Actor lasthit; ChunkTrail trail; double rollvel, pitchvel, yawvel; double lifetime, lifespeed; int lifetics; Default { Obituary "%o was ripped to shreds by %k's Flak Cannon."; Radius 4; Height 4; Speed 50; DamageFunction Random[Flak](12,18); DamageType 'Shredded'; BounceType "Doom"; BounceFactor 0.8; PROJECTILE; +USEBOUNCESTATE -BOUNCEAUTOOFF Scale 0.5; } override bool CanCollideWith( Actor other, bool passive ) { return (vel.length()>4.0); } override void PostBeginPlay() { Super.PostBeginPlay(); lifetime = 0; lifespeed = FRandom[Flak](0.004,0.008); trail = ChunkTrail(Spawn("ChunkTrail",pos)); trail.target = self; trail.speed = 0.5; rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1); pitchvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1); yawvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1); scale *= Frandom[Flak](0.8,1.2); SetState(ResolveState("Spawn")+Random[Flak](0,3)); } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; lifetics++; if ( lifetics > 3 ) { lifetics = 0; if ( frame < 11 ) frame++; } lifetime += lifespeed; if ( (waterlevel <= 0) && (frame < 10) ) A_SpawnParticle("AAAAAA",0,35,2.0,velx:FRandom[Flak](-0.1,0.1),vely:FRandom[Flak](-0.1,0.1),velz:FRandom[Flak](-0.1,0.1),accelz:0.02,startalphaf:scale.x/0.5,sizestep:0.2); if ( trail ) trail.alpha = max(0,11-frame)/11.; if ( InStateSequence(CurState,FindState("Death")) ) return; A_SetRoll(roll+rollvel,SPF_INTERPOLATE); A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE); A_SetAngle(angle+pitchvel,SPF_INTERPOLATE); } action void A_HandleBounce() { A_SprayDecal("WallCrack",-8); int numpt = Random[Flak](8,12); for ( int i=0; i 2 ) Destroy(); } } Class FlakCannon : UTWeapon { action void A_Loading( bool first = false ) { if ( first ) A_PlaySound("flak/load",CHAN_WEAPON); else A_PlaySound("flak/reload",CHAN_WEAPON); } action void A_FireChunks() { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; A_PlaySound("flak/fire",CHAN_WEAPON); A_AlertMonsters(); A_QuakeEx(1,1,1,3,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05); Vector3 x, y, z; double a, s; [x, y, z] = Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+2.0*y-3.0*z; A_Overlay(-2,"MuzzleFlash"); A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); A_OverlayRenderstyle(-2,STYLE_Add); [x, y, z] = Matrix4.GetAxes(BulletSlope(),angle,roll); Actor p; for ( int i=0; i<8; i++ ) { p = Spawn("FlakChunk",origin); a = FRandom[Flak](0,360); s = FRandom[Flak](0,0.2); Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit(); p.angle = atan2(dir.y,dir.x); p.pitch = -asin(dir.z); p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed; p.target = self; } int numpt = Random[Flak](20,30); for ( int i=0; i 0 ) A_Loading(); } FLKL BCDEFGHIJKLMNO 1; Idle: FLKI A 10; FLKI A 1 A_WeaponReady(); Wait; Fire: FLKF A 1 A_FireChunks(); FLKF BCDEFGHIJ 1; FLKF JJ 4; Goto Loading; AltFire: FLKA A 1 A_FireSlug(); FLKA BCDEFGHIJK 2; FLKA KKK 4; Goto Loading; Select: FLKS A 1 A_Raise(int.max); Wait; Deselect: FLKD ABCDEFGHIJ 2; FLKD J 1 A_Lower(int.max); Wait; MuzzleFlash: FMUZ A 3 Bright { let l = Spawn("FlakLight",pos); l.target = self; } Stop; } }