Sigil 2 (v1.0) and Eviternity 2 (RC5) support.

+ Invinciball activation now voiced by Demo (thanks, Vyolette).
+ Retooled exit line merging (should fix those pesky duplicate exit markers).

Note: Oneliners for the Eviternity 2 final boss are not voiced yet.
This commit is contained in:
Mari the Deer 2024-01-04 19:50:26 +01:00
commit cbb1b2a8cb
36 changed files with 1177 additions and 165 deletions

View file

@ -105,6 +105,12 @@ Class SWWMLevelCompatibility : LevelPostProcessor
break;
// SIGIL E5M8
case '6EAD80DA1F30B4B3546FA294EEF9F87C':
level.nextsecretmap = level.nextmap; // so the handler can detect this
if ( LevelInfo.MapExists("E6M1") ) level.nextmap = "E6M1";
else if ( LevelInfo.MapExists("MAP01") ) level.nextmap = "MAP01";
break;
// SIGIL II E6M8
case '5BA3D00F6B64F6268E11C6851D47ECBF':
level.nextsecretmap = level.nextmap; // so the handler can detect this
if ( LevelInfo.MapExists("MAP01") ) level.nextmap = "MAP01";
break;
@ -152,6 +158,7 @@ Class SWWMLevelCompatibility : LevelPostProcessor
break;
// Ultimate Doom 2 MAP20 (dv3.1)
case '96C5914A9B4A2383DE6BBE363940DF2F':
{
// add a "sector enter" action for reaching the exit room
// and make it trigger a dialogue
uint nt = AddThing(9998,(-9360,12768,12));
@ -162,6 +169,7 @@ Class SWWMLevelCompatibility : LevelPostProcessor
nt = AddThing(4206930,(0,0,0));
SetThingID(nt,tiddy);
break;
}
// EQUINOX: various boss brain setups that could be cheesed with the Ynykron or silver bullet
// Equinox MAP04
case 'E66BCCFAD7AC40EFB21E2A19131E1522':
@ -484,6 +492,26 @@ Class SWWMLevelCompatibility : LevelPostProcessor
for ( int i=0; i<13; i++ )
AddThing(4206900+i,(1472+64*i,640,0),0,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE);
break;
// Eviternity 2 MAP01 (RC5)
case '3907915FEC75DEE3A53374D90C4F4B65':
// special trigger for a bunch of dialogues
AddThing(4206931,(0,0,0));
break;
// Eviternity 2 MAP26 (RC5)
case '16D93AEE8243E17D8F241CE49FD5D7B6':
{
// add a "sector actor hits floor" action for going down into the hole™
// and make it trigger a dialogue
uint nt = AddThing(9999,(-576,1344,-352));
SetThingFlags(nt,MODES_ALL|MTF_STANDSTILL); // trigger once
SetThingSpecial(nt,Thing_Activate);
int tiddy = level.FindUniqueTid(9999);
SetThingArgument(nt,0,tiddy);
nt = AddThing(4206932,(0,0,0));
SetThingID(nt,tiddy);
break;
}
break;
// Eviternity 2 MAP33 (RC5)
case '043FE06534270E95882CA128AF7B0402':
// add autosave triggers to a couple sections

View file

@ -185,7 +185,18 @@ Class SWWMHandler : EventHandler
if ( !SWWMUtility.IsKnownMap() ) break;
if ( s.myplayer != players[consoleplayer] ) continue;
int clust = level.cluster;
if ( SWWMUtility.IsEviternity() )
if ( SWWMUtility.IsEviternityTwo() )
{
// clusters have to be remapped here
if ( clust == 5 ) clust = 1;
else if ( (clust == 6) || (clust == 13) ) clust = 2;
else if ( (clust == 7) || (clust == 14) ) clust = 3;
else if ( (clust == 8) || (clust == 15) ) clust = 4;
else if ( (clust == 9) || (clust == 16) ) clust = 5;
else if ( (clust == 10) || (clust == 17) ) clust = 6;
else if ( (clust == 11) || (clust == 12) || (clust == 18) || (clust == 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;

View file

@ -61,7 +61,7 @@ extend Class SWWMHandler
l.DirectAdd("Saya");
l.DirectAdd("UAC");
l.DirectAdd("DemonInvasion");
if ( SWWMUtility.IsEviternity() )
if ( SWWMUtility.IsEviternity() || SWWMUtility.IsEviternityTwo() )
{
l.DirectAdd("Gods");
l.DirectAdd("SUSAN");

View file

@ -721,7 +721,8 @@ extend Class SWWMHandler
else if ( e.Replacee is 'KeyBlue' ) e.Replacement = 'SWWMKeyBlue';
else if ( e.Replacee is 'KeyYellow' ) e.Replacement = 'SWWMKeyYellow';
else if ( e.Replacee.GetClassName() == 'KeyRed' ) e.Replacement = 'SWWMKeyRed';
else if ( (e.Replacee is 'Chainsaw') || (e.Replacee is 'Gauntlets') || (e.Replacee is 'FWeapAxe') ) e.Replacement = SWWMUtility.PickSWWMSlot1();
else if ( (e.Replacee is 'Chainsaw') || (e.Replacee is 'Gauntlets') || (e.Replacee is 'FWeapAxe') ) e.Replacement = SWWMUtility.IsEviternityTwo()?SWWMUtility.PickSWWMSlot0():SWWMUtility.PickSWWMSlot1();
else if ( (e.Replacee.GetClassName() == 'Perforator') && SWWMUtility.IsEviternityTwo() ) SWWMUtility.PickSWWMSlot0(); // Eviternity 2
else if ( (e.Replacee is 'Fist') || (e.Replacee is 'Staff') ) e.Replacement = 'DeepImpact';
else if ( (e.Replacee is 'Pistol') || (e.Replacee is 'GoldWand') || (e.Replacee is 'FWeapFist') || (e.Replacee is 'CWeapMace') || (e.Replacee is 'MWeapWand') ) e.Replacement = SWWMUtility.PickSWWMSlot2();
else if ( (e.Replacee is 'Shotgun') || (e.Replacee is 'CWeapStaff') ) e.Replacement = SWWMUtility.IsDoomOne()?SWWMUtility.PickDoomSlot3():SWWMUtility.PickSWWMSlot3();

View file

@ -98,6 +98,10 @@ extend Class SWWMHandler
ui int cummdamage, lastcummtic; // please do not misread
ui Font mSmallFont, mTinyFont;
bool archangelus_zapped; // skips second phase dialogue
bool eviternatus_zapped; // bonus dlg for ynykron survival
bool eviternatus_postzap; // so the bonus dlg doesn't play twice
enum EVanillaMap
{
MAP_NONE,
@ -118,7 +122,8 @@ extend Class SWWMHandler
MAP_HMAP38,
MAP_HMAP40,
MAP_HMAP60,
MAP_EVMAP30 // eviternity
MAP_EVMAP30, // eviternity
MAP_EVIIMAP30 // eviternity 2
};
static play void AddBoss( int tid, String tag, bool endgame = false )
@ -228,6 +233,8 @@ extend Class SWWMHandler
return MAP_HMAP60;
if ( mapsum ~== "5C5E5C08AF3572F31CF27318679F2B4E" )
return MAP_EVMAP30;
if ( mapsum ~== "966EF50BC1C9994F0F303CD1835014FF" ) // subject to change, not final
return MAP_EVIIMAP30;
return MAP_NONE;
}
private void VanillaBossSpawn( WorldEvent e )
@ -459,7 +466,74 @@ extend Class SWWMHandler
bosstag = "$BT_ARCHANGELUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EVIB");
if ( !archangelus_zapped )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EVIB");
}
}
else if ( bossmap == MAP_EVIIMAP30 )
{
if ( e.Thing.GetClassName() == "EviternatusAntaSpawner" )
{
bossactors.Push(e.Thing);
bossviewactor = e.Thing;
bosstag = "$BT_EVITERNATUS";
// hack to avoid "all clear" between phases
level.total_monsters += 3;
}
else if ( e.Thing.GetClassName() == "EviternatusAnta" )
{
// first phase
bossactors.Clear();
bossviewactor = null;
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
bosstag = "$BT_EVITERNATUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
// undo the hack (part 1)
level.total_monsters--;
}
else if ( e.Thing.GetClassName() == "EviternatusBete" )
{
// second phase
bossactors.Clear();
bossviewactor = null;
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
bosstag = "$BT_EVITERNATUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
if ( eviternatus_zapped )
{
eviternatus_postzap = true;
SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2N");
}
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2L");
// undo the hack (part 2)
level.total_monsters--;
}
else if ( e.Thing.GetClassName() == "EviternatusCeph" )
{
// third phase
bossactors.Clear();
bossviewactor = null;
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
bosstag = "$BT_EVITERNATUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
if ( eviternatus_zapped )
{
if ( eviternatus_postzap )
SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2O");
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2N");
}
else SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2M");
// undo the hack (part 3)
level.total_monsters--;
}
}
if ( ccloaded && (e.Thing.GetClassName() == "CCards_Boss_Romero") )
@ -481,7 +555,7 @@ extend Class SWWMHandler
{
if ( !a ) continue;
if ( (!a.target || !a.CheckSight(a.target,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
&& (!bossviewactor || (bossviewactor && !bossviewactor.target)) ) continue;
&& (!bossviewactor || (bossviewactor && !bossviewactor.InStateSequence(bossviewactor.CurState,bossviewactor.SeeState))) ) continue;
initialized = true;
// oneliners
if ( bossmap == MAP_DMAP30 )
@ -505,6 +579,16 @@ extend Class SWWMHandler
highesttic = gametic;
lastcombat = AddOneliner("archangelus",1,300);
}
else if ( bossmap == MAP_EVIIMAP30 )
{
highesttic = gametic;
if ( a.GetClassName() == "EviternatusAnta" )
lastcombat = AddOneliner("eviternatus1",1,40);
else if ( a.GetClassName() == "EviternatusBete" )
lastcombat = AddOneliner("eviternatus2",1,40);
else if ( a.GetClassName() == "EviternatusCeph" )
lastcombat = AddOneliner("eviternatus3",1,40);
}
break;
}
}

View file

@ -65,7 +65,19 @@ extend Class SWWMHandler
{
int clust = 0;
bool secret = false;
if ( SWWMUtility.IsEviternity() )
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;
@ -270,6 +282,9 @@ extend Class SWWMHandler
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");
@ -309,6 +324,9 @@ extend Class SWWMHandler
|| (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")
@ -334,6 +352,28 @@ extend Class SWWMHandler
// 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" )
@ -425,9 +465,10 @@ extend Class SWWMHandler
allclearsector = 18414; // only check all-clear if the player is standing in this sector
gdat.disablerevive = true; // ONE TRY
}
// for skipping over merged exit lines (sharing vertices)
Array<Line> skipme;
skipme.Clear();
Array<Line> exits;
Array<int> exittypes;
exits.Clear();
exittypes.Clear();
// find exit lines, and use lines that aren't exits
foreach ( l:level.Lines )
{
@ -442,68 +483,51 @@ extend Class SWWMHandler
}
let [isexit, exittype] = SWWMUtility.IsExitLine(l);
if ( !isexit ) continue;
exits.Push(l);
exittypes.Push(exittype);
}
// for skipping over merged exit lines (sharing vertices)
Array<Line> skipme;
skipme.Clear();
for ( int i=0; i<exits.Size(); i++ )
{
let l = exits[i];
if ( skipme.Find(l) < skipme.Size() ) continue;
skipme.Push(l);
// look for connected lines
// only stop once we cannot find more
Array<Line> con;
con.Clear();
con.Push(l);
int found;
if ( l.frontsector )
do
{
do
found = 0;
for ( int j=0; j<exits.Size(); j++ )
{
found = 0;
foreach ( l2:l.frontsector.Lines )
let l2 = exits[j];
if ( (l2 == l) || !SWWMUtility.SameSpecial(l,l2) || (skipme.Find(l2) < skipme.Size()) || (con.Find(l2) < con.size()) ) continue;
// needs to have at least one point in common with this one or any of the added lines
bool nomatches = true;
foreach ( c:con )
{
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++;
if ( (l2.v1.p != c.v1.p) && (l2.v2.p != c.v2.p) && (l2.v1.p != c.v2.p) && (l2.v2.p != c.v1.p) )
continue;
nomatches = false;
break;
}
if ( nomatches ) continue;
found++;
skipme.Push(l2);
con.Push(l2);
}
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 );
}
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);
SWWMInterest.Spawn(self,lpos,theline:l,theexit:exittypes[i]);
}
// spawn loot
if ( !deathmatch ) Chancebox.SpawnChanceboxes();

View file

@ -116,6 +116,13 @@ extend Class SWWMHandler
let t = new("KoraxYeeted");
t.ChangeStatNum(Thinker.STAT_USER);
}
// Archangelus instakill
if ( (e.Thing.GetClassName() == "ArchangelusA") && (e.Thing.DamageType == 'Ynykron') )
{
// this will skip the second phase dialogue
// (note that you can only have an Ynykron in this fight by cheating, tho)
archangelus_zapped = true;
}
// Archangelus death
if ( e.Thing.GetClassName() == "ArchangelusB" )
{
@ -128,6 +135,12 @@ extend Class SWWMHandler
a.DamageMobj(e.Thing,e.Thing,a.Health,'EndMii',DMG_FORCED|DMG_THRUSTLESS);
}
}
// Eviternatus instakill
if ( ((e.Thing.GetClassName() == "EviternatusAnta") || (e.Thing.GetClassName() == "EviternatusBete")) && (e.Thing.DamageType == 'Ynykron') )
{
// this will trigger special dialogue on the next phase
eviternatus_zapped = true;
}
if ( swwm_partytime )
{
let pt = Actor.Spawn("PartyTime",e.Thing.pos);
@ -264,6 +277,35 @@ extend Class SWWMHandler
e.Thing.SetTag("$FN_FCAPTAIN");
else if ( e.Thing.GetClassName() == "NightmareDemon" )
e.Thing.SetTag("$FN_NDEMON");
// eviternity 2 stuff
else if ( e.Thing.GetClassName() == "FormerCorporal" )
e.Thing.SetTag("$FN_FCORPORAL");
else if ( e.Thing.GetClassName() == "AstralArachnotron" )
e.Thing.SetTag("$FN_ASTRALARACH");
else if ( e.Thing.GetClassName() == "AstralCacodemon" )
e.Thing.SetTag("$FN_ASTRAL");
else if ( e.Thing.GetClassName() == "Veilimp" )
e.Thing.SetTag("$FN_VEILIMP");
else if ( (e.Thing.GetClassName() == "GoldenAstralCaco")
|| (e.Thing.GetClassName() == "GoldenAstralCacoBoss") )
e.Thing.SetTag("$FN_ASTRALGOLD");
else if ( e.Thing.GetClassName() == "DukeOfHell" )
e.Thing.SetTag("$FN_DUKE");
else if ( e.Thing.GetClassName() == "AstralBabycaco" )
e.Thing.SetTag("$FN_ASTRALBABY");
else if ( e.Thing.GetClassName() == "NAC" )
e.Thing.SetTag("$FN_NAC");
else if ( e.Thing.GetClassName() == "AstralMancubus" )
e.Thing.SetTag("$FN_ASTRALFATSO");
else if ( (e.Thing.GetClassName() == "NecromenaceA")
|| (e.Thing.GetClassName() == "NecromenaceB")
|| (e.Thing.GetClassName() == "NecromenaceC")
|| (e.Thing.GetClassName() == "NecromenaceD") )
e.Thing.SetTag("$FN_NECROMENACE");
else if ( (e.Thing.GetClassName() == "EviternatusAnta")
|| (e.Thing.GetClassName() == "EviternatusBete")
|| (e.Thing.GetClassName() == "EviternatusCeph") )
e.Thing.SetTag("$FN_EVITERNATUS");
// doom vacation stuff
else if ( indoomvacation )
{

View file

@ -101,6 +101,7 @@ Class SWWMOneLiner : HUDMessageBase
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
}
ymargin += 10;
if ( whichline == "" ) return; // don't draw empty strings
// split so it can fit
if ( !l ) l = mSmallFont.BreakLines(whichline,int(min(ss.x,ss.y/.5625)*.5));
@ -593,6 +594,67 @@ Class SWWMDialogueTrigger : SWWMNonInteractiveActor abstract
}
Class SWWMDialogueTriggerGOTCHAEND : SWWMDialogueTrigger {}
Class SWWMDialogueTriggerSpcEV2BCD : SWWMNonInteractiveActor
{
Actor thecaco;
int spcstate;
// this one is very special, yup
override void PostBeginPlay()
{
// the one singular astral cacodemon in this map
// needed for everything
foreach ( c:AllActorClasses )
{
if ( c.GetClassName() != "AstralCacodemon" ) continue;
thecaco = Actor(ThinkerIterator.Create(c).Next());
break;
}
if ( !thecaco )
{
Destroy();
return;
}
}
override void Tick()
{
if ( !thecaco || (thecaco.Health <= 0) )
{
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2D");
Destroy();
return;
}
double dist;
switch ( spcstate )
{
case 0:
// check that the player is close to the astral cacodemon
dist = (thecaco.pos.xy-players[consoleplayer].mo.pos.xy).length();
if ( dist < 1024 )
{
spcstate++;
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2B");
}
break;
case 1:
// wait until the astral caco leaves its spawn position
dist = (thecaco.pos.xy-thecaco.spawnpoint.xy).length();
if ( dist > 64 ) spcstate++;
break;
case 2:
// check that the player is close to where the astral cacodemon originally was
dist = (thecaco.spawnpoint.xy-players[consoleplayer].mo.pos.xy).length();
if ( dist < 1024 )
{
spcstate++;
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2C");
}
break;
}
}
}
Class SWWMDialogueTriggerEV2J : SWWMDialogueTrigger {}
// I'm just doing this as an experiment, don't mind me

View file

@ -843,7 +843,6 @@ Class FuckingInvinciball : Inventory
{
if ( pickup && !deathmatch ) return false;
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP);
Owner.A_StartSound("misc/sundowner",CHAN_POWERUPEXTRA);
let i = InvinciballPower(Owner.FindInventory("InvinciballPower"));
if ( i )
{
@ -853,7 +852,11 @@ Class FuckingInvinciball : Inventory
if ( Owner is 'Demolitionist' )
Demolitionist(Owner).lastbump *= 1.1;
}
else Owner.GiveInventory("InvinciballPower",1);
else
{
Owner.GiveInventory("InvinciballPower",1);
SWWMHandler.AddOneliner("invinciball",2,40);
}
SWWMUtility.AchievementProgressInc("sunny",1,Owner.player);
return true;
}

View file

@ -57,6 +57,18 @@ extend Class DemolitionistMenu
c_minute = 9;
c_tz = "+09";
}
else if ( SWWMUtility.IsEviternityTwo() )
{
// June 11th 2150, 04:09 +09
// (June 11th 2150, 04:09 JST)
// Epoch: 5694174540
c_year = 2150;
c_month = 5;
c_day = 10;
c_hour = 4;
c_minute = 9;
c_tz = "+09";
}
else // Doom
{
// June 6th 2148, 18:37 EDT

View file

@ -24,6 +24,7 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
// saves time
bool nrftl = false;
bool eviternity = false;
bool eviternitwo = false;
bool hexdd = false;
String missionstr;
let stats = SWWMStats.Find(players[consoleplayer]);
@ -32,7 +33,20 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
int clus = level.cluster;
if ( clus == 11 ) nrftl = true;
eviternity = SWWMUtility.IsEviternity();
if ( eviternity )
eviternitwo = SWWMUtility.IsEviternityTwo();
if ( eviternitwo )
{
// clusters in eviternity 2 have to be remapped
if ( clus == 5 ) clus = 1;
else if ( (clus == 6) || (clus == 13) ) clus = 2;
else if ( (clus == 7) || (clus == 14) ) clus = 3;
else if ( (clus == 8) || (clus == 15) ) clus = 4;
else if ( (clus == 9) || (clus == 16) ) clus = 5;
else if ( (clus == 10) || (clus == 17) ) clus = 6;
else if ( (clus == 11) || (clus == 12) || (clus == 18) || (clus == 19) ) clus = 7;
missionstr = String.Format("$SWWM_MISSION_EVITERNITYII%d",clus);
}
else if ( eviternity )
{
// we have to do some heavy lifting here because episodes don't match clusters
if ( level.levelnum <= 5 ) clus = 1;
@ -48,6 +62,8 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
// naive method to guess if this is sigil
else if ( (clus == 5) && (level.mapname.Left(2) == "E5") )
missionstr = String.Format("$SWWM_MISSION_SIGIL");
else if ( (clus == 6) && (level.mapname.Left(2) == "E6") )
missionstr = String.Format("$SWWM_MISSION_SIGIL2");
else missionstr = String.Format("$SWWM_MISSION_DOOM%d",clus);
int csiz = stats.clustervisit.Size();
if ( (csiz > 0) && stats.secretdone[csiz-1] )
@ -61,11 +77,11 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
for ( int i=0; i<csiz; i++ )
{
// also include sigil
if ( !eviternity && (stats.clustervisit[i] >= 5) && (stats.clustervisit[i] != 25) ) continue;
if ( !eviternity && !eviternitwo && (stats.clustervisit[i] >= 5) && (stats.clustervisit[i] != 25) && (stats.clustervisit[i] != 26) ) continue;
fromdoomone = true;
break;
}
if ( !eviternity && (clus == 5) && fromdoomone )
if ( !eviternity && !eviternitwo && (clus == 5) && fromdoomone )
missionstr = "$SWWM_MISSION_DOOM5_FROMDOOM1";
if ( StringTable.Localize(missionstr) ~== missionstr.Mid(1) )
missionstr = "$SWWM_MISSION_NONE";
@ -76,8 +92,8 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
if ( (stats.clustervisit[i] == clus) && !firstskip )
continue;
firstskip = true;
String xstr = String.Format(eviternity?"$SWWM_MISSION_EVITERNITY%d":"$SWWM_MISSION_DOOM%d",stats.clustervisit[i]);
if ( !eviternity && (stats.clustervisit[i] == 5) && fromdoomone )
String xstr = String.Format(eviternitwo?"$SWWM_MISSION_EVITERNITYII%d":eviternity?"$SWWM_MISSION_EVITERNITY%d":"$SWWM_MISSION_DOOM%d",stats.clustervisit[i]);
if ( !eviternity && !eviternitwo && (stats.clustervisit[i] == 5) && fromdoomone )
xstr = "$SWWM_MISSION_DOOM5_FROMDOOM1";
if ( stats.secretdone[i] )
{
@ -89,6 +105,18 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
continue;
mtext.Push(new("DemolitionistMenuTextBox").Init(master,xstr));
}
if ( eviternitwo )
{
// prepend all mission briefings from Eviternity
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY6")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY5")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY4_SECRET")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY8")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY7")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY3")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY2")));
mtext.Push(new("DemolitionistMenuTextBox").Init(master,StringTable.Localize("$SWWM_MISSION_EVITERNITY1")));
}
}
else if ( (gameinfo.gametype&GAME_Heretic) && SWWMUtility.IsKnownMap() )
{
@ -155,23 +183,23 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
break;
case MK_LEFT:
// cycle mission texts
if ( mtext.Size() > 1 )
if ( (mtext.Size() > 1) && (sel < (mtext.Size()-1)) )
{
master.MenuSound("menu/demoscroll");
sel--;
if ( sel < 0 ) sel = mtext.Size()-1;
mtext[sel].smofs = mtext[sel].ofs = 0;
sel++;
mtext[sel].smofs = 0.;
mtext[sel].ofs = 0;
drag = false; // just in case
}
break;
case MK_RIGHT:
// cycle mission texts
if ( mtext.Size() > 1 )
if ( (mtext.Size() > 1) && (sel > 0) )
{
master.MenuSound("menu/demoscroll");
sel++;
if ( sel >= mtext.Size() ) sel = 0;
mtext[sel].smofs = mtext[sel].ofs = 0;
sel--;
mtext[sel].smofs = 0.;
mtext[sel].ofs = 0;
drag = false; // just in case
}
break;
@ -193,23 +221,23 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
break;
}
// cycle mission texts
if ( mtext.Size() > 1 )
if ( (mtext.Size() > 1) && (sel > 0) )
{
master.MenuSound("menu/demoscroll");
sel--;
if ( sel < 0 ) sel = mtext.Size()-1;
mtext[sel].smofs = mtext[sel].ofs;
mtext[sel].smofs = 0.;
mtext[sel].ofs = 0;
drag = false; // just in case
}
break;
case MB_RIGHT:
// cycle mission texts
if ( mtext.Size() > 1 )
if ( (mtext.Size() > 1) && (sel < (mtext.Size()-1)) )
{
master.MenuSound("menu/demoscroll");
sel++;
if ( sel >= mtext.Size() ) sel = 0;
mtext[sel].smofs = mtext[sel].ofs;
mtext[sel].smofs = 0.;
mtext[sel].ofs = 0;
drag = false; // just in case
}
break;
@ -285,7 +313,7 @@ Class DemolitionistMissionTab : DemolitionistMenuTab
if ( mtext.Size() <= 1 ) return;
double xx = master.ws.x-(mtext[sel].scrollbar?11:3);
double yy = master.ws.y-25;
String str = String.Format("%d \cf/\c- %d",sel+1,mtext.Size());
String str = String.Format("%d \cf/\c- %d",mtext.Size()-sel,mtext.Size());
Screen.DrawText(master.mTinyFont,Font.CR_FIRE,(master.origin.x+xx)-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
}
}

View file

@ -20,7 +20,7 @@ Class DemolitionistSecretTab : DemolitionistMenuTab
String str = StringTable.Localize("$SWWM_KIRINPOEM");
l = master.mSmallFont.BreakLines(str,600);
}
else if ( (gameinfo.gametype&GAME_Heretic) || SWWMUtility.IsEviternity() )
else if ( (gameinfo.gametype&GAME_Heretic) || SWWMUtility.IsEviternity() || SWWMUtility.IsEviternityTwo() )
{
img = TexMan.CheckForTexture("graphics/KBase/Drawing_Ibuki.png");
sub = StringTable.Localize("$SWWM_CUTIECLUB");

View file

@ -44,7 +44,7 @@ Class SWWMHelpMenu : GenericMenu
pagehdr[i] = StringTable.Localize("$SWWM_HELP_STORY");
if ( gameinfo.gametype&GAME_Heretic ) pagetxt[i] = mSmallFont.BreakLines(StringTable.Localize("$SWWM_HELP_STORYHERETIC"),600);
else if ( gameinfo.gametype&GAME_Hexen ) pagetxt[i] = mSmallFont.BreakLines(StringTable.Localize("$SWWM_HELP_STORYHEXEN"),600);
else if ( SWWMUtility.IsEviternity() ) pagetxt[i] = mSmallFont.BreakLines(StringTable.Localize("$SWWM_HELP_STORYEVITERNITY"),600);
else if ( SWWMUtility.IsEviternity() || SWWMUtility.IsEviternityTwo() ) pagetxt[i] = mSmallFont.BreakLines(StringTable.Localize("$SWWM_HELP_STORYEVITERNITY"),600);
else pagetxt[i] = mSmallFont.BreakLines(StringTable.Localize("$SWWM_HELP_STORYDOOM"),600);
break;
case PAGE_DEMO:

View file

@ -584,7 +584,7 @@ Class SWWMLoreLibrary : SWWMStaticThinker
else if ( text ~== "SWWM_LORETXT_MARISA" )
text = "SWWM_LORETXT_MARISA2"; // post-invasion update
}
if ( (gameinfo.gametype&GAME_Raven) || SWWMUtility.IsEviternity() || (mlog && (mlog.year >= 2150) && (mlog.month >= 5)) )
if ( (gameinfo.gametype&GAME_Raven) || SWWMUtility.IsEviternity() || SWWMUtility.IsEviternityTwo() || (mlog && (mlog.year >= 2150) && (mlog.month >= 5)) )
{
if ( text ~== "SWWM_LORETXT_AKARILABS" )
text = "SWWM_LORETXT_AKARILABS2"; // demo won, akari project announced

View file

@ -50,6 +50,7 @@ extend Class SWWMUtility
if ( gameinfo.gametype&GAME_DOOM )
{
if ( IsEviternity() ) return true;
if ( IsEviternityTwo() ) return true;
if ( IsUltDoom2() ) return true;
}
return false;
@ -73,6 +74,18 @@ extend Class SWWMUtility
return false;
}
// detect eviternity 2 (naive method)
static bool IsEviternityTwo()
{
foreach ( cls:AllActorClasses )
{
if ( cls.GetClassName() != "EviternatusAnta" )
continue;
return true;
}
return false;
}
// detect doom vacation
static bool InDoomVacation()
{

View file

@ -41,6 +41,8 @@ extend Class SWWMUtility
basetag = "SPECTRE";
break;
case 'LostSoul':
case 'LostSoulEvit2':
case 'LostSoulCount':
basetag = "LOST";
break;
case 'Cacodemon':
@ -78,6 +80,8 @@ extend Class SWWMUtility
basetag = "SPIDER";
break;
case 'Cyberdemon':
case 'CyberdemonEvit2':
case 'CyberdemonMAP24':
basetag = "CYBER";
break;
case 'SWWMBossBrain':
@ -223,6 +227,46 @@ extend Class SWWMUtility
case 'NightmareDemon':
basetag = "NDEMON";
break;
// eviternity 2
case 'FormerCorporal':
basetag = "FCORPORAL";
break;
case 'AstralArachnotron':
basetag = "ASTRALARACH";
break;
case 'AstralCacodemon':
basetag = "ASTRAL";
break;
case 'Veilimp':
basetag = "VEILIMP";
break;
case 'GoldenAstralCaco':
case 'GoldenAstralCacoBoss':
basetag = "ASTRALGOLD";
break;
case 'DukeOfHell':
basetag = "DUKE";
break;
case 'AstralBabyCaco':
basetag = "ASTRALBABY";
break;
case 'NAC':
basetag = "NAC";
break;
case 'AstralMancubus':
basetag = "ASTRALFATSO";
break;
case 'NecromenaceA':
case 'NecromenaceB':
case 'NecromenaceC':
case 'NecromenaceD':
basetag = "NECROMENACE";
break;
case 'EviternatusAnta':
case 'EviternatusBete':
case 'EviternatusCeph':
basetag = "EVITERNATUS";
break;
}
if ( basetag == "" ) return a.GetTag(defstr);
String funtag = "FN_"..basetag.."_FUN";
@ -263,6 +307,11 @@ extend Class SWWMUtility
if ( a == 'StealthRevenant' ) return 'Revenant';
if ( a == 'StealthShotgunGuy' ) return 'ShotgunGuy';
if ( a == 'StealthZombieMan' ) return 'ZombieMan';
// eviternity 2 hackery
if ( a.GetClassName() == 'LostSoulEvit2' ) return 'LostSoul';
if ( a.GetClassName() == 'LostSoulCount' ) return 'LostSoul';
if ( a.GetClassName() == 'CyberdemonEvit2' ) return 'Cyberdemon';
if ( a.GetClassName() == 'CyberdemonMAP24' ) return 'Cyberdemon';
// heretic monsters
if ( a == 'Sorcerer2' ) return 'Sorcerer1';
if ( a == 'HereticImpLeader' ) return 'HereticImp';

View file

@ -676,4 +676,15 @@ extend Class SWWMUtility
// is the point behind both lines?
return (Level.PointOnLineSide(p,a) && Level.PointOnLineSide(p,b));
}
static bool SameSpecial( Line a, Line b )
{
if ( a.special != b.special ) return false;
for ( int i=0; i<5; i++ )
{
if ( a.args[i] != b.args[i] )
return false;
}
return true;
}
}