Class UTPlayer : DoomPlayer { bool lastground; double lastvelz, prevvelz; transient CVar footsteps, utmovement, doomspeed, doomaircontrol, nowalkdrop; Vector2 acceleration; Vector3 acceleration3; int last_fm_tap, last_sm_tap; int last_fm, last_sm; const groundspeed = 400.; const accelrate = 2048.; const walkfactor = 0.3; const utaircontrol = 0.35; const groundspeed_doomish = 600.; Default { Player.StartItem "Enforcer"; Player.StartItem "ImpactHammer"; Player.StartItem "MiniAmmo", 30; Player.DamageScreenColor "FF 00 00"; Player.ViewHeight 46; Player.GruntSpeed 20; } // Have to modify the give cheat to handle UT armor override void CheatGive( String name, int amount ) { if ( PlayerNumber() != consoleplayer ) A_Log(String.Format("%s is a cheater: give %s\n",player.GetUserName(),name)); if ( !player.mo || (player.health <= 0) ) return; int giveall = ALL_NO; if ( name ~== "all" ) giveall = ALL_YES; else if (name ~== "everything") giveall = ALL_YESYES; if ( name ~== "health" ) { if ( amount > 0 ) { health += amount; player.health = health; } else player.health = health = GetMaxHealth(true); } if ( giveall || (name ~== "backpack") ) { // Select the correct type of backpack based on the game let type = (class)(gameinfo.backpacktype); if ( type ) GiveInventory(type,1,true); if ( !giveall ) return; } if ( giveall || (name ~== "ammo") ) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. for ( int i=0; i)(AllActorClasses[i]); if ( !type || (type.GetParentClass() != "Ammo") ) continue; // Only give if it's for a valid weapon, unless using "give everything" bool isvalid = false; for ( int j=0; j)(AllActorClasses[j]); if ( !type2 ) continue; let rep = GetReplacement(type2); if ( (rep != type2) && !(rep is "DehackedPickup") ) continue; readonly weap = GetDefaultByType(type2); if ( !player.weapons.LocateWeapon(type2) || (weap.bCheatNotWeapon && (giveall != ALL_YESYES)) ) continue; if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) ) { isvalid = true; break; } } if ( !isvalid ) continue; let ammoitem = FindInventory(type); if ( !ammoitem ) { ammoitem = Inventory(Spawn(type)); ammoitem.AttachToOwner(self); ammoitem.Amount = ammoitem.MaxAmount; } else if ( ammoitem.Amount < ammoitem.MaxAmount ) ammoitem.Amount = ammoitem.MaxAmount; } if ( !giveall ) return; } if ( giveall || (name ~== "armor") ) { // Doom Tournament just gives the player a shield belt and maximum bonuses let belt = Inventory(Spawn("UTShieldBelt")); if ( !belt.CallTryPickup(self) ) belt.Destroy(); let bonus = Inventory(Spawn("UTArmorBonus")); bonus.Amount = bonus.MaxAmount; if ( !bonus.CallTryPickup(self) ) bonus.Destroy(); level.total_items -= 2; // spawning them in raises item count if ( !giveall ) return; } if ( giveall || (name ~== "keys") ) { for ( int i=0; i)(AllActorClasses[i]); if ( !type || (type == "Weapon") ) continue; // Don't give replaced weapons unless the replacement was done by Dehacked. let rep = GetReplacement(type); if ( (rep == type) || (rep is "DehackedPickup") ) { // Give the weapon only if it is set in a weapon slot. if ( !player.weapons.LocateWeapon(type) ) continue; readonly def = GetDefaultByType(type); if ( (giveall == ALL_YESYES) || !def.bCheatNotWeapon ) GiveInventory(type,1,true); } } player.PendingWeapon = savedpending; if ( !giveall ) return; } if ( giveall || (name ~== "artifacts") ) { for ( int i=0; i)(AllActorClasses[i]); if ( !type ) continue; let def = GetDefaultByType (type); if ( def.Icon.isValid() && (def.MaxAmount > 1) && !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor")) { // Do not give replaced items unless using "give everything" if ( (giveall == ALL_YESYES) || (GetReplacement(type) == type) ) GiveInventory(type,(amount<=0)?def.MaxAmount:amount,true); } } if ( !giveall ) return; } if ( giveall || (name ~== "puzzlepieces") ) { for ( int i=0; i)(AllActorClasses[i]); if ( !type ) continue; let def = GetDefaultByType(type); if ( !def.Icon.isValid() ) continue; // Do not give replaced items unless using "give everything" if ( (giveall == ALL_YESYES) || (GetReplacement(type) == type) ) GiveInventory(type,(amount<=0)?def.MaxAmount:amount,true); } if ( !giveall ) return; } if ( giveall ) return; let type = name; if ( !type ) { if ( PlayerNumber() == consoleplayer ) A_Log(String.Format("Unknown item \"%s\"\n",name)); } else GiveInventory(type,amount,true); } override void Tick() { Super.Tick(); if ( !player ) return; if ( !footsteps ) footsteps = CVar.GetCVar('flak_footsteps',players[consoleplayer]); if ( !footsteps.GetBool() ) return; double ang = level.time/(20*TICRATE/35.)*360.; bool forcefootstep = false; if ( player.onground && !bNoGravity && !lastground && (waterlevel < 3) ) { if ( lastvelz < -4 ) { double vol = clamp((-lastvelz-4)*0.05,0.01,1.0); if ( ((waterlevel > 0) || GetFloorTerrain().IsLiquid) && !bOnMobj ) A_PlaySound("ut/wetsplash",CHAN_AUTO,vol); else A_PlaySound("*uland",CHAN_AUTO,vol); } else forcefootstep = true; } if ( forcefootstep || ((abs(sin(ang)) >= 1.0) && player.onground && (player.cmd.forwardmove || player.cmd.sidemove) && (waterlevel < 3)) ) { double vol = abs(vel.xy.length())*0.03; if ( forcefootstep ) vol = clamp(-lastvelz*0.05,0.01,1.0); if ( (waterlevel > 0) || GetFloorTerrain().IsLiquid && !bOnMobj ) A_PlaySound("ut/playerfootstepwet",CHAN_5,vol); else A_PlaySound("ut/playerfootstep",CHAN_5,vol); } lastground = player.onground; lastvelz = prevvelz; prevvelz = vel.z; } double FrictionToUnreal() { double fin = GetFriction(); if ( fin >= 1.0 ) return 0.0; return 734.2969*fin*fin-1485.0868*fin+750.7899; } override void MovePlayer() { if ( !utmovement ) utmovement = CVar.GetCVar('flak_utmovement'); if ( !doomspeed ) doomspeed = CVar.GetCVar('flak_doomspeed'); if ( !doomaircontrol ) doomaircontrol = CVar.GetCVar('flak_doomaircontrol'); if ( !nowalkdrop ) nowalkdrop = CVar.GetCVar('flak_nowalkdrop'); bNODROPOFF = false; if ( !utmovement.GetBool() ) { Super.MovePlayer(); return; } UserCmd cmd = player.cmd; if ( player.turnticks ) { player.turnticks--; Angle += (180./TURN180_TICKS); } else Angle += cmd.yaw*(360./65536.); player.onground = (pos.z <= floorz) || bOnMobj || bMBFBouncer || (player.cheats & CF_NOCLIP2); double friction = FrictionToUnreal(); double fs = TweakSpeeds(1.0,0.0); if ( !doomspeed.GetBool() ) { if ( cmd.buttons&BT_SPEED ) fs *= walkfactor; } else fs *= max(abs(cmd.forwardmove/12800.),abs(cmd.sidemove/10240.)); if ( CanCrouch() && (player.crouchfactor != -1) ) fs *= player.crouchfactor; acceleration = rotatevector((cmd.forwardmove,-cmd.sidemove),angle); if ( player.onground ) { if ( nowalkdrop.GetBool() ) bNODROPOFF = ((acceleration.length() > double.epsilon) && (cmd.buttons&BT_SPEED)); // Hook in Unreal physics Vector2 dir = (0,0); if ( vel.xy.length() > double.epsilon ) dir = vel.xy.unit(); if ( acceleration.length() <= double.epsilon ) { Vector2 oldvel = vel.xy; vel.xy = vel.xy - (2 * dir) * vel.xy.length() * friction/TICRATE; if ( oldvel dot vel.xy < 0.0 ) vel.xy *= 0; } else { Vector2 acceldir = acceleration.unit(); acceleration = acceldir * Min(acceleration.length(), accelrate/TICRATE); vel.xy = vel.xy - (dir - acceldir) * vel.xy.length() * friction/TICRATE; } vel.xy = vel.xy + acceleration * (1./TICRATE); double maxvel; if ( doomspeed.GetBool() ) maxvel = (groundspeed_doomish*fs)/TICRATE; else maxvel = (groundspeed*fs)/TICRATE; double doomfriction = clamp(GetFriction()/ORIG_FRICTION,0.0,1.0); maxvel *= doomfriction; if ( vel.xy.length() > maxvel ) vel.xy = vel.xy.unit()*maxvel; if ( !(player.cheats & CF_PREDICTING) ) { if ( acceleration.length() <= double.epsilon ) PlayIdle(); else PlayRunning(); } player.vel = vel.xy; } else if ( !bNoGravity && !waterlevel ) { // air acceleration when falling float maxaccel = accelrate/TICRATE; if ( vel.xy.length() < (40./TICRATE) ) maxaccel += (40.-vel.xy.length())/TICRATE; if ( acceleration.length() > maxaccel ) acceleration = acceleration.unit()*maxaccel; acceleration *= doomaircontrol.GetBool()?level.aircontrol:0.35; vel.xy += acceleration/TICRATE; player.vel *= 0; } else { // swimming uses standard physics, otherwise things break double forwardmove, sidemove; double bobfactor; double friction, movefactor; double fm, sm; [friction, movefactor] = GetFriction(); bobfactor = (friction 1) && (last_fm*fm>0) ) dodge += RotateVector((fm,0),angle).unit(); last_fm_tap = gametic; last_fm = fm; } if ( sm ) { int clk = abs(gametic-last_sm_tap); if ( (clk < 5) && (clk > 1) && (last_sm*sm>0) ) dodge += RotateVector((0,-sm),angle).unit(); last_sm_tap = gametic; last_sm = sm; } if ( dodge.length() > 0 ) { if ( doomspeed.GetBool() ) vel += dodge.unit()*(groundspeed_doomish*1.5)/TICRATE; else vel += dodge.unit()*(groundspeed*1.5)/TICRATE; vel.z += jumpz*0.5; bOnMobj = false; player.jumpTics = -1; if ( !(player.cheats&CF_PREDICTING) ) A_PlaySound("*jump",CHAN_BODY); } } Super.CheckJump(); } } // Random Spawner that passes through dropped status to items Class RandomSpawner2 : RandomSpawner { override void PostSpawn( Actor spawned ) { if ( !bDROPPED ) return; if ( spawned is 'Inventory' ) Inventory(spawned).bTOSSED = bDROPPED; if ( spawned is 'UTWeapon' ) { spawned.SetState(spawned.ResolveState("Spawn")+1); Inventory(spawned).bALWAYSPICKUP = true; if ( UTWeapon(spawned).DropAmmo > 0 ) Weapon(spawned).AmmoGive1 = min(UTWeapon(spawned).DropAmmo,Weapon(spawned).AmmoGive1); } } } Class UTWeapon : Weapon { int DropAmmo; Property DropAmmo: DropAmmo; // Drawstuffs under HUD virtual ui void PreRender( double lbottom ) {} // Drawstuffs over HUD virtual ui void PostRender( double lbottom ) {} override Inventory CreateTossable( int amt ) { if ( Ammo1 && (Ammo1.Amount <= 0) ) return null; Inventory d = Super.CreateTossable(amt); if ( d && (d.GetClass() == GetClass()) ) { d.SetState(d.ResolveState("Spawn")+1); d.bALWAYSPICKUP = true; } return d; } override bool SpecialDropAction( Actor dropper ) { SetState(ResolveState("Spawn")+1); bALWAYSPICKUP = true; return false; } override void Tick() { Super.Tick(); if ( !Owner || !Owner.player || (Owner.player.ReadyWeapon != self) ) return; Owner.player.WeaponState |= WF_WEAPONBOBBING; // UT weapons always bob } void FireEffect() { let amp = DamageAmplifier(Owner.FindInventory("DamageAmplifier",true)); if ( amp ) amp.FireEffect(); } override void OwnerDied() { Super.OwnerDied(); A_ClearRefire(); } Default { Weapon.BobStyle "Smooth"; Weapon.BobSpeed 1.5; Weapon.BobRangeX 0.2; Weapon.BobRangeY 0.4; Weapon.YAdjust 0; +WEAPON.NOALERT; } } Class UTTeleportLight : DynamicLight { Default { DynamicLight.Type "Point"; Args 128,160,255,80; } override void Tick() { Super.Tick(); if ( alpha <= 0 ) { Destroy(); return; } args[LIGHT_RED] = int(128*alpha); args[LIGHT_GREEN] = int(160*alpha); args[LIGHT_BLUE] = int(255*alpha); args[LIGHT_INTENSITY] = Random[Tele](10,14)*8; alpha -= 1./35; } } Class UTItemLight : DynamicLight { Default { DynamicLight.Type "Point"; Args 255,224,160,48; } override void Tick() { Super.Tick(); if ( alpha <= 0 ) { Destroy(); return; } args[LIGHT_RED] = int(255*alpha); args[LIGHT_GREEN] = int(224*alpha); args[LIGHT_BLUE] = int(160*alpha); args[LIGHT_INTENSITY] = Random[Tele](6,8)*8; alpha -= 3./35; } } Class UTTeleportFog : Actor replaces TeleportFog { Default { +NOBLOCKMAP; +NOTELEPORT; +NOGRAVITY; RenderStyle "Add"; } override void PostBeginPlay() { Super.PostBeginPlay(); Spawn("UTTeleportLight",pos+(0,0,16)); A_PlaySound ("misc/teleport"); } States { Spawn: TELE ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 Bright A_FadeOut(1./35); TEL2 ABCDEFGHI 1 Bright A_FadeOut(1./35); Stop; } } Class UTItemFog : Actor replaces ItemFog { Default { +NOBLOCKMAP; +NOTELEPORT; +NOGRAVITY; RenderStyle "Add"; } override void PostBeginPlay() { Super.PostBeginPlay(); Spawn("UTItemLight",pos+(0,0,16)); } States { Spawn: TNT1 A 1; Stop; } } Class UTSpark : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +FORCEXYBILLBOARD; +MISSILE; +MOVEWITHSECTOR; +THRUACTORS; +NOTELEPORT; +DONTSPLASH; BounceType "Doom"; BounceFactor 0.4; Gravity 0.5; Scale 0.05; } override void Tick() { Super.Tick(); if ( waterlevel > 0 ) { let b = Spawn("UTBubble",pos); b.vel = vel; b.scale *= 0.3; Destroy(); } } States { Spawn: SPRK A 1 Bright A_FadeOut(0.01); Wait; Death: SPRK A 1 Bright A_FadeOut(0.05); Wait; } } Class UTViewSpark : UTSpark { Default { +NOCLIP; -MISSILE; BounceType "None"; } Vector3 ofs, vvel; override void Tick() { Actor.Tick(); if ( !target || !target.player ) { Destroy(); return; } Vector3 x, y, z; [x, y, z] = Matrix4.GetAxes(target.pitch,target.angle,target.roll); Vector3 origin = x*ofs.x+y*ofs.y+z*ofs.z+(0,0,target.player.viewz); SetOrigin(target.Vec2OffsetZ(origin.x,origin.y,origin.z),true); bInvisible = (players[consoleplayer].camera != target); if ( level.frozen || globalfreeze ) return; ofs += vvel; vvel.z -= 0.1; scale *= 0.8; if ( (scale.x <= 0.01) || (waterlevel > 0) ) Destroy(); } } Class UTChip : Actor { int deadtimer; double rollvel, anglevel, pitchvel; Default { Radius 2; Height 2; +NOBLOCKMAP; +MISSILE; +MOVEWITHSECTOR; +THRUACTORS; +NOTELEPORT; +DONTSPLASH; BounceType "Doom"; BounceFactor 0.3; Gravity 0.7; Scale 0.2; } override void PostBeginPlay() { Super.PostBeginPlay(); deadtimer = 0; anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); frame = Random[Junk](0,3); scale *= Frandom[Junk](0.8,1.2); } override void Tick() { Super.Tick(); if ( level.frozen || globalfreeze ) return; if ( InStateSequence(CurState,ResolveState("Death")) ) { deadtimer++; if ( deadtimer > 300 ) A_FadeOut(0.05); return; } } States { Spawn: CHIP # 1 { A_SetAngle(angle+anglevel,SPF_INTERPOLATE); A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE); A_SetRoll(roll+rollvel,SPF_INTERPOLATE); } Loop; Bounce: CHIP # 0 { anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); } Goto Spawn; Death: CHIP # -1; Stop; Dummy: CHIP ABCD -1; Stop; } } Class UTBubble : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; +NOTELEPORT; Scale 0.05; } override void PostBeginPlay() { Super.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8); if ( waterlevel <= 0 ) Destroy(); SetState(ResolveState("Spawn")+Random[Puff](0,2)); } override void Tick() { Super.Tick(); if ( level.frozen || globalfreeze ) return; vel *= 0.96; vel.z += 0.05; if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy(); } States { Spawn: BUBL ABC -1; Stop; } } Class UTSmoke : Actor { Default { RenderStyle "Shaded"; StencilColor "FFFFFF"; Radius 2; Height 2; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +FORCEXYBILLBOARD; +THRUACTORS; +NOTELEPORT; +CANBOUNCEWATER; -BOUNCEAUTOOFF; BounceType "Hexen"; BounceFactor 1.0; WallBounceFactor 1.0; Scale 0.5; } override void PostBeginPlay() { Super.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.5,1.5); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8); } override void Tick() { Super.Tick(); if ( level.frozen || globalfreeze ) return; vel *= 0.96; vel.z += 0.01; A_FadeOut(1/32.); if ( waterlevel > 0 ) { let b = Spawn("UTBubble",pos); b.vel = vel; Destroy(); } } States { Spawn: TNT1 A 0 NoDelay A_Jump(255,"US1","US2","US3","US4","US5","US6","US7","US8","US9","US10"); Stop; US1: US1_ ABCDEFGHIJKLMNOP 2; Stop; US2: US2_ ABCDEFGHIJKLMNOP 2; Stop; US3: US3_ ABCDEFGHIJKLMNOP 2; Stop; US4: US4_ ABCDEFGHIJKLMNO 2; Stop; US5: US5_ ABCDEFGHIJKLMNO 2; Stop; US6: US6_ ABCDEFGHIJKLMNOP 2; Stop; US7: US7_ ABCDEFGHIJKLMNOP 2; Stop; US8: US8_ ABCDEFGHIJKLMNOP 2; Stop; US9: US9_ ABCDEFGHIJKLMNOP 2; Stop; US10: US10 ABCDEFGHIJKLMNOP 2; Stop; } } Class UTSmallSmoke : UTSmoke { override void PostBeginPlay() { Actor.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16); } } Class UTViewSmoke : UTSmoke { Vector3 ofs, vvel; override void PostBeginPlay() { Actor.PostBeginPlay(); double ang, pt; scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vvel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16); } override void Tick() { Actor.Tick(); if ( !target || !target.player ) { Destroy(); return; } Vector3 x, y, z; [x, y, z] = Matrix4.GetAxes(target.pitch,target.angle,target.roll); Vector3 origin = x*ofs.x+y*ofs.y+z*ofs.z+(0,0,target.player.viewz); SetOrigin(target.Vec2OffsetZ(origin.x,origin.y,origin.z),true); bInvisible = (players[consoleplayer].camera != target); if ( level.frozen || globalfreeze ) return; ofs += vvel; vvel *= 0.96; vvel.z += 0.01; A_FadeOut(1/32.); if ( waterlevel > 0 ) Destroy(); } } Class UTStaticViewSmoke : UTViewSmoke { override void PostBeginPlay() { Actor.PostBeginPlay(); scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); } } Class UTRedSkull : RedSkull replaces RedSkull { Default { Tag "Red Skull"; Species "RedSkull"; Inventory.PickupMessage "You got the Red Skull."; } States { Spawn: USKL A -1; Stop; } } Class UTGoldSkull : YellowSkull replaces YellowSkull { Default { Tag "Gold Skull"; Species "YellowSkull"; Inventory.PickupMessage "You got the Gold Skull."; } States { Spawn: USKL B -1; Stop; } } Class UTBlueSkull : BlueSkull replaces BlueSkull { Default { Tag "Blue Skull"; Species "BlueSkull"; Inventory.PickupMessage "You got the Blue Skull."; } States { Spawn: USKL C -1; Stop; } } Class UTRedKey : RedCard replaces RedCard { Default { Tag "Red Key"; Species "RedCard"; Inventory.PickupMessage "You got the Red Key."; } States { Spawn: UKEY A -1; Stop; } } Class UTGoldKey : YellowCard replaces YellowCard { Default { Tag "Gold Key"; Species "YellowCard"; Inventory.PickupMessage "You got the Gold Key."; } States { Spawn: UKEY B -1; Stop; } } Class UTBlueKey : BlueCard replaces BlueCard { Default { Tag "Blue Key"; Species "BlueCard"; Inventory.PickupMessage "You got the Blue Key."; } States { Spawn: UKEY C -1; Stop; } } Class GenericFlash : HUDMessageBase { Color col; int duration; double alpha; Actor cam; GenericFlash Setup( Actor camera, Color c, int d ) { alpha = 1.0; col = c; duration = d; cam = camera; return self; } override bool Tick() { alpha -= 1./duration; return (alpha<=0); } override void Draw( int bottom, int visibility ) { if ( automapactive || (visibility != BaseStatusBar.HUDMSGLayer_UnderHUD) ) return; if ( cam && (players[consoleplayer].camera != cam) ) return; Screen.Dim(col,(col.a/255.)*alpha,0,0,Screen.GetWidth(),Screen.GetHeight()); } } Class QueuedFlash { Color c; int duration; int tic; Actor cam; } Class UTMainHandler : StaticEventHandler { ui TextureID tex; Array flashes; transient CVar nobosstelefrag; override void WorldLoaded( WorldEvent e ) { if ( gamestate != GS_LEVEL || e.IsSaveGame ) return; // prettify Kinsie's test map for a more Unreal feel if ( level.levelname ~== "Modder Test Map" ) { TexMan.ReplaceTextures("-noflat-","-kinsie-",0); TextureID skytx = TexMan.CheckForTexture("BlueSky",TexMan.Type_Any); level.ChangeSky(skytx,skytx); // TODO handplace some dynamic lights and add Unreal/UT ambient sounds } } override void WorldThingSpawned( WorldEvent e ) { if ( !nobosstelefrag ) nobosstelefrag = CVar.GetCVar('flak_nobosstelefrag'); if ( nobosstelefrag.GetBool() && e.Thing.bBOSS ) e.Thing.bNOTELEFRAG = true; } ui void StartMenu() { int proto = CVar.GetCVar('flak_protomenu',players[consoleplayer]).GetInt(); if ( proto ) { tex = TexMan.CheckForTexture("protobg",TexMan.Type_Any); if ( gamestate != GS_TITLELEVEL ) return; if ( proto > 1 ) S_ChangeMusic("menu2"); else S_ChangeMusic("xyzdMenu"); } else { tex = TexMan.CheckForTexture("finalbg",TexMan.Type_Any); if ( gamestate != GS_TITLELEVEL ) return; S_ChangeMusic("utmenu23"); } } override void PlayerEntered( PlayerEvent e ) { if ( CVar.GetCVar('flak_translocator').GetBool() ) players[e.playernumber].mo.GiveInventory("Translocator",1); } override void PlayerRespawned( PlayerEvent e ) { if ( CVar.GetCVar('flak_translocator').GetBool() ) players[e.playernumber].mo.GiveInventory("Translocator",1); } override void NetworkProcess( ConsoleEvent e ) { if ( e.Name ~== "refreshtrans" ) { if ( CVar.GetCVar('flak_translocator').GetBool() ) { for ( int i=0; i= gametic ) continue; flashes.Delete(i); i--; } } override void PostUiTick() { for ( int i=0; i ExplosionRadius) ) continue; Vector3 midpoint = a.Vec3Offset(0,0,a.height*0.5); a.vel += Level.Vec3Diff(Source.pos,midpoint).unit()*(MomentumTransfer/(Thinker.TICRATE*a.mass)); } } // Same for this static void DoKnockback( Actor Victim, Vector3 HitDirection, double MomentumTransfer ) { if ( !Victim ) return; Victim.vel += HitDirection*(MomentumTransfer/(Thinker.TICRATE*Victim.Mass)); } }