- Reduce number of collectibles (some might come back in the future).
- Merge both DLC weaponsets into one, removing redundant weapons.
- Readjust prices of some items.
- Initial work on collectibles (currently Frispy Corn is done).
- Added bigfont for main menu, based on Source Han Sans.
- Reduced default HUD margin to 10.
- Added blob shadows.
- Added precise crosshair drawing.
- Tweaked decals, imported more stuff from UT.
- Swapped the Ynykron impact decal for something better.
- Fixes to slope alignment code.
- Implemented headpats for MBF Helper Dogs and Cacodemons.
- Implemented partial HDoom support, with love and headpats.
- Fix various string functions breaking on unicode.
- Added cracktro-style text scroll to Titlemap.
- Fixed handling of healthbars for friendly monsters.
- Workaround for maps that use the old author name hack (" - by: " separator).
- Fixed Silver Bullet not autoswitching on first pickup.
- Fixed misalignment of Silver Bullet zoomed aim.
- Silver Bullet is unchambered on first pickup, consistent with Candygun.
- Adjusted collision sizes of all items across the board.
- Implemented "Use To Pickup" to work around any issues introduced by the previous change.
- Swapped CHANF_LOOPING for CHANF_LOOP in many cases, this was a typo.
- Tweaked Biospark arc lengths, for balance and higher performance.
- Fix misaligned fire offsets of some weapons (most noticeable on Wallbuster).
- Prettified the loading disclaimers for BD and HDoom.
- Add pickup flash to all items.
- Add custom key models for Doom and Heretic.
- Fix blown kisses giving you "need key" messages.
- Fix worn armor and embiggeners not being removed on scripted inventory resets.
- Remove all references to the no longer planned Radio.
- Workaround for gzdoom devbuild quirk where MenuSound changed its argument type.
- Added timezone to fake clock.
- Fix some times and dates in said clock.
- SWWM blood now also hits ceilings.
- Added default properties to DLC ammo and weapon stubs.
- Lore entries for collectibles and dlc weapons (incomplete).
- Massive amount of typo fixes across the board.
1453 lines
57 KiB
Text
1453 lines
57 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[3], InventoryTex, ChatTex[6],
|
|
HealthTex[5], FuelTex[2], DashTex, EnemyBTex, EnemyHTex[5], GenericAmmoTex[3];
|
|
HUDFont mTewiFont, mMiniwiFont, mMPlusFont, mk6x8Font;
|
|
|
|
// "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;
|
|
Array<SWWMItemSense> senseitems;
|
|
|
|
// 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, pois, targettag, lang, maxtarg, maxscore, maxdamns, hscale, bscale, nscale, sscale, iscale, dscale, midcol, midbcol, midduration, bigtags, showitems, showmaplabel, showmonsters, showsecrets, showtime, showtotaltime;
|
|
|
|
// shared stuff
|
|
Vector2 ss, hs;
|
|
Vector2 ssb, hsb;
|
|
Vector2 ssn, hsn;
|
|
Vector2 sss, hss;
|
|
Vector2 ssi, hsi;
|
|
Vector2 ssd, hsd;
|
|
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, ScoreInter2, FuelInter, DashInter;
|
|
|
|
Inventory lastsel;
|
|
Weapon lastwep;
|
|
transient CVar ntags;
|
|
String ntagstr;
|
|
int ntagtic, ntagcol;
|
|
|
|
String midstr;
|
|
int midtic, midtype;
|
|
|
|
bool koraxhack;
|
|
|
|
// if playing in Japanese, returns an alternate font of the same height
|
|
// Tewi -> MPlus
|
|
// Miniwi -> k6x8
|
|
Font LangFont( HUDFont req )
|
|
{
|
|
if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]);
|
|
if ( lang.GetString() ~== "jp" )
|
|
{
|
|
if ( req == mMiniwiFont ) return mk6x8Font.mFont;
|
|
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--;
|
|
}
|
|
// flush nametag
|
|
ntagstr = "";
|
|
ntagtic = 0;
|
|
}
|
|
|
|
override bool ProcessMidPrint( Font fnt, String msg, bool bold )
|
|
{
|
|
// check for Korax lines, add them to chat (and reply to some of them)
|
|
bool koraxline = false;
|
|
if ( msg == StringTable.Localize("$TXT_ACS_MAP02_9_GREET") )
|
|
koraxline = true;
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP02_11_AREYO") )
|
|
{
|
|
EventHandler.SendNetworkEvent("swwmkoraxline",0,consoleplayer);
|
|
koraxline = true;
|
|
}
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP13_11_MYSER") )
|
|
{
|
|
EventHandler.SendNetworkEvent("swwmkoraxline",1,consoleplayer);
|
|
koraxline = true;
|
|
}
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_27_YOUHA") )
|
|
koraxline = true;
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_29_ITHIN") )
|
|
{
|
|
EventHandler.SendNetworkEvent("swwmkoraxline",2,consoleplayer);
|
|
koraxline = true;
|
|
}
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_8_WORSH") )
|
|
koraxline = true;
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_10_THENA") )
|
|
{
|
|
EventHandler.SendNetworkEvent("swwmkoraxline",3,consoleplayer);
|
|
koraxline = true;
|
|
}
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_12_AREYO") )
|
|
koraxline = true;
|
|
else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_14_TOFAC") )
|
|
{
|
|
EventHandler.SendNetworkEvent("swwmkoraxline",4,consoleplayer);
|
|
koraxline = true;
|
|
}
|
|
if ( koraxline )
|
|
{
|
|
koraxhack = true;
|
|
Console.Printf(msg);
|
|
koraxhack = false;
|
|
return true;
|
|
}
|
|
if ( !fnt || (fnt == smallfont) )
|
|
{
|
|
midstr = msg;
|
|
midtic = level.totaltime;
|
|
midtype = bold?2:0;
|
|
return true;
|
|
}
|
|
if ( (fnt == bigfont) || (fnt == originalbigfont) )
|
|
{
|
|
midstr = msg;
|
|
midtic = level.totaltime;
|
|
midtype = bold?3:1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool ProcessNotify( EPrintLevel printlevel, String outline )
|
|
{
|
|
if ( koraxhack )
|
|
{
|
|
// treat as chat message
|
|
printlevel = PRINT_CHAT;
|
|
outline = "\cmKorax\c-: "..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);
|
|
}
|
|
|
|
// quicksort (points of interest)
|
|
private int partition_intpoints( Array<SWWMInterest> a, int l, int h )
|
|
{
|
|
SWWMInterest pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpInterest(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMInterest tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMInterest tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_intpoints( Array<SWWMInterest> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_intpoints(a,l,h);
|
|
qsort_intpoints(a,l,p-1);
|
|
qsort_intpoints(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (combat trackers)
|
|
private int partition_trackers( Array<SWWMCombatTracker> a, int l, int h )
|
|
{
|
|
SWWMCombatTracker pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpTarget(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMCombatTracker tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMCombatTracker tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_trackers( Array<SWWMCombatTracker> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_trackers(a,l,h);
|
|
qsort_trackers(a,l,p-1);
|
|
qsort_trackers(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (score objects)
|
|
private int partition_scoreobjs( Array<SWWMScoreObj> a, int l, int h )
|
|
{
|
|
SWWMScoreObj pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpScore(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMScoreObj tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMScoreObj tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_scoreobjs( Array<SWWMScoreObj> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_scoreobjs(a,l,h);
|
|
qsort_scoreobjs(a,l,p-1);
|
|
qsort_scoreobjs(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (item sense)
|
|
private int partition_itemsense( Array<SWWMItemSense> a, int l, int h )
|
|
{
|
|
SWWMItemSense pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMItemSense tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMItemSense tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_itemsense( Array<SWWMItemSense> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_itemsense(a,l,h);
|
|
qsort_itemsense(a,l,p-1);
|
|
qsort_itemsense(a,p+1,h);
|
|
}
|
|
|
|
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]);
|
|
if ( !pois ) pois = CVar.GetCVar('swwm_pois',players[consoleplayer]);
|
|
if ( !maxtarg ) maxtarg = CVar.GetCVar('swwm_maxtargets',players[consoleplayer]);
|
|
if ( !maxscore ) maxscore = CVar.GetCVar('swwm_maxscorenums',players[consoleplayer]);
|
|
if ( !maxdamns ) maxdamns = CVar.GetCVar('swwm_maxdamnums',players[consoleplayer]);
|
|
int maxtargetnum = max(0,maxtarg.GetInt());
|
|
int maxscorenum = max(0,maxscore.GetInt());
|
|
int maxdamnum = max(0,maxdamns.GetInt());
|
|
// 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"));
|
|
int s1, s2;
|
|
[s1, s2] = SWWMCredits.Get(CPlayer);
|
|
ScoreInter.Update(s1);
|
|
if ( ScoreInter.GetValue() >= ScoreInter.mCurrentValue ) ScoreInter2.Update(s2);
|
|
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");
|
|
let cam = players[consoleplayer].camera;
|
|
Vector3 viewvec = (cos(viewrot.x)*cos(viewrot.y),sin(viewrot.x)*cos(viewrot.y),sin(-viewrot.y));
|
|
int sz;
|
|
if ( thesight && pois.GetBool() )
|
|
{
|
|
// 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 )
|
|
{
|
|
// ignore points clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,poi.pos);
|
|
if ( viewvec dot tdir < 0 ) continue;
|
|
proj.ProjectWorldPos(viewpos+tdir);
|
|
proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() || !proj.IsInScreen() ) continue;
|
|
intpoints[i++] = poi;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != hnd.intpoints_cnt )
|
|
intpoints.Resize(i);
|
|
// sort by distance
|
|
qsort_intpoints(intpoints,0,intpoints.Size()-1);
|
|
}
|
|
if ( targetter.GetBool() )
|
|
{
|
|
// update target stuff
|
|
if ( trackers.Size() != hnd.trackers_cnt )
|
|
trackers.Resize(hnd.trackers_cnt);
|
|
int i = 0;
|
|
for ( SWWMCombatTracker trk=hnd.trackers; trk; trk=trk.next )
|
|
{
|
|
// ignore dormant/invisible targets
|
|
if ( !trk.mytarget || trk.mytarget.bDORMANT || trk.mytarget.bINVISIBLE ) continue;
|
|
// 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
|
|
if ( trk.mytarget is 'PlayerGone' ) continue; // ignore "gone" players
|
|
int mtime = 35;
|
|
if ( thesight && (trk.lasthealth > 0) ) mtime += 105;
|
|
if ( level.maptime > trk.updated+mtime ) continue;
|
|
// ignore trackers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,trk.pos);
|
|
if ( viewvec dot tdir < 0 ) continue;
|
|
proj.ProjectWorldPos(viewpos+tdir);
|
|
proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() || !proj.IsInScreen() ) continue;
|
|
trackers[i++] = trk;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != hnd.trackers_cnt )
|
|
trackers.Resize(i);
|
|
// sort by distance (give priority to players)
|
|
qsort_trackers(trackers,0,trackers.Size()-1);
|
|
// cap if limited (must cap after sorting, though, otherwise it'll look weird)
|
|
if ( maxtargetnum && (trackers.Size() > maxtargetnum) )
|
|
{
|
|
int endo = trackers.Size()-maxtargetnum;
|
|
// we gotta push the frontmost bars to the start, due to the inverted draw order
|
|
for ( int i=maxtargetnum-1; i>=0; i-- )
|
|
trackers[i] = trackers[endo+i];
|
|
trackers.Resize(maxtargetnum);
|
|
}
|
|
}
|
|
else trackers.Clear();
|
|
// update floating scores, adding the scorenums first, then the damnums
|
|
int total_sz = 0;
|
|
if ( scorenums.GetBool() ) total_sz += maxscorenum?min(maxscorenum,hnd.scorenums_cnt):hnd.scorenums_cnt;
|
|
if ( healthnums.GetBool() ) total_sz += maxdamnum?min(maxdamnum,hnd.damnums_cnt):hnd.damnums_cnt;
|
|
if ( scoreobjs.Size() != total_sz )
|
|
scoreobjs.Resize(total_sz);
|
|
int i = 0;
|
|
if ( scorenums.GetBool() )
|
|
{
|
|
for ( SWWMScoreObj scr=hnd.scorenums; scr && (i<total_sz); scr=scr.next )
|
|
{
|
|
// ignore numbers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,scr.pos);
|
|
if ( viewvec dot tdir < 0 ) continue;
|
|
proj.ProjectWorldPos(viewpos+tdir);
|
|
proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() || !proj.IsInScreen() ) continue;
|
|
scoreobjs[i++] = scr;
|
|
}
|
|
}
|
|
if ( healthnums.GetBool() )
|
|
{
|
|
for ( SWWMScoreObj scr=hnd.damnums; scr && (i<total_sz); scr=scr.next )
|
|
{
|
|
// ignore numbers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,scr.pos);
|
|
if ( viewvec dot tdir < 0 ) continue;
|
|
proj.ProjectWorldPos(viewpos+tdir);
|
|
proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() || !proj.IsInScreen() ) continue;
|
|
scoreobjs[i++] = scr;
|
|
}
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != total_sz )
|
|
scoreobjs.Resize(i);
|
|
// sort by distance
|
|
qsort_scoreobjs(scoreobjs,0,scoreobjs.Size()-1);
|
|
// check if player has item sense
|
|
let demo = Demolitionist(CPlayer.mo);
|
|
if ( demo && (demo.itemsense_cnt > 0) )
|
|
{
|
|
if ( senseitems.Size() != demo.itemsense_cnt )
|
|
senseitems.Resize(demo.itemsense_cnt);
|
|
total_sz = demo.itemsense_cnt;
|
|
i = 0;
|
|
for ( SWWMItemSense s=demo.itemsense; s && (i<total_sz); s=s.next )
|
|
{
|
|
// ignore points clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,s.pos);
|
|
if ( viewvec dot tdir < 0 ) continue;
|
|
proj.ProjectWorldPos(viewpos+tdir);
|
|
proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() || !proj.IsInScreen() ) continue;
|
|
if ( !thesight && (level.maptime > s.updated+35) ) continue;
|
|
senseitems[i++] = s;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != total_sz )
|
|
senseitems.Resize(i);
|
|
// sort by distance
|
|
qsort_itemsense(senseitems,0,senseitems.Size()-1);
|
|
}
|
|
// part of gross hackery to override nametag display
|
|
if ( !ntags ) ntags = CVar.GetCVar('displaynametags',players[consoleplayer]);
|
|
if ( CPlayer.inventorytics > 0 )
|
|
{
|
|
if ( CPlayer.mo.InvSel && (CPlayer.mo.InvSel != lastsel) && (ntags.GetInt()&1) && (CPlayer == players[consoleplayer]) )
|
|
{
|
|
ntagstr = CPlayer.mo.InvSel.GetTag();
|
|
ntagtic = level.totaltime;
|
|
ntagcol = CVar.GetCVar('nametagcolor',players[consoleplayer]).GetInt();
|
|
}
|
|
lastsel = CPlayer.mo.InvSel;
|
|
}
|
|
if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon != lastwep) )
|
|
{
|
|
if ( (ntags.GetInt()&2) && (CPlayer == players[consoleplayer]) && !(CPlayer.PendingWeapon is 'SWWMGesture') )
|
|
{
|
|
ntagstr = CPlayer.PendingWeapon.GetTag();
|
|
ntagtic = level.totaltime;
|
|
ntagcol = CVar.GetCVar('nametagcolor',players[consoleplayer]).GetInt();
|
|
}
|
|
}
|
|
lastwep = CPlayer.PendingWeapon;
|
|
// make sure vanilla nametags don't display
|
|
DetachMessageID(0x5745504e); // WEPN
|
|
DetachMessageID(0x53494e56); // SINV
|
|
// also try with different endianness, just in case
|
|
DetachMessageID(0x4e504557); // WEPN
|
|
DetachMessageID(0x564e4953); // SINV
|
|
}
|
|
|
|
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[0] = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
|
|
FuelTex[1] = TexMan.CheckForTexture("graphics/HUD/FuelBarS.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[0] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxL.png",TexMan.Type_Any);
|
|
ScoreTex[1] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxM.png",TexMan.Type_Any);
|
|
ScoreTex[2] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxR.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");
|
|
mk6x8Font = HUDFont.Create("k6x8Shaded");
|
|
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
|
|
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,999999999);
|
|
ScoreInter2 = 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\cc%s",int(meters/1000.),StringTable.Localize("$SWWM_UNIT_KILOMETER"));
|
|
return String.Format("\cj%d\cc%s",int(meters),StringTable.Localize("$SWWM_UNIT_METER"));
|
|
}
|
|
|
|
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-",poi.keytag);
|
|
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-hsi.x*fnt.StringWidth(tag)/2.)/hsi.x,(vpos.y-hsi.y*fnt.GetHeight()/2.)/hsi.y,tag,DTA_VirtualWidthF,ssi.x,DTA_VirtualHeightF,ssi.y,DTA_KeepRatio,true);
|
|
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsi.x*fnt.StringWidth(tag)/2.)/hsi.x,(vpos.y+hsi.y*fnt.GetHeight()/2.)/hsi.y,tag,DTA_VirtualWidthF,ssi.x,DTA_VirtualHeightF,ssi.y,DTA_KeepRatio,true);
|
|
}
|
|
}
|
|
// sensed items
|
|
let demo = Demolitionist(CPlayer.mo);
|
|
if ( demo && (demo.itemsense_cnt > 0) )
|
|
{
|
|
for ( int i=0; i<senseitems.Size(); i++ )
|
|
{
|
|
let s = senseitems[i];
|
|
if ( !s || !s.item ) continue;
|
|
Vector3 tdir = Level.Vec3Diff(ViewPos,s.pos);
|
|
proj.ProjectWorldPos(ViewPos+tdir);
|
|
Vector2 npos = proj.ProjectToNormal();
|
|
if ( !proj.IsInFront() ) continue;
|
|
Vector2 vpos = viewport.SceneToWindow(npos);
|
|
Font fnt = LangFont(mMiniwiFont);
|
|
int mtime = thesight?70:35;
|
|
double alph = clamp(((s.updated+mtime)-level.maptime)/35.,0.,1.);
|
|
alph *= clamp(1.5-1.5*(tdir.length()/(thesight?1200.:800.)),0.,1.);
|
|
tag = s.tag;
|
|
Screen.DrawText(fnt,Font.CR_GREEN,(vpos.x-hsd.x*fnt.StringWidth(tag)/2.)/hsd.x,(vpos.y-hsd.y*fnt.GetHeight()/2.)/hsd.y,tag,DTA_VirtualWidthF,ssd.x,DTA_VirtualHeightF,ssd.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsd.x*fnt.StringWidth(tag)/2.)/hsd.x,(vpos.y+hsd.y*fnt.GetHeight()/2.)/hsd.y,tag,DTA_VirtualWidthF,ssd.x,DTA_VirtualHeightF,ssd.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
}
|
|
}
|
|
// targetting array
|
|
for ( int i=0; i<trackers.Size(); i++ )
|
|
{
|
|
let targ = trackers[i];
|
|
if ( !targ ) continue;
|
|
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 *= hsb.x;
|
|
barsiz.y *= hsb.y;
|
|
Vector2 barpos = vpos-(barsiz/2.);
|
|
barpos.y -= 16.;
|
|
if ( !bigtags ) bigtags = CVar.GetCVar('swwm_bigtags',players[consoleplayer]);
|
|
Font fnt = LangFont(bigtags.GetBool()?mTewiFont:mMiniwiFont);
|
|
if ( targettag.GetBool() || targ.myplayer && (tag != "") )
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hsb.x)/2.)/hsb.x,(barpos.y-fnt.GetHeight()*hsb.y)/hsb.y,tag,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
Screen.DrawTexture(EnemyBTex,false,barpos.x/hsb.x,barpos.y/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
double ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*10);
|
|
double hw = (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*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
|
|
continue;
|
|
}
|
|
Screen.DrawTexture(EnemyHTex[0],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
|
|
if ( ht > targ.maxhealth )
|
|
{
|
|
hw = (min(ht-targ.maxhealth,targ.maxhealth)*50.)/targ.maxhealth;
|
|
Screen.DrawTexture(EnemyHTex[1],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
|
|
}
|
|
if ( ht > targ.maxhealth*2 )
|
|
{
|
|
hw = (min(ht-targ.maxhealth*2,targ.maxhealth*3)*50.)/(targ.maxhealth*3);
|
|
Screen.DrawTexture(EnemyHTex[2],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
|
|
}
|
|
if ( ht > targ.maxhealth*5 )
|
|
{
|
|
hw = (min(ht-targ.maxhealth*5,targ.maxhealth*5)*50.)/(targ.maxhealth*5);
|
|
Screen.DrawTexture(EnemyHTex[3],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,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);
|
|
tag = String.Format("%+d",snum.score);
|
|
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
|
|
Vector2 fo = (0,0);
|
|
bool isscore = false;
|
|
if ( snum.tcolor == Font.CR_RED )
|
|
{
|
|
// damage falls down
|
|
int initspd = (128-snum.seed);
|
|
int boostup = 64+snum.seed2;
|
|
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) || (snum.tcolor == Font.CR_BLUE) )
|
|
{
|
|
// health falls up (?)
|
|
int initspd = (128-snum.seed);
|
|
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
|
|
{
|
|
// score rises linearly
|
|
fo.y = snum.initialspan-(snum.lifespan-fractic);
|
|
isscore = true;
|
|
}
|
|
Font fnt = mMiniwiFont.mFont;
|
|
if ( isscore )
|
|
Screen.DrawText(fnt,snum.tcolor,(vpos.x-hss.x*(fo.x+fnt.StringWidth(tag)/2.))/hss.x,(vpos.y-hss.y*(fo.y+(fnt.GetHeight()/2.)))/hss.y,tag,DTA_VirtualWidthF,sss.x,DTA_VirtualHeightF,sss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
else
|
|
Screen.DrawText(fnt,snum.tcolor,(vpos.x-hsn.x*(fo.x+fnt.StringWidth(tag)/2.))/hsn.x,(vpos.y-hsn.y*(fo.y+(fnt.GetHeight()/2.)))/hsn.y,tag,DTA_VirtualWidthF,ssn.x,DTA_VirtualHeightF,ssn.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
// extra strings (if available)
|
|
if ( !scorebonus.GetBool() ) continue;
|
|
fo.y += fnt.GetHeight();
|
|
fnt = LangFont(mMiniwiFont);
|
|
for ( int i=0; i<snum.xcnt; i++ )
|
|
{
|
|
tag = snum.xstr[i];
|
|
if ( snum.xscore[i] == int.max ) tag.AppendFormat(" MAX");
|
|
else if ( snum.xscore[i] > 0 ) tag.AppendFormat(" x%d",snum.xscore[i]);
|
|
Screen.DrawText(fnt,snum.xtcolor[i],(vpos.x-hss.x*(fo.x+fnt.StringWidth(tag)/2.))/hss.x,(vpos.y-hss.y*(fo.y+(fnt.GetHeight()/2.)))/hss.y,tag,DTA_VirtualWidthF,sss.x,DTA_VirtualHeightF,sss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
fo.y += fnt.GetHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
override void DrawMyPos()
|
|
{
|
|
String str = String.Format("(%d,%d,%d)",CPlayer.mo.pos.X,CPlayer.mo.pos.Y,CPlayer.mo.pos.Z);
|
|
let fnt = LangFont(mMiniwiFont);
|
|
Screen.DrawText(fnt,Font.CR_GREEN,(ss.x-fnt.StringWidth(str))/2,4,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
|
|
override void DrawAutomapHUD( double ticFrac )
|
|
{
|
|
// do nothing, DrawScore handles this
|
|
}
|
|
|
|
private void DrawScore()
|
|
{
|
|
if ( ScoreInter2.GetValue() > 0 )
|
|
{
|
|
int digits = 9;
|
|
digits += int(Log10(ScoreInter2.GetValue()))+1;
|
|
int xx = 19+6*digits;
|
|
Screen.DrawTexture(ScoreTex[0],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 15;
|
|
for ( int i=0; i<digits; i++ )
|
|
{
|
|
Screen.DrawTexture(ScoreTex[1],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 6;
|
|
}
|
|
Screen.DrawTexture(ScoreTex[2],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,ss.x-(margin+4+6*digits),margin+1,String.Format("%d",clamp(ScoreInter2.GetValue(),0,999999999)),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);
|
|
}
|
|
else
|
|
{
|
|
int xx = 73;
|
|
Screen.DrawTexture(ScoreTex[0],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 15;
|
|
for ( int i=0; i<9; i++ )
|
|
{
|
|
Screen.DrawTexture(ScoreTex[1],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 6;
|
|
}
|
|
Screen.DrawTexture(ScoreTex[2],false,ss.x-(margin+xx),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);
|
|
}
|
|
// draw stats and timer when automap is open
|
|
int yy = margin+19;
|
|
if ( automapactive )
|
|
{
|
|
if ( !showitems ) showitems = CVar.GetCVar('am_showitems',players[consoleplayer]);
|
|
if ( !showmaplabel ) showmaplabel = CVar.GetCVar('am_showmaplabel',players[consoleplayer]);
|
|
if ( !showmonsters ) showmonsters = CVar.GetCVar('am_showmonsters',players[consoleplayer]);
|
|
if ( !showsecrets ) showsecrets = CVar.GetCVar('am_showsecrets',players[consoleplayer]);
|
|
if ( !showtime ) showtime = CVar.GetCVar('am_showtime',players[consoleplayer]);
|
|
if ( !showtotaltime ) showtotaltime = CVar.GetCVar('am_showtotaltime',players[consoleplayer]);
|
|
int xx = int(ss.x-(margin+2));
|
|
String str;
|
|
int label = showmaplabel.GetInt();
|
|
String ln = level.levelname;
|
|
int iof = ln.IndexOf(" - by: ");
|
|
if ( iof != -1 ) ln.Truncate(iof);
|
|
if ( !label || ((level.clusterflags&level.CLUSTER_HUB) && (label == 2)) ) str = ln;
|
|
else str = String.Format("%s - %s",level.mapname.MakeUpper(),ln);
|
|
let fnt = LangFont(mTewiFont);
|
|
Screen.DrawText(fnt,Font.CR_FIRE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
fnt = LangFont(mMiniwiFont);
|
|
if ( (level.total_monsters > 0) && showmonsters.GetBool() )
|
|
{
|
|
str = String.Format("\cxK \c-%d\cu/\c-%d",level.killed_monsters,level.total_monsters);
|
|
Screen.DrawText(fnt,(level.killed_monsters>=level.total_monsters)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
if ( (level.total_items > 0) && showitems.GetBool() )
|
|
{
|
|
str = String.Format("\cxI \c-%d\cu/\c-%d",level.found_items,level.total_items);
|
|
Screen.DrawText(fnt,(level.found_items>=level.total_items)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
if ( (level.total_secrets > 0) && showsecrets.GetBool() )
|
|
{
|
|
str = String.Format("\cxS \c-%d\cu/\c-%d",level.found_secrets,level.total_secrets);
|
|
Screen.DrawText(fnt,(level.found_secrets>=level.total_secrets)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
int sec;
|
|
if ( showtime.GetBool() )
|
|
{
|
|
sec = Thinker.Tics2Seconds(level.maptime);
|
|
str = String.Format("\cxT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
|
Screen.DrawText(fnt,(sec>3600)?Font.CR_RED:(sec<=level.partime)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
if ( showtotaltime.GetBool() )
|
|
{
|
|
sec = Thinker.Tics2Seconds(level.totaltime);
|
|
str = String.Format("\cxTT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
yy += 3;
|
|
}
|
|
// in doom/heretic (draw key icons)
|
|
if ( !(gameinfo.gametype&(GAME_DOOMCHEX|GAME_HERETIC)) ) return;
|
|
Vector2 keypos = (ss.x-(margin+2),yy);
|
|
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,ss.x,DTA_VirtualHeightF,ss.y,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,ss.x,DTA_VirtualHeightF,ss.y,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,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
}
|
|
}
|
|
|
|
private void DrawInventory()
|
|
{
|
|
// active items (armor / powerups)
|
|
double xx = margin+2;
|
|
double yy = ss.y-(margin+58);
|
|
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+58);
|
|
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+60),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
DrawInvIcon(CPlayer.mo.InvSel,margin+2,ss.y-(margin+58));
|
|
}
|
|
|
|
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+13), yy = ss.y-(margin+42);
|
|
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;
|
|
}
|
|
xx = ss.x-(margin+13);
|
|
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+60),ss.y-(margin+28),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
double xx = ss.x-(margin+57), yy = ss.y-(margin+28);
|
|
for ( int i=1; i<=10; i++ )
|
|
{
|
|
int ncolor = Font.CR_WHITE;
|
|
SWWMGesture hasgesture = null;
|
|
if ( CPlayer.PendingWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.PendingWeapon);
|
|
else if ( CPlayer.ReadyWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.ReadyWeapon);
|
|
if ( !CPlayer.HasWeaponsInSlot(i%10) ) ncolor = Font.CR_DARKGRAY;
|
|
else if ( hasgesture && (hasgesture.formerweapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
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+57);
|
|
yy += 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawStatus()
|
|
{
|
|
Screen.DrawTexture(StatusTex,false,margin,ss.y-(margin+26),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
let d = Demolitionist(CPlayer.mo);
|
|
double 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+20),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dw,DTA_Alpha,alph);
|
|
double fw = FuelInter.GetValue()/2.;
|
|
Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+2,ss.y-(margin+24),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,fw);
|
|
double ht = clamp(HealthInter.GetValue(),0,10000);
|
|
double hw = min(ht,100);
|
|
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
|
|
{
|
|
Screen.DrawTexture(HealthTex[4],false,margin+2,ss.y-(margin+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,margin+108,ss.y-(margin+15),String.Format("%03d",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+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
|
|
if ( ht > 100 )
|
|
{
|
|
hw = min(ht-100,100);
|
|
Screen.DrawTexture(HealthTex[1],false,margin+2,ss.y-(margin+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
|
|
}
|
|
if ( ht > 200 )
|
|
{
|
|
hw = min(ht-200,300)/3.;
|
|
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
|
|
}
|
|
if ( ht > 500 )
|
|
{
|
|
hw = min(ht-500,500)/5.;
|
|
Screen.DrawTexture(HealthTex[3],false,margin+2,ss.y-(margin+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,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+15),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]);
|
|
Font fnt = LangFont(mTewiFont);
|
|
int h = fnt.GetHeight();
|
|
// draw nametags below them
|
|
double yy;
|
|
double nalph = 0.;
|
|
int tagtime = (ntagtic+70)-level.totaltime;
|
|
if ( (ntagstr != "") && (tagtime > 0) )
|
|
{
|
|
nalph = clamp(tagtime/20.,0.,1.);
|
|
yy = ss.y-(margin+50);
|
|
// shift up if boss healthbar is present
|
|
if ( bosshnd && (bosshnd.alpha > 0.) ) yy -= int(25*clamp(bosshnd.alpha*2.,0.,1.));
|
|
int len = fnt.StringWidth(ntagstr);
|
|
double xx = (ss.x-len)/2.;
|
|
Screen.Dim("Black",.8*nalph,int((xx-6)*hs.x),int(yy*hs.y),int((len+12)*hs.x),int((h+4)*hs.y));
|
|
Screen.DrawText(fnt,ntagcol,int(xx),yy+2,ntagstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,nalph);
|
|
}
|
|
if ( PickupQueue.Size() <= 0 ) return;
|
|
// reverse order since they're drawn bottom to top
|
|
int mend = max(0,PickupQueue.Size()-(maxpick.GetInt()));
|
|
yy = ss.y-(margin+50);
|
|
// shift up if boss healthbar is present
|
|
if ( bosshnd && (bosshnd.alpha > 0.) ) yy -= int(25*clamp(bosshnd.alpha*2.,0.,1.));
|
|
// shift up again if nametag is present
|
|
if ( nalph > 0. ) yy -= int((fnt.GetHeight()+6)*clamp(nalph*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.);
|
|
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;
|
|
}
|
|
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(),int(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 ( !midduration ) midduration = CVar.GetCVar('con_midtime',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 ( !midcol ) midcol = CVar.GetCVar('msgmidcolor',players[consoleplayer]);
|
|
if ( !midbcol ) midbcol = CVar.GetCVar('msgmidcolor2',players[consoleplayer]);
|
|
Font fnt = LangFont(mTewiFont);
|
|
double xx, yy;
|
|
if ( midstr != "" )
|
|
{
|
|
double ssp = (midtype&1)?.5:1.;
|
|
double hsp = (midtype&1)?2.:1.;
|
|
int col = (midtype&2)?midbcol.GetInt():midcol.GetInt();
|
|
int curtime = (midtic+int(35*midduration.GetFloat()))-level.totaltime;
|
|
double alph = clamp(curtime/20.,0.,1.);
|
|
BrokenLines l = fnt.BreakLines(midstr,int(ss.x*ssp));
|
|
int h = fnt.GetHeight();
|
|
int maxlen = 0;
|
|
for ( int i=0; i<l.Count(); i++ ) maxlen = max(maxlen,fnt.StringWidth(l.StringAt(i)));
|
|
xx = (ss.x*ssp-maxlen)/2.;
|
|
yy = ss.y*ssp*.375;
|
|
yy -= (h*l.Count()+4)/2.; // center
|
|
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x*hsp),int(yy*hs.y*hsp),int((maxlen+12)*hs.x*hsp),int((h*l.Count()+4)*hs.y*hsp));
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
int len = fnt.StringWidth(l.StringAt(i));
|
|
xx = (ss.x*ssp-len)/2.;
|
|
Screen.DrawText(fnt,col,int(xx),yy+2,l.StringAt(i),DTA_VirtualWidthF,ss.x*ssp,DTA_VirtualHeightF,ss.y*ssp,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy += h;
|
|
}
|
|
}
|
|
if ( MainQueue.Size() <= 0 ) return;
|
|
int mstart = max(0,MainQueue.Size()-(maxchat[chatopen>=gametic].GetInt()));
|
|
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.);
|
|
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);
|
|
let goner = PlayerGone(CPlayer.mo);
|
|
if ( (!demo && !goner) || (CPlayer.Health > 0) || (CPlayer != players[consoleplayer]) ) return;
|
|
String str;
|
|
double alph;
|
|
int len;
|
|
double xx, yy;
|
|
Font fnt;
|
|
int deadtimer = goner?goner.deadtimer:demo.deadtimer;
|
|
if ( goner || (demo.player.viewheight <= 6) )
|
|
{
|
|
Screen.Dim("Black",goner?1.:min(deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight());
|
|
if ( demo && (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((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) )
|
|
{
|
|
if ( sv_norespawn ) return;
|
|
alph = clamp((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((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 ( goner || !swwm_revive )
|
|
return;
|
|
alph = clamp((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]);
|
|
if ( !hscale ) hscale = CVar.GetCVar('swwm_hudscale',players[consoleplayer]);
|
|
if ( !bscale ) bscale = CVar.GetCVar('swwm_barscale',players[consoleplayer]);
|
|
if ( !nscale ) nscale = CVar.GetCVar('swwm_numscale',players[consoleplayer]);
|
|
if ( !sscale ) sscale = CVar.GetCVar('swwm_scrscale',players[consoleplayer]);
|
|
if ( !iscale ) iscale = CVar.GetCVar('swwm_poiscale',players[consoleplayer]);
|
|
if ( !dscale ) dscale = CVar.GetCVar('swwm_detscale',players[consoleplayer]);
|
|
BeginHUD();
|
|
if ( hscale.GetInt() <= 0 ) hs = GetHUDScale();
|
|
else
|
|
{
|
|
hs.x = hscale.GetInt();
|
|
if ( Screen.GetWidth()/hs.x < 640. ) hs.x = max(1,floor(Screen.GetWidth()/640.));
|
|
hs.y = hs.x;
|
|
}
|
|
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
|
|
margin = clamp(safezone.GetInt(),0,(ss.x<640)?10:40);
|
|
if ( bscale.GetInt() <= 0 ) hsb = GetHUDScale();
|
|
else
|
|
{
|
|
hsb.x = bscale.GetInt();
|
|
hsb.y = hsb.x;
|
|
}
|
|
ssb = (Screen.GetWidth()/hsb.x,Screen.GetHeight()/hsb.y);
|
|
if ( nscale.GetInt() <= 0 ) hsn = GetHUDScale();
|
|
else
|
|
{
|
|
hsn.x = nscale.GetInt();
|
|
hsn.y = hsn.x;
|
|
}
|
|
ssn = (Screen.GetWidth()/hsn.x,Screen.GetHeight()/hsn.y);
|
|
if ( sscale.GetInt() <= 0 ) hss = GetHUDScale();
|
|
else
|
|
{
|
|
hss.x = sscale.GetInt();
|
|
hss.y = hss.x;
|
|
}
|
|
sss = (Screen.GetWidth()/hss.x,Screen.GetHeight()/hss.y);
|
|
if ( iscale.GetInt() <= 0 ) hsi = GetHUDScale();
|
|
else
|
|
{
|
|
hsi.x = iscale.GetInt();
|
|
hsi.y = hsi.x;
|
|
}
|
|
ssi = (Screen.GetWidth()/hsi.x,Screen.GetHeight()/hsi.y);
|
|
if ( dscale.GetInt() <= 0 ) hsd = GetHUDScale();
|
|
else
|
|
{
|
|
hsd.x = dscale.GetInt();
|
|
hsd.y = hsd.x;
|
|
}
|
|
ssd = (Screen.GetWidth()/hsd.x,Screen.GetHeight()/hsd.y);
|
|
FracTic = TicFrac;
|
|
DrawTarget();
|
|
DrawScore();
|
|
DrawInventory();
|
|
DrawStatus();
|
|
DrawWeapon();
|
|
if ( !bosshnd ) bosshnd = SWWMVanillaBossHandler(EventHandler.Find("SWWMVanillaBossHandler"));
|
|
else bosshnd.DrawBossBar(self);
|
|
DrawPickups();
|
|
DrawDeath();
|
|
DrawMessages();
|
|
}
|
|
}
|