swwmgz_m/zscript/handler/swwm_handler_worldload.zsc

278 lines
8.5 KiB
Text

// WorldLoaded/WorldUnloaded events
extend Class SWWMHandler
{
// list contains a sector that belongs to each portal group
// used to ease some portal-aware functions
Array<int> psectors;
// for minimap
Array<int> ffsectors;
Array<Key> mapkeys;
// 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;
}
// reset score on dead players (death exit™)
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || (players[i].Health > 0) ) continue;
let c = SWWMCredits.Find(players[i]);
if ( c ) c.credits = c.hcredits = 0;
}
// end of episode resets
if ( level.nextsecretmap.Left(6) == "enDSeQ" )
{
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || !players[i].mo ) continue;
players[i].mo.GiveInventory("InventoryWipeToken",1);
}
}
// did we complete this map without collecting any of its keys? (doesn't work for hubs)
if ( (mapkeys.Size() > 0) && !(level.clusterflags&LevelLocals.CLUSTER_HUB) )
{
bool collected = false;
for ( int i=0; i<mapkeys.Size(); i++ )
{
if ( !mapkeys[i].Owner || !mapkeys[i].Owner.player ) continue;
collected = true;
break;
}
if ( !collected ) SWWMUtility.MarkAchievement('swwm_achievement_cliffyb',players[consoleplayer]);
}
// beat the par time?
if ( level.partime && (Thinker.Tics2Seconds(level.maptime) <= level.partime) )
SWWMUtility.AchievementProgressInc('swwm_progress_par',1,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);
}
}
}
}
override void WorldLoaded( WorldEvent e )
{
if ( e.IsReopen ) return;
if ( gamestate != GS_TITLELEVEL ) AddOneliner("mapstart",3);
if ( level.levelname ~== "Modder Test Map" )
{
level.ReplaceTextures("-noflat-","kinstile",0);
S_ChangeMusic("music/CARDISH1.XM");
}
// doom vacation map01 hackaround for OPEN script not letting us
// change certain line specials in levelpostprocessor because
// HOLY FUCK IS EVERYTHING SHIT SOMETIMES
if ( (level.GetChecksum() ~== "F286BABF0D152259CD6B996E8920CA70")
|| (level.GetChecksum() ~== "A52BD2038CF814101AAB7D9C78F9ACE2") )
level.ExecuteSpecial(ACS_Execute,null,null,false,-Int('DVACATION_UNFUCK'));
// setup cached lockdefs data
let cli = SWWMCachedLockInfo.GetInstance();
if ( cli.ent.Size() == 0 ) SetupLockdefsCache(cli);
// keep a list of sectors containing 3D floors, for use by the minimap
// also does the same for the portal group list
ffsectors.Clear();
psectors.Clear();
for ( int i=0; i<level.sectors.Size(); i++ )
{
Sector s = level.sectors[i];
if ( psectors.Size() <= s.portalgroup )
psectors.Resize(s.portalgroup+1);
psectors[s.portalgroup] = s.Index();
if ( !s.Get3DFloorCount() ) continue;
int realcount = 0;
for ( int j=0; j<s.Get3DFloorCount(); j++ )
{
F3DFloor rover = s.Get3DFloor(j);
if ( rover.flags&F3DFloor.FF_THISINSIDE ) continue;
if ( !(rover.flags&F3DFloor.FF_EXISTS) ) continue;
if ( rover.alpha == 0 ) continue;
realcount++;
}
if ( !realcount ) continue;
ffsectors.Push(s.Index());
}
// for skipping over merged exit lines (sharing vertices)
Array<Line> skipme;
skipme.Clear();
// find exit lines, and use lines that aren't exits
for ( int i=0; i<level.lines.Size(); i++ )
{
Line l = level.lines[i];
// while we're at it, add teleporter sparks
if ( SWWMUtility.IsTeleportLine(l) )
{
let a = SWWMTeleportLine(Actor.Spawn("SWWMTeleportLine"));
a.tline = l;
}
if ( !SWWMUtility.IsExitLine(l) )
continue;
if ( skipme.Find(l) < skipme.Size() ) continue;
Vector3 lpos = SWWMUtility.UseLinePos(l);
// look for connected lines
int xcnt = 1;
if ( l.frontsector )
{
for ( int j=0; j<l.frontsector.Lines.Size(); j++ )
{
let l2 = l.frontsector.Lines[j];
if ( (l2 == l) || (l2.special != l.special) ) continue;
// needs to have a point in common with this one or any of the added lines
if ( (l2.v1 != l.v1) && (l2.v2 != l.v2) && (l2.v1 != l.v2) && (l2.v2 != l.v1) )
{
bool nomatches = true;
for ( int k=0; k<skipme.Size(); k++ )
{
if ( (l2.v1 != skipme[k].v1) && (l2.v2 != skipme[k].v2) && (l2.v1 != skipme[k].v2) && (l2.v2 != skipme[k].v1) )
continue;
nomatches = false;
break;
}
if ( nomatches ) continue;
}
skipme.Push(l2);
xcnt++;
lpos += SWWMUtility.UseLinePos(l2);
}
}
if ( l.backsector )
{
for ( int j=0; j<l.backsector.Lines.Size(); j++ )
{
let l2 = l.backsector.Lines[j];
if ( (l2 == l) || (l2.special != l.special) ) continue;
// needs to have a point in common with this one or any of the added lines
if ( (l2.v1 != l.v1) && (l2.v2 != l.v2) && (l2.v1 != l.v2) && (l2.v2 != l.v1) )
{
bool nomatches = true;
for ( int k=0; k<skipme.Size(); k++ )
{
if ( (l2.v1 != skipme[k].v1) && (l2.v2 != skipme[k].v2) && (l2.v1 != skipme[k].v2) && (l2.v2 != skipme[k].v1) )
continue;
nomatches = false;
break;
}
if ( nomatches ) continue;
}
skipme.Push(l2);
xcnt++;
lpos += SWWMUtility.UseLinePos(l2);
}
}
lpos /= xcnt;
SWWMInterest.Spawn(lpos,theline:l);
}
// spawn loot
Chancebox.SpawnChanceboxes();
// list map keys
let ti = ThinkerIterator.Create("Key");
Key k;
while ( k = Key(ti.Next()) )
{
if ( k.Owner ) continue;
mapkeys.Push(k);
}
}
}