swwmgz_m/zscript/swwm_hud.zsc
Marisa Kirisame faddb088c1 Hellblazer fully implemented.
Rebalanced Candygun.
Added vanilla boss healthbars + vanilla boss boosting (both optional).
Adjustments so the E1M8 exit and similar work fine with this mod.
Various language changes (mostly vanilla monster tags).
Doubled damage of Pusher altfire, so it matches the projectile's.
Adjusted minimum fall speed for stomping.
Other small fixed and adjustments.
2020-04-20 21:42:43 +02:00

963 lines
38 KiB
Text

// The SWWM GZ HUD is mostly built on top of what I had already done for SWWM Z, also a bit of Dark Souls
Class MsgLine
{
String str;
int tic, type, rep;
}
Class SWWMStatusBar : BaseStatusBar
{
TextureID StatusTex, WeaponTex, ScoreTex, InventoryTex, ChatTex[6],
HealthTex[5], FuelTex, DashTex, EnemyBTex, EnemyHTex[5], GenericAmmoTex[3];
HUDFont mTewiFont, mMiniwiFont, mMPlusFont;
// "Full History" contains all messages since session start, nothing is flushed
// this can be accessed from a section of the knowledge base
Array<MsgLine> MainQueue, PickupQueue, FullHistory;
// sorted arrays of various elements
Array<SWWMInterest> intpoints;
Array<SWWMScoreObj> scoreobjs;
Array<SWWMCombatTracker> trackers;
// the event handler, holding all sorts of stuff
SWWMHandler hnd;
// the boss stuff handler, for the boss healthbar
SWWMVanillaBossHandler bosshnd;
// client cvars
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, targettag, lang;
// shared stuff
Vector2 ss, hs;
int margin;
double FracTic;
int chatopen;
// shared from renderunderlay, needed for proper interpolation of some things
Vector3 viewpos, viewrot;
// libeye stuff
swwmLe__ProjScreen proj;
swwmLe__GLScreen gl_proj;
swwmLe__SWScreen sw_proj;
swwmLe__Viewport viewport;
bool can_project;
transient CVar cvar_renderer;
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
// returns MPlus if we're playing in Japanese, otherwise returns the requested font
Font LangFont( HUDFont req )
{
if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]);
if ( lang.GetString() ~== "jp" ) return mMPlusFont.mFont;
return req.mFont;
}
override void FlushNotify()
{
// flush interpolators (useful since this virtual gets called
// when loading saves, too)
HealthInter.Reset(CPlayer.Health);
ScoreInter.Reset(SWWMCredits.Get(CPlayer));
FuelInter.Reset((CPlayer.mo is 'Demolitionist')?int(Demolitionist(CPlayer.mo).dashfuel):0);
DashInter.Reset((CPlayer.mo is 'Demolitionist')?int((40-Demolitionist(CPlayer.mo).dashcooldown)*3.):0);
if ( level.maptime <= 1 )
{
// flush ALL messages
MainQueue.Clear();
PickupQueue.Clear();
return;
}
// flush non-chat messages
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( MainQueue[i].type >= PRINT_CHAT ) continue;
MainQueue.Delete(i);
i--;
}
}
override bool ProcessMidPrint( Font fnt, String msg, bool bold )
{
// check for Korax lines
if ( msg == StringTable.Localize("$TXT_ACS_MAP02_11_AREYO") )
EventHandler.SendNetworkEvent("swwmkoraxline",0,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP13_11_MYSER") )
EventHandler.SendNetworkEvent("swwmkoraxline",1,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_29_ITHIN") )
EventHandler.SendNetworkEvent("swwmkoraxline",2,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_10_THENA") )
EventHandler.SendNetworkEvent("swwmkoraxline",3,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_14_TOFAC") )
EventHandler.SendNetworkEvent("swwmkoraxline",4,consoleplayer);
return false;
}
override bool ProcessNotify( EPrintLevel printlevel, String outline )
{
let m = new("MsgLine");
m.str = outline.Left(outline.Length()-1); // strip newline
m.type = printlevel;
m.tic = level.totaltime;
m.rep = 1;
// append chat messages to full history
if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) )
FullHistory.Push(m);
// ignore during intermission
if ( gamestate != GS_LEVEL ) return false;
if ( (printlevel < PRINT_LOW) || (printlevel > PRINT_TEAMCHAT) ) return true; // we couldn't care less about these
if ( printlevel == PRINT_LOW )
{
// check if repeated
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( PickupQueue[i].str != m.str ) continue;
// delete old one and add its repeats
m.rep += PickupQueue[i].rep;
PickupQueue.Delete(i);
break;
}
PickupQueue.Push(m);
}
else
{
// check if repeated
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( MainQueue[i].str != m.str ) continue;
// delete old one and add its repeats
m.rep += MainQueue[i].rep;
MainQueue.Delete(i);
break;
}
MainQueue.Push(m);
}
return true;
}
void PrepareProjection()
{
if ( !cvar_renderer ) cvar_renderer = CVar.GetCVar("vid_rendermode",players[consoleplayer]);
if ( !cvar_renderer )
{
can_project = proj = gl_proj;
return;
}
switch ( cvar_renderer.GetInt() )
{
case 0:
case 1:
proj = sw_proj;
break;
default:
proj = gl_proj;
break;
}
can_project = proj;
}
private bool CmpTarget( SWWMCombatTracker a, SWWMCombatTracker b )
{
if ( !a || !b ) return true;
return (a.myplayer && !b.myplayer);
}
private bool CmpScore( SWWMScoreObj a, SWWMScoreObj b )
{
if ( !a || !b ) return true;
int srt[4] = { Font.CR_GOLD, Font.CR_FIRE, Font.CR_GREEN, Font.CR_RED };
int s1 = 0, s2 = 0;
for ( int i=0; i<3; i++ )
{
if ( a.tcolor == srt[i] ) s1 = i;
if ( b.tcolor == srt[i] ) s2 = i;
}
return s1 < s2;
}
private bool CmpInterest( SWWMInterest a, SWWMInterest b )
{
if ( !a || !b ) return true;
return a.type < b.type;
}
private bool CmpDist( Vector3 a, Vector3 b )
{
double dista = level.Vec3Diff(viewpos,a).length();
double distb = level.Vec3Diff(viewpos,b).length();
return (dista < distb);
}
override void Tick()
{
Super.Tick();
PrepareProjection();
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
if ( !targetter ) targetter = CVar.GetCVar('swwm_targeter',players[consoleplayer]);
if ( !healthnums ) healthnums = CVar.GetCVar('swwm_healthnums',players[consoleplayer]);
if ( !scorenums ) scorenums = CVar.GetCVar('swwm_scorenums',players[consoleplayer]);
// prune old messages
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( level.totaltime < (PickupQueue[i].tic+35*pickduration.GetInt()) ) continue;
PickupQueue.Delete(i);
i--;
}
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( (MainQueue[i].type <= PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+35*msgduration.GetInt())) ) continue;
else if ( (MainQueue[i].type > PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+35*chatduration.GetInt())) ) continue;
MainQueue.Delete(i);
i--;
}
// update interpolators
HealthInter.Update(CPlayer.health);
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
ScoreInter.Update(SWWMCredits.Get(CPlayer));
let d = Demolitionist(CPlayer.mo);
if ( d )
{
FuelInter.Update(int(d.dashfuel));
DashInter.Update(int((40-d.dashcooldown)*3.));
}
else
{
FuelInter.Update(0);
DashInter.Update(0);
}
// let weapons update their own interpolators
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' )
SWWMWeapon(CPlayer.ReadyWeapon).HudTick();
bool thesight = CPlayer.mo.FindInventory("Omnisight");
if ( thesight )
{
// update omnisight stuff
if ( intpoints.Size() != hnd.intpoints_cnt )
intpoints.Resize(hnd.intpoints_cnt);
int i = 0;
for ( SWWMInterest poi=hnd.intpoints; poi; poi=poi.next )
intpoints[i++] = poi;
// sort by distance
for ( int i=0; i<hnd.intpoints_cnt; i++ )
{
int j = 1;
while ( j < hnd.intpoints_cnt )
{
int k = j;
while ( (k > 0) && (CmpInterest(intpoints[k-1],intpoints[k]) || CmpDist(intpoints[k-1].pos,intpoints[k].pos)) )
{
SWWMInterest tmp = intpoints[k];
intpoints[k] = intpoints[k-1];
intpoints[k-1] = tmp;
k--;
}
j++;
}
}
}
if ( targetter.GetBool() )
{
// update target stuff
if ( trackers.Size() != hnd.trackers_cnt )
trackers.Resize(hnd.trackers_cnt);
int i = 0, actual = 0;
for ( SWWMCombatTracker trk=hnd.trackers; trk; trk=trk.next )
{
actual++;
// ignore player unless chasecamming
if ( (trk.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( trk.myplayer && deathmatch ) continue; // no players in dm
int mtime = 35;
if ( thesight && (trk.lasthealth > 0) ) mtime += 105;
if ( level.maptime > trk.updated+mtime ) continue;
trackers[i++] = trk;
}
// squeeze if some were discarded
if ( i != hnd.trackers_cnt )
trackers.Resize(i);
// sort by distance (give priority to players)
for ( int i=0; i<trackers.Size(); i++ )
{
int j = 1;
while ( j < trackers.Size() )
{
int k = j;
while ( (k > 0) && (CmpTarget(trackers[k-1],trackers[k]) || CmpDist(trackers[k-1].pos,trackers[k].pos)) )
{
SWWMCombatTracker tmp = trackers[k];
trackers[k] = trackers[k-1];
trackers[k-1] = tmp;
k--;
}
j++;
}
}
}
// update floating scores, adding the scorenums first, then the damnums
int total_sz = 0;
if ( scorenums.GetBool() ) total_sz += hnd.scorenums_cnt;
if ( healthnums.GetBool() ) total_sz += min(50,hnd.damnums_cnt);
if ( scoreobjs.Size() != total_sz )
scoreobjs.Resize(total_sz);
int i = 0;
if ( scorenums.GetBool() )
{
for ( SWWMScoreObj scr=hnd.scorenums; scr; scr=scr.next )
scoreobjs[i++] = scr;
}
if ( healthnums.GetBool() )
{
for ( SWWMScoreObj scr=hnd.damnums; scr && (i<total_sz); scr=scr.next )
scoreobjs[i++] = scr;
}
// sort by distance
for ( int i=0; i<total_sz; i++ )
{
int j = 1;
while ( j < total_sz )
{
int k = j;
while ( (k > 0) && (CmpScore(scoreobjs[k-1],scoreobjs[k]) || CmpDist(scoreobjs[k-1].pos,scoreobjs[k].pos)) )
{
SWWMScoreObj tmp = scoreobjs[k];
scoreobjs[k] = scoreobjs[k-1];
scoreobjs[k-1] = tmp;
k--;
}
j++;
}
}
}
override void Init()
{
Super.Init();
SetSize(0,640,360);
StatusTex = TexMan.CheckForTexture("graphics/HUD/StatusBox.png",TexMan.Type_Any);
DashTex = TexMan.CheckForTexture("graphics/HUD/DashBar.png",TexMan.Type_Any);
FuelTex = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
HealthTex[0] = TexMan.CheckForTexture("graphics/HUD/HealthBar0.png",TexMan.Type_Any);
HealthTex[1] = TexMan.CheckForTexture("graphics/HUD/HealthBar1.png",TexMan.Type_Any);
HealthTex[2] = TexMan.CheckForTexture("graphics/HUD/HealthBar2.png",TexMan.Type_Any);
HealthTex[3] = TexMan.CheckForTexture("graphics/HUD/HealthBar3.png",TexMan.Type_Any);
HealthTex[4] = TexMan.CheckForTexture("graphics/HUD/HealthBarS.png",TexMan.Type_Any);
ScoreTex = TexMan.CheckForTexture("graphics/HUD/ScoreBox.png",TexMan.Type_Any);
WeaponTex = TexMan.CheckForTexture("graphics/HUD/WeaponBox.png",TexMan.Type_Any);
ChatTex[0] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop.png",TexMan.Type_Any);
ChatTex[1] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine.png",TexMan.Type_Any);
ChatTex[2] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom.png",TexMan.Type_Any);
ChatTex[3] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop_Smol.png",TexMan.Type_Any);
ChatTex[4] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine_Smol.png",TexMan.Type_Any);
ChatTex[5] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom_Smol.png",TexMan.Type_Any);
InventoryTex = TexMan.CheckForTexture("graphics/HUD/InventoryBox.png",TexMan.Type_Any);
EnemyBTex = TexMan.CheckForTexture("graphics/HUD/EnemyBox.png",TexMan.Type_Any);
EnemyHTex[0] = TexMan.CheckForTexture("graphics/HUD/EnemyBar0.png",TexMan.Type_Any);
EnemyHTex[1] = TexMan.CheckForTexture("graphics/HUD/EnemyBar1.png",TexMan.Type_Any);
EnemyHTex[2] = TexMan.CheckForTexture("graphics/HUD/EnemyBar2.png",TexMan.Type_Any);
EnemyHTex[3] = TexMan.CheckForTexture("graphics/HUD/EnemyBar3.png",TexMan.Type_Any);
EnemyHTex[4] = TexMan.CheckForTexture("graphics/HUD/EnemyBarS.png",TexMan.Type_Any);
GenericAmmoTex[0] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxL.png",TexMan.Type_Any);
GenericAmmoTex[1] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxM.png",TexMan.Type_Any);
GenericAmmoTex[2] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxR.png",TexMan.Type_Any);
mTewiFont = HUDFont.Create("TewiShaded");
mMiniwiFont = HUDFont.Create("MiniwiShaded");
mMPlusFont = HUDFont.Create("MPlusShaded");
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,999999999);
FuelInter = DynamicValueInterpolator.Create(120,.5,1,100);
DashInter = DynamicValueInterpolator.Create(120,.5,1,40);
gl_proj = new("swwmLe__GLScreen");
sw_proj = new("swwmLe__SWScreen");
PrepareProjection();
hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
}
static private string FormatDist( double dist )
{
double meters = dist/32.;
if ( meters > 1000. ) return String.Format("\cj%d\cckm",int(meters/1000.));
return String.Format("\cj%d\ccm",int(meters));
}
private void DrawTarget()
{
// don't draw when dead or with automap open
if ( (CPlayer.health <= 0) || automapactive ) return;
if ( !targettag ) targettag = CVar.GetCVar('swwm_targettags',players[consoleplayer]);
viewport.FromHud();
proj.CacheResolution();
proj.CacheFov(players[consoleplayer].fov);
proj.Reorient(ViewPos,ViewRot);
proj.BeginProjection();
Vector3 vdir = (cos(ViewRot.x)*cos(ViewRot.y),sin(ViewRot.x)*cos(ViewRot.y),-sin(ViewRot.y));
bool thesight = !!CPlayer.mo.FindInventory("Omnisight");
// points of interest
String tag;
if ( thesight )
{
for ( int i=0; i<intpoints.Size(); i++ )
{
let poi = intpoints[i];
if ( !poi ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,poi.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",StringTable.Localize(poi.trackedkey.GetTag()));
else if ( poi.type == INT_Exit )
{
if ( poi.trackedline.special == Exit_Secret )
tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT"));
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
Font fnt = LangFont(mMiniwiFont);
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hs.x*fnt.StringWidth(tag)/2.)/hs.x,(vpos.y-hs.y*fnt.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hs.x*fnt.StringWidth(tag)/2.)/hs.x,(vpos.y+hs.y*fnt.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
// targetting array
int displayed = 0;
for ( int i=0; i<trackers.Size(); i++ )
{
let targ = trackers[i];
if ( !targ ) continue;
// cap to 40, so the screen isn't too cluttered
if ( displayed++ > 40 ) break;
Vector3 tdir = Level.Vec3Diff(ViewPos,targ.prevpos*(1.-fractic)+targ.pos*fractic);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
tag = targ.mytag;
if ( targ.legged )
{
if ( StringTable.Localize("$SWWM_LEGPREFIX") == "R" ) tag = tag..StringTable.Localize("$SWWM_LEG");
else tag = StringTable.Localize("$SWWM_LEG")..tag;
}
int mtime = 35;
if ( thesight && (targ.lasthealth > 0) ) mtime += 105;
double alph = clamp(((targ.updated+mtime)-level.maptime)/35.,0.,1.);
Vector2 barsiz = TexMan.GetScaledSize(EnemyBTex);
barsiz.x *= hs.x;
barsiz.y *= hs.y;
Vector2 barpos = vpos-(barsiz/2.);
barpos.y -= 16.;
Font fnt = LangFont(mMiniwiFont);
if ( targettag.GetBool() || targ.myplayer && (tag != "") )
Screen.DrawText(fnt,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hs.x)/2.)/hs.x,(barpos.y-fnt.GetHeight()*hs.y)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
Screen.DrawTexture(EnemyBTex,false,barpos.x/hs.x,barpos.y/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
int ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*10);
int hw = int((min(ht,targ.maxhealth)*50.)/targ.maxhealth);
if ( targ.mytarget && (targ.mytarget.bInvulnerable || (targ.myplayer && (targ.myplayer.cheats&(CF_GODMODE|CF_GODMODE2))) || targ.mytarget.FindInventory("InvinciballPower")) )
{
Screen.DrawTexture(EnemyHTex[4],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
continue;
}
Screen.DrawTexture(EnemyHTex[0],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
if ( ht > targ.maxhealth )
{
hw = int((min(ht-targ.maxhealth,targ.maxhealth)*50.)/targ.maxhealth);
Screen.DrawTexture(EnemyHTex[1],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targ.maxhealth*2 )
{
hw = int((min(ht-targ.maxhealth*2,targ.maxhealth*3)*50.)/(targ.maxhealth*3));
Screen.DrawTexture(EnemyHTex[2],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targ.maxhealth*5 )
{
hw = int((min(ht-targ.maxhealth*5,targ.maxhealth*5)*50.)/(targ.maxhealth*5));
Screen.DrawTexture(EnemyHTex[3],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
}
if ( !scorebonus ) scorebonus = CVar.GetCVar('swwm_scorebonus',players[consoleplayer]);
// floating kill scores and others
for ( int i=0; i<scoreobjs.Size(); i++ )
{
let snum = scoreobjs[i];
if ( !snum ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,snum.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( snum.str != "" )
{
if ( !scorebonus.GetBool() ) continue;
tag = StringTable.Localize(snum.str);
if ( snum.score == int.max ) tag.AppendFormat(" %s",StringTable.Localize("$SWWM_MAX"));
else if ( snum.score > 0 ) tag.AppendFormat(" x%d",snum.score);
}
else tag = String.Format("%+d",snum.score);
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
Vector2 fo = (0,0);
if ( snum.tcolor == Font.CR_RED )
{
// damage falls down
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 64+snum.seed2/2;
fo.x = (.05*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.8);
fo.y = -((snum.initialspan-(snum.lifespan-fractic))**1.5)+boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else if ( snum.tcolor == Font.CR_GREEN )
{
// health falls up (?)
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 16+snum.seed2/4;
fo.x = (.15*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.6);
fo.y = ((snum.initialspan-(snum.lifespan-fractic))**1.2)-boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else fo.y = snum.initialspan-(snum.lifespan-fractic); // score rises linearly
Font fnt = (snum.str!="")?LangFont(mMiniwiFont):mMiniwiFont.mFont;
fo.y += snum.ofs*fnt.GetHeight();
Screen.DrawText(fnt,snum.tcolor,(vpos.x-hs.x*(fo.x+fnt.StringWidth(tag)/2.))/hs.x,(vpos.y-hs.y*(fo.y+(fnt.GetHeight()/2.)))/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
private void DrawScore()
{
Screen.DrawTexture(ScoreTex,false,ss.x-(margin+73),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,ss.x-(margin+58),margin+1,String.Format("%09d",clamp(ScoreInter.GetValue(),0,999999999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// in doom/heretic (draw key icons)
if ( !(gameinfo.gametype&(GAME_DOOMCHEX|GAME_HERETIC)) ) return;
Vector2 keypos = (ss.x-(margin+2),margin+19);
int colc = 0;
double colh = 0;
int n = Key.GetKeyTypeCount();
for ( int i=0; i<n; i++ )
{
let k = Key(CPlayer.mo.FindInventory(Key.GetKeyType(i)));
if ( !k || !k.Icon.IsValid() ) continue;
Vector2 siz = TexMan.GetScaledSize(k.Icon);
Screen.DrawTexture(k.Icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
keypos.x -= siz.x+2;
colh = max(colh,siz.y);
if ( ++colc == 8 )
{
keypos.x = ss.x-(margin+2);
keypos.y += colh+2;
colh = colc = 0;
}
}
}
private void DrawInvIcon( Inventory i, double xx, double yy, double alpha = 1., bool forceamt = false, bool aspowerup = false )
{
if ( !i || !i.Icon.IsValid() ) return;
Vector2 scl = TexMan.GetScaledSize(i.Icon);
double mscl = 30./max(scl.x,scl.y);
double dw = (ss.x/mscl), dh = (ss.y/mscl);
double dx = (xx+(30-scl.x*mscl)/2)/mscl, dy = (yy+(30-scl.y*mscl)/2)/mscl;
if ( i is 'Powerup' )
{
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
String nstr = String.Format("%ds",Powerup(i).EffectTics/Thinker.TICRATE);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha);
return;
}
if ( (i is 'SWWMLamp') && aspowerup )
{
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
String nstr = String.Format("%d%%",SWWMLamp(i).Charge);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha);
return;
}
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
if ( (i.Amount > 1) || forceamt )
{
String nstr;
if ( (i.Amount > 99999) && !forceamt ) nstr = "99999";
else nstr = String.Format("%d",i.Amount);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha);
}
}
private void DrawInventory()
{
// active items (armor / powerups)
double xx = margin+2;
double yy = ss.y-(margin+60);
if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
bool drewarmor = false;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i.Amount <= 0) || (!(i is 'SWWMArmor') && !(i is 'BasicArmor')) ) continue;
DrawInvIcon(i,xx,yy,forceamt:true);
yy -= 34;
drewarmor = true;
}
yy = ss.y-(margin+60);
if ( drewarmor ) xx += 40;
else if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i is 'SWWMLamp') )
{
DrawInvIcon(i,xx,yy,aspowerup:true);
yy -= 34;
continue;
}
if ( !(i is 'Powerup') || (Powerup(i).EffectTics <= 0) || !(Powerup(i).Icon) ) continue;
DrawInvIcon(i,xx,yy);
yy -= 34;
}
// inventory box / bar
if ( !CPlayer.mo.InvSel ) return;
if ( isInventoryBarVisible() )
{
Array<Inventory> bar;
bar.Clear();
for ( Inventory i=CPlayer.mo.FirstInv(); i; i=i.NextInv() ) bar.Push(i);
int ps = bar.Find(CPlayer.mo.InvSel);
Inventory prev[2], next[2];
if ( bar.Size() > 1 )
{
if ( ps+1 >= bar.Size() ) next[0] = bar[0];
else next[0] = bar[ps+1];
if ( ps-1 < 0 ) prev[0] = bar[bar.Size()-1];
else prev[0] = bar[ps-1];
}
if ( bar.Size() > 2 )
{
if ( ps+2 >= bar.Size() ) next[1] = bar[(ps+2)-bar.Size()];
else next[1] = bar[ps+2];
if ( ps-2 < 0 ) prev[1] = bar[bar.Size()+(ps-2)];
else prev[1] = bar[ps-2];
}
xx = (ss.x-34)/2;
yy = (ss.y+64)/2;
Screen.DrawTexture(InventoryTex,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
DrawInvIcon(CPlayer.mo.InvSel,xx+2,yy+2);
DrawInvIcon(prev[0],xx-32,yy+2,2./3.);
DrawInvIcon(prev[1],xx-66,yy+2,1./3.);
DrawInvIcon(next[0],xx+36,yy+2,2./3.);
DrawInvIcon(next[1],xx+70,yy+2,1./3.);
return;
}
Screen.DrawTexture(InventoryTex,false,margin,ss.y-(margin+61),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
DrawInvIcon(CPlayer.mo.InvSel,margin+2,ss.y-(margin+59));
}
private void DrawWeapon()
{
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(CPlayer.ReadyWeapon).DrawWeapon(FracTic,ss.x-margin,ss.y-(margin+28),hs,ss);
else if ( CPlayer.ReadyWeapon )
{
// generic display
double xx = ss.x-(margin+14), yy = ss.y-(margin+43);
int maxlen = 0;
String astr2, astr1;
if ( CPlayer.ReadyWeapon.Ammo2 ) astr2 = String.Format("%d",CPlayer.ReadyWeapon.Ammo2.Amount);
if ( CPlayer.ReadyWeapon.Ammo1 ) astr1 = String.Format("%d",CPlayer.ReadyWeapon.Ammo1.Amount);
maxlen = max(astr1.Length(),astr2.Length());
if ( CPlayer.ReadyWeapon.Ammo2 )
{
yy -= 14;
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
for ( int i=0; i<maxlen; i++ )
{
xx -= 6;
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
Screen.DrawTexture(GenericAmmoTex[0],false,xx-3,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,xx,yy,astr2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 14;
}
if ( CPlayer.ReadyWeapon.Ammo1 )
{
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
for ( int i=0; i<maxlen; i++ )
{
xx -= 6;
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
Screen.DrawTexture(GenericAmmoTex[0],false,xx-3,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,xx,yy,astr1,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
Screen.DrawTexture(WeaponTex,false,ss.x-(margin+61),ss.y-(margin+29),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
double xx = ss.x-(margin+58), yy = ss.y-(margin+29);
for ( int i=1; i<=10; i++ )
{
int ncolor = Font.CR_WHITE;
if ( !CPlayer.HasWeaponsInSlot(i%10) ) ncolor = Font.CR_DARKGRAY;
else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
else
{
bool hasammo = false;
for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv )
{
bool dummy;
int slot;
if ( inv is 'Weapon' ) [dummy, slot] = CPlayer.weapons.LocateWeapon(Weapon(inv).GetClass());
else continue;
if ( slot != (i%10) ) continue;
// CheckAmmo can't be called from ui, so we have to improvise
// for SWWM weapons I made a function for this at least
if ( (inv is 'SWWMWeapon') && SWWMWeapon(inv).ReportHUDAmmo() )
hasammo = true;
else if ( !(inv is 'SWWMWeapon') && ((!Weapon(inv).Ammo1 || (Weapon(inv).Ammo1.Amount > 0)) || (Weapon(inv).Ammo2 && (Weapon(inv).Ammo2.Amount > 0))) )
hasammo = true;
}
if ( !hasammo ) ncolor = Font.CR_RED;
}
Screen.DrawText(mTewiFont.mFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 12;
if ( i == 5 )
{
xx = ss.x-(margin+58);
yy += 14;
}
}
}
private void DrawStatus()
{
Screen.DrawTexture(StatusTex,false,margin,ss.y-(margin+27),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
let d = Demolitionist(CPlayer.mo);
int dw = DashInter.GetValue();
double alph = .6;
if ( !d || (d.dashfuel > 20) || ((gametic%10) < 5) ) alph = 1.;
Screen.DrawTexture(DashTex,false,margin+2,ss.y-(margin+21),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,dw,DTA_Alpha,alph);
int fw = FuelInter.GetValue();
Screen.DrawTexture(FuelTex,false,margin+2,ss.y-(margin+25),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,fw);
int ht = clamp(HealthInter.GetValue(),0,10000);
int hw = min(ht,100);
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
{
Screen.DrawTexture(HealthTex[4],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,margin+108,ss.y-(margin+16),String.Format("%3d",Random[HudStuff](0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
Screen.DrawTexture(HealthTex[0],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
if ( ht > 100 )
{
hw = min(ht-100,100);
Screen.DrawTexture(HealthTex[1],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
if ( ht > 200 )
{
hw = int(min(ht-200,300)/3.);
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
if ( ht > 500 )
{
hw = int(min(ht-500,500)/5.);
Screen.DrawTexture(HealthTex[3],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
int hcolor = Font.CR_RED;
if ( ht > 500 ) hcolor = Font.CR_GOLD;
else if ( ht > 200 ) hcolor = Font.CR_PURPLE;
else if ( ht > 100 ) hcolor = Font.CR_CYAN;
Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+16),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
private void DrawPickups()
{
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
if ( !pickcol ) pickcol = CVar.GetCVar('msg0color',players[consoleplayer]);
if ( PickupQueue.Size() <= 0 ) return;
// reverse order since they're drawn bottom to top
int mend = max(0,PickupQueue.Size()-(1+maxpick.GetInt()));
double yy = ss.y-(margin+50);
if ( bosshnd && (bosshnd.alpha > 0.) ) yy -= int(25*clamp(bosshnd.alpha*2.,0.,1.));
for ( int i=PickupQueue.Size()-1; i>=mend; i-- )
{
String cstr = PickupQueue[i].str;
if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep);
int curtime = (PickupQueue[i].tic+35*pickduration.GetInt())-level.totaltime;
double alph = clamp(curtime/20.,0.,1.);
Font fnt = LangFont(mTewiFont);
BrokenLines l = fnt.BreakLines(cstr,int(ss.x*.75));
int maxlen = 0;
for ( int j=0; j<l.Count(); j++ )
{
int len = fnt.StringWidth(l.StringAt(j));
if ( len > maxlen ) maxlen = len;
}
int h = fnt.GetHeight();
double xx = (ss.x-maxlen)/2.;
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y));
for ( int j=l.Count()-1; j>=0; j-- )
{
int len = fnt.StringWidth(l.StringAt(j));
xx = (ss.x-len)/2.;
Screen.DrawText(fnt,pickcol.GetInt(),xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
yy -= h;
}
yy -= 6;
}
}
private void DrawMessages()
{
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
if ( !obitcol ) obitcol = CVar.GetCVar('msg1color',players[consoleplayer]);
if ( !critcol ) critcol = CVar.GetCVar('msg2color',players[consoleplayer]);
if ( !chatcol ) chatcol = CVar.GetCVar('msg3color',players[consoleplayer]);
if ( !teamcol ) teamcol = CVar.GetCVar('msg4color',players[consoleplayer]);
if ( MainQueue.Size() <= 0 ) return;
int mstart = max(0,MainQueue.Size()-(1+maxchat[chatopen>=gametic].GetInt()));
double xx = margin, yy = margin;
bool smol = (ss.x<640);
Screen.DrawTexture(ChatTex[smol?3:0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy++;
for ( int i=mstart; i<MainQueue.Size(); i++ )
{
int col = critcol.GetInt();
if ( MainQueue[i].type == PRINT_MEDIUM ) col = obitcol.GetInt();
else if ( MainQueue[i].type == PRINT_CHAT ) col = chatcol.GetInt();
else if ( MainQueue[i].type == PRINT_TEAMCHAT ) col = teamcol.GetInt();
String cstr = MainQueue[i].str;
if ( MainQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep);
int curtime = MainQueue[i].tic-level.totaltime;
if ( MainQueue[i].type < PRINT_CHAT ) curtime += 35*msgduration.GetInt();
else curtime += 35*chatduration.GetInt();
double alph = clamp(curtime/20.,0.,1.);
Font fnt = LangFont(mTewiFont);
BrokenLines l = fnt.BreakLines(cstr,smol?211:361);
for ( int j=0; j<l.Count(); j++ )
{
Screen.DrawTexture(ChatTex[smol?4:1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(fnt,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
yy += 13;
}
}
Screen.DrawTexture(ChatTex[smol?5:2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
override bool DrawChat( String txt )
{
// ignore during intermission
if ( gamestate != GS_LEVEL ) return false;
chatopen = gametic+1; // have to add 1 because DrawChat is called after everything else
double xx = 2;
double yy = ss.y-14;
Screen.Dim("Black",.8,0,Screen.GetHeight()-int(15*hs.y),Screen.GetWidth(),int(15*hs.y));
String pname = players[consoleplayer].GetUserName();
// strip colors
SWWMUtility.StripColor(pname);
String fullstr = String.Format("\cq%s\cd@\cqdemolitionist%d\cn ~ \c-wall %s_",pname,consoleplayer+1,txt);
Font fnt = LangFont(mTewiFont);
// cut out to fit
int w = fnt.StringWidth(fullstr);
if ( w > ss.x-4 )
{
// draw trailing dots
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,"...",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// shift back
xx -= w-(ss.x-4);
// draw trimmed
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipLeft,int(26*hs.x));
}
else Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return true;
}
override void DrawPowerups()
{
// don't do anything
}
private void DrawDeath()
{
// death prompt
let demo = Demolitionist(CPlayer.mo);
if ( !demo || (CPlayer.Health > 0) ) return;
String str;
double alph;
int len;
double xx, yy;
Font fnt;
if ( demo.player.viewheight <= 6 )
{
Screen.Dim("Black",min(demo.deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight());
if ( demo.revivefail > level.maptime )
{
Screen.Dim("Red",clamp((demo.revivefail-level.maptime)/60.,0.,.2),0,0,Screen.GetWidth(),Screen.GetHeight());
str = StringTable.Localize("$SWWM_REFAIL");
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = ss.y-48;
if ( ((demo.revivefail-level.maptime)%16) < 8 )
Screen.DrawText(fnt,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
alph = clamp((demo.deadtimer-60)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = (ss.y-fnt.GetHeight()*4)/2.;
Screen.DrawText(fnt,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) )
{
alph = clamp((demo.deadtimer-90)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDEDMP"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = ss.y/2.;
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
return;
}
alph = clamp((demo.deadtimer-140)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED2"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = ss.y/2.;
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
if ( !swwm_revive )
return;
alph = clamp((demo.deadtimer-160)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED3"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = (ss.y+fnt.GetHeight()*2)/2.;
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
override void Draw( int state, double TicFrac )
{
Super.Draw(state,TicFrac);
if ( (state != HUD_StatusBar) && (state != HUD_Fullscreen) ) return;
if ( !safezone ) safezone = CVar.GetCVar('swwm_hudmargin',players[consoleplayer]);
if ( !maxchat[0] ) maxchat[0] = CVar.GetCVar('swwm_maxshown',players[consoleplayer]);
if ( !maxchat[1] ) maxchat[1] = CVar.GetCVar('swwm_maxshownbig',players[consoleplayer]);
if ( !maxpick ) maxpick = CVar.GetCVar('swwm_maxpickup',players[consoleplayer]);
BeginHUD();
hs = GetHUDScale();
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
margin = clamp(safezone.GetInt(),0,(ss.x<640)?10:40);
FracTic = TicFrac;
DrawTarget();
DrawScore();
DrawInventory();
DrawStatus();
DrawWeapon();
if ( !bosshnd ) bosshnd = SWWMVanillaBossHandler(EventHandler.Find("SWWMVanillaBossHandler"));
else bosshnd.DrawBossBar(self);
DrawPickups();
DrawDeath();
DrawMessages();
}
}