swwmgz_m/zscript/handler/swwm_handler_vanillaboss.zsc

603 lines
18 KiB
Text

// vanilla boss stuff
Class EndgameBossMarker : Inventory {}
Class BossMarker : Inventory {}
Class IconMessage : Inventory
{
override void DoEffect()
{
if ( Owner.InStateSequence(Owner.CurState,Owner.SeeState) )
{
Console.PrintfEx(PRINT_CHAT,StringTable.Localize("$BOSSLINE_IOS"));
DepleteOrDestroy();
return;
}
}
}
Class ArchangelusMessage : Inventory
{
override void DoEffect()
{
if ( Owner.InStateSequence(Owner.CurState,Owner.SeeState) )
{
Console.PrintfEx(PRINT_CHAT,StringTable.Localize("$BOSSLINE_ARCHANGELUS"));
DepleteOrDestroy();
return;
}
}
}
Class DSparilMessage : Inventory
{
override void DoEffect()
{
if ( Owner.InStateSequence(Owner.CurState,Owner.SeeState) )
{
Console.PrintfEx(PRINT_CHAT,StringTable.Localize("$BOSSLINE_DSPARIL"));
DepleteOrDestroy();
return;
}
}
}
Class ROM3R0Message : Inventory
{
override void DoEffect()
{
if ( Owner.InStateSequence(Owner.CurState,Owner.SeeState) )
{
Console.PrintfEx(PRINT_CHAT,StringTable.Localize("$BOSSLINE_ROM3R0"));
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.ROMERO");
DepleteOrDestroy();
return;
}
}
}
Class ROM3R0Death : Inventory
{
override void OwnerDied()
{
// copied from boss brain
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a = Actor(ti.Next()) )
{
if ( a is 'BossEye' ) a.SetStateLabel("Null");
else if ( a is 'SpawnShot' )
{
a.Spawn("SpawnFire",a.pos,ALLOW_REPLACE);
a.SetStateLabel("Null");
}
else if ( (a.Health > 0) && (a.bBossSpawned || a.bCOUNTKILL) )
a.DamageMobj(self,self,a.Health,'EndMii',DMG_FORCED|DMG_THRUSTLESS);
}
DepleteOrDestroy();
return;
}
}
extend Class SWWMHandler
{
String bosstag;
Array<Actor> bossactors;
Actor bossbrainactor;
Actor bossviewactor;
TextureID facetex[5];
bool initialized;
ui bool ui_initialized;
ui TextureID bbar_f, bbar_r, bbar_d;
ui double bossalpha;
ui SmoothLinearValueInterpolator ihealth;
ui SmoothDynamicValueInterpolator ihealthr;
ui int thealth, hmax;
ui int oldhealth[30];
ui int cummdamage, lastcummtic; // please do not misread
ui Font mSmallFont, mTinyFont;
enum EVanillaMap
{
MAP_NONE,
MAP_DE1M8,
MAP_DE2M8,
MAP_DE3M8,
MAP_DE4M8,
MAP_HE1M8_HE4M8,
MAP_HE2M8_HE5M8,
MAP_HE3M8,
MAP_DMAP07,
MAP_DMAP30,
MAP_DLVL08,
MAP_HMAP12,
MAP_HMAP23_HMAP27_HMAP48_HMAP55,
MAP_HMAP36,
MAP_HMAP37,
MAP_HMAP38,
MAP_HMAP40,
MAP_HMAP60,
MAP_EVMAP30 // eviternity
};
static play void AddBoss( int tid, String tag, bool endgame = false )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( !hnd ) return;
hnd.bossactors.Clear();
hnd.initialized = false;
let ai = level.CreateActorIterator(tid);
Actor a;
while ( a = ai.Next() )
{
hnd.bossactors.Push(a);
a.GiveInventory('BossMarker',1);
if ( endgame ) a.GiveInventory('EndgameBossMarker',1);
// boss brain type actors need to set an eye so we can detect when they "aggro"
if ( a is 'BossBrain' )
{
hnd.bossbrainactor = a;
// look for boss eyes
let eye = Actor(ThinkerIterator.Create("BossEye").Next());
hnd.bossviewactor = eye;
}
}
if ( hnd.bossactors.Size() == 0 ) return;
hnd.bosstag = (tag!="")?tag:hnd.bossactors[0].GetTag();
}
static play void AddBossActor( Actor a, String tag, bool endgame = false )
{
if ( !a ) return;
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( !hnd ) return;
hnd.bossactors.Clear();
hnd.initialized = false;
hnd.bossactors.Push(a);
a.GiveInventory('BossMarker',1);
hnd.bosstag = (tag!="")?tag:a.GetTag();
// boss brain type actors need to set an eye so we can detect when they "aggro"
if ( a is 'BossBrain' )
{
hnd.bossbrainactor = a;
// look for boss eyes
let eye = Actor(ThinkerIterator.Create("BossEye").Next());
hnd.bossviewactor = eye;
}
}
private clearscope int WhichVanillaBossMap() const
{
String mapsum = level.GetChecksum();
if ( (mapsum ~== "94500F4B006B316FE03AC46865AEABF8")
|| (mapsum ~== "97079958C7E89C1908890730B8B9FEB7")
|| (mapsum ~== "058FB092EA1B70DA1E3CBF501C4A91A1") )
return MAP_DE1M8;
if ( mapsum ~== "EFFE91DF41AD41F6973C06F0AD67DDB9" )
return MAP_DE2M8;
if ( mapsum ~== "EF128313112110ED6C1549AF96AF26C9" )
return MAP_DE3M8;
if ( mapsum ~== "2DC939E508AB8EB68AF79D5B60568711" )
return MAP_DE4M8;
if ( (mapsum ~== "27639D04F8090D57A47D354992435893")
|| (mapsum ~== "30D1480A6D4F3A3153739D4CCF659C4E") )
return MAP_HE1M8_HE4M8;
if ( (mapsum ~== "5158C22A0F30CE5E558FD2A05D67685E")
|| (mapsum ~== "85AC7D20D18F9BC49B9696CC2E67F029") )
return MAP_HE2M8_HE5M8;
if ( mapsum ~== "4719C2C71EF28F52310B889DD5A9778B" )
return MAP_HE3M8;
if ( (mapsum ~== "291F24417FB3DD411339AE82EF9B3597")
|| (mapsum ~== "FF8620A6B4EB60CCE737EBC1E6CC7A9F") ) // second sum is for Ultimate Doom 2
return MAP_DMAP07;
if ( mapsum ~== "5EECD88F4491F516D590CE4BBF45F532" )
return MAP_DMAP30;
if ( mapsum ~== "7EB864A03948C3F918F9223B2D1F8911" )
return MAP_DLVL08;
if ( (mapsum ~== "89C4CD26EF05E2577B10CAFE56226662")
|| (mapsum ~== "441BF111747671066A10A146C03EEFC4")
|| (mapsum ~== "55E321849F3699655D7E062C90682F63") )
return MAP_HMAP12;
if ( (mapsum ~== "E3B06F44DBF6F7E7754D7B1DAEF707E4")
|| (mapsum ~== "FC832437D7A2B7094A9B56C3909773D9")
|| (mapsum ~== "91AD797F95CC4C6D6AE33B21F664C60B")
|| (mapsum ~== "188B1B4244BD8DA501D8532696EC8654")
|| (mapsum ~== "5B29D0889DF09A8250D62FA09EB2B452")
|| (mapsum ~== "D3C5FA777BA52264546E6569F167AF0D")
|| (mapsum ~== "15FC0991D975325556EFF71F241A4458")
|| (mapsum ~== "2FAD54B58487884F06EAFA507B553921") )
return MAP_HMAP23_HMAP27_HMAP48_HMAP55;
if ( (mapsum ~== "4444C95C2029DA6EECAC92DAA31CE665")
|| (mapsum ~== "33752742BCA8E539A6EE3E5D0FDA8744")
|| (mapsum ~== "3FFAF2F624C1B4BB6F581DCF7B99CBA7") )
return MAP_HMAP36;
if ( (mapsum ~== "78979A583B1E30D94C9DAE2BCFA9A18D")
|| (mapsum ~== "FDC90F44C65A71E0901C1B9FFFCF3D02")
|| (mapsum ~== "088ECE0E0F3E68448FA1D901001A0084") )
return MAP_HMAP37;
if ( (mapsum ~== "3BF62E4F9FB3CF9AF267421CE2D5F348")
|| (mapsum ~== "4799E1FDB5A3C0E3AD650B5AC215A737")
|| (mapsum ~== "5C63A02B0B04D9AE95CA51687DC3406F") )
return MAP_HMAP38;
if ( (mapsum ~== "EFAFE59092DE5E613562ACF52B86C37F")
|| (mapsum ~== "1C5DE5A921DEE405E98E7E09D9829387")
|| (mapsum ~== "2A6C4235B942467D25FD50D5B313E67A") )
return MAP_HMAP40;
if ( mapsum ~== "B0ADDB295A3ACCE43978AAC91FB8C58A" )
return MAP_HMAP60;
if ( mapsum ~== "5C5E5C08AF3572F31CF27318679F2B4E" )
return MAP_EVMAP30;
return MAP_NONE;
}
private void VanillaBossSpawn( WorldEvent e )
{
if ( bossmap == -1 ) bossmap = WhichVanillaBossMap();
if ( bossmap == MAP_DE1M8 )
{
if ( e.Thing is 'BaronOfHell' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 3;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_BRUISERS";
}
}
else if ( bossmap == MAP_DE2M8 )
{
if ( e.Thing is 'Cyberdemon' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_CYBIE";
}
}
else if ( bossmap == MAP_DE3M8 )
{
if ( e.Thing is 'Spidermastermind' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 6;
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
bosstag = "$BT_SPIDER";
}
}
else if ( bossmap == MAP_DE4M8 )
{
if ( e.Thing is 'Spidermastermind' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 4;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_SPIDER2";
}
}
else if ( bossmap == MAP_DMAP07 )
{
if ( (e.Thing is 'Fatso') || (e.Thing is 'Arachnotron') )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 2;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_DIMPLE";
}
}
else if ( bossmap == MAP_DMAP30 )
{
if ( e.Thing is 'BossBrain' )
{
bossbrainactor = e.Thing;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 40; // goodbye, instakills
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
bosstag = "$BT_IOS";
}
if ( e.Thing is 'BossEye' )
{
bossviewactor = e.Thing;
e.Thing.GiveInventory('IconMessage',1);
}
}
else if ( bossmap == MAP_DLVL08 )
{
if ( e.Thing is 'Cyberdemon' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 4;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_CYBIE2";
}
}
else if ( bossmap == MAP_HE1M8_HE4M8 )
{
if ( e.Thing is 'IronLich' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 4;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_LICHES";
}
}
else if ( bossmap == MAP_HE2M8_HE5M8 )
{
if ( e.Thing is 'Minotaur' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 3;
e.Thing.GiveInventory('BossMarker',1);
bosstag = "$BT_MINOTAUR";
}
}
else if ( bossmap == MAP_HE3M8 )
{
if ( e.Thing is 'Sorcerer1' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 2;
bosstag = "$BT_DSPARIL";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
}
else if ( e.Thing is 'Sorcerer2' )
{
// second phase
bossactors.Clear();
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 8;
bosstag = "$BT_DSPARIL2";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
e.Thing.GiveInventory('DSparilMessage',1);
}
}
else if ( bossmap == MAP_HMAP38 )
{
if ( e.Thing is 'ClericBoss' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 2;
bosstag = "$BT_CLERIC";
e.Thing.GiveInventory('BossMarker',1);
}
}
else if ( bossmap == MAP_HMAP36 )
{
if ( e.Thing is 'FighterBoss' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 2;
bosstag = "$BT_FIGHTER";
e.Thing.GiveInventory('BossMarker',1);
}
}
else if ( bossmap == MAP_HMAP37 )
{
if ( e.Thing is 'MageBoss' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 2;
bosstag = "$BT_MAGE";
e.Thing.GiveInventory('BossMarker',1);
}
}
else if ( bossmap == MAP_HMAP12 )
{
if ( e.Thing is 'Dragon' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 4;
bosstag = "$BT_DRAGON";
e.Thing.GiveInventory('BossMarker',1);
}
}
else if ( bossmap == MAP_HMAP23_HMAP27_HMAP48_HMAP55 )
{
if ( e.Thing is 'Heresiarch' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 8;
bosstag = "$BT_HERESIARCH";
e.Thing.GiveInventory('BossMarker',1);
}
}
else if ( bossmap == MAP_HMAP40 )
{
if ( e.Thing is 'Korax' )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 10;
bosstag = "$BT_KORAX";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
}
}
else if ( bossmap == MAP_HMAP60 )
{
if ( (e.Thing is 'FighterBoss') || (e.Thing is 'ClericBoss') || (e.Thing is 'MageBoss') )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 4;
bosstag = "$BT_DEATHKINGS";
initialized = true; // healthbar shows from the start
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
}
}
else if ( bossmap == MAP_EVMAP30 )
{
if ( e.Thing.GetClassName() == "Archangelus" )
{
bossactors.Push(e.Thing);
bossviewactor = e.Thing;
bosstag = "$BT_ARCHANGELUS";
e.Thing.GiveInventory('ArchangelusMessage',1);
}
else if ( e.Thing.GetClassName() == "ArchangelusA" )
{
// first phase
bossactors.Clear();
bossviewactor = null;
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
bosstag = "$BT_ARCHANGELUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
}
else if ( e.Thing.GetClassName() == "ArchangelusB" )
{
// second phase
bossactors.Clear();
bossviewactor = null;
initialized = false;
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 5;
bosstag = "$BT_ARCHANGELUS";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EVIB");
}
}
if ( ccloaded && (e.Thing.GetClassName() == "CCards_Boss_Romero") )
{
bossactors.Push(e.Thing);
e.Thing.StartHealth = e.Thing.Health *= 10;
bosstag = "ROM3R-0.666";
e.Thing.GiveInventory('BossMarker',1);
e.Thing.GiveInventory('EndgameBossMarker',1);
e.Thing.GiveInventory('ROM3R0Message',1);
e.Thing.GiveInventory('ROM3R0Death',1);
}
}
private void VanillaBossTick()
{
if ( initialized ) return;
// wait until bosses are active
foreach ( a:bossactors )
{
if ( !a ) continue;
if ( (!a.target || !a.CheckSight(a.target,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
&& (!bossviewactor || (bossviewactor && !bossviewactor.target)) ) continue;
initialized = true;
// oneliners
if ( bossmap == MAP_DMAP30 )
{
highesttic = gametic;
lastcombat = AddOneliner("romero",1,200);
}
else if ( bossmap == MAP_HE3M8 )
{
highesttic = gametic;
if ( bosstag = "$BT_DSPARIL2" ) lastcombat = AddOneliner("dsparilb",1,100);
else lastcombat = AddOneliner("dsparila",1,80);
}
else if ( bossmap == MAP_HMAP40 )
{
highesttic = gametic;
lastcombat = AddOneliner("korax",1,40);
}
else if ( (bossmap == MAP_EVMAP30) && bossviewactor )
{
highesttic = gametic;
lastcombat = AddOneliner("archangelus",1,300);
}
break;
}
}
private ui void VanillaBossUiTick()
{
if ( (!ui_initialized && initialized) || (ui_initialized && !initialized) )
{
ui_initialized = true;
thealth = 0;
foreach ( a:bossactors )
{
if ( !a ) continue;
thealth += max(0,a.SpawnHealth());
}
hmax = thealth;
for ( int i=0; i<30; i++ ) oldhealth[i] = thealth;
cummdamage = 0;
if ( !ihealth ) ihealth = SmoothLinearValueInterpolator.Create(thealth,max(1,hmax/50));
else ihealth.Reset(thealth);
if ( !ihealthr ) ihealthr = SmoothDynamicValueInterpolator.Create(thealth,.5);
else ihealthr.Reset(thealth);
return;
}
if ( !ui_initialized ) return;
// update healthbar
int newhealth = 0;
foreach ( a:bossactors )
{
if ( !a ) continue;
newhealth += max(0,a.Health);
}
oldhealth[0] = newhealth;
int curcumm = max(0,thealth-newhealth);
if ( curcumm > 0 )
{
cummdamage += curcumm;
lastcummtic = gametic;
}
else if ( gametic > lastcummtic+150 ) cummdamage = 0;
thealth = newhealth;
ihealthr.Update(thealth);
if ( thealth > oldhealth[29] )
for ( int i=29; i>0; i-- )
oldhealth[i] = thealth;
ihealth.Update(oldhealth[29]);
for ( int i=29; i>0; i-- )
oldhealth[i] = oldhealth[i-1];
if ( thealth > 0 ) bossalpha = min(3.,bossalpha+1./30.);
else bossalpha = max(0,bossalpha-1./50.);
}
// called by HUD (done here for the sake of cleaner code)
ui void DrawBossBar( SWWMStatusBar bar )
{
if ( !ui_initialized || (bossalpha <= 0.) ) return;
if ( !mSmallFont ) mSmallFont = Font.GetFont('TewiFontOutline');
if ( !mTinyFont ) mTinyFont = Font.GetFont('MiniwiFontOutline');
if ( !bbar_f ) bbar_f = TexMan.CheckForTexture("graphics/HUD/BossHealthBarBox.png");
if ( !bbar_r ) bbar_r = TexMan.CheckForTexture("graphics/HUD/BossHealthBar.png");
if ( !bbar_d ) bbar_d = TexMan.CheckForTexture("graphics/HUD/BossHealthBarDecay.png");
Vector2 vpos = ((bar.ss.x-300)/2.,bar.ss.y-(bar.ymargin+50));
Screen.DrawTexture(bbar_f,false,vpos.x-2,vpos.y-2,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha);
if ( hmax )
{
double rw = clamp((ihealthr.GetValue(bar.FracTic)*300.)/hmax,0.,300.);
double dw = clamp((ihealth.GetValue(bar.FracTic)*300.)/hmax,0.,300.);
Screen.DrawTexture(bbar_d,false,vpos.x,vpos.y,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha,DTA_WindowRightF,dw);
Screen.DrawTexture(bbar_r,false,vpos.x,vpos.y,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha,DTA_WindowRightF,rw);
}
if ( (cummdamage > 0) && (gametic < lastcummtic+150) )
{
double calph = clamp(((lastcummtic+150)-gametic)/50.,0.,1.);
string dnum = String.Format("%d",cummdamage);
Screen.DrawText(mTinyFont,Font.CR_RED,vpos.x+300-mTinyFont.StringWidth(dnum),vpos.y-(mTinyFont.GetHeight()+2),dnum,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha*calph);
}
String bname = bosstag;
if ( (bname.Left(1) == "$") && swwm_funtags )
{
String fun = bname.."_FUN";
if ( !(StringTable.Localize(fun) ~== fun.Mid(1)) ) bname = fun;
}
Screen.DrawText(mSmallFont,Font.CR_WHITE,vpos.x,vpos.y-(mSmallFont.GetHeight()+2),StringTable.Localize(bname),DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,bossalpha);
}
// can't use this until I actually figure out how to make those walls damageable
/*override void WorldLineDamaged( WorldEvent e )
{
// allow boss brain to take (reduced) damage from the facewall being shot
if ( level.mapname ~== "MAP30" )
{
if ( !SWWMUtility.IsIOSWall(e.DamageLine) ) return;
if ( bossbrainactor )
bossbrainactor.DamageMobj(e.Inflictor,e.DamageSource,e.Damage/3,e.DamageType,e.DamageFlags,e.DamageAngle);
e.NewDamage = 0;
}
}*/
}