swwmgz_m/zscript/handler/swwm_handler_worldload.zsc

489 lines
16 KiB
Text

// 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;
}
}
extend Class SWWMHandler
{
bool maphaskeys;
// 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.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);
}
// reset score on dead players (death exit™)
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || (players[i].playerstate != PST_DEAD) ) continue;
let c = SWWMCredits.Find(players[i]);
if ( c ) c.credits = 0;
}
// end of episode resets and enforced pistol starts
LevelInfo nextlv = LevelInfo.FindLevelInfo(e.NextMap);
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || !players[i].mo ) continue;
let demo = Demolitionist(players[i].mo);
if ( !demo ) continue;
if ( level.nextsecretmap.Left(6) == "enDSeQ" ) demo.invwipe |= Demolitionist.WIPE_EPISODE;
if ( nextlv && (level.cluster!=nextlv.cluster) ) demo.invwipe |= (Demolitionist.WIPE_CLUSTER|Demolitionist.WIPE_MAP);
if ( !(level.clusterflags&LevelLocals.CLUSTER_HUB) ) demo.invwipe |= Demolitionist.WIPE_MAP;
// the playerpawn will know what to do with this in its PreTravelled()
}
// did we complete this map without collecting any of its keys? (doesn't work for hubs)
if ( maphaskeys && !(level.clusterflags&LevelLocals.CLUSTER_HUB) )
{
bool collected = false;
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || !players[i].mo ) continue;
for ( Inventory inv=players[i].mo.inv; inv; inv=inv.inv )
{
if ( !(inv is 'Key') ) continue;
collected = true;
break;
}
}
if ( !collected ) SWWMUtility.MarkAchievement("cliffyb",players[consoleplayer]);
}
// these can't be done on hexen
if ( gameinfo.GameType&GAME_Hexen ) return;
// beat the par time?
if ( level.partime && (Thinker.Tics2Seconds(level.maptime) <= level.partime) )
SWWMUtility.AchievementProgressInc("par",1,players[consoleplayer]);
// blaze it?
if ( Thinker.Tics2Seconds(level.maptime) == 260 )
SWWMUtility.MarkAchievement("blaze",players[consoleplayer]);
// one standing?
if ( (level.total_monsters-level.killed_monsters) == 1 )
SWWMUtility.MarkAchievement("onestanding",players[consoleplayer]);
// nice?
if ( players[consoleplayer].Health == 69 )
SWWMUtility.MarkAchievement("nice",players[consoleplayer]);
// peaceful/untouchable?
if ( !dealtdamage[consoleplayer] )
SWWMUtility.MarkAchievement("peace",players[consoleplayer]);
if ( !reallytookdamage[consoleplayer] )
SWWMUtility.MarkAchievement("untouchable",players[consoleplayer]);
// in a hurry?
if ( ((level.total_monsters > 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]);
}
private void SetupLockdefsCache( SWWMCachedLockInfo cli )
{
for ( int i=0; i<Wads.GetNumLumps(); i++ )
{
String lname = Wads.GetLumpName(i);
if ( !(lname ~== "LOCKDEFS") ) continue;
String data = Wads.ReadLump(i);
Array<String> lines;
lines.Clear();
data.Split(lines,"\n");
bool valid = false;
for ( int j=0; j<lines.Size(); j++ )
{
// strip leading whitespace
while ( (lines[j].Left(1) == " ") || (lines[j].Left(1) == "\t") )
lines[j] = lines[j].Mid(1);
if ( lines[j].Left(10) ~== "CLEARLOCKS" )
{
for ( int k=0; k<cli.ent.Size(); k++ )
cli.ent[k].Destroy();
cli.ent.Clear();
}
else if ( Lines[j].Left(5) ~== "LOCK " )
{
Array<String> spl;
spl.Clear();
lines[j].Split(spl," ",TOK_SKIPEMPTY);
// check game string (if any)
if ( spl.Size() > 2 )
{
if ( (spl[2] ~== "DOOM") && !(gameinfo.gametype&GAME_Doom) ) continue;
else if ( (spl[2] ~== "HERETIC") && !(gameinfo.gametype&GAME_Heretic) ) continue;
else if ( (spl[2] ~== "HEXEN") && !(gameinfo.gametype&GAME_Hexen) ) continue;
else if ( (spl[2] ~== "STRIFE") && !(gameinfo.gametype&GAME_Strife) ) continue;
else if ( (spl[2] ~== "CHEX") && !(gameinfo.gametype&GAME_Chex) ) continue;
}
// valid lock, prepare it
let li = new("LIEntry");
li.locknumber = spl[1].ToInt();
li.hascolor = false;
// see if there's a Mapcolor defined
int k = j+1;
for ( int k=j+2; k<lines.Size(); k++ )
{
// strip leading whitespace
while ( (lines[k].Left(1) == " ") || (lines[k].Left(1) == "\t") )
lines[k] = lines[k].Mid(1);
if ( lines[k].Left(5) ~== "LOCK " )
break; // we reached the next lock
if ( !(lines[k].Left(9) ~== "MAPCOLOR ") )
continue;
// here it is
spl.Clear();
lines[k].Split(spl," ",TOK_SKIPEMPTY);
if ( spl.Size() < 4 ) break;
li.hascolor = true;
li.mapcolor = Color(spl[1].ToInt(),spl[2].ToInt(),spl[3].ToInt());
}
cli.ent.Push(li);
}
}
}
}
private void MapStartDialogues()
{
int whichboss = WhichVanillaBossMap();
switch ( whichboss )
{
case MAP_DE1M8:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_PHOBOS);
break;
case MAP_DE2M8:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_DEIMOS);
break;
case MAP_DE3M8:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_DIS);
break;
case MAP_DE4M8:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_THY);
break;
case MAP_DMAP07:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_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",SWWMDLG_RAMPANCY);
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_IOS);
break;
case MAP_DLVL08:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_NERVE);
break;
case MAP_EVMAP30:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_EVIA);
break;
case MAP_HE1M8_HE4M8:
if ( level.mapname ~== "E1M8" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_MAW);
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_HEADS);
break;
case MAP_HE2M8_HE5M8:
if ( level.mapname ~== "E2M8" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_PORTALS);
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_BULLS);
break;
case MAP_HE3M8:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_DSPARIL);
break;
case MAP_HMAP38:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CLERIC);
break;
case MAP_HMAP36:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_FIGHTER);
break;
case MAP_HMAP37:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_MAGE);
break;
case MAP_HMAP12:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_HYPO);
break;
case MAP_HMAP40:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_KORAX);
break;
case MAP_HMAP23_HMAP27_HMAP48_HMAP55:
if ( level.mapname ~== "MAP48" ) SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CONSTABLE);
break;
case MAP_HMAP60:
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_DEATHKINGS);
break;
case MAP_NONE:
String csum = level.GetChecksum();
// SIGIL E5M8
if ( (csum ~== "3D72FD17F36D2D43FD9A21E6E57EE357")
|| (csum ~== "09B30C9DA9D73D3D5A709502FBB947AA")
|| (csum ~== "6EAD80DA1F30B4B3546FA294EEF9F87C") )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_SIGIL);
// Doom 2 MAP11
else if ( (csum ~== "73D9E03CEE7BF1A97EFD2EAD86688EF8")
|| (csum ~== "F4F2A769609988837458772AAE99008C")
|| (csum ~== "DF6A001A6C42DB5CCA599EE5883B294A") )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CIRCLE);
// Doom 2 MAP20
else if ( (csum ~== "8898F5EC9CBDCD98019A1BC1BF892A8A")
|| (csum ~== "CC53CFFCB30E873669AA2F09DA0D3566") )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_GOTCHA);
// Eviternity
// MAP05
else if ( csum ~== "33B8501B10CE5E2555C03725F765A914" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_DMN);
// MAP10
else if ( csum ~== "9E83602D325677B8D7C3BC44BEF9B03F" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CRE);
// MAP15
else if ( csum ~== "CA40E6DDAB6B5C924CDC36B1F851421E" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CRY);
// MAP20
else if ( csum ~== "F34B3FD4D13AC763469A8E0D7379B9D0" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_CON);
// MAP25
else if ( csum ~== "196BC735473C593F924A59B238574C35" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_SLA);
// Deathkings
// Blight
else if ( csum ~== "E3EFB0156A20ADF2DF00915A0EA85DF5" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_BLIGHT);
// Nave
else if ( csum ~== "E2B5D1400279335811C1C1C0B437D9C8" )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue",SWWMDLG_NAVE);
break;
}
}
override void WorldLoaded( WorldEvent e )
{
if ( e.IsReopen ) return;
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;
}
// setup cached lockdefs data
let cli = SWWMCachedLockInfo.GetInstance();
if ( cli.ent.Size() == 0 ) SetupLockdefsCache(cli);
// for skipping over merged exit lines (sharing vertices)
Array<Line> skipme;
skipme.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;
}
bool isexit;
int exittype;
[isexit, exittype] = SWWMUtility.IsExitLine(l);
if ( !isexit ) continue;
if ( skipme.Find(l) < skipme.Size() ) continue;
skipme.Push(l);
// look for connected lines
Array<Line> con;
con.Clear();
con.Push(l);
int found;
if ( l.frontsector )
{
do
{
found = 0;
foreach ( l2:l.frontsector.Lines )
{
if ( (l2.special != l.special) || (con.Find(l2) < con.Size()) ) continue;
// needs to have a point in common with this one or any of the added lines
bool nomatches = true;
foreach ( c:con )
{
if ( (l2.v1 != c.v1) && (l2.v2 != c.v2) && (l2.v1 != c.v2) && (l2.v2 != c.v1) )
continue;
nomatches = false;
break;
}
if ( nomatches ) continue;
skipme.Push(l2);
con.Push(l2);
found++;
}
}
while ( found > 0 );
}
if ( l.backsector )
{
do
{
found = 0;
foreach ( l2:l.backsector.Lines )
{
if ( (l2.special != l.special) || (con.Find(l2) < con.Size()) ) continue;
// needs to have a point in common with this one or any of the added lines
bool nomatches = true;
foreach ( s:skipme )
{
if ( (l2.v1 != s.v1) && (l2.v2 != s.v2) && (l2.v1 != s.v2) && (l2.v2 != s.v1) )
continue;
nomatches = false;
break;
}
if ( nomatches ) continue;
skipme.Push(l2);
con.Push(l2);
found++;
}
}
while ( found > 0 );
}
Vector3 lpos = (0,0,0);
foreach ( c:con )
lpos += SWWMUtility.UseLinePos(c);
lpos /= con.Size();
SWWMInterest.Spawn(self,lpos,theline:l,theexit:exittype);
}
// 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;
}
}
}