Reduced the smoke on the minigun and casings for better performance. Corrected the number of chunks (was 6, should be 8) fired by the flak cannon. Reduced flak chunk spread (should be ~5.5 degrees, was double of that) on the weapon and slugs. Reduced the size of the shock rifle combo shockwave mesh to be closer to vanilla UT. Misc. tweaks to health item textures. Reduced the blur in the Redeemer view shader, it was too strong. Fix expiration messages on powerups appearing on level changes. Address complaints about how I change Kinsie's test map. Shouldn't be too dark now.
1945 lines
53 KiB
Text
1945 lines
53 KiB
Text
Class UTPlayer : DoomPlayer
|
|
{
|
|
bool lastground;
|
|
int lastgroundtic;
|
|
double lastvelz, prevvelz;
|
|
transient CVar footsteps;
|
|
Vector2 acceleration;
|
|
Vector3 acceleration3;
|
|
int last_fm, last_sm;
|
|
int last_fm_tap, last_sm_tap;
|
|
int last_tap_fm, last_tap_sm;
|
|
int last_jump_held;
|
|
|
|
int dolltype;
|
|
|
|
Property DollType : dolltype;
|
|
|
|
enum EDollType
|
|
{
|
|
DOLL_Male,
|
|
DOLL_Female,
|
|
DOLL_Boss
|
|
};
|
|
|
|
const groundspeed = 400.;
|
|
const swimspeed = 200.;
|
|
const baseaccelrate = 2048.;
|
|
const walkfactor = 0.3;
|
|
const utaircontrol = 0.35;
|
|
const swimspeed_doomish = 400.;
|
|
const groundspeed_doomish = 600.;
|
|
const dodgez = 210.;
|
|
const utjumpz = 325.;
|
|
const groundfriction = 8.;
|
|
const fluidfriction = 1.2;
|
|
const terminalvelocity = 2500.;
|
|
|
|
Default
|
|
{
|
|
Player.StartItem "Enforcer";
|
|
Player.StartItem "ImpactHammer";
|
|
Player.StartItem "MiniAmmo", 30;
|
|
Player.DamageScreenColor "FF 00 00";
|
|
Player.ViewHeight 46;
|
|
Player.GruntSpeed 20;
|
|
+NOMENU;
|
|
UTPlayer.DollType DOLL_Male;
|
|
}
|
|
|
|
// 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<Inventory>)(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.Size(); i++ )
|
|
{
|
|
let type = (class<Ammo>)(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.Size(); j++ )
|
|
{
|
|
let type2 = (class<Weapon>)(AllActorClasses[j]);
|
|
if ( !type2 ) continue;
|
|
let rep = GetReplacement(type2);
|
|
if ( (rep != type2) && !(rep is "DehackedPickup") ) continue;
|
|
readonly<Weapon> 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.Size(); i++ )
|
|
{
|
|
if ( !(AllActorClasses[i] is "Key") ) continue;
|
|
let keyitem = GetDefaultByType(AllActorClasses[i]);
|
|
if ( keyitem.special1 )
|
|
{
|
|
let item = Inventory(Spawn(AllActorClasses[i]));
|
|
if ( !item.CallTryPickup(self) ) item.Destroy();
|
|
}
|
|
}
|
|
if ( !giveall ) return;
|
|
}
|
|
if ( giveall || (name ~== "weapons") )
|
|
{
|
|
let savedpending = player.PendingWeapon;
|
|
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
|
{
|
|
let type = (class<Weapon>)(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<Weapon> 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.Size(); i++ )
|
|
{
|
|
let type = (class<Inventory>)(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.Size(); i++ )
|
|
{
|
|
let type = (class<PuzzleItem>)(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 || (player.mo != self) ) return;
|
|
if ( flak_utmovement )
|
|
{
|
|
bNOFRICTION = true;
|
|
bNOFRICTIONBOUNCE = true;
|
|
}
|
|
else
|
|
{
|
|
bNOFRICTION = false;
|
|
bNOFRICTIONBOUNCE = false;
|
|
}
|
|
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 < 2) )
|
|
{
|
|
player.jumptics = 0;
|
|
if ( lastvelz < -8 )
|
|
{
|
|
double vol = clamp((-lastvelz-8)*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 && lastground && (player.jumptics == 0) && (player.cmd.forwardmove || player.cmd.sidemove) && (waterlevel < 2)) )
|
|
{
|
|
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 PlayFootstep(vol);
|
|
}
|
|
lastground = player.onground;
|
|
lastvelz = prevvelz;
|
|
prevvelz = vel.z;
|
|
// TODO exit/entry sounds for water
|
|
}
|
|
|
|
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 ( !flak_utmovement || !player || (player.mo != self) )
|
|
{
|
|
Super.MovePlayer();
|
|
return;
|
|
}
|
|
bNODROPOFF = false;
|
|
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);
|
|
if ( player.onground ) lastgroundtic = gametic;
|
|
if ( !player.onground && !bNoGravity && (waterlevel < 2) && (abs(pos.z-floorz) <= maxdropoffheight) && (player.jumptics == 0) && (vel.z < 0) )
|
|
{
|
|
SetOrigin(Vec2OffsetZ(0,0,floorz),true);
|
|
player.onground = true;
|
|
}
|
|
double friction = FrictionToUnreal();
|
|
double fs = TweakSpeeds(1.0,0.0);
|
|
if ( !flak_doomspeed )
|
|
{
|
|
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);
|
|
double accelrate = baseaccelrate*fs;
|
|
Vector2 dodge = (0,0);
|
|
int fm = cmd.forwardmove;
|
|
int sm = cmd.sidemove;
|
|
if ( fm )
|
|
{
|
|
int clk = abs(gametic-last_fm_tap);
|
|
if ( (clk < flak_taptics) && (last_fm*fm == 0) && (last_tap_fm*fm>0) )
|
|
dodge += RotateVector((fm,0),angle).unit();
|
|
if ( !last_fm && (last_jump_held < gametic-1) )
|
|
{
|
|
last_fm_tap = gametic;
|
|
last_tap_fm = fm;
|
|
}
|
|
}
|
|
last_fm = fm;
|
|
if ( sm )
|
|
{
|
|
int clk = abs(gametic-last_sm_tap);
|
|
if ( (clk < flak_taptics) && (last_sm*sm == 0) && (last_tap_sm*sm>0) )
|
|
dodge += RotateVector((0,-sm),angle).unit();
|
|
if ( !last_sm && (last_jump_held < gametic-1) )
|
|
{
|
|
last_sm_tap = gametic;
|
|
last_tap_sm = sm;
|
|
}
|
|
}
|
|
last_sm = sm;
|
|
if ( !bNoGravity && player.onground && (waterlevel < 2) )
|
|
{
|
|
if ( flak_tapdodge && (dodge.length() > 0) )
|
|
{
|
|
if ( flak_doomspeed ) vel += dodge.unit()*(groundspeed_doomish*1.5)/TICRATE;
|
|
else vel += dodge.unit()*(groundspeed*1.5)/TICRATE;
|
|
vel.z += dodgez/TICRATE;
|
|
bOnMobj = false;
|
|
if ( !(player.cheats&CF_PREDICTING) )
|
|
A_PlaySound("*jump",CHAN_BODY);
|
|
if ( player.cheats & CF_REVERTPLEASE )
|
|
{
|
|
player.cheats &= ~CF_REVERTPLEASE;
|
|
player.camera = player.mo;
|
|
}
|
|
player.vel *= 0;
|
|
player.jumptics = -2;
|
|
}
|
|
else
|
|
{
|
|
if ( flak_nowalkdrop )
|
|
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();
|
|
double doomfriction = clamp(GetFriction()/ORIG_FRICTION,0.0,1.0);
|
|
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/TICRATE;
|
|
double maxvel;
|
|
if ( flak_doomspeed ) maxvel = groundspeed_doomish/TICRATE;
|
|
else maxvel = groundspeed/TICRATE;
|
|
maxvel *= fs*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 < 2) )
|
|
{
|
|
// 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;
|
|
Vector2 dir = (0,0);
|
|
if ( vel.xy.length() > double.epsilon ) dir = vel.xy.unit();
|
|
if ( acceleration.length() > double.epsilon )
|
|
{
|
|
Vector2 acceldir = acceleration.unit();
|
|
acceleration = acceldir * Min(acceleration.length(), accelrate/TICRATE);
|
|
}
|
|
acceleration *= flak_doomaircontrol?level.aircontrol:utaircontrol;
|
|
double maxvel;
|
|
if ( flak_doomspeed ) maxvel = (groundspeed_doomish*fs)/TICRATE;
|
|
else maxvel = (groundspeed*fs)/TICRATE;
|
|
// TODO attempt to replicate walk on ice velocity increase glitch
|
|
// if new velocity is higher than ground speed, steer but don't increase it
|
|
if ( (vel.xy+acceleration/TICRATE).length() > maxvel )
|
|
{
|
|
double vsiz = vel.xy.length();
|
|
vel.xy = (vel.xy+acceleration/TICRATE).unit()*vsiz;
|
|
}
|
|
else vel.xy = vel.xy+acceleration/TICRATE;
|
|
if ( vel.length() > terminalvelocity/TICRATE ) vel = vel.unit()*(terminalvelocity/TICRATE);
|
|
player.vel *= 0;
|
|
player.jumptics = -2;
|
|
}
|
|
else if ( bFly || (player.cheats&CF_NOCLIP2) )
|
|
{
|
|
// fly cheat has infinite friction (player stops moving when movement keys are released)
|
|
Vector3 dir = (0,0,0);
|
|
if ( vel.length() > double.epsilon ) dir = vel.unit();
|
|
Vector3 x, y;
|
|
[x, y] = dt_Matrix4.GetAxes(pitch,angle,0);
|
|
acceleration3 = x*player.cmd.forwardmove+y*player.cmd.sidemove;
|
|
if ( player.cmd.buttons&BT_JUMP ) acceleration3.z = 0x500;
|
|
else if ( player.cmd.buttons&BT_CROUCH ) acceleration3.z = -0x500;
|
|
if ( acceleration3.length() <= double.epsilon ) vel *= 0;
|
|
else
|
|
{
|
|
Vector3 acceldir = acceleration3.unit();
|
|
acceleration3 = acceldir*Min(acceleration3.length(),accelrate/TICRATE);
|
|
vel = vel-(dir-acceldir)*vel.length();
|
|
}
|
|
vel = vel+acceleration3/TICRATE;
|
|
double maxvel;
|
|
if ( flak_doomspeed ) maxvel = groundspeed_doomish/TICRATE;
|
|
else maxvel = groundspeed/TICRATE;
|
|
maxvel *= fs;
|
|
if ( vel.length() > maxvel ) vel = vel.unit()*maxvel;
|
|
player.vel *= 0;
|
|
player.jumptics = -2;
|
|
if ( !(player.cheats & CF_PREDICTING) ) PlayIdle();
|
|
}
|
|
else
|
|
{
|
|
// swimming is pretty much like ground movement, but with much reduced friction and lower speed
|
|
friction *= fluidfriction/groundfriction;
|
|
Vector3 dir = (0,0,0);
|
|
if ( vel.length() > double.epsilon ) dir = vel.unit();
|
|
double doomfriction = clamp(GetFriction()/ORIG_FRICTION,0.0,1.0);
|
|
Vector3 x, y;
|
|
[x, y] = dt_Matrix4.GetAxes(pitch,angle,0);
|
|
acceleration3 = x*player.cmd.forwardmove+y*player.cmd.sidemove;
|
|
if ( player.cmd.buttons&BT_JUMP ) acceleration3.z = 0x500;
|
|
else if ( player.cmd.buttons&BT_CROUCH ) acceleration3.z = -0x500;
|
|
if ( acceleration3.length() <= double.epsilon )
|
|
{
|
|
Vector3 oldvel = vel;
|
|
vel = vel-(2*dir)*vel.length()*friction/TICRATE;
|
|
if ( oldvel dot vel < 0.0 ) vel *= 0;
|
|
}
|
|
else
|
|
{
|
|
Vector3 acceldir = acceleration3.unit();
|
|
acceleration3 = acceldir*Min(acceleration3.length(),accelrate/TICRATE);
|
|
vel = vel-(dir-acceldir)*vel.length()*friction/TICRATE;
|
|
}
|
|
vel = vel+acceleration3/TICRATE;
|
|
double maxvel;
|
|
if ( flak_doomspeed ) maxvel = swimspeed_doomish/TICRATE;
|
|
else maxvel = swimspeed/TICRATE;
|
|
maxvel *= fs*doomfriction;
|
|
if ( vel.length() > maxvel ) vel = vel.unit()*maxvel;
|
|
player.vel = vel.xy;
|
|
player.jumptics = -2;
|
|
if ( !(player.cheats & CF_PREDICTING) )
|
|
{
|
|
if ( acceleration3.length() <= double.epsilon ) PlayIdle();
|
|
else PlayRunning();
|
|
}
|
|
}
|
|
if ( player.cheats & CF_REVERTPLEASE )
|
|
{
|
|
player.cheats &= ~CF_REVERTPLEASE;
|
|
player.camera = player.mo;
|
|
}
|
|
}
|
|
override void CheckCrouch( bool totallyfrozen )
|
|
{
|
|
if ( !flak_utmovement || !player || (player.mo != self) )
|
|
{
|
|
Super.CheckCrouch(totallyfrozen);
|
|
return;
|
|
}
|
|
if ( player.cmd.buttons&BT_JUMP ) player.cmd.buttons &= ~BT_CROUCH;
|
|
if ( CanCrouch() && (player.health > 0) && level.IsCrouchingAllowed() && player.onground ) // in UT you can't crouch unless you're on the ground
|
|
{
|
|
if ( !totallyfrozen )
|
|
{
|
|
int crouchdir = player.crouching;
|
|
if ( !crouchdir ) crouchdir = (player.cmd.buttons&BT_CROUCH)?-1:1;
|
|
else if ( player.cmd.buttons&BT_CROUCH ) player.crouching = 0;
|
|
if ( (crouchdir == 1) && (player.crouchfactor < 1) && (pos.Z+height < ceilingz) )
|
|
CrouchMove(1);
|
|
else if ( (crouchdir == -1) && (player.crouchfactor > 0.5 ))
|
|
CrouchMove(-1);
|
|
}
|
|
}
|
|
else player.Uncrouch();
|
|
player.crouchoffset = -(ViewHeight)*(1-player.crouchfactor);
|
|
}
|
|
override void CheckJump()
|
|
{
|
|
if ( !flak_utmovement || !player || (player.mo != self) )
|
|
{
|
|
Super.CheckJump();
|
|
return;
|
|
}
|
|
if ( player.cmd.buttons&BT_JUMP )
|
|
{
|
|
if ( player.crouchoffset ) player.crouching = 1;
|
|
else if ( level.IsJumpingAllowed() && player.onground && (player.jumpTics == 0) && (last_jump_held < gametic-1) && !bNoGravity && (waterlevel < 2) && !(player.cheats&(CF_FLY|CF_NOCLIP2)) )
|
|
{
|
|
double jumpvelz;
|
|
if ( flak_doomspeed ) jumpvelz = jumpz;
|
|
else jumpvelz = utjumpz/TICRATE;
|
|
double jumpfac = 0;
|
|
for ( let p = Inv; p != null; p = p.Inv )
|
|
{
|
|
let pp = PowerHighJump(p);
|
|
if ( !pp ) continue;
|
|
double f = pp.Strength;
|
|
if ( f > jumpfac ) jumpfac = f;
|
|
}
|
|
if ( jumpfac > 0 ) jumpvelz *= jumpfac;
|
|
Vel.z += jumpvelz;
|
|
bOnMobj = false;
|
|
player.jumpTics = -1;
|
|
if ( !(player.cheats&CF_PREDICTING) )
|
|
A_PlaySound("*jump",CHAN_BODY);
|
|
}
|
|
last_jump_held = gametic;
|
|
}
|
|
if ( !player.onground || player.jumptics )
|
|
last_jump_held = gametic;
|
|
}
|
|
|
|
virtual void PlayFootstep( double vol )
|
|
{
|
|
A_PlaySound("ut/playerfootstep",CHAN_5,vol);
|
|
}
|
|
}
|
|
|
|
// these only exist for sound
|
|
// female classes have identical sounds, so they use the same soundclass here
|
|
Class UTPlayerTMale1 : UTPlayer
|
|
{
|
|
Default
|
|
{
|
|
Player.SoundClass "tmale1";
|
|
Player.DisplayName "M Commando";
|
|
Player.Portrait "Blake";
|
|
-NOMENU;
|
|
}
|
|
}
|
|
Class UTPlayerTMale2 : UTPlayer
|
|
{
|
|
Default
|
|
{
|
|
Player.SoundClass "tmale2";
|
|
Player.DisplayName "M Soldier";
|
|
Player.Portrait "Brock";
|
|
-NOMENU;
|
|
}
|
|
}
|
|
Class UTPlayerTFemale1 : UTPlayer
|
|
{
|
|
Default
|
|
{
|
|
Player.SoundClass "tfemale";
|
|
Player.DisplayName "F Commando";
|
|
Player.Portrait "Ivana";
|
|
UTPlayer.DollType DOLL_Female;
|
|
-NOMENU;
|
|
}
|
|
}
|
|
Class UTPlayerTFemale2 : UTPlayer
|
|
{
|
|
Default
|
|
{
|
|
Player.SoundClass "tfemale";
|
|
Player.DisplayName "F Soldier";
|
|
Player.Portrait "Lauren";
|
|
UTPlayer.DollType DOLL_Female;
|
|
-NOMENU;
|
|
}
|
|
}
|
|
Class UTPlayerTBoss : UTPlayer
|
|
{
|
|
transient CVar bossfootsteps;
|
|
Default
|
|
{
|
|
Player.SoundClass "tboss";
|
|
Player.DisplayName "Boss";
|
|
Player.Portrait "Xan";
|
|
UTPlayer.DollType DOLL_Boss;
|
|
// should have NOBLOOD, but Xan did bleed in vanilla UT so...
|
|
// (this is what gave birth to the theory that Xan was actually Jerl Liandri himself)
|
|
-NOMENU;
|
|
}
|
|
override void PlayFootstep( double vol )
|
|
{
|
|
if ( !bossfootsteps ) bossfootsteps = CVar.GetCVar('flak_bossfootsteps',players[consoleplayer]);
|
|
if ( bossfootsteps.GetBool() ) A_PlaySound("ut/bossfootstep",CHAN_5,vol);
|
|
else Super.PlayFootstep(vol);
|
|
}
|
|
}
|
|
|
|
Class UTWeapon : Weapon
|
|
{
|
|
int DropAmmo;
|
|
bool bExtraPickup;
|
|
|
|
Property DropAmmo: DropAmmo;
|
|
|
|
// Drawstuffs under HUD
|
|
virtual ui void PreRender( double lbottom ) {}
|
|
// Drawstuffs over HUD
|
|
virtual ui void PostRender( double lbottom ) {}
|
|
// Future preparations for scripted textures
|
|
virtual ui void RenderOverlay( RenderEvent e ) {}
|
|
|
|
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();
|
|
// don't slide on floor when dropped
|
|
if ( CurState == ResolveState("Spawn")+1 )
|
|
{
|
|
if ( pos.z <= floorz )
|
|
vel.xy *= 0;
|
|
}
|
|
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();
|
|
}
|
|
|
|
override bool HandlePickup( Inventory item )
|
|
{
|
|
if (item.GetClass() == GetClass())
|
|
{
|
|
if ( Weapon(item).PickupForAmmo(self) )
|
|
item.bPickupGood = true;
|
|
if ( (MaxAmount > 1) || bALWAYSPICKUP )
|
|
return Inventory.HandlePickup(item);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
override bool ShouldStay()
|
|
{
|
|
if ( ((multiplayer && (!deathmatch && !alwaysapplydmflags)) || sv_weaponstay) && !bDropped )
|
|
return (!bExtraPickup && !bALWAYSPICKUP);
|
|
return false;
|
|
}
|
|
override bool TryPickup( in out Actor toucher )
|
|
{
|
|
if ( !bExtraPickup ) bExtraPickup = ((MaxAmount > 1) && (toucher.CountInv(GetClass()) < MaxAmount));
|
|
return Super.TryPickup(toucher);
|
|
}
|
|
|
|
// Whole chain of function rewrites because of some stupid hardcoded deathmatch ammo multiplier
|
|
override bool TryPickupRestricted( in out Actor toucher )
|
|
{
|
|
if ( ShouldStay() ) return false;
|
|
bExtraPickup = false;
|
|
bool gaveSome = !!(NonIdioticAddAmmo(toucher,AmmoType1,AmmoGive1));
|
|
gaveSome |= !!(NonIdioticAddAmmo(toucher,AmmoType2,AmmoGive2));
|
|
if ( gaveSome ) GoAwayAndDie();
|
|
return gaveSome;
|
|
}
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
bExtraPickup = false;
|
|
Inventory.AttachToOwner(other);
|
|
Ammo1 = NonIdioticAddAmmo(Owner,AmmoType1,AmmoGive1);
|
|
Ammo2 = NonIdioticAddAmmo(Owner,AmmoType2,AmmoGive2);
|
|
SisterWeapon = AddWeapon(SisterWeaponType);
|
|
if ( Owner.player )
|
|
{
|
|
if ( !Owner.player.GetNeverSwitch() && !bNo_Auto_Switch )
|
|
Owner.player.PendingWeapon = self;
|
|
if ( Owner.player.mo == players[consoleplayer].camera )
|
|
StatusBar.ReceivedWeapon(self);
|
|
}
|
|
GivenAsMorphWeapon = false;
|
|
}
|
|
|
|
// rewrite of AddAmmo without stupid hardcoded 2.5x ammo multiplier
|
|
protected Ammo NonIdioticAddAmmo( Actor other, Class<Ammo> ammotype, int amount )
|
|
{
|
|
if ( !ammotype ) return null;
|
|
Ammo ammoitem;
|
|
if ( !bIgnoreSkill ) amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
ammoitem = Ammo(other.FindInventory(ammotype));
|
|
if ( !ammoitem )
|
|
{
|
|
ammoitem = Ammo(Spawn(ammotype));
|
|
ammoitem.Amount = min(amount,ammoitem.MaxAmount);
|
|
ammoitem.AttachToOwner(other);
|
|
}
|
|
else if ( ammoitem.Amount < ammoitem.MaxAmount )
|
|
{
|
|
ammoitem.Amount += amount;
|
|
if ( ammoitem.Amount > ammoitem.MaxAmount )
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
return ammoitem;
|
|
}
|
|
|
|
override void OnDrop( Actor dropper )
|
|
{
|
|
Vector2 hofs = RotateVector((dropper.radius,0),dropper.angle);
|
|
SetOrigin(dropper.Vec3Offset(hofs.x,hofs.y,dropper.height*0.5),false);
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_Matrix4.GetAxes(dropper.pitch,dropper.angle,dropper.roll);
|
|
vel = x*12.0;
|
|
vel.z += 4.0;
|
|
angle = dropper.angle;
|
|
pitch = 0;
|
|
roll = 0;
|
|
}
|
|
|
|
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
|
|
{
|
|
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
|
|
{
|
|
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.2;
|
|
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] = dt_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;
|
|
+INTERPOLATEANGLES;
|
|
BounceType "Doom";
|
|
BounceFactor 0.3;
|
|
Gravity 0.35;
|
|
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
|
|
{
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
roll += rollvel;
|
|
}
|
|
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] = dt_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
|
|
{
|
|
Default
|
|
{
|
|
Tag "Red Skull";
|
|
Species "RedSkull";
|
|
Inventory.PickupMessage "You got the Red Skull.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
USKL A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTGoldSkull : YellowSkull
|
|
{
|
|
Default
|
|
{
|
|
Tag "Gold Skull";
|
|
Species "YellowSkull";
|
|
Inventory.PickupMessage "You got the Gold Skull.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
USKL B -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTBlueSkull : BlueSkull
|
|
{
|
|
Default
|
|
{
|
|
Tag "Blue Skull";
|
|
Species "BlueSkull";
|
|
Inventory.PickupMessage "You got the Blue Skull.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
USKL C -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTRedKey : RedCard
|
|
{
|
|
Default
|
|
{
|
|
Tag "Red Key";
|
|
Species "RedCard";
|
|
Inventory.PickupMessage "You got the Red Key.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
UKEY A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTGoldKey : YellowCard
|
|
{
|
|
Default
|
|
{
|
|
Tag "Gold Key";
|
|
Species "YellowCard";
|
|
Inventory.PickupMessage "You got the Gold Key.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
UKEY B -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTBlueKey : BlueCard
|
|
{
|
|
Default
|
|
{
|
|
Tag "Blue Key";
|
|
Species "BlueCard";
|
|
Inventory.PickupMessage "You got the Blue Key.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
UKEY C -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ShredCorpseHitbox : Actor
|
|
{
|
|
int accdamage;
|
|
|
|
Default
|
|
{
|
|
+NOGRAVITY;
|
|
-SOLID;
|
|
+DONTSPLASH;
|
|
+SHOOTABLE;
|
|
Health int.max;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
accdamage = target.Health;
|
|
A_SetSize(target.radius,target.height);
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !flak_corpsedamage || !target || (target.Health > 0) || target.InStateSequence(target.CurState,target.FindState("XDeath")) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
A_SetSize(target.radius,target.height);
|
|
}
|
|
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
|
{
|
|
accdamage -= damage;
|
|
int gibhealth = (target.GibHealth==int.min)?-target.SpawnHealth():target.GibHealth;
|
|
if ( accdamage < gibhealth )
|
|
{
|
|
// force gib (cheap ATM)
|
|
State gib = target.FindState("XDeath");
|
|
if ( !gib ) gib = target.FindState("Death.Extreme");
|
|
if ( gib ) target.SetState(gib);
|
|
Destroy();
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Enum ESwingMode
|
|
{
|
|
SWING_Straight, // constant increment
|
|
SWING_Spring, // bounces back after a delay
|
|
};
|
|
|
|
Class Swinger : Thinker
|
|
{
|
|
Actor target;
|
|
Vector2 dir;
|
|
double inc, rmul;
|
|
int steps, mode, delay;
|
|
double str, tstr;
|
|
int cnt, cstate;
|
|
|
|
Enum ESwingerState
|
|
{
|
|
STATE_Initial,
|
|
STATE_Wait,
|
|
STATE_Return,
|
|
};
|
|
|
|
override void Tick()
|
|
{
|
|
if ( !target ) cstate = -1;
|
|
switch ( cstate )
|
|
{
|
|
case STATE_Initial:
|
|
target.A_SetAngle(target.angle+dir.x*str*flak_swingerstrength,SPF_INTERPOLATE);
|
|
target.A_SetPitch(target.pitch+dir.y*str*flak_swingerstrength,SPF_INTERPOLATE);
|
|
str += inc;
|
|
if ( ++cnt >= steps )
|
|
{
|
|
cnt = 0;
|
|
str = tstr/steps;
|
|
cstate = (mode==SWING_Straight)?(-1):(delay>0)?STATE_Wait:STATE_Return;
|
|
}
|
|
else tstr += str;
|
|
break;
|
|
case STATE_Wait:
|
|
if ( ++cnt >= delay )
|
|
{
|
|
cnt = 0;
|
|
cstate = STATE_Return;
|
|
}
|
|
break;
|
|
case STATE_Return:
|
|
target.A_SetAngle(target.angle-dir.x*(str/rmul)*flak_swingerstrength,SPF_INTERPOLATE);
|
|
target.A_SetPitch(target.pitch-dir.y*(str/rmul)*flak_swingerstrength,SPF_INTERPOLATE);
|
|
if ( ++cnt >= steps*rmul )
|
|
{
|
|
cnt = 0;
|
|
cstate = -1;
|
|
}
|
|
break;
|
|
default:
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
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<QueuedFlash> flashes;
|
|
|
|
override void CheckReplacement( ReplaceEvent e )
|
|
{
|
|
if ( (e.Replacee == 'Chainsaw') || (e.Replacee == 'Gauntlets') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'UTChainsaw';
|
|
else e.Replacement = 'Enforcer';
|
|
}
|
|
else if ( (e.Replacee == 'Fist') || (e.Replacee == 'Staff') ) e.Replacement = 'ImpactHammer';
|
|
else if ( (e.Replacee == 'Pistol') || (e.Replacee == 'GoldWand') ) e.Replacement = 'Enforcer';
|
|
else if ( (e.Replacee == 'Shotgun') || (e.Replacee == 'SuperShotgun') || (e.Replacee == 'Crossbow') )
|
|
{
|
|
if ( !Random[Replacements](0,3) ) e.Replacement = 'Enforcer';
|
|
else if ( Random[Replacements](0,1) ) e.Replacement = 'BioRifle';
|
|
else e.Replacement = 'ShockRifle';
|
|
}
|
|
else if ( (e.Replacee == 'Chaingun') || (e.Replacee == 'Blaster') )
|
|
{
|
|
if ( Random[Replacements](0,2) ) e.Replacement = 'PulseGun';
|
|
else e.Replacement = 'Ripper2';
|
|
}
|
|
else if ( (e.Replacee == 'RocketLauncher') || (e.Replacee == 'PhoenixRod') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'FlakCannon';
|
|
else e.Replacement = 'UTRocketLauncher';
|
|
}
|
|
else if ( (e.Replacee == 'PlasmaRifle') || (e.Replacee == 'SkullRod') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'Minigun';
|
|
else e.Replacement = 'SniperRifle';
|
|
}
|
|
else if ( e.Replacee == 'BFG9000' ) e.Replacement = 'WarheadLauncher';
|
|
else if ( e.Replacee == 'Mace' )
|
|
{
|
|
if ( !Random[Replacements](0,6) ) e.Replacement = 'EnhancedShockRifle';
|
|
else e.Replacement = 'WarheadLauncher';
|
|
}
|
|
else if ( (e.Replacee == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') ) e.Replacement = 'EClip';
|
|
else if ( (e.Replacee == 'ClipBox') )
|
|
{
|
|
if ( !Random[Replacements](0,2) ) e.Replacement = 'EClip';
|
|
else if ( Random[Replacements](0,2) ) e.Replacement = 'PulseAmmo';
|
|
else e.Replacement = 'RipperAmmo';
|
|
}
|
|
else if ( (e.Replacee == 'BlasterAmmo') || (e.Replacee == 'BlasterHefty') )
|
|
{
|
|
if ( Random[Replacements](0,2) ) e.Replacement = 'PulseAmmo';
|
|
else e.Replacement = 'RipperAmmo';
|
|
}
|
|
else if ( (e.Replacee == 'Shell') || (e.Replacee == 'CrossbowAmmo') )
|
|
{
|
|
if ( !Random[Replacements](0,2) ) e.Replacement = 'EClip';
|
|
else if ( Random[Replacements](0,1) ) e.Replacement = 'BioAmmo2';
|
|
else e.Replacement = 'ShockAmmo2';
|
|
}
|
|
else if ( (e.Replacee == 'ShellBox') || (e.Replacee == 'CrossbowHefty') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'BioAmmo';
|
|
else e.Replacement = 'ShockAmmo';
|
|
}
|
|
else if ( (e.Replacee == 'RocketAmmo') || (e.Replacee == 'PhoenixRodAmmo') || (e.Replacee == 'MaceAmmo') )
|
|
{
|
|
if ( Random[Replacements](0,1) )
|
|
{
|
|
if ( !Random[Replacements](0,3) ) e.Replacement = 'FlakAmmo';
|
|
else e.Replacement = 'FlakAmmo2';
|
|
}
|
|
else
|
|
{
|
|
if ( !Random[Replacements](0,3) ) e.Replacement = 'UTRocketAmmo';
|
|
else e.Replacement = 'UTRocketAmmo2';
|
|
}
|
|
}
|
|
else if ( (e.Replacee == 'RocketBox') || (e.Replacee == 'PhoenixRodHefty') || (e.Replacee == 'MaceHefty') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'FlakAmmo';
|
|
else e.Replacement = 'UTRocketAmmo';
|
|
}
|
|
else if ( (e.Replacee == 'Cell') || (e.Replacee == 'SkullRodAmmo') )
|
|
{
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'EClip';
|
|
else if ( !Random[Replacements](0,3) ) e.Replacement = 'RifleAmmo';
|
|
else e.Replacement = 'RifleAmmo2';
|
|
}
|
|
else if ( (e.Replacee == 'CellPack') || (e.Replacee == 'SkullRodHefty') )
|
|
{
|
|
if ( !Random[Replacements](0,6) ) e.Replacement = 'WarheadAmmo';
|
|
else if ( Random[Replacements](0,1) ) e.Replacement = 'MiniAmmo';
|
|
else e.Replacement = 'RifleAmmo';
|
|
}
|
|
else if ( e.Replacee == 'InvulnerabilitySphere' ) e.Replacement = 'EnhancedShockRifle';
|
|
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiEgg') ) e.Replacement = 'UDamage';
|
|
else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) e.Replacement = 'UTHealthPack';
|
|
else if ( (e.Replacee == 'Megasphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'UTShieldBelt';
|
|
else if ( (e.Replacee == 'Allmap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'UTMapRevealer';
|
|
else if ( (e.Replacee == 'BlurSphere') || (e.Replacee == 'ArtiInvisibility') ) e.Replacement = 'UTInvisibility';
|
|
else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') ) e.Replacement = 'Searchlight';
|
|
else if ( (e.Replacee == 'RadSuit') || (e.Replacee == 'ArtiFly') ) e.Replacement = 'UTJumpBoots';
|
|
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') ) e.Replacement = 'UTBackpack';
|
|
else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') ) e.Replacement = 'UTArmorBonus';
|
|
else if ( (e.Replacee == 'HealthBonus') || (e.Replacee == 'CrystalVial') ) e.Replacement = 'UTHealthBonus';
|
|
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'Silvershield') ) e.Replacement = 'UTThighPads';
|
|
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'UTBodyArmor';
|
|
else if ( e.Replacee == 'Stimpack' ) e.Replacement = 'UTMedBox';
|
|
else if ( e.Replacee == 'Medikit' ) e.Replacement = 'UTHealthBox';
|
|
else if ( e.Replacee == 'ArtiHealth' )
|
|
{
|
|
if ( !Random[Replacements](0,3) ) e.Replacement = 'UTHealthBox';
|
|
else e.Replacement = 'UTMedBox';
|
|
}
|
|
else if ( e.Replacee == 'ArtiTeleport' )
|
|
{
|
|
// I have no idea what to replace this with, so just have some random stuff
|
|
if ( Random[Replacements](0,1) ) e.Replacement = 'UTBackpack';
|
|
else if ( Random[Replacements](0,1) ) e.Replacement = 'UTShieldBelt';
|
|
else if ( Random[Replacements](0,1) ) e.Replacement = 'UTHealthPack';
|
|
else e.Replacement = 'UDamage';
|
|
}
|
|
else if ( e.Replacee == 'RedCard' ) e.Replacement = 'UTRedKey';
|
|
else if ( e.Replacee == 'BlueCard' ) e.Replacement = 'UTBlueKey';
|
|
else if ( e.Replacee == 'YellowCard' ) e.Replacement = 'UTGoldKey';
|
|
else if ( e.Replacee == 'RedSkull' ) e.Replacement = 'UTRedSkull';
|
|
else if ( e.Replacee == 'BlueSkull' ) e.Replacement = 'UTBlueSkull';
|
|
else if ( e.Replacee == 'YellowSkull' ) e.Replacement = 'UTGoldSkull';
|
|
else if ( e.Replacee == 'TeleportFog' ) e.Replacement = 'UTTeleportFog';
|
|
else if ( e.Replacee == 'ItemFog' ) e.Replacement = 'UTItemFog';
|
|
else if ( flak_blood && (e.Replacee == 'Blood') ) e.Replacement = 'UTBlood';
|
|
else if ( e.Replacee == 'KeyYellow' ) e.Replacement = 'UTHereticYellowKey';
|
|
else if ( e.Replacee == 'KeyGreen' ) e.Replacement = 'UTHereticGreenKey';
|
|
else if ( e.Replacee == 'KeyBlue' ) e.Replacement = 'UTHereticBlueKey';
|
|
}
|
|
|
|
private Actor AddLight( Vector3 pos, Color col, int radius )
|
|
{
|
|
Actor l = Actor.Spawn("PointLightAttenuated",pos);
|
|
if ( !l ) return null;
|
|
l.args[0] = col.r;
|
|
l.args[1] = col.g;
|
|
l.args[2] = col.b;
|
|
l.args[3] = radius;
|
|
return l;
|
|
}
|
|
|
|
private Actor AddAmbient( Vector3 pos, String snd, double volume = 1., double attenuation = ATTN_NORM )
|
|
{
|
|
Actor a = Actor.Spawn("MapSpot",pos);
|
|
if ( !a ) return null;
|
|
a.A_PlaySound(snd,CHAN_BODY,volume,true,attenuation);
|
|
return a;
|
|
}
|
|
|
|
override void WorldLoaded( WorldEvent e )
|
|
{
|
|
if ( gamestate != GS_LEVEL || e.IsSaveGame ) return;
|
|
// just replace the -noflat- with a better scaled version and change the sky
|
|
if ( !flak_doomtest )
|
|
{
|
|
if ( (level.GetChecksum() ~== "FBC3B6622A8B74AE06DE01E70007AC33") || (level.GetChecksum() ~== "D8206A3414DA967F2159473B5791139E") )
|
|
{
|
|
TexMan.ReplaceTextures("-noflat-","DefTex",0);
|
|
TextureID skytx = TexMan.CheckForTexture("BlueSky",TexMan.Type_Any);
|
|
level.ChangeSky(skytx,skytx);
|
|
}
|
|
return;
|
|
}
|
|
// prettify Kinsie's test map for a more Unreal feel
|
|
if ( level.GetChecksum() ~== "FBC3B6622A8B74AE06DE01E70007AC33" )
|
|
{
|
|
TextureID deftex = TexMan.CheckForTexture("-noflat-",TexMan.Type_Any);
|
|
TextureID skytx = TexMan.CheckForTexture("KGDaySky",TexMan.Type_Any);
|
|
TextureID baseflor = TexMan.CheckForTexture("rClfFlr0",TexMan.Type_Any);
|
|
TextureID baseceil = TexMan.CheckForTexture("rClfBas0",TexMan.Type_Any);
|
|
TextureID basewall = TexMan.CheckForTexture("uAlnWl2b",TexMan.Type_Any);
|
|
TextureID xbasewall = TexMan.CheckForTexture("xAlnWl2b",TexMan.Type_Any);
|
|
TextureID glasstex = TexMan.CheckForTexture("Glassg",TexMan.Type_Any);
|
|
level.ChangeSky(skytx,skytx);
|
|
for ( int i=0; i<level.sectors.size(); i++ )
|
|
{
|
|
level.sectors[i].lightlevel = min(level.sectors[i].lightlevel,64);
|
|
level.sectors[i].SetPlaneLight(0,0);
|
|
level.sectors[i].SetPlaneLight(1,0);
|
|
// open some ceilings
|
|
if ( level.sectors[i].ceilingplane.ZAtPoint(level.sectors[i].centerspot) == 1280 )
|
|
level.sectors[i].SetTexture(1,skyflatnum);
|
|
if ( level.sectors[i].GetTexture(0) == deftex )
|
|
{
|
|
level.sectors[i].SetTexture(0,(i==47)?baseceil:baseflor);
|
|
level.sectors[i].SetXScale(0,2.);
|
|
level.sectors[i].SetYScale(0,2.);
|
|
}
|
|
if ( level.sectors[i].GetTexture(1) == deftex )
|
|
{
|
|
level.sectors[i].SetTexture(1,(i==47)?baseflor:baseceil);
|
|
level.sectors[i].SetXScale(1,2.);
|
|
level.sectors[i].SetYScale(1,2.);
|
|
}
|
|
}
|
|
for ( int i=0; i<level.sides.size(); i++ )
|
|
{
|
|
level.sides[i].light = 0;
|
|
for ( int j=0; j<3; j++ )
|
|
{
|
|
if ( level.sides[i].GetTexture(j) != deftex ) continue;
|
|
if ( (i==529) || (i==530) || (i==533) || (i==534) )
|
|
{
|
|
level.sides[i].SetTexture(j,xbasewall);
|
|
level.sides[i].SetTextureYOffset(j,-2304);
|
|
}
|
|
else level.sides[i].SetTexture(j,basewall);
|
|
level.sides[i].SetTextureXScale(j,2.);
|
|
level.sides[i].SetTextureYScale(j,2.);
|
|
}
|
|
}
|
|
// fixup
|
|
for ( int i=215; i<246; i++ )
|
|
{
|
|
if ( (i==218) || (i==221) || (i==227)
|
|
|| (i==230) || (i==232) || (i==234)
|
|
|| (i==238) || (i==243) ) continue;
|
|
level.sectors[i].SetSpecialColor(0,"00 00 00");
|
|
}
|
|
level.sectors[53].SetFade("00 00 20");
|
|
level.sides[1844].SetTexture(1,glasstex);
|
|
level.lines[945].alpha = 0.5;
|
|
AddLight((0,-288,128),"E0 E0 FF",256);
|
|
AddLight((-2560,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((0,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((2560,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((-384,-160,64),"FF FF FF",128);
|
|
AddLight((-384,-288,64),"FF FF FF",128);
|
|
AddLight((-384,-416,64),"FF FF FF",128);
|
|
AddLight((0,2816,96),"FF FF FF",512);
|
|
AddLight((2904,1344,128),"80 80 FF",256);
|
|
AddLight((3408,1344,128),"80 80 FF",256);
|
|
AddLight((1568,1760,64),"20 20 80",128);
|
|
AddLight((1824,1760,64),"80 20 20",128);
|
|
AddLight((2080,1760,64),"FF 80 20",128);
|
|
AddLight((2336,1760,64),"20 FF 20",128);
|
|
AddLight((2592,1760,64),"80 80 20",128);
|
|
AddLight((2848,1760,64),"A0 A0 30",128);
|
|
AddLight((2944,960,64),"20 FF 20",128);
|
|
AddLight((2944,736,64),"20 FF 20",128);
|
|
AddLight((3264,960,64),"FF 20 20",128);
|
|
AddLight((3264,736,64),"A0 A0 30",128);
|
|
AddLight((3264,512,64),"80 80 20",128);
|
|
AddLight((3584,960,64),"80 80 20",128);
|
|
AddLight((3584,736,64),"20 FF 20",128);
|
|
AddLight((3584,512,64),"FF 80 20",128);
|
|
AddLight((3584,288,64),"FF 80 FF",128);
|
|
AddAmbient((0,-288,192),"testamb/wind1",0.5,1.6);
|
|
AddAmbient((-2560,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((0,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((2560,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((768,1600,1280),"testamb/wind2",0.8,1.6);
|
|
AddAmbient((3174,1344,128),"testamb/water",0.4,1.6);
|
|
AddAmbient((1568,1760,64),"testamb/water",0.4,2.4);
|
|
AddAmbient((2080,1760,64),"testamb/lava",0.8,2.4);
|
|
AddAmbient((2336,1760,64),"testamb/slime",0.4,2.4);
|
|
AddAmbient((2944,960,64),"testamb/slime",0.4,2.4);
|
|
AddAmbient((2944,736,64),"testamb/slime",0.4,2.4);
|
|
AddAmbient((3584,736,64),"testamb/slime",0.4,2.4);
|
|
AddAmbient((3584,512,64),"testamb/lava",0.8,2.4);
|
|
}
|
|
else if ( level.GetChecksum() ~== "D8206A3414DA967F2159473B5791139E" )
|
|
{
|
|
TextureID deftex = TexMan.CheckForTexture("-noflat-",TexMan.Type_Any);
|
|
TextureID skytx = TexMan.CheckForTexture("BlueSky",TexMan.Type_Any);
|
|
TextureID baseflor = TexMan.CheckForTexture("rClfFlr0",TexMan.Type_Any);
|
|
TextureID baseceil = TexMan.CheckForTexture("rClfBas0",TexMan.Type_Any);
|
|
TextureID basewall = TexMan.CheckForTexture("uAlnWl2b",TexMan.Type_Any);
|
|
TextureID xbasewall = TexMan.CheckForTexture("xAlnWl2b",TexMan.Type_Any);
|
|
TextureID glasstex = TexMan.CheckForTexture("Glassg",TexMan.Type_Any);
|
|
level.ChangeSky(skytx,skytx);
|
|
for ( int i=0; i<level.sectors.size(); i++ )
|
|
{
|
|
level.sectors[i].lightlevel = 0;
|
|
level.sectors[i].SetPlaneLight(0,0);
|
|
level.sectors[i].SetPlaneLight(1,0);
|
|
// open some ceilings
|
|
if ( level.sectors[i].ceilingplane.ZAtPoint(level.sectors[i].centerspot) == 1280 )
|
|
level.sectors[i].SetTexture(1,skyflatnum);
|
|
if ( level.sectors[i].GetTexture(0) == deftex )
|
|
{
|
|
level.sectors[i].SetTexture(0,(i==47)?baseceil:baseflor);
|
|
level.sectors[i].SetXScale(0,2.);
|
|
level.sectors[i].SetYScale(0,2.);
|
|
}
|
|
if ( level.sectors[i].GetTexture(1) == deftex )
|
|
{
|
|
level.sectors[i].SetTexture(1,(i==47)?baseflor:baseceil);
|
|
level.sectors[i].SetXScale(1,2.);
|
|
level.sectors[i].SetYScale(1,2.);
|
|
}
|
|
}
|
|
for ( int i=0; i<level.sides.size(); i++ )
|
|
{
|
|
level.sides[i].light = 0;
|
|
for ( int j=0; j<3; j++ )
|
|
{
|
|
if ( level.sides[i].GetTexture(j) != deftex ) continue;
|
|
if ( (i==295) || (i==296) || (i==309) || (i==310) )
|
|
{
|
|
level.sides[i].SetTexture(j,xbasewall);
|
|
level.sides[i].SetTextureYOffset(j,-2304);
|
|
}
|
|
else level.sides[i].SetTexture(j,basewall);
|
|
level.sides[i].SetTextureXScale(j,2.);
|
|
level.sides[i].SetTextureYScale(j,2.);
|
|
}
|
|
}
|
|
// fixup
|
|
for ( int i=104; i<134; i++ )
|
|
{
|
|
if ( (i==107) || (i==110) || (i==116)
|
|
|| (i==119) || (i==121) || (i==127)
|
|
|| (i==132) ) continue;
|
|
level.sectors[i].SetSpecialColor(0,"00 00 00");
|
|
}
|
|
level.sectors[53].SetFade("00 00 20");
|
|
level.sides[216].SetTexture(1,glasstex);
|
|
level.lines[125].alpha = 0.5;
|
|
AddLight((0,-288,128),"E0 E0 FF",256);
|
|
AddLight((-2560,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((0,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((2560,1024,1280),"E0 E0 FF",1024);
|
|
AddLight((-384,-160,64),"FF FF FF",128);
|
|
AddLight((-384,-288,64),"FF FF FF",128);
|
|
AddLight((-384,-416,64),"FF FF FF",128);
|
|
AddLight((0,2816,96),"FF FF FF",512);
|
|
AddLight((2904,1344,128),"80 80 FF",256);
|
|
AddLight((3408,1344,128),"80 80 FF",256);
|
|
AddLight((1568,1760,64),"20 20 80",128);
|
|
AddLight((1824,1760,64),"A0 A0 30",128);
|
|
AddLight((2080,1760,64),"80 80 20",128);
|
|
AddLight((2336,1760,64),"20 20 80",128);
|
|
AddLight((2592,1760,64),"FF 80 20",128);
|
|
AddLight((2944,960,64),"A0 A0 30",128);
|
|
AddLight((2944,736,64),"A0 A0 30",128);
|
|
AddLight((3264,960,64),"A0 A0 30",128);
|
|
AddLight((3264,736,64),"A0 A0 30",128);
|
|
AddLight((3264,512,64),"A0 A0 30",128);
|
|
AddLight((3264,288,64),"FF 80 20",128);
|
|
AddLight((3584,960,64),"A0 A0 30",128);
|
|
AddLight((3584,736,64),"80 80 20",128);
|
|
AddLight((3584,512,64),"FF 80 20",128);
|
|
AddLight((3584,288,64),"A0 A0 30",128);
|
|
AddAmbient((0,-288,192),"testamb/wind1",0.5,1.6);
|
|
AddAmbient((-2560,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((0,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((2560,1024,768),"testamb/wind1",0.4,0.8);
|
|
AddAmbient((768,1600,1280),"testamb/wind2",0.8,1.6);
|
|
AddAmbient((3174,1344,128),"testamb/water",0.4,1.6);
|
|
AddAmbient((1568,1760,64),"testamb/water",0.4,2.4);
|
|
AddAmbient((2336,1760,64),"testamb/water",0.4,2.4);
|
|
AddAmbient((2592,1760,64),"testamb/lava",0.8,2.4);
|
|
AddAmbient((3584,512,64),"testamb/lava",0.8,2.4);
|
|
AddAmbient((3264,288,64),"testamb/lava",0.8,2.4);
|
|
}
|
|
}
|
|
|
|
override void WorldThingSpawned( WorldEvent e )
|
|
{
|
|
if ( flak_nobosstelefrag && e.Thing.bBOSS ) e.Thing.bNOTELEFRAG = true;
|
|
}
|
|
|
|
ui void StartMenu()
|
|
{
|
|
CVar protomenu = CVar.GetCVar('flak_protomenu',players[consoleplayer]);
|
|
if ( !protomenu ) return; // this can happen
|
|
int proto = protomenu.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 ( flak_translocator )
|
|
players[e.playernumber].mo.GiveInventory("Translocator",1);
|
|
}
|
|
override void PlayerRespawned( PlayerEvent e )
|
|
{
|
|
if ( flak_translocator )
|
|
players[e.playernumber].mo.GiveInventory("Translocator",1);
|
|
}
|
|
|
|
override void NetworkProcess( ConsoleEvent e )
|
|
{
|
|
if ( e.Name ~== "refreshtrans" )
|
|
{
|
|
if ( flak_translocator )
|
|
{
|
|
for ( int i=0; i<MAXPLAYERS; i++ ) if ( playeringame[i] ) players[i].mo.GiveInventory("Translocator",1);
|
|
}
|
|
else
|
|
{
|
|
for ( int i=0; i<MAXPLAYERS; i++ ) if ( playeringame[i] ) players[i].mo.TakeInventory("Translocator",1);
|
|
}
|
|
}
|
|
}
|
|
|
|
override void ConsoleProcess( ConsoleEvent e )
|
|
{
|
|
if ( e.Name ~== "refreshmenu" ) StartMenu();
|
|
if ( e.Name ~== "refreshtrans" ) EventHandler.SendNetworkEvent("refreshtrans");
|
|
}
|
|
|
|
override void WorldTick()
|
|
{
|
|
for ( int i=0; i<flashes.size(); i++ )
|
|
{
|
|
if ( flashes[i].tic >= gametic ) continue;
|
|
flashes.Delete(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
override void PostUiTick()
|
|
{
|
|
for ( int i=0; i<flashes.size(); i++ )
|
|
{
|
|
if ( flashes[i].tic < gametic ) continue;
|
|
GenericFlash gf = new("GenericFlash").Setup(flashes[i].cam,flashes[i].c,flashes[i].duration);
|
|
StatusBar.AttachMessage(gf,0,BaseStatusBar.HUDMSGLayer_UnderHUD);
|
|
}
|
|
if ( gametic <= 0 ) StartMenu();
|
|
}
|
|
|
|
override void RenderOverlay( RenderEvent e )
|
|
{
|
|
// well this if sure is a long one
|
|
if ( players[consoleplayer].camera.player && players[consoleplayer].camera.player.ReadyWeapon && (players[consoleplayer].camera.player.ReadyWeapon is 'UTWeapon') )
|
|
UTWeapon(players[consoleplayer].camera.player.ReadyWeapon).RenderOverlay(e);
|
|
if ( !menuactive ) return;
|
|
if ( tex.IsNull() || !tex.IsValid() ) return;
|
|
if ( !CVar.GetCVar('flak_showmenu',players[consoleplayer]).GetBool() ) return;
|
|
Screen.Dim("Black",1.0,0,0,Screen.GetWidth(),Screen.GetHeight());
|
|
Screen.DrawTexture(tex,true,0,0,DTA_VirtualWidth,1024,DTA_VirtualHeight,768);
|
|
}
|
|
|
|
override void WorldThingDied( WorldEvent e )
|
|
{
|
|
if ( e.Thing.bDONTGIB ) return;
|
|
// gibbers
|
|
if ( flak_gibs && !e.Thing.bNOBLOOD && (e.Thing.FindState("XDeath") || e.Thing.FindState("Death.Extreme")) && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.Thing.Health < e.Thing.GetGibHealth())) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) )
|
|
{
|
|
// players have special gibbing
|
|
if ( e.Thing.player )
|
|
{
|
|
// TODO
|
|
return;
|
|
}
|
|
// generic gibbing
|
|
let a = Actor.Spawn("UTGibber",e.Thing.pos);
|
|
a.vel = e.Thing.vel;
|
|
a.Scale = e.Thing.Scale;
|
|
a.Translation = e.Thing.BloodTranslation;
|
|
if ( e.Thing.BloodColor ) a.SetShade(e.Thing.BloodColor);
|
|
else a.SetShade(gameinfo.defaultbloodcolor);
|
|
a.A_SetSize(e.Thing.radius,e.Thing.height);
|
|
e.Thing.A_XScream();
|
|
e.Thing.A_NoBlocking();
|
|
e.Thing.A_BossDeath();
|
|
e.Thing.Destroy();
|
|
return;
|
|
}
|
|
// attach damage accumulator for corpses
|
|
if ( !flak_corpsedamage ) return;
|
|
let a = Actor.Spawn("ShredCorpseHitbox",e.Thing.pos);
|
|
a.target = e.Thing;
|
|
}
|
|
|
|
static void DoFlash( Actor camera, Color c, int duration )
|
|
{
|
|
QueuedFlash qf = new("QueuedFlash");
|
|
qf.duration = duration;
|
|
qf.c = c;
|
|
qf.tic = gametic;
|
|
qf.cam = camera;
|
|
let hnd = UTMainHandler(StaticEventHandler.Find("UTMainHandler"));
|
|
hnd.flashes.push(qf);
|
|
}
|
|
|
|
// Doom's explosions aren't fully 3D
|
|
static void DoBlast( Actor Source, double ExplosionRadius, double MomentumTransfer )
|
|
{
|
|
BlockThingsIterator bi = BlockThingsIterator.Create(Source,ExplosionRadius);
|
|
while ( bi.Next() )
|
|
{
|
|
Actor a = bi.Thing;
|
|
if ( !a || !a.bSHOOTABLE || !Source.CheckSight(a,0xf) || (a == Source) || (Source.Distance3D(a) > 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));
|
|
}
|
|
|
|
static void DoSwing( Actor target, Vector2 dir, double initial, double inc, int steps, int mode = 0, int delay = 0, double rmul = 1.0 )
|
|
{
|
|
if ( !flak_swingers ) return;
|
|
let s = new("Swinger");
|
|
s.ChangeStatNum(Thinker.STAT_USER);
|
|
s.target = target;
|
|
s.dir = dir;
|
|
s.inc = inc;
|
|
s.rmul = rmul;
|
|
s.steps = steps;
|
|
s.mode = mode;
|
|
s.delay = delay;
|
|
s.cnt = 0;
|
|
s.cstate = 0;
|
|
s.str = initial;
|
|
s.tstr = initial;
|
|
}
|
|
}
|