382 lines
12 KiB
Text
382 lines
12 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
|
|
{
|
|
// 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;
|
|
}
|
|
// avoid cluster zero (ignores test maps and such)
|
|
if ( clust != 0 )
|
|
{
|
|
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 ( (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("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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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'));
|
|
// 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");
|
|
}
|
|
// 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];
|
|
// 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;
|
|
for ( int j=0; j<l.frontsector.Lines.Size(); j++ )
|
|
{
|
|
let l2 = l.frontsector.Lines[j];
|
|
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;
|
|
for ( int k=0; k<con.Size(); k++ )
|
|
{
|
|
if ( (l2.v1 != con[k].v1) && (l2.v2 != con[k].v2) && (l2.v1 != con[k].v2) && (l2.v2 != con[k].v1) )
|
|
continue;
|
|
nomatches = false;
|
|
break;
|
|
}
|
|
if ( nomatches ) continue;
|
|
skipme.Push(l2);
|
|
con.Push(l2);
|
|
found++;
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
}
|
|
if ( l.backsector )
|
|
{
|
|
do
|
|
{
|
|
found = 0;
|
|
for ( int j=0; j<l.backsector.Lines.Size(); j++ )
|
|
{
|
|
let l2 = l.backsector.Lines[j];
|
|
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;
|
|
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);
|
|
con.Push(l2);
|
|
found++;
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
}
|
|
Vector3 lpos = (0,0,0);
|
|
for ( int i=0; i<con.Size(); i++ )
|
|
lpos += SWWMUtility.UseLinePos(con[i]);
|
|
lpos /= con.Size();
|
|
SWWMInterest.Spawn(self,lpos,theline:l,theexit:exittype);
|
|
}
|
|
// spawn loot
|
|
if ( !deathmatch ) Chancebox.SpawnChanceboxes();
|
|
// list map keys
|
|
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());
|
|
}
|
|
}
|
|
}
|