// Base class for all SWWM Armors Class SWWMArmor : Armor abstract { meta int priority; meta String drainmsg; meta Class parent; private int SArmorFlags; Property ArmorPriority : priority; Property DrainMessage : drainmsg; Property GiverArmor : parent; FlagDef NoHitFlash : SArmorFlags, 0; // doesn't flash when taking damage FlagDef NoHitSound : SArmorFlags, 1; // doesn't play a sound when taking damage FlagDef NoDrain : SArmorFlags, 2; // amount is not drained, will always reduce as long as amount is non-zero // useful for powerup-given armors transient int lastautousetic; // accumulated damage can make the use sounds stack transient int lasthittic; // same here Default { +INVENTORY.AUTOACTIVATE; +INVENTORY.UNTOSSABLE; +INVENTORY.UNDROPPABLE; +INVENTORY.KEEPDEPLETED; +INVENTORY.ALWAYSPICKUP; } override void AttachToOwner( Actor other ) { Super.AttachToOwner(other); // find last armor that's better than us Inventory found = null; for ( Inventory i=other.Inv; i; i=i.Inv ) { if ( !(i is 'SWWMArmor') || (i == self) || (SWWMArmor(i).priority < priority) ) continue; found = i; } if ( !found ) { // find first item with an armor worse than us after it for ( Inventory i=other.Inv; i; i=i.Inv ) { if ( (i == self) || !(i.Inv is 'SWWMArmor') ) continue; if ( SWWMArmor(i.Inv).priority > priority ) continue; found = i; break; } } if ( !found ) { // check if first item in inventory is health or a sandwich if ( (other.Inv is 'SWWMHealth') || (other.Inv is 'GrilledCheeseSandwich') ) { // we're good return; } // find first item with health or sandwich after it for ( Inventory i=other.Inv; i; i=i.Inv ) { if ( (i == self) || (!(i.Inv is 'SWWMHealth' ) && !(i.Inv is 'GrilledCheeseSandwich')) ) continue; found = i; break; } } if ( !found ) return; // place ourselves right after it Inventory saved = found.Inv; found.Inv = self; other.Inv = Inv; Inv = saved; } // for subclasses virtual int HandleDamage( int damage, Name damageType, int flags ) { return damage; } override void AbsorbDamage( int damage, Name damageType, int &newdamage, Actor inflictor, Actor source, int flags ) { int saved; if ( (amount <= 0) || DamageTypeDefinition.IgnoreArmor(damageType) || (damage <= 0) ) return; if ( !bNOHITFLASH ) SWWMHandler.DoFlash(Owner,Color(int(clamp(damage*.15,1,16)),255,224,192),3); if ( !bNOHITSOUND && (lasthittic < gametic) ) { Owner.A_StartSound("armor/hit",CHAN_DAMAGE,CHANF_OVERLAP,clamp(damage*.03,0.,1.),2.5); lasthittic = gametic; } saved = HandleDamage(damage,damageType,flags); int healed = max(0,saved-damage); saved = min(saved,damage); if ( !bNODRAIN && (amount <= saved) ) saved = amount; newdamage -= saved; if ( healed > 0 ) Owner.GiveBody(healed); if ( (swwm_strictuntouchable == 1) && (saved > 0) && Owner.player ) { let hnd = SWWMHandler(EventHandler.Find('SWWMHandler')); if ( hnd ) hnd.tookdamage[Owner.PlayerNumber()] = true; } if ( !bNODRAIN ) amount -= saved; damage = newdamage; if ( (amount <= (MaxAmount-default.Amount)) && (Owner.CountInv(parent) > 0) ) { if ( GetDefaultByType(parent).UseSound && (lastautousetic < gametic) ) { Owner.A_StartSound(GetDefaultByType(parent).UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP,.6); lastautousetic = gametic; } int tgive = 0; while ( (amount <= (MaxAmount-default.Amount)) && (Owner.CountInv(parent) > 0) ) { Amount += default.Amount; if ( Owner.player == players[consoleplayer] ) SWWMScoreObj.SpawnAtActorBunch(default.Amount,Owner,Font.CR_GREEN); Owner.TakeInventory(parent,1); // absorb the extra damage too saved = HandleDamage(damage,damageType,flags); healed = max(0,saved-damage); saved = min(saved,damage); if ( amount <= saved ) saved = amount; newdamage -= saved; if ( healed > 0 ) Owner.GiveBody(healed); amount -= saved; damage = newdamage; } } else if ( amount <= 0 ) { if ( Owner.CheckLocalView() && (drainmsg != "") ) Console.Printf(StringTable.Localize(drainmsg)); DepleteOrDestroy(); return; } } } // gives armor when used Class SWWMSpareArmor : Inventory abstract { Mixin SWWMAutoUseFix; Mixin SWWMUseToPickup; Mixin SWWMOverlapPickupSound; Mixin SWWMRespawn; Mixin SWWMRotatingPickup; Mixin SWWMPickupGlow; Mixin SWWMUnrealStyleDrop; meta Class giveme; Property GiveArmor : giveme; override bool Use( bool pickup ) { let cur = Owner.FindInventory(giveme); if ( !cur || (!pickup && (cur.Amount < cur.MaxAmount)) || (GetDefaultByType(giveme).Amount+cur.Amount <= cur.MaxAmount) || ((default.MaxAmount <= 0) && (cur.Amount < cur.MaxAmount)) ) { if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) { bool bPlayMe = true; if ( self is 'ArmorNuggetItem' ) { let hnd = SWWMHandler(EventHandler.Find('SWWMHandler')); if ( hnd ) { if ( hnd.lastnuggettic[Owner.PlayerNumber()] == gametic ) bPlayMe = false; // don't play if picked up on the same exact tic (overlapping items) hnd.lastnuggettic[Owner.PlayerNumber()] = gametic; } } if ( bPlayMe ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP); } Owner.GiveInventory(giveme,GetDefaultByType(giveme).Amount); SWWMHandler.ArmorFlash(Owner.PlayerNumber()); if ( Owner.player == players[consoleplayer] ) SWWMScoreObj.SpawnAtActorBunch(GetDefaultByType(giveme).Amount,Owner,Font.CR_GREEN); return true; } return false; } Default { +INVENTORY.INVBAR; +INVENTORY.ISARMOR; +INVENTORY.AUTOACTIVATE; Inventory.MaxAmount 5; Inventory.InterHubAmount 5; Inventory.PickupFlash 'SWWMGreenPickupFlash'; +FLOATBOB; +DONTGIB; FloatBobStrength 0.25; } }