Class UTRocketAmmo : Ammo { Default { Tag "Rocket Pack"; Inventory.PickupMessage "You picked up a Rocket Pack."; Inventory.Amount 12; Inventory.MaxAmount 48; Ammo.BackpackAmount 12; Ammo.BackpackMaxAmount 96; Ammo.DropAmount 3; } States { Spawn: RPAK A -1; Stop; } } // There was no single rocket ammo in UT, so this one is also just improvised like the Redeemer ammo pickup Class UTRocketAmmo2 : UTRocketAmmo { Default { Tag "Single Rocket"; Inventory.PickupMessage "You picked up a Single Rocket."; Inventory.Amount 1; Ammo.DropAmount 1; +INVENTORY.IGNORESKILL; } States { Spawn: RCKT A -1; Stop; } } Class RocketLight : DynamicLight { Default { DynamicLight.Type "Point"; Args 255,224,128,32; } override void Tick() { Super.Tick(); if ( !target ) { Destroy(); return; } SetOrigin(target.pos,true); } } Class UTRocketTrail : Actor { Default { RenderStyle "Add"; Radius 0.1; Height 0; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; Scale 0.7; } override void PostBeginPlay() { Super.PostBeginPlay(); let l = Spawn("RocketLight",pos); l.target = self; } override void Tick() { Super.Tick(); if ( !target || target.InStateSequence(target.CurState,target.FindState("Death")) ) { Destroy(); return; } SetOrigin(target.pos,true); } States { Spawn: RFLA A -1 Bright; Stop; } } Class RocketExplLight : SlugLight { Default { Args 255,224,128,120; } } Class UTRocket : Actor { Vector3 InitialDir, Acceleration; int ticcnt; Default { Obituary "%o was smacked down by %k's Rocket Launcher."; DamageType 'RocketDeath'; Radius 2; Height 2; Speed 20; PROJECTILE; +SKYEXPLODE; +EXPLODEONWATER; +SEEKERMISSILE; +FORCERADIUSDMG; +NODAMAGETHRUST; } override void PostBeginPlay() { Super.PostBeginPlay(); let l = Spawn("UTRocketTrail",pos); l.target = self; A_PlaySound("utrl/fly",CHAN_VOICE,1.0,true,2.5); if ( tracer ) vel *= 0.9; Acceleration = vel.unit()*50; } action void A_RocketExplode( int dmg, int rad ) { bFORCEXYBILLBOARD = true; A_SetRenderStyle(1.0,STYLE_Add); A_SprayDecal("RocketBlast",50); A_NoGravity(); A_SetScale(0.75); UTMainHandler.DoBlast(self,rad,80000); A_Explode(dmg,rad); A_QuakeEx(3,3,3,8,0,rad+50,"",QF_RELATIVE|QF_SCALEDOWN,falloff:rad,rollIntensity:0.2); A_PlaySound("utrl/explode",CHAN_VOICE); A_AlertMonsters(); Spawn("RocketExplLight",pos); int numpt = Random[Eightball](15,30); for ( int i=0; i 0 ) { double MagnitudeVel = Vel.length(); SeekingDir = (SeekingDir*0.5*MagnitudeVel+Vel).unit(); Vel = MagnitudeVel * SeekingDir; invoker.Acceleration = 25 * SeekingDir; } } } States { Spawn: RCKT B 1 { A_SetRoll(roll+30,SPF_INTERPOLATE); if ( invoker.ticcnt++ > 3 ) { invoker.ticcnt = 0; A_RocketSeek(); } vel += invoker.Acceleration/TICRATE; if ( vel.length() > 45. ) vel = Vel.unit()*45.; Vector3 dir = vel.unit(); if ( waterlevel <= 0 ) vel = dir*min(vel.length()+1,32); A_SetAngle(atan2(dir.y,dir.x),SPF_INTERPOLATE); A_SetPitch(asin(-dir.z),SPF_INTERPOLATE); for ( int i=0; i<3; i++ ) { let s = Spawn("UTSmoke",pos); s.vel = (FRandom[Eightball](-0.2,0.2),FRandom[Eightball](-0.2,0.2),FRandom[Eightball](-0.2,0.2)); s.vel += vel*0.1; } } Wait; Death: TNT1 A 0 A_RocketExplode(Random[Eightball](90,120),160); SSMX ABCDEFGHIJ 2 Bright; Stop; } } Class UTGrenade : UTRocket { double rollvel, pitchvel, anglevel; Default { DamageType 'GrenadeDeath'; -NOGRAVITY; +USEBOUNCESTATE; -BOUNCEAUTOOFF; +BOUNCEAUTOOFFFLOORONLY; -EXPLODEONWATER; +CANBOUNCEWATER; BounceType "Doom"; BounceFactor 0.75; ReactionTime 85; Speed 20; } override void PostBeginPlay() { Actor.PostBeginPlay(); rollvel = FRandom[Eightball](-8,8); pitchvel = FRandom[Eightball](-8,8); anglevel = FRandom[Eightball](-8,8); ReactionTime += Random[Eightball](0,20); } States { Spawn: RCKT A 1 { A_SetAngle(angle+anglevel,SPF_INTERPOLATE); A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE); A_SetRoll(roll+rollvel,SPF_INTERPOLATE); A_Countdown(); } Wait; Bounce: RCKT A 0 { A_PlaySound("utrl/bounce"); rollvel = FRandom[Eightball](-16,16); pitchvel = FRandom[Eightball](-16,16); anglevel = FRandom[Eightball](-16,16); } Goto Spawn; Death: TNT1 A 0 A_RocketExplode(Random[Eightball](100,150),140); Goto Super::Death+1; } } Class UTRocketLauncher : UTWeapon { bool LockedOn; Actor LockedTarget; TextureID lockontex; int locktics; bool bSingleRocket; override void PostBeginPlay() { Super.PostBeginPlay(); lockontex = TexMan.CheckForTexture("Crosshr6",TexMan.Type_Any); } override void PreRender( double lbottom ) { if ( LockedTarget ) Screen.DrawTexture(lockontex,false,Screen.GetWidth()*0.5,Screen.GetHeight()*0.5); } override void Tick() { Super.Tick(); if ( !Owner ) return; if ( LockedOn && (!LockedTarget || (LockedTarget.Health <= 0) || !LockedTarget.bIsMonster || LockedTarget.bKilled || LockedTarget.bCorpse || !LockedTarget.bShootable) ) { LockedTarget = null; LockedOn = false; Owner.A_PlaySound("utrl/seeklost",CHAN_WEAPON); } if ( LockedTarget ) crosshair = 99; else crosshair = 0; } // consumes 1 ammo action void A_LoadRocket( bool checktarget = true ) { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; if ( weap.bAltFire ) { invoker.LockedTarget = null; invoker.LockedOn = false; } if ( checktarget && !weap.bAltFire ) A_CheckTarget(); } // refire that is ignored if there's no ammo action void A_LoadedRefire( statelabel flash = null ) { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; A_Refire(flash); } // fire all the rockets (or grenades) action void A_FireRockets( int num ) { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.bAltFire ) A_PlaySound("utrl/altfire",CHAN_WEAPON); else A_PlaySound("utrl/fire",CHAN_WEAPON); invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(64,255,0,0),1); A_AlertMonsters(); A_QuakeEx(2+num,2+num,2+num,6+num,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1+num*0.05); Vector3 x, y, z, x2, y2, z2; double a, s; [x, y, z] = Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-3.0*z; [x2, y2, z2] = Matrix4.GetAxes(BulletSlope(),angle,roll); Actor p; if ( weap.bAltFire ) { // grenades for ( int i=0; i1)?12:0); Vector3 dir = (x2+cos(a)*y2*s*0.004+sin(a)*z2*s*0.004).unit(); p = Spawn("UTGrenade",origin+cos(a)*y*s+sin(a)*z*s); p.vel = x*(vel dot x)*0.4 + dir*p.speed*FRandom[Eightball](1.0,1.2); p.vel.z += 6; p.target = self; } } else if ( num <= 1 ) { // single rocket p = Spawn("UTRocket",origin+cos(a)*y*s+sin(a)*z*s); p.vel = x2*p.speed; p.target = self; p.tracer = invoker.LockedTarget; } else if ( player.cmd.buttons&BT_ALTATTACK ) { // rockets ("tight wad" as UT calls it) double step = 360/num; a = 90; s = (num>1)?6:0; for ( int i=0; i 2000 ) continue; if ( reldir.unit() dot viewdir < 0.99 ) continue; if ( reldist < closest ) { closest = reldist; invoker.LockedTarget = a; } } if ( invoker.LockedTarget ) A_PlaySound("utrl/seeklock",CHAN_WEAPON); else if ( invoker.LockedOn ) A_PlaySound("utrl/seeklost",CHAN_WEAPON); if ( invoker.LockedTarget ) invoker.LockedOn = true; } Default { Tag "Rocket Launcher"; Inventory.PickupMessage "You got the Rocket Launcher."; Weapon.UpSound "utrl/select"; Weapon.SlotNumber 9; Weapon.SelectionOrder 1; Weapon.AmmoType "UTRocketAmmo"; Weapon.AmmoUse 1; Weapon.AmmoType2 "UTRocketAmmo"; Weapon.AmmoUse2 1; Weapon.AmmoGive 6; UTWeapon.DropAmmo 3; } States { Spawn: EBLP A -1; Stop; EBLP B -1; Stop; Select: EBLS A 1 A_Raise(int.max); Wait; Ready: EBLS ABCDEFGHIJKLMNOPQRST 1 A_WeaponReady(WRF_NOFIRE); Idle: EBLI A 1 { invoker.locktics = 0; A_CheckReload(); A_WeaponReady(WRF_ALLOWRELOAD); } EBLI A 1 { A_CheckReload(); A_WeaponReady(WRF_ALLOWRELOAD); invoker.locktics++; if ( invoker.locktics > 42 ) { invoker.locktics = 0; A_CheckTarget(); } } Wait; Reload: EBLI A 5 { A_PlaySound("utrl/load",CHAN_6,0.3); if ( invoker.bSingleRocket = !invoker.bSingleRocket ) A_Print("Instant Rocket mode enabled"); else A_Print("Instant Rocket mode disabled"); } Goto Idle; Fire: AltFire: // one is loaded already EBLI A 1 A_LoadRocket(false); EBLI A 2 A_JumpIf(!invoker.bAltFire&&invoker.bSingleRocket,"FireOne"); EBLI A 0 A_LoadedRefire(1); Goto FireOne; // load two EBLI A 2; EBL1 A 0; EBR1 A 2 A_PlaySound("utrl/rotate",CHAN_6,0.1); EBR1 B 0 A_Refire(1); Goto FireOne; EBR1 B 2; EBR1 C 0 A_Refire(1); Goto FireOne; EBR1 C 2; EBR1 D 0 A_Refire(1); Goto FireOne; EBR1 D 2; EBR1 E 0 A_Refire(1); Goto FireOne; EBR1 E 2; EBR1 F 0 A_Refire(1); Goto FireOne; EBR1 F 2; EBR1 G 0 A_Refire(1); Goto FireOne; EBR1 G 2; EBL2 A 0 A_Refire(1); Goto FireOne; EBL2 A 3 A_PlaySound("utrl/load",CHAN_6); EBL2 B 0 A_Refire(1); Goto FireOne; EBL2 B 3; EBL2 C 0 A_Refire(1); Goto FireOne; EBL2 C 3; EBL2 D 0 A_Refire(1); Goto FireOne; EBL2 D 3; EBL2 E 0 A_Refire(1); Goto FireOne; EBL2 E 3; EBL2 F 0 A_Refire(1); Goto FireOne; EBL2 F 3; EBL2 G 0 A_Refire(1); Goto FireOne; EBL2 G 3 A_LoadRocket(); EBR2 A 0 A_LoadedRefire(1); Goto FireTwo; // load three EBR2 A 2 A_PlaySound("utrl/rotate",CHAN_6,0.1); EBR2 B 0 A_Refire(1); Goto FireTwo; EBR2 B 2; EBR2 C 0 A_Refire(1); Goto FireTwo; EBR2 C 2; EBR2 D 0 A_Refire(1); Goto FireTwo; EBR2 D 2; EBR2 E 0 A_Refire(1); Goto FireTwo; EBR2 E 2; EBR2 F 0 A_Refire(1); Goto FireTwo; EBR2 F 2; EBR2 G 0 A_Refire(1); Goto FireTwo; EBR2 G 2; EBL3 A 0 A_Refire(1); Goto FireTwo; EBL3 A 3 A_PlaySound("utrl/load",CHAN_6); EBL3 B 0 A_Refire(1); Goto FireTwo; EBL3 B 3; EBL3 C 0 A_Refire(1); Goto FireTwo; EBL3 C 3; EBL3 D 0 A_Refire(1); Goto FireTwo; EBL3 D 3; EBL3 E 0 A_Refire(1); Goto FireTwo; EBL3 E 3; EBL3 F 0 A_Refire(1); Goto FireTwo; EBL3 F 3; EBL3 G 0 A_Refire(1); Goto FireTwo; EBL3 G 3 A_LoadRocket(); EBR3 A 0 A_LoadedRefire(1); Goto FireThree; // load four EBR3 A 2 A_PlaySound("utrl/rotate",CHAN_6,0.1); EBR3 B 0 A_Refire(1); Goto FireThree; EBR3 B 2; EBR3 C 0 A_Refire(1); Goto FireThree; EBR3 C 2; EBR3 D 0 A_Refire(1); Goto FireThree; EBR3 D 2; EBR3 E 0 A_Refire(1); Goto FireThree; EBR3 E 2; EBR3 F 0 A_Refire(1); Goto FireThree; EBR3 F 2; EBR3 G 0 A_Refire(1); Goto FireThree; EBR3 G 2; EBL4 A 0 A_Refire(1); Goto FireThree; EBL4 A 3 A_PlaySound("utrl/load",CHAN_6); EBL4 B 0 A_Refire(1); Goto FireThree; EBL4 B 3; EBL4 C 0 A_Refire(1); Goto FireThree; EBL4 C 3; EBL4 D 0 A_Refire(1); Goto FireThree; EBL4 D 3; EBL4 E 0 A_Refire(1); Goto FireThree; EBL4 E 3; EBL4 F 0 A_Refire(1); Goto FireThree; EBL4 F 3; EBL4 G 0 A_Refire(1); Goto FireThree; EBL4 G 3 A_LoadRocket(); EBR4 A 0 A_LoadedRefire(1); Goto FireFour; // load five EBR4 A 2 A_PlaySound("utrl/rotate",CHAN_6,0.1); EBR4 B 0 A_Refire(1); Goto FireFour; EBR4 B 2; EBR4 C 0 A_Refire(1); Goto FireFour; EBR4 C 2; EBR4 D 0 A_Refire(1); Goto FireFour; EBR4 D 2; EBR4 E 0 A_Refire(1); Goto FireFour; EBR4 E 2; EBR4 F 0 A_Refire(1); Goto FireFour; EBR4 F 2; EBR4 G 0 A_Refire(1); Goto FireFour; EBR4 G 2; EBL5 A 0 A_Refire(1); Goto FireFour; EBL5 A 3 A_PlaySound("utrl/load",CHAN_6); EBL5 B 0 A_Refire(1); Goto FireFour; EBL5 B 3; EBL5 C 0 A_Refire(1); Goto FireFour; EBL5 C 3; EBL5 D 0 A_Refire(1); Goto FireFour; EBL5 D 3; EBL5 E 0 A_Refire(1); Goto FireFour; EBL5 E 3; EBL5 F 0 A_Refire(1); Goto FireFour; EBL5 F 3; EBL5 G 0 A_Refire(1); Goto FireFour; EBL5 G 3 A_LoadRocket(); EBR5 A 0 A_LoadedRefire(1); Goto FireFive; // load six EBR5 A 2 A_PlaySound("utrl/rotate",CHAN_6,0.1); EBR5 B 0 A_Refire(1); Goto FireFive; EBR5 B 2; EBR5 C 0 A_Refire(1); Goto FireFive; EBR5 C 2; EBR5 D 0 A_Refire(1); Goto FireFive; EBR5 D 2; EBR5 E 0 A_Refire(1); Goto FireFive; EBR5 E 2; EBR5 F 0 A_Refire(1); Goto FireFive; EBR5 F 2; EBR5 G 0 A_Refire(1); Goto FireFive; EBR5 G 2; EBL6 A 0 A_Refire(1); Goto FireFive; EBL6 A 3 A_PlaySound("utrl/load",CHAN_6); EBL6 B 0 A_Refire(1); Goto FireFive; EBL6 B 3; EBL6 C 0 A_Refire(1); Goto FireFive; EBL6 C 3; EBL6 D 0 A_Refire(1); Goto FireFive; EBL6 D 3; EBL6 E 0 A_Refire(1); Goto FireFive; EBL6 E 3; EBL6 F 0 A_Refire(1); Goto FireFive; EBL6 F 3 A_LoadRocket(); Goto FireSix; FireOne: EBF1 A 0 A_FireRockets(1); EBF1 ABCDEFGH 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; FireTwo: EBF2 A 0 A_FireRockets(2); EBF2 ABCDEFGHIJK 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; FireThree: EBF3 A 0 A_FireRockets(3); EBF3 ABCDEFGHIJ 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; FireFour: EBF4 A 0 A_FireRockets(4); EBF4 ABCDEFGHIJK 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; FireFive: EBF5 A 0 A_FireRockets(5); EBF5 ABCDEFGHIJKLM 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; FireSix: EBF6 A 0 A_FireRockets(6); EBF6 ABCDEFGHIJKLMNOP 2; EBL1 A 0 A_CheckReload(); EBL1 A 2 A_PlaySound("utrl/load",CHAN_6); EBL1 BCDEFG 2; EBLI A 0; Goto Idle; Deselect: EBLD ABCDEFGHIJK 1; EBLD K 1 A_Lower(int.max); Wait; } }