172 lines
5.1 KiB
Text
172 lines
5.1 KiB
Text
// player-specific item stuff
|
|
|
|
// lucky collar
|
|
// made by Ashley Knox, given to you and Ibuki by Saya
|
|
Class SayaCollar : Inventory
|
|
{
|
|
Default
|
|
{
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.UNCLEARABLE;
|
|
}
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( (damage <= 0) || (flags&(DMG_FORCED|DMG_NO_ARMOR)) ) return;
|
|
newdamage = damage;
|
|
// oopsies are halved
|
|
if ( source == Owner ) newdamage = max(1,newdamage/2);
|
|
// in danger? reduce to a quarter
|
|
if ( (Owner.Health-newdamage < 25) )
|
|
{
|
|
int splitdmg[2];
|
|
splitdmg[0] = max(0,Owner.Health-25); // non-reduced part (>=25% health)
|
|
splitdmg[1] = max(1,(newdamage-splitdmg[0])/4); // reduced part (<25% health)
|
|
newdamage = splitdmg[0]+splitdmg[1];
|
|
}
|
|
}
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
// if first item is health or sandwich, ignore
|
|
if ( (other.Inv is 'SWWMHealth') || (other.Inv is 'GrilledCheeseSandwich') )
|
|
return;
|
|
// if there's items before health/sandwich, squeeze right in
|
|
for ( Inventory i=other.Inv; i; i=i.Inv )
|
|
{
|
|
if ( (i == self) || (!(i.Inv is 'SWWMHealth' ) && !(i.Inv is 'GrilledCheeseSandwich')) ) continue;
|
|
Inventory saved = i.Inv;
|
|
i.Inv = self;
|
|
other.Inv = Inv;
|
|
Inv = saved;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// high-resonant almasteel plating
|
|
// EXTRA THICC as Saya requested
|
|
Class AlmasteelPlating : Inventory
|
|
{
|
|
Inventory dbf;
|
|
|
|
Default
|
|
{
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.UNCLEARABLE;
|
|
Inventory.RestrictedTo "Demolitionist";
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !dbf ) return;
|
|
dbf.Amount = int(dbf.Amount*.95-1); // rapidly dissipate Telebrium corrosion
|
|
}
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( inflictor && (inflictor is 'CorrodeDebuff') ) dbf = Inventory(inflictor);
|
|
if ( (damage <= 0) || (flags&(DMG_FORCED|DMG_NO_ARMOR)) ) return;
|
|
newdamage = damage;
|
|
// 80% reduction for explosions
|
|
if ( flags&DMG_EXPLOSION ) newdamage = newdamage/5;
|
|
// 50% reduction for crushing
|
|
if ( damageType == 'Crush' )
|
|
{
|
|
newdamage = newdamage/2;
|
|
// additionally, check if we can break any active crushers
|
|
double gaph = (Owner.ceilingz-Owner.floorz);
|
|
if ( gaph > Owner.height*.6 ) return;
|
|
// the smaller the gap, the more likely the crusher will snap
|
|
if ( Random[Demolitionist](0,3) && (FRandom[Demolitionist](0,gaph/Owner.height) > .1) ) return;
|
|
double diffh = 8.+(Owner.default.height-gaph); // how much the crusher will have to "snap" after breaking
|
|
let ceil = Owner.ceilingsector;
|
|
let flor = Owner.floorsector;
|
|
let ceilse = ceil.ceilingdata;
|
|
let florse = flor.floordata;
|
|
if ( ceilse && florse )
|
|
{
|
|
// snap both planes
|
|
let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot)));
|
|
q.special1 = 6;
|
|
q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot)));
|
|
q.special1 = 6;
|
|
SWWMCrusherBroken.Create(flor,ceil,diffh/2.);
|
|
}
|
|
else if ( ceilse )
|
|
{
|
|
// snap ceiling
|
|
let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot)));
|
|
q.special1 = 10;
|
|
SWWMCrusherBroken.Create(null,ceil,diffh);
|
|
}
|
|
else if ( florse )
|
|
{
|
|
// snap floor
|
|
let q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot)));
|
|
q.special1 = 10;
|
|
SWWMCrusherBroken.Create(flor,null,diffh);
|
|
}
|
|
}
|
|
}
|
|
override bool HandlePickup( Inventory item )
|
|
{
|
|
// disallow vanilla armors
|
|
if ( (item is 'BasicArmor') || (item is 'BasicArmorBonus') || (item is 'BasicArmorPickup') || (item is 'HexenArmor') )
|
|
{
|
|
item.bPickupGood = true; // but act as if we picked them up
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
// if first item is the collar, just ignore
|
|
if ( other.Inv is 'SayaCollar' ) return;
|
|
// if there's items before collar, squeeze right in
|
|
for ( Inventory i=other.Inv; i; i=i.Inv )
|
|
{
|
|
if ( (i == self) || !(i.Inv is 'SayaCollar') ) continue;
|
|
Inventory saved = i.Inv;
|
|
i.Inv = self;
|
|
other.Inv = Inv;
|
|
Inv = saved;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Class ReviveCooldown : Powerup
|
|
{
|
|
Default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Revive.png";
|
|
Powerup.Duration -30;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( !Owner ) Destroy();
|
|
if ( Owner.Health <= 0 ) return; // timer does not go down when dead
|
|
if ( (EffectTics == 0) || ((EffectTics > 0) && (--EffectTics == 0)) )
|
|
Destroy ();
|
|
}
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
// adjust the duration
|
|
EffectTics = max(0,swwm_revivecooldown)*GameTicRate;
|
|
}
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_StartSound("demolitionist/revive",CHAN_ITEMEXTRA);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_REFAIL"));
|
|
}
|
|
override void OwnerDied()
|
|
{
|
|
// do nothing, this "powerup" is preserved on death
|
|
}
|
|
}
|