stinger_m/zscript/unrealcommon.zsc
Marisa Kirisame 3926b5e574 Beta 5 Goddamn Hotfix 4:
- Correct ammo use values for Dispersion Pistol upgrade levels (1→2→4→5→6), odd progression, I know.
 - Stunner also has the same deathmatch regeneration behaviour as the Dispersion Pistol now.
 - Corrected how the ammo regen speed works for both weapons.
2019-10-03 21:41:55 +02:00

1322 lines
38 KiB
Text

Class UPlayer : UTPlayer
{
Default
{
Player.StartItem "Automag";
Player.StartItem "DispersionPistol";
Player.StartItem "UMiniAmmo", 30;
Player.StartItem "DefaultAmmo", 50;
}
override void GiveDefaultInventory()
{
if ( !player ) return;
// HexenArmor must always be the first item in the inventory because
// it provides player class based protection that should not affect
// any other protection item.
let myclass = GetClass();
GiveInventoryType('HexenArmor');
let harmor = HexenArmor(FindInventory('HexenArmor'));
harmor.Slots[4] = self.HexenArmor[0];
for ( int i=0; i<4; ++i ) harmor.SlotsIncrement[i] = self.HexenArmor[i+1];
// BasicArmor must come right after that. It should not affect any
// other protection item as well but needs to process the damage
// before the HexenArmor does.
GiveInventoryType('BasicArmor');
// Now add the items from the DECORATE definition
let di = GetDropItems();
for ( DropItem di=GetDropItems(); di; di=di.Next )
{
Class<Actor> ti = di.Name;
if ( !ti ) continue;
// no pistol start
if ( sting_nopstart && ((ti is 'Automag') || (ti is 'UMiniAmmo')) ) continue;
let tinv = (class<Inventory>)(ti);
if ( !tinv )
{
Console.Printf(TEXTCOLOR_ORANGE.."%s is not an inventory item and cannot be given to a player as start item.\n",di.Name);
continue;
}
let item = FindInventory(tinv);
if ( item ) item.Amount = clamp(item.Amount+(di.Amount?di.Amount:item.default.Amount),0,item.MaxAmount);
else
{
item = Inventory(Spawn(ti));
item.bIgnoreSkill = true; // no skill multipliers here
item.Amount = di.Amount;
let weap = Weapon(item);
if ( weap )
{
// To allow better control any weapon is emptied of
// ammo before being given to the player.
weap.AmmoGive1 = weap.AmmoGive2 = 0;
}
bool res;
Actor check;
[res,check] = item.CallTryPickup(self);
if ( !res )
{
item.Destroy();
item = null;
}
else if ( check != self )
{
// Player was morphed. This is illegal at game start.
// This problem is only detectable when it's too late to do something about it...
ThrowAbortException("Cannot give morph item '%s' when starting a game!",di.Name);
}
}
let weap = Weapon(item);
if ( weap && weap.CheckAmmo(Weapon.EitherFire,false) )
player.ReadyWeapon = player.PendingWeapon = weap;
}
}
// 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") )
{
// Doomreal gives the player all subclasses of UnrealArmor
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
if ( !(AllActorClasses[i].GetParentClass() is "UnrealArmor") ) continue;
let item = Inventory(Spawn(AllActorClasses[i]));
item.ClearCounters(); // don't increase item counts
item.Amount = item.MaxAmount;
if ( !item.CallTryPickup(self) ) item.Destroy();
}
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);
if ( (type is 'Automag') && sting_automags )
{
// force akimbo
let t = FindInventory(type);
if ( t ) t.Amount = 2;
}
else if ( (type is 'Betamag') && sting_protomags )
{
// force akimbo
let t = FindInventory(type);
if ( t ) t.Amount = 2;
}
else if ( type is 'DispersionPistol' )
{
// force upgrade
let dsp = DispersionPistol(FindInventory('DispersionPistol'));
if ( dsp )
{
dsp.Ammo1.Amount = dsp.Ammo1.MaxAmount = 90;
if ( (player.ReadyWeapon == dsp) && (player.PendingWeapon == WP_NOCHANGE) )
dsp.pendingupgrade = 4;
else
{
dsp.pendingupgrade = dsp.upgradelevel = 4;
dsp.MainUse = 6;
dsp.UpdateSelectionOrder();
}
}
}
}
}
}
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 'UnrealInventory')) &&
!(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 PlayAttacking()
{
if ( player.Health <= 0 ) return;
// no animation if crouched
if ( (player && (player.mo == self)) && (player.crouchdir == -1) ) return;
// check weapon type
if ( ((player.ReadyWeapon is 'URifle') && !sting_rifle && (player.buttons&BT_ALTATTACK)) || ((player.ReadyWeapon is 'Peacemaker') && player.buttons&BT_ALTATTACK) )
return;
let psp = player.FindPSprite(PSP_WEAPON);
if ( (player.ReadyWeapon is 'Eightball')
|| ((player.ReadyWeapon is 'DispersionPistol') && DispersionPistol(player.ReadyWeapon).bCharging)
|| ((player.ReadyWeapon is 'UBioRifle') && UBioRifle(player.ReadyWeapon).bCharging)
|| ((player.ReadyWeapon is 'FlameGun') && FlameGun(player.ReadyWeapon).bCharging)
|| (player.ReadyWeapon is 'Razorjack') || (player.ReadyWeapon is 'Stunner')
|| ((player.ReadyWeapon is 'UFlamethrower') && UFlamethrower(player.ReadyWeapon).bCharging) )
{
if ( !InStateSequence(CurState,FindState("MissileRepStill")) )
SetStateLabel("MissileRepStill");
}
else if ( ((player.ReadyWeapon is 'Stinger') && psp
&& psp.CurState.InStateSequence(player.ReadyWeapon.FindState("Hold")))
|| (player.ReadyWeapon is 'UFlamethrower') || (player.ReadyWeapon is 'UMinigun')
|| ((player.ReadyWeapon is 'Bonesaw') && player.buttons&BT_ATTACK)
|| ((player.ReadyWeapon is 'Impaler') && player.buttons&BT_ALTATTACK) )
{
if ( !InStateSequence(CurState,FindState("MissileRep")) )
SetStateLabel("MissileRep");
}
else SetStateLabel("Missile");
}
override void PlayFootstep( double vol )
{
let boot = UJumpBoots(FindInventory("UJumpBoots"));
if ( boot ) A_PlaySound("u1/bootfootstep",CHAN_5,min(1.,vol*2));
else A_PlaySound("ut/playerfootstep",CHAN_5,vol);
}
}
Class UFemaleArmGibber : UTGibber
{
bool firstgib;
override void BurstGibs()
{
Actor a;
double ang, pt;
Vector3 dir;
if ( !firstgib )
{
firstgib = true;
Actor a = Spawn("UTFemaleArm",Vec3Offset(-14*sin(angle),14*cos(angle),36));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.6+dir*FRandom[Blod](3.0,6.0);
}
for ( int i=0; i<gibsize; i++ )
{
Vector3 box = (FRandom[Blod](-4,4),FRandom[Blod](12,18),FRandom[Blod](32,40));
let a = Spawn("UTBloodPuff",Vec3Offset(box.x*cos(angle)-box.y*sin(angle),box.x*sin(angle)+box.y*cos(angle),box.z));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.2+dir*FRandom[Blod](1.5,3.0);
}
A_CountDown();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
gibsize = 3;
reactiontime = 5;
}
States
{
Spawn:
TNT1 A 0 NoDelay; // no sound, done by player
TNT1 A 1 BurstGibs();
Wait;
}
}
Class UPlayerFemale : UPlayer
{
Default
{
Player.SoundClass "ufemale";
UTPlayer.VoiceType VOICE_FemaleOne;
}
void A_ArmPop()
{
armlessL = true;
let a = Actor.Spawn("UFemaleArmGibber",pos);
a.vel = vel;
a.Scale = Scale;
a.A_SetSize(radius,height);
UTGibber(a).Gibbed = self;
}
States
{
Reload:
#### # 3;
PLYR ABCDEF 4;
Goto Spawn;
Death.Zapped:
#### # 0;
Goto Death;
Death.Decapitated:
#### # 0 A_HeadPop();
PLD6 A 3 A_PlayerScream();
PLD6 B 3 A_NoBlocking();
PLD6 CDEFGHIJ 3;
PLD6 K 1 A_DMFade();
Wait;
Death:
#### # 0 A_JumpIf(Health<(GetGibHealth()/3),"Death7");
#### # 0 A_JumpIf(vel.length()>20,"Death2");
#### # 0 A_JumpIf(vel.length()>10,"Death5");
#### # 0 A_Jump(256,"Death1","Death3","Death4");
Death1:
#### # 3;
PLD1 A 3 A_PlayerScream();
PLD1 B 3 A_NoBlocking();
PLD1 CDEFGHIJKLMNOPQRSTU 3;
PLD1 V 1 A_DMFade();
Wait;
Death2:
#### # 3;
PLD2 A 3 A_PlayerScream();
PLD2 B 3 A_NoBlocking();
PLD2 CDEFGHIJKLMNOPQ 3;
PLD2 R 1 A_DMFade();
Wait;
Death3:
#### # 3;
PLD3 A 3 A_PlayerScream();
PLD3 B 3 A_NoBlocking();
PLD3 CDEFGHIJKLMNO 3;
PLD3 P 1 A_DMFade();
Wait;
Death4:
#### # 3;
PLD4 A 3 A_PlayerScream();
PLD4 B 3 A_NoBlocking();
PLD4 CDEFGHIJKL 3;
PLD4 M 1 A_DMFade();
Wait;
Death5:
#### # 3;
PLD5 A 3 A_PlayerScream();
PLD5 B 3 A_NoBlocking();
PLD5 CDEFGHIJKLMNO 3;
PLD5 P 1 A_DMFade();
Wait;
Death7:
#### # 0 A_ArmPop();
PLD7 A 3 A_PlayerScream();
PLD7 B 3 A_NoBlocking();
PLD7 CDEFGHIJKLMNOPQRSTUV 3;
PLD7 W 1 A_DMFade();
Wait;
Taunt1:
#### # 5;
PLT1 ABCDEFGHIJKLMNO 3;
Goto Spawn+1;
Taunt2:
#### # 5;
PLT2 ABCDEFGHIJKLMNOPQR 3;
Goto Spawn+1;
Taunt3:
#### # 5;
PLT3 ABCDEFGHIJKLMNO 3;
Goto Spawn+1;
Taunt4:
#### # 0;
Goto Spawn;
}
}
Class UPlayerFemale1 : UPlayerFemale
{
Default
{
Player.DisplayName "$N_FEMALE1";
UTPlayer.VoiceType VOICE_FemaleTwo;
-NOMENU;
}
States
{
See:
GINA A -1;
Stop;
}
}
Class UPlayerFemale2 : UPlayerFemale
{
Default
{
Player.SoundClass "ufemale";
Player.DisplayName "$N_FEMALE2";
-NOMENU;
}
States
{
See:
SONY A -1;
Stop;
}
}
Class UMaleTorsoGibber : UTGibber
{
bool firstgib;
override void BurstGibs()
{
static const class<Actor> parts[] = {"UTMaleArm","UTMaleArm","UTMaleTorso","UTHeadMale","UTHeart","UTLiver","UTStomach"};
static const double partofsy[] = {14,-14,0,0,-2,5,-3};
static const double partofsz[] = {36,36,32,48,40,32,35};
Actor a;
double ang, pt;
Vector3 dir;
if ( !firstgib )
{
firstgib = true;
for ( int i=0; i<7; i++ )
{
Actor a = Spawn(parts[i],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.6+dir*FRandom[Blod](3.0,6.0);
}
}
for ( int i=0; i<gibsize; i++ )
{
Vector3 box = (FRandom[Blod](-15,15),FRandom[Blod](15,15),FRandom[Blod](30,50));
let a = Spawn("UTBloodPuff",Vec3Offset(box.x*cos(angle)-box.y*sin(angle),box.x*sin(angle)+box.y*cos(angle),box.z));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.2+dir*FRandom[Blod](1.5,3.0);
}
A_CountDown();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
gibsize = 3;
reactiontime = 5;
}
States
{
Spawn:
TNT1 A 0 NoDelay; // no sound, done by player
TNT1 A 1 BurstGibs();
Wait;
}
}
Class UPlayerMale : UPlayer
{
Default
{
Player.SoundClass "umale1";
UTPlayer.VoiceType VOICE_MaleOne;
}
void A_TorsoPop()
{
headless = true;
armlessL = true;
armlessR = true;
torsoless = true;
let a = Actor.Spawn("UMaleTorsoGibber",pos);
a.vel = vel;
a.Scale = Scale;
a.A_SetSize(radius,height);
UTGibber(a).Gibbed = self;
}
States
{
Death:
#### # 0 A_JumpIf(Health<(GetGibHealth()/3),"Death5");
#### # 0 A_JumpIf(vel.length()>20,"Death6");
#### # 0 A_JumpIf(vel.length()>10,"Death1");
#### # 0 A_Jump(256,"Death2","Death3","Death7");
Death5:
#### # 0 A_TorsoPop();
PLD5 A 3 A_PlayerScream();
PLD5 B 3 A_NoBlocking();
PLD5 CDEFGHIJKLMNOPQRSTUV 3;
PLD5 W 1 A_DMFade();
Wait;
Death6:
#### # 3;
PLD6 A 3 A_PlayerScream();
PLD6 B 3 A_NoBlocking();
PLD6 CDEFGHIJKLMNOPQRSTUVWXYZ[ 3;
PLD6 \ 1 A_DMFade();
Wait;
Taunt1:
#### # 5;
PLT1 ABCDEFG 6;
Goto Spawn+1;
Taunt2:
#### # 5;
PLT2 ABCDEFGHIJKLMNOPQRSTUVWXY 3;
Goto Spawn+1;
Taunt3:
#### # 5;
PLT3 ABCDEFGHIJKLMNO 3;
Goto Spawn+1;
Taunt4:
#### # 0;
Goto Spawn;
}
}
Class UPlayerMale1 : UPlayerMale
{
override void PlayFootstep( double vol )
{
let boot = UJumpBoots(FindInventory("UJumpBoots"));
if ( boot ) A_PlaySound("u1/bootfootstep",CHAN_5,min(1.,vol*2));
else
{
double ang = level.time/(20*TICRATE/35.)*360.;
if ( sin(ang) > 0 ) A_PlaySound("u1/metalfootstep",CHAN_5,min(1.,vol*2));
else A_PlaySound("ut/playerfootstep",CHAN_5,vol);
}
}
Default
{
Player.DisplayName "$N_MALE1";
-NOMENU;
}
States
{
See:
KURG A -1;
Stop;
}
}
Class UPlayerMale2 : UPlayerMale
{
Default
{
Player.SoundClass "umale2";
Player.DisplayName "$N_MALE2";
-NOMENU;
}
States
{
See:
ASH_ A -1;
Stop;
}
}
Class UPlayerMale3 : UPlayerMale
{
Default
{
Player.SoundClass "umale3";
Player.DisplayName "$N_MALE3";
UTPlayer.VoiceType VOICE_MaleTwo;
-NOMENU;
}
States
{
See:
DANT A -1;
Stop;
}
}
Class UnrealInventory : Inventory
{
bool bActive; // is currently activated
int Charge; // for timed items
int DefaultCharge;
private int UItemFlags;
Property Charge : DefaultCharge;
FlagDef DrawSpecial : UItemFlags, 0; // hud draws special1 as amount
FlagDef UnlimitedCopies : UItemFlags, 1; // can pick up unlimited copies
// Drawstuffs under HUD
virtual ui void PreRender( double lbottom ) {}
// Drawstuffs over HUD
virtual ui void PostRender( double lbottom ) {}
virtual bool DrainCharge( int val )
{
Charge -= val;
if ( Charge > 0 ) return false;
if ( Amount > 1 )
{
Amount--;
Charge = DefaultCharge;
bActive = false;
return true;
}
return true;
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
if ( !Charge ) Charge = DefaultCharge;
// it's annoying to set this per-subclass
InterHubAmount = bUNLIMITEDCOPIES?int.max:MaxAmount;
}
override bool HandlePickup( Inventory item )
{
if ( (item.GetClass() == GetClass()) && ((MaxAmount > 1) || (DefaultCharge > 0)) )
{
if ( MaxAmount > 1 )
{
if ( UnrealInventory(item).Charge ) // redistribute charge among copies
{
int addcharge = Charge+UnrealInventory(item).Charge;
charge = min(DefaultCharge,addcharge);
// if there's charge to spare, increase amount
if ( addcharge > charge )
{
if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max;
Amount = min(bUNLIMITEDCOPIES?int.max:MaxAmount,Amount+item.Amount);
charge = addcharge-charge;
}
}
else
{
if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max;
Amount = min(bUNLIMITEDCOPIES?int.max:MaxAmount,Amount+item.Amount); // fully charged new copy, just increase
}
}
else Charge = DefaultCharge; // reset charge
item.bPickupGood = true;
return true;
}
if ( item.GetClass() == GetClass() )
{
if ( (Amount < MaxAmount) || bUNLIMITEDCOPIES || (sv_unlimited_pickup && !item.ShouldStay()) )
{
if ( (Amount > 0) && (Amount+item.Amount < 0) )
Amount = int.max;
else Amount += item.Amount;
if ( Amount > MaxAmount && !sv_unlimited_pickup && !bUNLIMITEDCOPIES )
Amount = MaxAmount;
item.bPickupGood = true;
}
return true;
}
return false;
}
override void Tick()
{
Super.Tick();
// don't slide on floor when dropped
if ( bDROPPED && (pos.z <= floorz) )
vel.xy *= 0;
}
override void DetachFromOwner()
{
Super.DetachFromOwner();
// deactivate
bActive = false;
}
override void OnDrop( Actor dropper )
{
Super.OnDrop(dropper);
// drop like weapons
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_CoordUtil.GetAxes(dropper.pitch,dropper.angle,dropper.roll);
vel = x*12.0;
vel.z += 4.0;
angle = dropper.angle;
pitch = 0;
roll = 0;
}
Default
{
+INVENTORY.INVBAR;
UnrealInventory.Charge 0;
Inventory.PickupSound "misc/p_pkup";
}
}
Class UTeleportFog : Actor
{
Default
{
+NOBLOCKMAP;
+NOTELEPORT;
+NOGRAVITY;
RenderStyle "Add";
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
Spawn("UTTeleportLight",Vec3Offset(0,0,16));
A_PlaySound("misc/teleport",volume:.5);
Spawn("UTeleportParticles",Vec3Offset(0,0,16));
}
States
{
Spawn:
TNT1 A 1;
Stop;
}
}
Class UTeleportParticles : UTParticleMesh
{
Default
{
Tag "telepo;UTeleParticle";
Args 21;
ReactionTime 35;
XScale 0.06;
YScale 0.16;
}
}
Class UTeleParticle : UTMeshParticle
{
Default
{
Scale 0.2;
}
States
{
Spawn:
TPNT A -1 Bright;
Stop;
}
}
Class UnrealWeapon : UTWeapon
{
override void FireEffect()
{
Super.FireEffect();
let invis = UInvisibility(Owner.FindInventory("UInvisibility"));
if ( invis && invis.bActive ) invis.special1 = -1;
}
override void PlayUpSound( Actor origin )
{
origin.A_PlaySound(upsound,CHAN_WEAPON,Dampener.Active(origin)?.1:1.);
}
// For clips
virtual clearscope int, int, bool, bool GetClipAmount() const
{
return -1, -1, false, false;
}
}
Class UnrealStaticHandler : StaticEventHandler
{
ui TextureID tex[8];
ui int mtics, cur;
ui String lastmusic;
ui void StartMenu()
{
CVar protomenu = CVar.GetCVar('stinger_introtype',players[consoleplayer]);
if ( !protomenu ) return; // this can happen
int proto = protomenu.GetInt();
tex[0] = TexMan.CheckForTexture("graphics/UnLogo0.png",TexMan.Type_Any);
tex[1] = TexMan.CheckForTexture("graphics/UnLogo1.png",TexMan.Type_Any);
tex[2] = TexMan.CheckForTexture("graphics/UnLogo3.png",TexMan.Type_Any);
tex[3] = TexMan.CheckForTexture("graphics/UnLogo2.png",TexMan.Type_Any);
tex[4] = TexMan.CheckForTexture("graphics/UnBg.png",TexMan.Type_Any);
tex[5] = TexMan.CheckForTexture("graphics/97Bg.png",TexMan.Type_Any);
tex[6] = TexMan.CheckForTexture("graphics/96Bg.png",TexMan.Type_Any);
tex[7] = TexMan.CheckForTexture("graphics/95Bg.png",TexMan.Type_Any);
if ( proto > 2 ) S_ChangeMusic("Unreal");
else if ( proto == 2 ) S_ChangeMusic("Isotox96");
else if ( proto == 1 ) S_ChangeMusic("Unreal2");
else S_ChangeMusic("FlyBy");
cur = proto;
}
override void OnRegister()
{
// remove the UT static handler
let hnd = UTStaticHandler(StaticEventHandler.Find("UTStaticHandler"));
if ( hnd ) hnd.Destroy();
}
override void ConsoleProcess( ConsoleEvent e )
{
if ( gamestate != GS_TITLELEVEL ) return;
if ( e.Name ~== "refreshmenu" ) StartMenu();
}
override void PostUiTick()
{
if ( gamestate != GS_TITLELEVEL ) return;
if ( gametic <= 0 ) StartMenu();
if ( musplaying.Name != lastmusic )
{
mtics = 0;
lastmusic = musplaying.Name;
}
else mtics++;
}
override void RenderUnderlay( RenderEvent e )
{
if ( gamestate != GS_TITLELEVEL ) return;
double ar = Screen.GetAspectRatio();
Vector2 tsize = TexMan.GetScaledSize(tex[cur+4]);
double sar = tsize.x/tsize.y;
Vector2 vsize;
if ( sar > ar ) vsize = (tsize.y*ar,tsize.y);
else if ( sar < ar ) vsize = (tsize.x,tsize.x/ar);
else vsize = tsize;
Screen.DrawTexture(tex[cur+4],false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true);
Screen.Dim("Black",clamp(1.-((mtics+e.FracTic)/Thinker.TICRATE)*.2,0.,1.),0,0,Screen.GetWidth(),Screen.GetHeight());
if ( menuactive ) return;
tsize = TexMan.GetScaledSize(tex[cur]);
sar = tsize.x/tsize.y;
if ( sar > ar ) vsize = (tsize.x,tsize.x/ar);
else if ( sar < ar ) vsize = (tsize.y*ar,tsize.y);
else vsize = tsize;
double alf = clamp(((mtics+e.FracTic)/Thinker.TICRATE)-8,0.,1.);
Screen.DrawTexture(tex[cur],false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true,DTA_Alpha,alf);
}
override void RenderOverlay( RenderEvent e )
{
// we have to stand in for the UT handler on this function
// although it doesn't make much sense yet
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);
}
}
Class AmmoUsedInSlot
{
Class<Ammo> AmmoType;
bool UsedInSlot[10];
}
Class UnrealMainHandler : EventHandler
{
Array<AmmoUsedInSlot> AmmoSlots;
transient int slotflash[10]; // used by the 0.83 hud
override void WorldThingDamaged( WorldEvent e )
{
// blow up stinger pumped actors when taking damage from other sources
if ( e.DamageType == 'Stinger' ) return;
let ti = ThinkerIterator.Create("TarydiumDebuff",Thinker.STAT_USER);
TarydiumDebuff t;
while ( t = TarydiumDebuff(ti.Next()) )
{
if ( (t.victim != e.Thing) || t.exploding ) continue; // make sure to skip any debuffs that already blew up to prevent infinite recursion on chain reactions
t.Amount += e.Damage;
// stunner/asmd and others deal extra explosive charge
if ( e.DamageType == 'jolted' ) t.Amount += 50+e.Damage;
t.exploding = true;
break;
}
}
override void CheckReplacement( ReplaceEvent e )
{
if ( (e.Replacee == 'Chainsaw') || (e.Replacee == 'Gauntlets') )
{
if ( (sting_dubious || sting_olsmp) && !Random[Replacements](0,3) ) e.Replacement = 'WeaponPowerUp';
else if ( Random[Replacements](0,2) )
{
if ( sting_dubious && Random[Replacements](0,1) ) e.Replacement = 'Bonesaw';
else e.Replacement = 'Stunner';
}
else if ( !Random[Replacements](0,2) ) e.Replacement = 'Betamag';
else e.Replacement = 'Automag';
}
else if ( (e.Replacee == 'Fist') || (e.Replacee == 'Staff') ) e.Replacement = 'DispersionPistol';
else if ( (e.Replacee == 'Pistol') || (e.Replacee == 'GoldWand') )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'Betamag';
else e.Replacement = 'Automag';
}
else if ( (e.Replacee == 'Shotgun') || (e.Replacee == 'SuperShotgun') || (e.Replacee == 'Crossbow') )
{
if ( !Random[Replacements](0,3) && (e.Replacee != 'SuperShotgun') )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'Betamag';
else e.Replacement = 'Automag';
}
else switch( Random[Replacements](0,2) )
{
case 0:
e.Replacement = 'Stinger';
break;
case 1:
e.Replacement = 'ASMD';
break;
case 2:
e.Replacement = 'QuadShot';
break;
}
}
else if ( (e.Replacee == 'Chaingun') || (e.Replacee == 'Blaster') )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'UMinigun';
else e.Replacement = 'Razorjack';
}
else if ( (e.Replacee == 'RocketLauncher') || (e.Replacee == 'PhoenixRod') )
{
if ( !Random[Replacements](0,3) )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'UFlamethrower';
else e.Replacement = 'FlameGun';
}
else if ( Random[Replacements](0,1) ) e.Replacement = 'UFlakCannon';
else e.Replacement = 'Eightball';
}
else if ( (e.Replacee == 'PlasmaRifle') || (e.Replacee == 'SkullRod') )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'Impaler';
else if ( Random[Replacements](0,1) ) e.Replacement = 'URifle';
else e.Replacement = 'UBioRifle';
}
else if ( (e.Replacee == 'BFG9000') || (e.Replacee == 'Mace') )
{
if ( sting_olsmp && (!sting_dubious || Random[Replacements](0,1)) ) e.Replacement = 'OLSMP';
else if ( sting_dubious )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'SMiniGun';
else e.Replacement = 'BigGun';
}
else e.Replacement = 'WeaponPowerup'; // lousy, I know
}
else if ( (e.Replacee == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') ) e.Replacement = 'UClip';
else if ( (e.Replacee == 'ClipBox') )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'UClip';
else if ( Random[Replacements](0,1) ) e.Replacement = 'UMiniAmmo';
else e.Replacement = 'RazorAmmo';
}
else if ( (e.Replacee == 'BlasterAmmo') || (e.Replacee == 'BlasterHefty') )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'UMiniAmmo';
else e.Replacement = 'RazorAmmo';
}
else if ( (e.Replacee == 'Shell') || (e.Replacee == 'CrossbowAmmo') )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'UClip';
else switch( Random[Replacements](0,2) )
{
case 0:
e.Replacement = 'StingerAmmo';
break;
case 1:
e.Replacement = 'ASMDAmmo2';
break;
case 2:
e.Replacement = 'UShells2';
break;
}
}
else if ( (e.Replacee == 'ShellBox') || (e.Replacee == 'CrossbowHefty') )
{
switch( Random[Replacements](0,2) )
{
case 0:
e.Replacement = 'StingerAmmo2';
break;
case 1:
e.Replacement = 'ASMDAmmo';
break;
case 2:
e.Replacement = 'UShells';
break;
}
}
else if ( (e.Replacee == 'RocketAmmo') || (e.Replacee == 'PhoenixRodAmmo') || (e.Replacee == 'MaceAmmo') )
{
if ( !Random[Replacements](0,4) ) e.Replacement = 'FlameAmmo';
else if ( Random[Replacements](0,1) )
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'UFlakBox';
else e.Replacement = 'UFlakAmmo';
}
else
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'URocketAmmo';
else e.Replacement = 'URocketAmmo2';
}
}
else if ( (e.Replacee == 'RocketBox') || (e.Replacee == 'PhoenixRodHefty') || (e.Replacee == 'MaceHefty') )
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'FlameAmmo';
else if ( Random[Replacements](0,1) ) e.Replacement = 'UFlakBox';
else e.Replacement = 'URocketAmmo';
}
else if ( (e.Replacee == 'Cell') || (e.Replacee == 'SkullRodAmmo') )
{
if ( sting_dubious && !Random[Replacements](0,4) )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'BigAmmo2';
else e.Replacement = 'BigAmmo3';
}
else if ( !Random[Replacements](0,3) )
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'ImpalerAmmo';
else e.Replacement = 'ImpalerAmmo2';
}
else if ( Random[Replacements](0,1) )
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'UBioAmmo';
else e.Replacement = 'UBioAmmo2';
}
else
{
if ( !Random[Replacements](0,3) ) e.Replacement = 'URifleAmmo';
else e.Replacement = 'URifleAmmo2';
}
}
else if ( (e.Replacee == 'CellPack') || (e.Replacee == 'SkullRodHefty') )
{
if ( sting_dubious && !Random[Replacements](0,4) )
{
if ( !Random[Replacements](0,2) ) e.Replacement = 'BigAmmo';
else e.Replacement = 'BigAmmo2';
}
else if ( !Random[Replacements](0,3) ) e.Replacement = 'ImpalerAmmo';
else if ( sting_olsmp && !Random[Replacements](0,2) ) e.Replacement = 'OLSMPAmmo';
else if ( Random[Replacements](0,1) ) e.Replacement = 'UBioAmmo';
else e.Replacement = 'URifleAmmo';
}
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'PowerShield';
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') )
{
if ( sting_msentry && !Random[Replacements](0,9) ) e.Replacement = 'SentryItem';
else if ( (sting_dubious || sting_olsmp) && !Random[Replacements](0,2) ) e.Replacement = 'WeaponPowerUp';
else e.Replacement = 'Amplifier';
}
else if ( e.Replacee == 'ArtiEgg' ) e.Replacement = 'VoiceBox';
else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) e.Replacement = 'SuperHealth';
else if ( e.Replacee == 'Megasphere' ) e.Replacement = 'ShieldBelt';
else if ( (e.Replacee == 'Allmap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'MotionDetector';
else if ( (e.Replacee == 'BlurSphere') || (e.Replacee == 'ArtiInvisibility') ) e.Replacement = 'UInvisibility';
else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') ) e.Replacement = 'UFlashlight';
else if ( e.Replacee == 'RadSuit' ) e.Replacement = 'UJumpBoots';
else if ( e.Replacee == 'ArtiFly' ) e.Replacement = 'UJumpBoots';
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') ) e.Replacement = 'UnrealBackpack';
else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') )
{
if ( Random[Replacements](0,3) ) e.Replacement = 'UArmorBonus';
else e.Replacement = 'Flare';
}
else if ( (e.Replacee == 'HealthBonus') || (e.Replacee == 'CrystalVial') ) e.Replacement = 'Bandages';
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'Silvershield') ) e.Replacement = 'KevlarSuit';
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'UArmor';
else if ( (e.Replacee == 'Stimpack') || (e.Replacee == 'ArtiHealth') )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'UHealth';
else if ( Random[Replacements](0,2) ) e.Replacement = 'NaliFruit';
else e.Replacement = 'Seeds';
}
else if ( e.Replacee == 'Medikit' ) e.Replacement = 'UHealth';
else if ( e.Replacee == 'ArtiTeleport' )
{
// I have no idea what to replace this with, so just have some random stuff
switch( Random[Replacements](0,7) )
{
case 0:
e.Replacement = 'UnrealBackpack';
break;
case 1:
e.Replacement = 'ShieldBelt';
break;
case 2:
e.Replacement = 'SuperHealth';
break;
case 3:
e.Replacement = 'Amplifier';
break;
case 4:
e.Replacement = 'WeaponPowerUp';
break;
case 5:
e.Replacement = 'VoiceBox';
break;
case 6:
e.Replacement = 'SentryGunItem';
break;
case 7:
e.Replacement = 'Peacemaker';
break;
}
}
else if ( e.Replacee == 'TeleportFog' ) e.Replacement = 'UTeleportFog';
// replace UT items (while this is mainly for the DT map pack, it also has the added effect of preventing the guns from being added by "give all")
else if ( e.Replacee is 'ImpactHammer' ) e.Replacement = 'DispersionPistol';
else if ( e.Replacee is 'Translocator' ) e.Replacement = 'UTranslocator';
else if ( e.Replacee is 'UTChainsaw' ) e.Replacement = 'Slot1Weapons';
else if ( e.Replacee is 'Enforcer' ) e.Replacement = 'Slot2Weapons';
else if ( e.Replacee is 'BioRifle' ) e.Replacement = 'Slot3Weapons';
else if ( e.Replacee is 'ShockRifle' ) e.Replacement = 'Slot4Weapons';
else if ( e.Replacee is 'PulseGun' ) e.Replacement = 'Slot5Weapons';
else if ( e.Replacee is 'Ripper2' ) e.Replacement = 'Slot6Weapons';
else if ( e.Replacee is 'Minigun' ) e.Replacement = 'Slot7Weapons';
else if ( e.Replacee is 'FlakCannon' ) e.Replacement = 'Slot8Ammo';
else if ( e.Replacee is 'UTRocketLauncher' ) e.Replacement = 'Slot0Weapons';
else if ( e.Replacee is 'SniperRifle' ) e.Replacement = 'Slot0Weapons';
else if ( e.Replacee is 'WarheadLauncher' ) e.Replacement = 'Slot0SWeapons';
else if ( e.Replacee is 'EnhancedShockRifle' ) e.Replacement = 'Amplifier';
else if ( e.Replacee is 'ChainsawAmmo' ) e.Replacement = 'UNothing';
else if ( e.Replacee is 'EClip' ) e.Replacement = 'Slot2Ammo';
else if ( e.Replacee is 'BioAmmo' ) e.Replacement = 'Slot3Ammo';
else if ( e.Replacee is 'ShockAmmo' ) e.Replacement = 'Slot4Ammo';
else if ( e.Replacee is 'PulseAmmo' ) e.Replacement = 'Slot5Ammo';
else if ( e.Replacee is 'RipperAmmo' ) e.Replacement = 'Slot6Ammo';
else if ( e.Replacee is 'MiniAmmo' ) e.Replacement = 'Slot7Ammo';
else if ( e.Replacee is 'FlakAmmo' ) e.Replacement = 'Slot8Ammo';
else if ( e.Replacee is 'UTRocketAmmo' ) e.Replacement = 'Slot9Ammo';
else if ( e.Replacee is 'RifleAmmo' ) e.Replacement = 'Slot0Ammo';
else if ( e.Replacee is 'WarheadAmmo' ) e.Replacement = 'Slot0SAmmo';
else if ( e.Replacee is 'EnhancedShockAmmo' ) e.Replacement = 'UNothing';
else if ( e.Replacee is 'UTBackpack' ) e.Replacement = 'UnrealBackpack';
else if ( e.Replacee is 'UDamage' ) e.Replacement = 'Amplifier';
// we don't need these
else if ( e.Replacee is 'UTActivatable' ) e.Replacement = 'UNothing';
else if ( e.Replacee is 'UTActivatableHealth' ) e.Replacement = 'UNothing';
}
// translocator stuff
override void PlayerEntered( PlayerEvent e )
{
if ( flak_translocator )
players[e.playernumber].mo.TakeInventory("Translocator",1);
if ( sting_telegun )
players[e.playernumber].mo.GiveInventory("UTranslocator",1);
if ( sting_flares )
{
players[e.playernumber].mo.GiveInventory("LightFlare",1);
players[e.playernumber].mo.GiveInventory("DarkFlare",1);
}
}
override void PlayerRespawned( PlayerEvent e )
{
PlayerEntered(e);
}
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.TakeInventory("Translocator",1);
}
}
if ( sting_telegun )
{
for ( int i=0; i<MAXPLAYERS; i++ ) if ( playeringame[i] )
{
players[i].mo.GiveInventory("UTranslocator",1);
}
}
if ( sting_flares )
{
for ( int i=0; i<MAXPLAYERS; i++ ) if ( playeringame[i] )
{
players[i].mo.GiveInventory("LightFlare",1);
players[i].mo.GiveInventory("DarkFlare",1);
}
}
}
else if ( (e.Name ~== "usetranslator") && (e.player != -1) && playeringame[e.player] && !menuactive )
{
let t = players[e.player].mo.FindInventory("UTranslator");
if ( t ) t.Use(false);
}
else if ( e.Name ~== "Bar083SlotFlash" )
slotflash[e.Args[0]] = gametic+20;
}
private static bool CmpWeapon( Class<Weapon> a, Class <Weapon> b )
{
let defa = GetDefaultByType(a);
let defb = GetDefaultByType(b);
if ( defa.SlotPriority <= defb.SlotPriority ) return true;
if ( defa.SlotNumber > defb.SlotNumber ) return true;
return false;
}
override void WorldLoaded( WorldEvent e )
{
// More "authentic" Unreal flavor of these edits
if ( (level.GetChecksum() ~== "959A613006CC3AA912C4A22908B7566A") || (level.GetChecksum() ~== "0EADB2F82732A968B8513E4DC6138439") )
{
S_ChangeMusic("Cyrene");
TextureID sky95 = TexMan.CheckForTexture("Sky95",TexMan.Type_Any);
level.ChangeSky(sky95,sky95);
level.ReplaceTextures("rClfFlr0","C_flr19",0);
level.ReplaceTextures("rClfBas0","C_wal19k",0);
level.ReplaceTextures("uAlnWl2b","C_WAL19A",0);
level.ReplaceTextures("xAlnWl2b","C_WAL19F",0);
}
// populate weapons array
Array<Class<Weapon> > SortedWeapons;
SortedWeapons.Clear();
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let type = (class<Weapon>)(AllActorClasses[i]);
if ( !type || (type == "Weapon") ) continue;
let rep = Actor.GetReplacement(type);
if ( (rep != type) && !(rep is "DehackedPickup") ) continue;
readonly<Weapon> def = GetDefaultByType(type);
int wslot = def.SlotNumber;
if ( wslot == -1 ) continue;
if ( !def.AmmoType1 ) continue;
SortedWeapons.Push(type);
}
// sort weapons array
for ( int i=0; i<SortedWeapons.Size(); i++ )
{
int j = 1;
while ( j < SortedWeapons.Size() )
{
int k = j;
while ( (k > 0) && CmpWeapon(SortedWeapons[k-1],SortedWeapons[k]) )
{
Class<Weapon> tmp = SortedWeapons[k];
SortedWeapons[k] = SortedWeapons[k-1];
SortedWeapons[k-1] = tmp;
k--;
}
j++;
}
}
// populate ammo-by-slot array
AmmoSlots.Clear();
for ( int i=0; i<SortedWeapons.Size(); i++ )
{
readonly<Weapon> def = GetDefaultByType(SortedWeapons[i]);
int wslot = def.SlotNumber;
int found = -1;
for ( int j=0; j<AmmoSlots.Size(); j++ )
{
if ( AmmoSlots[j].AmmoType != def.AmmoType1 ) continue;
found = j;
}
if ( found == -1 )
{
let asl = new("AmmoUsedInSlot");
asl.AmmoType = def.AmmoType1;
asl.UsedInSlot[wslot] = true;
AmmoSlots.Push(asl);
}
else AmmoSlots[found].UsedInSlot[wslot] = true;
}
}
}