// WorldLoaded/WorldUnloaded events Class RampancyLogonDummy : Actor { States { Spawn: TNT1 A 7; TNT1 AAAAAAAAAAAAAAAA 1 { for ( int i=0; i<16; i++ ) A_Log("Remote login failed."); } TNT1 A 7; TNT1 A 1 A_Log("\cgWARNING:\cj 256 failed remote login attempts have been reported in the last second.\c-"); Stop; } } // this is used to speed up iteration through sector thinglists within a specific area Class SectorBounds { Vector4 bounds; int portalgroup; clearscope bool PointInSectorBounds( Vector2 p, int pg = -1 ) const { if ( (pg >= 0) && (level.GetPortalGroupCount() > 0) && (pg != portalgroup) ) p += level.GetDisplacement(pg,portalgroup); if ( p.x < bounds.x ) return false; if ( p.y < bounds.y ) return false; if ( p.x > bounds.z ) return false; if ( p.y > bounds.w ) return false; return true; } clearscope bool BoxInSectorBounds( Vector2 p, double r, int pg = -1 ) const { if ( (pg >= 0) && (level.GetPortalGroupCount() > 0) && (pg != portalgroup) ) p += level.GetDisplacement(pg,portalgroup); if ( p.x+r < bounds.x ) return false; if ( p.y+r < bounds.y ) return false; if ( p.x-r > bounds.z ) return false; if ( p.y-r > bounds.w ) return false; return true; } } extend Class SWWMHandler { bool maphaskeys; bool nogroundanchor; int allclearsector; // weird optimization Array sbounds; // level end stats override void WorldUnloaded( WorldEvent e ) { let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC); SWWMStats s; while ( s = SWWMStats(ti.Next()) ) { int clust = 0; bool secret = false; if ( SWWMUtility.IsEviternityTwo() ) { // clusters have to be remapped here let clus = level.cluster; if ( clus == 5 ) clust = 1; else if ( (clus == 6) || (clus == 13) ) clust = 2; else if ( (clus == 7) || (clus == 14) ) clust = 3; else if ( (clus == 8) || (clus == 15) ) clust = 4; else if ( (clus == 9) || (clus == 16) ) clust = 5; else if ( (clus == 10) || (clus == 17) ) clust = 6; else if ( (clus == 11) || (clus == 12) || (clus == 18) || (clus == 19) ) clust = 7; } else if ( SWWMUtility.IsEviternity() ) { // we have to do some heavy lifting here because episodes don't match clusters if ( level.levelnum <= 5 ) clust = 1; else if ( level.levelnum <= 10 ) clust = 2; else if ( level.levelnum <= 15 ) clust = 3; else if ( level.levelnum <= 20 ) clust = 4; else if ( level.levelnum <= 25 ) clust = 5; else if ( level.levelnum <= 30 ) clust = 6; else if ( level.levelnum <= 32 ) { secret = true; if ( level.levelnum <= 31 ) clust = 7; else clust = 8; } } else { if ( (gameinfo.gametype&GAME_DOOM) && ((level.cluster == 9) || (level.cluster == 10)) ) secret = true; clust = level.cluster; } int csiz = s.clustervisit.Size(); if ( csiz == 0 ) { s.clustervisit.Push(clust); s.secretdone.Push(secret); } else if ( s.clustervisit[csiz-1] != clust ) { s.clustervisit.Push(clust); s.secretdone.Push(secret|s.secretdone[csiz-1]); } s.AddLevelStats(); s.lastcluster = level.cluster; // nazi cleanup let ti = ThinkerIterator.Create("Actor"); Actor a; bool hasnazis = false; bool livenazis = false; while ( a = Actor(ti.Next()) ) { // yes, the dogs don't count (they're just dogs) if ( !(a is 'SWWMGuard') && !(a is 'SWWMSS') && !(a is 'SWWMHans') ) continue; hasnazis = true; if ( a.Health > 0 ) livenazis = true; } if ( hasnazis && !livenazis ) { if ( level.levelnum == 31 ) s.nazicleanup |= 1; else if ( level.levelnum == 32 ) s.nazicleanup |= 2; } if ( s.nazicleanup == 3 ) SWWMUtility.MarkAchievement("trash",s.myplayer); } // re-enable retries after Eviternity 2 MAP33 if ( level.GetChecksum() ~== "043FE06534270E95882CA128AF7B0402" ) gdat.disablerevive = false; // reset score on dead players (death exitâ„¢) for ( int i=0; i 0) || (level.total_items > 0) || (level.total_secrets > 0)) && (level.killed_monsters == 0) && (level.found_items == 0) && (level.found_secrets == 0) ) SWWMUtility.MarkAchievement("hurry",players[consoleplayer]); } clearscope bool PointInSectorBounds( Sector s, Vector2 p, int pg = -1 ) const { if ( sbounds.Size() <= 0 ) return false; int i = s.Index(); return sbounds[i].PointInSectorBounds(p,pg); } clearscope bool BoxInSectorBounds( Sector s, Vector2 p, double r, int pg = -1 ) const { if ( sbounds.Size() <= 0 ) return false; int i = s.Index(); return sbounds[i].BoxInSectorBounds(p,r,pg); } void PrecalculateSectorBounds() { sbounds.Resize(level.Sectors.Size()); foreach ( s:level.Sectors ) { let sb = new("SectorBounds"); sb.portalgroup = s.portalgroup; sb.bounds = ( 32767, 32767, -32768, -32768 ); foreach ( l:s.Lines ) { if ( l.v1.p.x < sb.bounds.x ) sb.bounds.x = l.v1.p.x; if ( l.v2.p.x < sb.bounds.x ) sb.bounds.x = l.v2.p.x; if ( l.v1.p.y < sb.bounds.y ) sb.bounds.y = l.v1.p.y; if ( l.v2.p.y < sb.bounds.y ) sb.bounds.y = l.v2.p.y; if ( l.v1.p.x > sb.bounds.z ) sb.bounds.z = l.v1.p.x; if ( l.v2.p.x > sb.bounds.z ) sb.bounds.z = l.v2.p.x; if ( l.v1.p.y > sb.bounds.w ) sb.bounds.w = l.v1.p.y; if ( l.v2.p.y > sb.bounds.w ) sb.bounds.w = l.v2.p.y; } sbounds[s.Index()] = sb; } } private void MapStartDialogues() { int whichboss = WhichVanillaBossMap(); switch ( whichboss ) { case MAP_DE1M8: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.PHOBOS"); break; case MAP_DE2M8: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DEIMOS"); break; case MAP_DE3M8: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DIS"); break; case MAP_DE4M8: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.THY"); break; case MAP_DMAP07: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DIMPLE"); break; case MAP_DMAP30: bool rampancy = false; foreach ( cls:AllActorClasses ) { if ( cls.GetClassName() != "Robot_BossBrain" ) continue; rampancy = true; break; } if ( rampancy ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.RAMPANCY"); else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.IOS"); break; case MAP_DLVL08: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.NERVE"); break; case MAP_EVMAP30: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EVIA"); break; case MAP_EVIIMAP30: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2K"); break; case MAP_HE1M8_HE4M8: if ( level.mapname ~== "E1M8" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.MAW"); else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.HEADS"); break; case MAP_HE2M8_HE5M8: if ( level.mapname ~== "E2M8" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.PORTALS"); else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.BULLS"); break; case MAP_HE3M8: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DSPARIL"); break; case MAP_HMAP38: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CLERIC"); break; case MAP_HMAP36: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.FIGHTER"); break; case MAP_HMAP37: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.MAGE"); break; case MAP_HMAP12: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.HYPO"); break; case MAP_HMAP40: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.KORAX"); break; case MAP_HMAP23_HMAP27_HMAP48_HMAP55: if ( level.mapname ~== "MAP48" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CONSTABLE"); break; case MAP_HMAP60: SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DEATHKINGS"); break; case MAP_NONE: String csum = level.GetChecksum(); // SIGIL E5M8 if ( (csum ~== "3D72FD17F36D2D43FD9A21E6E57EE357") || (csum ~== "09B30C9DA9D73D3D5A709502FBB947AA") || (csum ~== "6EAD80DA1F30B4B3546FA294EEF9F87C") ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.SIGIL"); // SIGIL 2 E6M8 if ( csum ~== "5BA3D00F6B64F6268E11C6851D47ECBF" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.SIGIL2"); // Doom 2 MAP11 else if ( (csum ~== "73D9E03CEE7BF1A97EFD2EAD86688EF8") || (csum ~== "F4F2A769609988837458772AAE99008C") || (csum ~== "DF6A001A6C42DB5CCA599EE5883B294A") ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CIRCLE"); // Doom 2 MAP20 else if ( (csum ~== "8898F5EC9CBDCD98019A1BC1BF892A8A") || (csum ~== "CC53CFFCB30E873669AA2F09DA0D3566") ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.GOTCHA"); // Eviternity // MAP05 else if ( csum ~== "33B8501B10CE5E2555C03725F765A914" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.DMN"); // MAP10 else if ( csum ~== "9E83602D325677B8D7C3BC44BEF9B03F" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CRE"); // MAP15 else if ( csum ~== "CA40E6DDAB6B5C924CDC36B1F851421E" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CRY"); // MAP20 else if ( csum ~== "F34B3FD4D13AC763469A8E0D7379B9D0" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.CON"); // MAP25 else if ( csum ~== "196BC735473C593F924A59B238574C35" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.SLA"); // Eviternity 2 (RC5) // MAP01 else if ( csum ~== "3907915FEC75DEE3A53374D90C4F4B65" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2A"); // MAP05 else if ( csum ~== "58A6A5A8214B0C2C28C9DADC349F2853" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2E"); // MAP10 else if ( csum ~== "9525AF4F176085C925124CF118E91DF1" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2F"); // MAP15 else if ( csum ~== "24EFC6868344643D3D4C56BDF2D1E8C7" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2G"); // MAP20 else if ( csum ~== "81B7BDE4BD0E98A9B8741B0405FAB839" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2H"); // MAP25 else if ( csum ~== "56A3EB18F91B2AE42DCF327888AEAA0A" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2I"); // MAP33 else if ( csum ~== "043FE06534270E95882CA128AF7B0402" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2P"); // Deathkings // Blight else if ( csum ~== "E3EFB0156A20ADF2DF00915A0EA85DF5" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.BLIGHT"); // Nave else if ( csum ~== "E2B5D1400279335811C1C1C0B437D9C8" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue.NAVE"); break; } } override void WorldLoaded( WorldEvent e ) { // session globals must be loaded here // (if we do it in OnRegister the existing thinker might not have been deserialized yet) gdat = SWWMGlobals.Get(); if ( e.IsReopen ) return; PrecalculateSectorBounds(); MapStartDialogues(); if ( gamestate != GS_TITLELEVEL ) { if ( (level.GetChecksum() ~== "D0E5ECD94BD38DF33F25515C00148693") || (level.GetChecksum() ~== "D20297AE8447232F6DBE4851E3104668") || (level.GetChecksum() ~== "EBBB8663AD4AB22294A8A1D211A026CD") ) { if ( !AddOneliner("nutstart",3) ) AddOneliner("mapstart",3); } else AddOneliner("mapstart",3); } if ( level.levelname ~== "Modder Test Map" ) { level.ReplaceTextures("-noflat-","kinstile",0); S_ChangeMusic("music/CARDISH1.XM"); AddBoss(6666,"$BT_DOOMTEST"); // for testing boss healthbars } // doom vacation map01 hackaround for OPEN script not letting us // change certain line specials in levelpostprocessor because // ACS is just mindbogglingly weird like that, seriously if ( (level.GetChecksum() ~== "F286BABF0D152259CD6B996E8920CA70") || (level.GetChecksum() ~== "A52BD2038CF814101AAB7D9C78F9ACE2") ) level.ExecuteSpecial(ACS_Execute,null,null,false,-Int('DVACATION_UNSCREW')); // rampancy boss brain fix (repeatedly triggering "map clear") let ti = ThinkerIterator.Create("Actor"); Actor a, brain; bool haseye = false; while ( a = Actor(ti.Next()) ) { if ( a.GetClassName() == "Robot_BossEye" ) haseye = true; if ( a.GetClassName() == "Robot_BossBrain" ) brain = a; } if ( haseye && brain ) { brain.bCOUNTKILL = true; level.total_monsters++; // while we're at it Actor.Spawn("RampancyLogonDummy"); } // KDiKDiZD abort fix due to voodoo doll post-spawn replacement // (we have our own mikoportal compatibility, anyway) // // note that the mods are mutually incompatible nonetheless // since KDiKDiZD requires software rendering, while this is a // hardware-only mod... but hey, they can sort-of-work together // (with broken visual effects, but still... somewhat working) foreach ( cls:AllClasses ) { if ( cls.GetClassName() != 'KdikdizdCompatEventHandler' ) continue; ti = ThinkerIterator.Create("Thinker"); Thinker t; while ( t = ti.Next() ) { if ( t.GetClassName() != 'VoodooPusher' ) continue; t.Destroy(); } break; } // Eviternity II MAP33 fix. Player movement physics need to // have ground anchoring disabled, as it will make some // segments impossible due to the player's feet immediately // touching the instant-kill lava if ( level.GetChecksum() ~== "043FE06534270E95882CA128AF7B0402" ) { nogroundanchor = true; allclearsector = 18414; // only check all-clear if the player is standing in this sector gdat.disablerevive = true; // ONE TRY } Array exits; Array exittypes; exits.Clear(); exittypes.Clear(); // find exit lines, and use lines that aren't exits foreach ( l:level.Lines ) { // all lines are immediately visible in DM if ( deathmatch && !(l.flags&Line.ML_DONTDRAW) ) l.flags |= Line.ML_MAPPED; // while we're at it, add teleporter sparks if ( SWWMUtility.IsTeleportLine(l) ) { let a = SWWMTeleportLine(Actor.Spawn("SWWMTeleportLine")); a.tline = l; } let [isexit, exittype] = SWWMUtility.IsExitLine(l); if ( !isexit ) continue; exits.Push(l); exittypes.Push(exittype); } // for skipping over merged exit lines (sharing vertices) Array skipme; skipme.Clear(); for ( int i=0; i con; con.Clear(); con.Push(l); int found; do { found = 0; for ( int j=0; j 0 ); Vector3 lpos = (0,0,0); foreach ( c:con ) lpos += SWWMUtility.UseLinePos(c); lpos /= con.Size(); SWWMInterest.Spawn(self,lpos,theline:l,theexit:exittypes[i]); } // spawn loot if ( !deathmatch ) Chancebox.SpawnChanceboxes(); // list map keys maphaskeys = false; ti = ThinkerIterator.Create("Key"); Key k; while ( k = Key(ti.Next()) ) { if ( k.Owner ) continue; maphaskeys = true; break; } } }