291 lines
9 KiB
Text
291 lines
9 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<Class<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++ )
|
|
{
|
|
for ( int j=0; j<MAXPLAYERS; j++ )
|
|
{
|
|
if ( !playeringame[j] || !players[j].mo ) continue;
|
|
if ( !players[j].mo.FindInventory(mapkeys[i]) ) continue;
|
|
collected = true;
|
|
break;
|
|
}
|
|
if ( collected ) 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]);
|
|
// one standing?
|
|
if ( (level.total_monsters-level.killed_monsters) == 1 )
|
|
SWWMUtility.MarkAchievement('swwm_achievement_onestanding',players[consoleplayer]);
|
|
// nice?
|
|
if ( players[consoleplayer].Health == 69 )
|
|
SWWMUtility.MarkAchievement('swwm_achievement_nice',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
|
|
if ( !deathmatch ) Chancebox.SpawnChanceboxes();
|
|
// list map keys
|
|
let ti = ThinkerIterator.Create("Key");
|
|
Key k;
|
|
while ( k = Key(ti.Next()) )
|
|
{
|
|
if ( k.Owner ) continue;
|
|
if ( mapkeys.Find(k.GetClass()) < mapkeys.Size() )
|
|
continue;
|
|
mapkeys.Push(k.GetClass());
|
|
}
|
|
}
|
|
}
|