Double capacity with backpack for all ammo (except Redeemer, it just gets one extra). Made Enhanced Shock Rifle ammo drain over time (1 unit per second). Uncapped health and armor numbers in the HUD. Fixed Jump Boots not persisting between levels. Increased duration of invisibility. Made translocator toggleable (currently requires manually selecting "apply changes" under the menu option).
509 lines
12 KiB
Text
509 lines
12 KiB
Text
Class UDamage : PowerupGiver replaces Berserk
|
|
{
|
|
Default
|
|
{
|
|
Tag "Damage Amplifier";
|
|
Inventory.PickupMessage "You got the Damage Amplifier!";
|
|
+COUNTITEM;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.BIGPOWERUP;
|
|
Inventory.MaxAmount 0;
|
|
Powerup.Type "DamageAmplifier";
|
|
Inventory.PickupSound "udamage/pickup";
|
|
Inventory.RespawnTics 4200;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
UDAM A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class DamageAmpLight : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
Args 238,0,255,80;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
args[LIGHT_INTENSITY] = Random[ASMD](10,12)*8;
|
|
bDORMANT = Powerup(master).isBlinking();
|
|
}
|
|
}
|
|
|
|
Class DamageAmplifier : Powerup
|
|
{
|
|
Actor l;
|
|
|
|
Default
|
|
{
|
|
Powerup.Duration -60;
|
|
Powerup.Color "EE00FF", 0.15;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
l = Spawn("DamageAmpLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( (EffectTics == 175) || (EffectTics == 140) || (EffectTics == 105) || (EffectTics == 70) || (EffectTics == 35) )
|
|
Owner.A_PlaySound("udamage/drain",CHAN_7,1.0,false,0.25);
|
|
}
|
|
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
PrintPickupMessage(true,"Damage Amplifier has worn off.");
|
|
}
|
|
|
|
override bool isBlinking()
|
|
{
|
|
return ((EffectTics <= 175) && (EffectTics%35 >= 30));
|
|
}
|
|
|
|
void FireEffect()
|
|
{
|
|
if ( EffectTics < 350 ) Owner.A_PlaySound("udamage/fire2",CHAN_7,1.0,false,0.25);
|
|
else Owner.A_PlaySound("udamage/fire1",CHAN_7,1.0,false,0.25);
|
|
UTMainHandler.DoFlash(Owner,Color(96,238,0,255),10);
|
|
}
|
|
|
|
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive )
|
|
{
|
|
if ( passive || (damage <= 0) ) return;
|
|
newdamage = max(1,ApplyDamageFactors(GetClass(),damageType,damage,damage*3));
|
|
if ( !(Owner.player.ReadyWeapon is 'UTWeapon') ) FireEffect();
|
|
}
|
|
}
|
|
|
|
// Backpack that only gives ammo for valid weapons
|
|
Class UTBackpack : BackpackItem replaces Backpack
|
|
{
|
|
override Inventory CreateCopy( Actor other )
|
|
{
|
|
// Find every unique type of ammoitem. Give it to the player if
|
|
// he doesn't have it already, and double its maximum capacity.
|
|
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
|
{
|
|
let type = (class<Ammo>)(AllActorClasses[i]);
|
|
if ( !type || (type.GetParentClass() != 'Ammo') ) continue;
|
|
// check that it's for a valid weapon
|
|
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 ( !other.player || !other.player.weapons.LocateWeapon(type2) || weap.bCheatNotWeapon ) continue;
|
|
if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) )
|
|
{
|
|
isvalid = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( !isvalid ) continue;
|
|
let ammoitem = Ammo(other.FindInventory(type));
|
|
int amount = GetDefaultByType(type).BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if ( !bIgnoreSkill ) amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
if ( amount < 0 ) amount = 0;
|
|
if ( !ammoitem )
|
|
{
|
|
// The player did not have the ammoitem. Add it.
|
|
ammoitem = Ammo(Spawn(type));
|
|
ammoitem.Amount = bDepleted?0:amount;
|
|
if ( ammoitem.BackpackMaxAmount > ammoitem.MaxAmount )
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
if ( ammoitem.Amount > ammoitem.MaxAmount )
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
ammoitem.AttachToOwner(other);
|
|
}
|
|
else
|
|
{
|
|
// The player had the ammoitem. Give some more.
|
|
if ( ammoitem.MaxAmount < ammoitem.BackpackMaxAmount )
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
if ( !bDepleted && (ammoitem.Amount < ammoitem.MaxAmount) )
|
|
{
|
|
ammoitem.Amount += amount;
|
|
if ( ammoitem.Amount > ammoitem.MaxAmount )
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
return Inventory.CreateCopy(other);
|
|
}
|
|
override bool HandlePickup (Inventory item)
|
|
{
|
|
// Since you already have a backpack, that means you already have every
|
|
// kind of ammo in your inventory, so we don't need to look at the
|
|
// entire PClass list to discover what kinds of ammo exist, and we don't
|
|
// have to alter the MaxAmount either.
|
|
if ( item is 'BackpackItem' )
|
|
{
|
|
for ( let probe = Owner.Inv; probe; probe = probe.Inv )
|
|
{
|
|
if ( probe.GetParentClass() != 'Ammo' ) continue;
|
|
if ( probe.Amount >= probe.MaxAmount && !sv_unlimited_pickup ) continue;
|
|
int amount = Ammo(probe).Default.BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if ( !bIgnoreSkill )
|
|
amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
probe.Amount += amount;
|
|
if ( (probe.Amount > probe.MaxAmount) && !sv_unlimited_pickup )
|
|
probe.Amount = probe.MaxAmount;
|
|
}
|
|
// The pickup always succeeds, even if you didn't get anything
|
|
item.bPickupGood = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
Default
|
|
{
|
|
Tag "Backpack";
|
|
Inventory.PickupMessage "You got a Backpack.";
|
|
Inventory.RespawnTics 2100;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BPAK A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class PowerUTInvisibility : PowerInvisibility
|
|
{
|
|
Default
|
|
{
|
|
Powerup.Duration -80;
|
|
Powerup.Strength 90;
|
|
Powerup.Mode "Additive";
|
|
Powerup.Color "FFFFFF", 0.1;
|
|
}
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
PrintPickupMessage(true,"Invisibility has worn off.");
|
|
}
|
|
}
|
|
|
|
Class UTInvisibility : PowerupGiver replaces BlurSphere
|
|
{
|
|
Default
|
|
{
|
|
Tag "Invisibility";
|
|
+COUNTITEM;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.BIGPOWERUP;
|
|
Inventory.MaxAmount 0;
|
|
Powerup.Type "PowerUTInvisibility";
|
|
Inventory.PickupMessage "You have Invisibility.";
|
|
Inventory.PickupSound "invis/pickup";
|
|
Inventory.RespawnTics 4200;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("UTInvisibilityX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
INVS A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTInvisibilityX : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
Radius 0.1;
|
|
Height 0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
bInvisible = target.bInvisible;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
INVS A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTMapRevealer : MapRevealer replaces Allmap
|
|
{
|
|
Default
|
|
{
|
|
+COUNTITEM;
|
|
+INVENTORY.FANCYPICKUPSOUND;
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
Inventory.MaxAmount 0;
|
|
Inventory.PickupSound "trans/pickup";
|
|
Inventory.PickupMessage "You got the Computer Map.";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TRNS A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTJumpBoots : Inventory replaces RadSuit
|
|
{
|
|
Default
|
|
{
|
|
Tag "AntiGrav Boots";
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
Inventory.Amount 3;
|
|
Inventory.MaxAmount 3;
|
|
Inventory.InterHubAmount 3;
|
|
Inventory.PickupMessage "You picked up the AntiGrav boots.";
|
|
Inventory.PickupSound "boot/pickup";
|
|
Inventory.RespawnTics 1050;
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup )
|
|
{
|
|
Owner.GiveInventory("PowerJumpBoots_HighJump",1);
|
|
Owner.GiveInventory("PowerJumpBoots_IronFeet",1);
|
|
}
|
|
return false;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !Owner || !Owner.player ) return;
|
|
if ( owner.player.jumptics == -1 )
|
|
{
|
|
Amount--;
|
|
Owner.A_PlaySound("boot/jump",CHAN_BODY);
|
|
if ( Amount <= 0 )
|
|
{
|
|
PrintPickupMessage(true,"The AntiGrav Boots have drained.");
|
|
DepleteOrDestroy();
|
|
}
|
|
}
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
Super.DetachFromOwner();
|
|
Owner.TakeInventory("PowerJumpBoots_HighJump",1);
|
|
Owner.TakeInventory("PowerJumpBoots_IronFeet",1);
|
|
}
|
|
override void OwnerDied()
|
|
{
|
|
Super.OwnerDied();
|
|
DepleteOrDestroy();
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
JBUT A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class PowerJumpBoots_HighJump : PowerHighJump
|
|
{
|
|
Default
|
|
{
|
|
Powerup.Strength 3;
|
|
Powerup.Duration int.max;
|
|
+INVENTORY.PERSISTENTPOWER;
|
|
}
|
|
}
|
|
Class PowerJumpBoots_IronFeet : PowerIronFeet
|
|
{
|
|
Default
|
|
{
|
|
Powerup.Duration int.max;
|
|
Powerup.Color "00 00 00", 0.0;
|
|
+INVENTORY.PERSISTENTPOWER;
|
|
}
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
|
|
{
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Powerup.DoEffect();
|
|
}
|
|
}
|
|
|
|
Class Searchlight : Inventory replaces Infrared
|
|
{
|
|
Actor lt[3];
|
|
int ticcnt;
|
|
Default
|
|
{
|
|
Tag "Searchligh";
|
|
+COUNTITEM;
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.FANCYPICKUPSOUND;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
Inventory.Amount 200;
|
|
Inventory.MaxAmount 200;
|
|
Inventory.InterHubAmount 0;
|
|
Inventory.PickupMessage "You picked up the Searchlight.";
|
|
}
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( !lt[0] ) lt[0] = Spawn("mkLight");
|
|
lt[0].target = owner;
|
|
lt[0].master = self;
|
|
if ( !lt[1] ) lt[1] = Spawn("mkLight2");
|
|
lt[1].target = owner;
|
|
lt[1].master = self;
|
|
if ( !lt[2] ) lt[2] = Spawn("mkLight3");
|
|
lt[2].target = owner;
|
|
lt[2].master = self;
|
|
return Super.Use(pickup);
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
Super.DetachFromOwner();
|
|
if ( lt[0] ) lt[0].Destroy();
|
|
if ( lt[1] ) lt[1].Destroy();
|
|
if ( lt[2] ) lt[2].Destroy();
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
if ( ticcnt++ < TICRATE ) return;
|
|
ticcnt = 0;
|
|
if ( --Amount <= 0 )
|
|
{
|
|
PrintPickupMessage(true,"Searchlight batteries have died.");
|
|
DepleteOrDestroy();
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SLIT A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
/* hello, Soundless Mound copypasted lights */
|
|
Class mkLight : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
+DynamicLight.SPOT;
|
|
+DynamicLight.ATTENUATE;
|
|
+DynamicLight.DONTLIGHTSELF;
|
|
args 255,224,160,350;
|
|
DynamicLight.SpotInnerAngle 20;
|
|
DynamicLight.SpotOuterAngle 35;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !Inventory(master) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player ) SetOrigin((target.pos.x,target.pos.y,target.player.viewz),true);
|
|
else SetOrigin(target.vec3Offset(0,0,target.height*0.75),true);
|
|
A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
A_SetPitch(target.pitch,SPF_INTERPOLATE);
|
|
args[LIGHT_RED] = GetDefaultByType(GetClass()).args[LIGHT_RED]*clamp(Inventory(master).amount/40.,0.,1.);
|
|
args[LIGHT_GREEN] = GetDefaultByType(GetClass()).args[LIGHT_GREEN]*clamp(Inventory(master).amount/40.,0.,1.);
|
|
args[LIGHT_BLUE] = GetDefaultByType(GetClass()).args[LIGHT_BLUE]*clamp(Inventory(master).amount/40.,0.,1.);
|
|
bDORMANT = (target.health <= 0);
|
|
if ( Inventory(target) && target.bInvisible ) bDORMANT = true;
|
|
// alert monsters hit by the light
|
|
if ( GetClass() != "mkLight" ) return;
|
|
if ( !bDORMANT && target.player && (target.health > 0) )
|
|
{
|
|
BlockThingsIterator bt = BlockThingsIterator.Create(target,args[LIGHT_INTENSITY]);
|
|
while ( bt.Next() )
|
|
{
|
|
if ( !bt.Thing || (Distance3D(bt.Thing) > args[LIGHT_INTENSITY]) ) continue;
|
|
Vector3 aimdir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
Vector3 reldir = Vec3To(bt.Thing).unit();
|
|
if ( (acos(aimdir dot reldir) < SpotOuterAngle+5) && bt.Thing.CheckSight(target) ) bt.Thing.LastHeard = target;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Class mkLight2 : mkLight
|
|
{
|
|
Default
|
|
{
|
|
args 128,112,96,450;
|
|
DynamicLight.SpotInnerAngle 0;
|
|
DynamicLight.SpotOuterAngle 50;
|
|
}
|
|
}
|
|
|
|
Class mkLight3 : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
+DynamicLight.ATTENUATE;
|
|
args 32,28,24,0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || Inventory(target) || !Inventory(master) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
args[LIGHT_RED] = GetDefaultByType(GetClass()).args[LIGHT_RED]*clamp(Inventory(master).amount/40,0.,1.);
|
|
args[LIGHT_GREEN] = GetDefaultByType(GetClass()).args[LIGHT_GREEN]*clamp(Inventory(master).amount/40,0.,1.);
|
|
args[LIGHT_BLUE] = GetDefaultByType(GetClass()).args[LIGHT_BLUE]*clamp(Inventory(master).amount/40,0.,1.);
|
|
SetOrigin(target.vec3Offset(0,0,target.height*0.5),true);
|
|
}
|
|
}
|