// identification and tagging extend Class SWWMUtility { // because GetTag() returns the localized string, we need to do things the hard way static play String GetFunTag( SWWMHandler hnd, Actor a, String defstr = "" ) { // look up fun tag services if available foreach ( sv:hnd.funtagsv ) { if ( !sv ) continue; String res = sv.GetString("GetFunTag",objectArg:a); if ( res == "" ) continue; return res; } int ntags = 1; String basetag = ""; switch ( a.GetClassName() ) { // Doom case 'ZombieMan': case 'StealthZombieMan': basetag = "ZOMBIE"; break; case 'ShotgunGuy': case 'StealthShotgunGuy': basetag = "SHOTGUN"; break; case 'ChaingunGuy': case 'StealthChaingunGuy': basetag = "HEAVY"; break; case 'DoomImp': case 'StealthDoomImp': basetag = "IMP"; break; case 'Demon': case 'StealthDemon': basetag = "DEMON"; break; case 'Spectre': basetag = "SPECTRE"; break; case 'LostSoul': case 'LostSoulEvit2': case 'LostSoulCount': basetag = "LOST"; break; case 'Cacodemon': case 'StealthCacodemon': basetag = "CACO"; break; case 'HellKnight': case 'StealthHellKnight': basetag = "HELL"; break; case 'BaronOfHell': case 'StealthBaron': basetag = "BARON"; break; case 'Arachnotron': case 'StealthArachnotron': basetag = "ARACH"; break; case 'PainElemental': basetag = "PAIN"; break; case 'Revenant': case 'StealthRevenant': basetag = "REVEN"; break; case 'Fatso': case 'StealthFatso': basetag = "MANCU"; break; case 'Archvile': case 'StealthArchvile': basetag = "ARCH"; break; case 'SpiderMastermind': basetag = "SPIDER"; break; case 'Cyberdemon': case 'CyberdemonEvit2': case 'CyberdemonMAP24': basetag = "CYBER"; break; case 'SWWMBossBrain': basetag = "BOSSBRAIN"; break; case 'WolfensteinSS': if ( IsUltDoom2() ) { basetag = "ELITEZOMBIE"; break; } // ensure it's not being replaced if ( CheckDehackery('WolfensteinSS') ) break; case 'SWWMSS': basetag = "WOLFSS"; break; case 'SWWMHangingKeen': basetag = "KEEN"; break; case 'MBFHelperDog': case 'SWWMDog': basetag = "DOG"; break; case 'SWWMGuard': basetag = "WOLFGUARD"; break; case 'SWWMHans': basetag = "WOLFHANS"; break; // Heretic case 'Chicken': basetag = "CHICKEN"; break; case 'Beast': basetag = "BEAST"; break; case 'Clink': basetag = "CLINK"; break; case 'Sorcerer1': case 'Sorcerer2': basetag = "DSPARIL"; break; case 'HereticImp': case 'HereticImpLeader': basetag = "HERETICIMP"; break; case 'Ironlich': basetag = "IRONLICH"; break; case 'Knight': case 'KnightGhost': basetag = "BONEKNIGHT"; break; case 'Minotaur': case 'MinotaurFriend': basetag = "MINOTAUR"; break; case 'Mummy': case 'MummyGhost': basetag = "MUMMY"; break; case 'MummyLeader': case 'MummyLeaderGhost': basetag = "MUMMYLEADER"; break; case 'Snake': basetag = "SNAKE"; break; case 'Wizard': basetag = "WIZARD"; break; // Hexen case 'FireDemon': basetag = "FIREDEMON"; break; case 'Demon1': case 'Demon1Mash': case 'Demon2': case 'Demon2Mash': basetag = "DEMON1"; break; case 'Ettin': case 'EttinMash': basetag = "ETTIN"; break; case 'Centaur': case 'CentaurMash': basetag = "CENTAUR"; break; case 'CentaurLeader': basetag = "SLAUGHTAUR"; break; case 'Bishop': basetag = "BISHOP"; break; case 'IceGuy': basetag = "ICEGUY"; break; case 'Serpent': case 'SerpentLeader': basetag = "SERPENT"; break; case 'Wraith': case 'WraithBuried': basetag = "WRAITH"; break; case 'Dragon': basetag = "DRAGON"; break; case 'Korax': basetag = "KORAX"; break; case 'FighterBoss': basetag = "FBOSS"; break; case 'MageBoss': basetag = "MBOSS"; break; case 'ClericBoss': basetag = "CBOSS"; break; case 'Heresiarch': basetag = "HERESIARCH"; break; case 'Pig': basetag = "PIG"; break; // eviternity case 'ArchangelusA': case 'ArchangelusB': basetag = "ANGEL"; break; case 'AstralCaco': basetag = "ASTRAL"; break; case 'Annihilator': basetag = "ANNIHIL"; break; case 'FormerCaptain': basetag = "FCAPTAIN"; break; case 'NightmareDemon': basetag = "NDEMON"; break; // eviternity 2 case 'FormerCorporal': basetag = "FCORPORAL"; break; case 'AstralArachnotron': basetag = "ASTRALARACH"; break; case 'AstralCacodemon': basetag = "ASTRAL"; break; case 'Veilimp': basetag = "VEILIMP"; break; case 'GoldenAstralCaco': case 'GoldenAstralCacoBoss': basetag = "ASTRALGOLD"; break; case 'DukeOfHell': basetag = "DUKE"; break; case 'AstralBabyCaco': basetag = "ASTRALBABY"; break; case 'NightmareCacodemon': basetag = "NAC"; break; case 'AstralMancubus': basetag = "ASTRALFATSO"; break; case 'NecromenaceA': case 'NecromenaceB': case 'NecromenaceC': case 'NecromenaceD': basetag = "NECROMENACE"; break; case 'The_Origin_Phase_1': case 'The_Origin_Phase_2': case 'The_Origin_Phase_3': case 'The_Absolute_Origin_Phase_1': case 'The_Absolute_Origin_Phase_2': case 'The_Absolute_Origin_Phase_3': basetag = "ORIGIN"; break; case 'SpectralAstralCacodemon': basetag = "SAC"; break; case 'GrandDukeofHell': basetag = "GDUKE"; break; } if ( basetag == "" ) return a.GetTag(defstr); String funtag = "FN_"..basetag.."_FUN"; String lfuntag = StringTable.Localize(funtag,false); if ( lfuntag != funtag ) return lfuntag; String nfuntag = "FN_"..basetag.."_FUNN"; String lnfuntag = StringTable.Localize(nfuntag,false); if ( lnfuntag == nfuntag ) return a.GetTag(defstr); ntags = lnfuntag.ToInt(); return StringTable.Localize(String.Format("$FN_%s_FUN%d",basetag,Random[FunTags](1,ntags))); } // used to "substitute" a monster class for another so killcount stats are merged // e.g.: "stealth" monsters and their non-stealth counterparts, // or "HereticImp" and "HereticImpLeader", which have the same exact tag, // and would result in an odd "duplication" of monster names static play Class MergeMonster( SWWMHandler hnd, Class a ) { // see if any services can resolve this first foreach ( sv:hnd.mergemonstersv ) { if ( !sv ) continue; String res = sv.GetString("MergeMonster",stringArg:a.GetClassName()); if ( res == "" ) continue; Class rescls = res; return rescls; } // stealth monsters, the worst thing ever invented if ( a == 'StealthArachnotron' ) return 'Arachnotron'; if ( a == 'StealthArchvile' ) return 'Archvile'; if ( a == 'StealthBaron' ) return 'BaronOfHell'; if ( a == 'StealthCacodemon' ) return 'Cacodemon'; if ( a == 'StealthChaingunGuy' ) return 'ChaingunGuy'; if ( a == 'StealthDemon' ) return 'Demon'; if ( a == 'StealthHellKnight' ) return 'HellKnight'; if ( a == 'StealthDoomImp' ) return 'DoomImp'; if ( a == 'StealthFatso' ) return 'Fatso'; if ( a == 'StealthRevenant' ) return 'Revenant'; if ( a == 'StealthShotgunGuy' ) return 'ShotgunGuy'; if ( a == 'StealthZombieMan' ) return 'ZombieMan'; // eviternity 2 hackery if ( a.GetClassName() == 'LostSoulEvit2' ) return 'LostSoul'; if ( a.GetClassName() == 'LostSoulCount' ) return 'LostSoul'; if ( a.GetClassName() == 'CyberdemonEvit2' ) return 'Cyberdemon'; if ( a.GetClassName() == 'CyberdemonMAP24' ) return 'Cyberdemon'; // merge all boss phases into one entry if ( a.GetClassName() == 'The_Origin_Phase_2' ) return 'The_Origin_Phase_1'; if ( a.GetClassName() == 'The_Origin_Phase_3' ) return 'The_Origin_Phase_1'; if ( a.GetClassName() == 'The_Absolute_Origin_Phase_1' ) return 'The_Origin_Phase_1'; if ( a.GetClassName() == 'The_Absolute_Origin_Phase_2' ) return 'The_Origin_Phase_1'; if ( a.GetClassName() == 'The_Absolute_Origin_Phase_2' ) return 'The_Origin_Phase_1'; // heretic monsters if ( a == 'Sorcerer2' ) return 'Sorcerer1'; if ( a == 'HereticImpLeader' ) return 'HereticImp'; if ( a == 'KnightGhost' ) return 'Knight'; if ( a == 'MummyGhost' ) return 'Mummy'; if ( a == 'MummyLeaderGhost' ) return 'MummyLeader'; // hexen monsters if ( a == 'CentaurMash' ) return 'Centaur'; if ( a == 'Demon1Mash' ) return 'Demon1'; if ( a == 'Demon2' ) return 'Demon1'; if ( a == 'Demon2Mash' ) return 'Demon1'; if ( a == 'EttinMash' ) return 'Ettin'; if ( a == 'SerpentLeader' ) return 'Serpent'; if ( a == 'WraithBuried' ) return 'Wraith'; return a; } // because gendered languages static bool SellFemaleItem( Inventory i, String loc = "SWWM_SELLEXTRA_FEM" ) { // no gendered string alt if ( StringTable.Localize("$"..loc) == loc ) return false; if ( i is 'DeepImpact' ) return true; if ( i is 'ExplodiumGun' ) return true; if ( i is 'Wallbuster' ) return true; if ( i is 'HeavyMahSheenGun' ) return true; if ( i is 'Quadravol' ) return true; if ( i is 'Sparkster' ) return true; if ( i is 'CandyGun' ) return true; //if ( i is 'RayKhom' ) return true; //if ( i is 'RafanKos' ) return true; if ( i is 'HealthNuggetItem' ) return true; if ( i is 'ArmorNuggetItem' ) return true; if ( i is 'WarArmor' ) return true; if ( i is 'FuckingInvinciball' ) return true; if ( i is 'SWWMLamp' ) return true; if ( i is 'AngerySigil' ) return true; return false; } // returns the plural tag (if available) static string GetAmmoTag( Inventory i ) { if ( i is 'MagAmmo' ) return StringTable.Localize("$T_"..MagAmmo(i).PickupTag.."S"); if ( i is 'SWWMAmmo' ) return StringTable.Localize("$T_"..SWWMAmmo(i).PickupTag.."S"); return i.GetTag(); } // because of zscript weirdness with GetDefaultByType static string GetAmmoTagClass( Class i ) { if ( i is 'MagAmmo' ) return StringTable.Localize("$T_"..GetDefaultByType((Class)(i)).PickupTag.."S"); if ( i is 'SWWMAmmo' ) return StringTable.Localize("$T_"..GetDefaultByType((Class)(i)).PickupTag.."S"); return GetDefaultByType(i).GetTag(); } // IsZeroDamage() can lead to some false negatives, we have to account for that static play bool ValidProjectile( Actor a ) { if ( !a.bMISSILE ) return false; if ( a is 'AirBullet' ) return true; if ( a is 'ExplodiumMagProj' ) return true; if ( a is 'TheBall' ) return true; if ( a is 'EvisceratorChunk' ) return true; if ( a is 'EvisceratorProj' ) return true; if ( a is 'HellblazerMissile' ) return true; if ( a is 'QuadProj' ) return true; if ( a is 'BigBiospark' ) return true; if ( a is 'BiosparkBall' ) return true; if ( a is 'BiosparkCore' ) return true; if ( a is 'CandyGunProj' ) return true; if ( a is 'CandyMagProj' ) return true; if ( a is 'MisterGrenade' ) return true; if ( a is 'LoveHeart' ) return true; if ( !a.IsZeroDamage() ) return true; return false; } // Is this a beam projectile? (speed == length) static bool IsBeamProj( Actor a ) { if ( a is 'SaltBeam' ) return true; if ( a is 'BiosparkBeam' ) return true; if ( a is 'BiosparkArc' ) return true; if ( a is 'CandyBeam' ) return true; if ( a is 'YnykronBeam' ) return true; if ( a is 'YnykronLightningArc' ) return true; if ( a is 'YnykronAltBeam' ) return true; if ( a is 'MykradvoTendril' ) return true; if ( a is 'MisterRailBeam' ) return true; return false; } // is this a YBeam type? (real pitch is pitch-90) static bool IsYBeam( Actor a ) { if ( a is 'MisterRailBeam' ) return true; return false; } static bool IdentifyingDog( Actor a ) { if ( a is 'MBFHelperDog' ) return true; if ( a is 'SWWMDog' ) return true; if ( a.GetClassName() == 'GermanDog' ) return true; // brote dote if ( a.GetClassName() == '64HellHound' ) return true; // brote dote 64 if ( a.GetClassName() == 'AbyssDemon2' ) return true; // CH if ( a.GetClassName() == 'WHOLETTHEDOGSOUT' ) return true; // CH // more dogs will be added as found // because all dogs must be pet return false; } static bool IdentifyingCaco( Actor a ) { if ( a is 'DeadCacodemon' ) return false; if ( a is 'Cacodemon' ) return true; if ( a.Species == 'RLCacodemon' ) return true; // DRLA if ( a.Species == 'Caco' ) return true; // CH and others if ( a.Species == 'Cacodemon' ) return true; // Beautiful Doom if ( a.GetClassName() == 'AstralCaco' ) return true; // Eviternity if ( a.GetParentClass().GetClassName() == 'LEG_BaseCaco' ) return true; // LEGION return false; } // Друг static bool IdentifyingDrug( Actor a ) { if ( a is 'Beast' ) return true; return false; } static bool IdentifyingDoubleBoi( Actor a ) { if ( a is 'Ettin' ) return true; return false; } static bool IsVipItem( Actor target ) { if ( (target is 'Chancebox') && (target.CurState==target.SpawnState) ) return true; if ( target is 'SWWMCollectible' ) return true; if ( (target is 'Ynykron')/* || (target is 'RafanKos')*/ ) return true; if ( (target is 'GoldShell') || (target is 'YnykronAmmo')/* || (target is 'UltimatePod') || (target is 'UltimateAmmo')*/ ) return true; if ( (target is 'Mykradvo') || (target is 'AngerySigil') || (target is 'DivineSprite') ) return true; if ( target is 'PuzzleItem' ) return true; return false; } // used by the store static bool IsVipItemClass( Class target ) { if ( (target is 'Ynykron')/* || (target is 'RafanKos')*/ ) return true; if ( (target is 'GoldShell') || (target is 'YnykronAmmo')/* || (target is 'UltimatePod') || (target is 'UltimateAmmo')*/ ) return true; if ( (target is 'Mykradvo') || (target is 'AngerySigil') || (target is 'DivineSprite') ) return true; return false; } static bool IsScoreItem( Actor target ) { if ( target is 'Key' ) return true; if ( target is 'HammerspaceEmbiggener' ) return true; return target.bCOUNTITEM; } }