Split HUD code into multiple files.

This commit is contained in:
Mari the Deer 2022-12-15 13:59:44 +01:00
commit 1aef77f0ac
10 changed files with 2425 additions and 2335 deletions

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r690 \cu(Thu 15 Dec 13:22:40 CET 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r690 \cu(2022-12-15 13:22:40)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r691 \cu(Thu 15 Dec 13:59:44 CET 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r691 \cu(2022-12-15 13:59:44)\c-";

View file

@ -57,6 +57,12 @@ version "4.10"
// hud
#include "zscript/hud/swwm_dialogue.zsc"
#include "zscript/hud/swwm_hud.zsc"
#include "zscript/hud/swwm_hud_target.zsc"
#include "zscript/hud/swwm_hud_topstuff.zsc"
#include "zscript/hud/swwm_hud_inventory.zsc"
#include "zscript/hud/swwm_hud_status.zsc"
#include "zscript/hud/swwm_hud_weapons.zsc"
#include "zscript/hud/swwm_hud_messages.zsc"
#include "zscript/hud/swwm_hudextra.zsc"
#include "zscript/hud/swwm_hudobjects.zsc"
// kbase

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,126 @@
// Inventory drawing
extend Class SWWMStatusBar
{
private bool DrawInvIcon( Inventory i, double xx, double yy, double alpha = 1., bool forceamt = false, bool selected = false, bool aspowerup = false )
{
if ( !i || !i.Icon.IsValid() ) return false;
Vector2 scl = TexMan.GetScaledSize(i.Icon);
double mscl = min(1.,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/GameTicRate);
int len = MiniHudFontOutline.StringWidth(nstr);
Screen.DrawText(MiniHudFontOutline,mhudfontcol[MCR_BRASS],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha);
return true;
}
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 = MiniHudFontOutline.StringWidth(nstr);
Screen.DrawText(MiniHudFontOutline,mhudfontcol[SWWMLamp(i).bActive?MCR_BRASS:MCR_WHITE],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha);
return true;
}
if ( (i is 'DivineSpriteEffect') && aspowerup )
{
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,DivineSpriteEffect(i).isBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
String nstr = String.Format("%ds",DivineSpriteEffect(i).healtim/GameTicRate);
int len = MiniHudFontOutline.StringWidth(nstr);
Screen.DrawText(MiniHudFontOutline,mhudfontcol[MCR_BRASS],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,DivineSpriteEffect(i).isBlinking()?alpha*.5:alpha);
return true;
}
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 = MiniHudFontOutline.StringWidth(nstr);
Screen.DrawText(MiniHudFontOutline,mhudfontcol[(i.Amount<=0)?MCR_RED:selected?MCR_BRASS:MCR_WHITE],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
}
return true;
}
private void DrawInventory()
{
int invy = 61;
// active items (armor / powerups)
double xx = margin+2;
double yy = ss.y-(margin+invy+9);
bool drewarmor = false;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i.Amount <= 0) || (!(i is 'SWWMArmor') && !(i is 'BasicArmor')) ) continue;
if ( !DrawInvIcon(i,xx,yy,forceamt:true,selected:true) ) continue;
yy -= 34;
drewarmor = true;
}
yy = ss.y-(margin+invy+9);
if ( drewarmor )
{
xx += 36;
if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
}
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i is 'SWWMLamp') && SWWMLamp(i).bActivated )
{
DrawInvIcon(i,xx,yy,selected:true,aspowerup:true);
yy -= 34;
continue;
}
if ( (i is 'DivineSpriteEffect') && !DivineSpriteEffect(i).bHealDone )
{
DrawInvIcon(i,xx,yy,selected:true,aspowerup:true);
yy -= 34;
continue;
}
if ( !(i is 'Powerup') || (Powerup(i).EffectTics <= 0) || !(Powerup(i).Icon) ) continue;
if ( 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,selected:true);
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+36,ss.y-(margin+invy+2),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
DrawInvIcon(CPlayer.mo.InvSel,margin+38,ss.y-(margin+invy),selected:true);
}
override void DrawPowerups()
{
// don't do anything, handled by inventory drawer
}
}

View file

@ -0,0 +1,391 @@
// messages (notifications, chat, pickups, midprint...)
extend Class SWWMStatusBar
{
override void FlushNotify()
{
if ( level.maptime <= 1 )
{
// flush ALL messages
MainQueue.Clear();
PickupQueue.Clear();
midstr = "";
midtic = 0;
ntagstr = "";
ntagtic = 0;
return;
}
// flush non-chat messages and nametag
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( MainQueue[i].type >= PRINT_CHAT ) continue;
MainQueue.Delete(i);
i--;
}
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;
SWWMDialogues.StartSeq(SWWMDLG_GREET);
}
else if ( msg == StringTable.Localize("$TXT_ACS_MAP13_11_MYSER") )
{
EventHandler.SendNetworkEvent("swwmkoraxline",1,consoleplayer);
koraxline = true;
SWWMDialogues.StartSeq(SWWMDLG_BLOOD);
}
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;
SWWMDialogues.StartSeq(SWWMDLG_GAME);
}
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;
SWWMDialogues.StartSeq(SWWMDLG_WORSHIP);
}
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;
SWWMDialogues.StartSeq(SWWMDLG_MASTERS);
}
if ( koraxline )
{
Console.PrintfEx(PRINT_CHAT,"\cmKorax\c-: "..msg);
return true;
}
bool ispuzzle = false;
let s = SWWMStats.Find(players[consoleplayer]);
if ( s )
{
puzzlecnt = s.puzzlecnt;
realpuzzlecnt = s.realpuzzlecnt;
}
// check for puzzle solving lines (oh god why), and increment the achievement
if ( ((level.mapname ~== "MAP04") || (level.mapname ~== "MAP05"))
&& ((msg == StringTable.Localize("$TXT_ACS_MAP04_9_ONEHA"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP04_11_ONETH"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP05_6_ONETH"))) )
{
if ( puzzlecnt >= 4 ) puzzlecnt = 0;
puzzlecnt++;
realpuzzlecnt++;
ispuzzle = true;
}
else if ( ((level.mapname ~== "MAP08") || (level.mapname ~== "MAP09") || (level.mapname ~== "MAP10"))
&& ((msg == StringTable.Localize("$TXT_ACS_MAP08_6_ONESI"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP09_6_ONESI"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP10_6_ONESI"))) )
{
if ( (puzzlecnt < 4) || (puzzlecnt >= 10) ) puzzlecnt = 4;
puzzlecnt++;
realpuzzlecnt++;
ispuzzle = true;
}
else if ( ((level.mapname ~== "MAP28") || (level.mapname ~== "MAP30") || (level.mapname ~== "MAP34"))
&& ((msg == StringTable.Localize("$TXT_ACS_MAP28_6_ONENI"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP30_6_ONENI"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP34_1_ONENI"))) )
{
if ( (puzzlecnt < 10) || (puzzlecnt >= 19) ) puzzlecnt = 10;
puzzlecnt++;
realpuzzlecnt++;
ispuzzle = true;
}
// deathkings
else if ( ((level.mapname ~== "MAP44") || (level.mapname ~== "MAP46"))
&& ((msg == StringTable.Localize("$TXT_ACS_MAP44_1_THREE"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP44_2_TWOMO"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP44_3_ONEMO"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP44_4_THEPU"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP44_10_ONETH"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP44_11_TWOTH"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP46_8_ONEFO"))) )
{
if ( (puzzlecnt < 19) || (puzzlecnt >= 30) ) puzzlecnt = 19;
puzzlecnt++;
realpuzzlecnt++;
ispuzzle = true;
}
else if ( (level.mapname ~== "MAP51")
&& ((msg == StringTable.Localize("$TXT_ACS_MAP51_8_ONETH"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP51_9_TWOTH"))
|| (msg == StringTable.Localize("$TXT_ACS_MAP51_10_THECR"))) )
{
if ( (puzzlecnt < 30) || (puzzlecnt >= 34) ) puzzlecnt = 30;
puzzlecnt++;
realpuzzlecnt++;
ispuzzle = true;
}
if ( ispuzzle )
{
EventHandler.SendNetworkEvent("swwmstorepuzzlecnt",consoleplayer,puzzlecnt,realpuzzlecnt);
int tpuz = SWWMUtility.IsDeathkings()?15:19;
if ( realpuzzlecnt >= tpuz ) SWWMUtility.MarkAchievement("puzzle",players[consoleplayer]);
if ( !swwm_nomapmsg )
{
switch ( puzzlecnt )
{
case 1:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE1);
break;
case 2:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE2);
break;
case 3:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE3);
break;
case 5:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE4);
break;
case 8:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE5);
break;
case 11:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE6);
break;
case 20:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE7);
break;
case 30:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE8);
break;
case 31:
SWWMDialogues.StartSeq(SWWMDLG_PUZZLE9);
break;
}
}
}
// rampancy fun stuff
bool mainframeline = false;
if ( (msg == StringTable.Localize("$AISPAWN_TEXT1"))
|| (msg == StringTable.Localize("$AISPAWN_TEXT2"))
|| (msg == StringTable.Localize("$AISEE_TEXT"))
|| (msg == StringTable.Localize("$AIACTIVE_TEXT1"))
|| (msg == StringTable.Localize("$AIACTIVE_TEXT2"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT1"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT2"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT3"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT4"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT5"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT6"))
|| (msg == StringTable.Localize("$AIPAIN_TEXT7")) )
mainframeline = true;
if ( mainframeline )
{
Console.PrintfEx(PRINT_CHAT,"\cmAI Mainframe\c-: "..msg);
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 )
{
// ignore outside of levels
if ( gamestate != GS_LEVEL ) return false;
int rprintlevel = printlevel&PRINT_TYPES;
// treat any unrecognized levels as critical messages
// note that checking for PRINT_LOG isn't needed as those are skipped early in the C++ side
if ( (rprintlevel < PRINT_LOW) || (rprintlevel > PRINT_TEAMCHAT) ) rprintlevel = PRINT_HIGH;
// strip trailing newline (all Printf type messages have this)
outline.DeleteLastCharacter();
// append chat messages to full history
if ( (rprintlevel == PRINT_CHAT) || (rprintlevel == PRINT_TEAMCHAT) )
EventHandler.SendNetworkEvent("swwmstoremessage."..outline,level.totaltime,rprintlevel,consoleplayer);
let m = new("MsgLine");
m.str = outline;
m.type = rprintlevel;
m.tic = level.totaltime;
m.rep = 1;
if ( rprintlevel == 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;
}
m.UpdateText(int(ss.x*.75));
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;
}
m.UpdateText();
MainQueue.Push(m);
}
return true;
}
private void TickMessages()
{
// prune old messages
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( level.totaltime < (PickupQueue[i].tic+GameTicRate*PICKDURATION) ) continue;
PickupQueue.Delete(i);
i--;
}
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( (MainQueue[i].type <= PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+GameTicRate*MSGDURATION)) ) continue;
else if ( (MainQueue[i].type > PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+GameTicRate*CHATDURATION)) ) continue;
MainQueue.Delete(i);
i--;
}
}
private void DrawPickups()
{
int h = mSmallFont.GetHeight();
// draw nametags below them
double yy;
double nalph = 0.;
double tagtime = (ntagtic+70)-(level.totaltime+fractic);
if ( (ntagstr != "") && (tagtime > 0) )
{
nalph = clamp(tagtime/20.,0.,1.);
yy = ss.y-(margin+50);
// shift up if boss healthbar is present
if ( hnd && (hnd.bossalpha > 0.) ) yy -= int(40*clamp(hnd.bossalpha*2.,0.,1.));
int len = mSmallFont.StringWidth(ntagstr);
double xx = (ss.x-len)/2.;
Screen.Dim("Black",.8*nalph,int((xx-6)*hs),int(yy*hs),int((len+12)*hs),int((h+4)*hs));
Screen.DrawText(mSmallFont,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()-MAXPICKUP);
yy = ss.y-(margin+50);
// shift up if boss healthbar is present
if ( hnd && (hnd.bossalpha > 0.) ) yy -= int(40*clamp(hnd.bossalpha*2.,0.,1.));
// shift up again if nametag is present
if ( nalph > 0. ) yy -= int((mSmallFont.GetHeight()+6)*clamp(nalph*2.,0.,1.));
for ( int i=PickupQueue.Size()-1; i>=mend; i-- )
{
PickupQueue[i].UpdateText(int(ss.x*.75));
double curtime = (PickupQueue[i].tic+GameTicRate*PICKDURATION)-(level.totaltime+fractic);
double alph = clamp(curtime/20.,0.,1.);
let l = PickupQueue[i].l;
int maxlen = 0;
for ( int j=0; j<l.Count(); j++ )
{
int len = mSmallFont.StringWidth(l.StringAt(j));
if ( len > maxlen ) maxlen = len;
}
double xx = (ss.x-maxlen)/2.;
Screen.Dim("Black",.8*alph,int((xx-6)*hs),int((yy-h*(l.Count()-1))*hs),int((maxlen+12)*hs),int((h*l.Count()+4)*hs));
for ( int j=l.Count()-1; j>=0; j-- )
{
int len = mSmallFont.StringWidth(l.StringAt(j));
xx = int((ss.x-len)/2.);
Screen.DrawText(mSmallFont,msg0color,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( double boxalph = 1. )
{
double xx, yy;
if ( midstr != "" )
{
double ssp = (midtype&1)?.5:1.;
double hsp = (midtype&1)?2.:1.;
int col = (midtype&2)?msgmidcolor2:msgmidcolor;
double curtime = (midtic+int(GameTicRate*con_midtime))-(level.totaltime+fractic);
double alph = clamp(curtime/20.,0.,1.);
if ( !midl || (midsz != int(ss.x*ssp)) )
{
if ( midl ) midl.Destroy();
midl = mSmallFont.BreakLines(midstr,int(ss.x*ssp));
}
int h = mSmallFont.GetHeight();
int maxlen = 0;
for ( int i=0; i<midl.Count(); i++ ) maxlen = max(maxlen,mSmallFont.StringWidth(midl.StringAt(i)));
xx = int((ss.x*ssp-maxlen)/2.);
yy = int(ss.y*ssp*.375);
yy -= (h*midl.Count()+4)/2; // center
Screen.Dim("Black",.8*alph,int((xx-6)*hs*hsp),int(yy*hs*hsp),int((maxlen+12)*hs*hsp),int((h*midl.Count()+4)*hs*hsp));
for ( int i=0; i<midl.Count(); i++ )
{
int len = mSmallFont.StringWidth(midl.StringAt(i));
xx = int((ss.x*ssp-len)/2.);
Screen.DrawText(mSmallFont,col,int(xx),yy+2,midl.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()-((chatopen>=gametic)?MAXSHOWNBIG:MAXSHOWN));
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,DTA_Alpha,boxalph);
yy += 2;
for ( int i=mstart; i<MainQueue.Size(); i++ )
{
int col = msg2color;
if ( MainQueue[i].type == PRINT_MEDIUM ) col = msg1color;
else if ( MainQueue[i].type == PRINT_CHAT ) col = msg3color;
else if ( MainQueue[i].type == PRINT_TEAMCHAT ) col = msg4color;
MainQueue[i].UpdateText();
let l = smol?MainQueue[i].ls:MainQueue[i].l;
double curtime = MainQueue[i].tic-(level.totaltime+fractic);
if ( MainQueue[i].type < PRINT_CHAT ) curtime += GameTicRate*MSGDURATION;
else curtime += GameTicRate*CHATDURATION;
double alph = clamp(curtime/20.,0.,1.);
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,DTA_Alpha,boxalph);
Screen.DrawText(mSmallFont,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,DTA_Alpha,boxalph);
}
}

View file

@ -0,0 +1,228 @@
// "Status bar" proper
extend Class SWWMStatusBar
{
private void FlushStatus()
{
int hp = CPlayer.Health;
HealthInter.Reset(hp);
for ( int i=9; i>0; i-- )
LagHealth[i] = hp;
LagHealthInter.Reset(hp);
let d = Demolitionist(CPlayer.mo);
if ( d )
{
FuelInter.Reset(d.dashfuel/2);
DashInter.Reset((40-d.dashcooldown)*3);
}
else
{
FuelInter.Reset(0);
DashInter.Reset(0);
}
}
private void TickStatusInterpolators()
{
int hp = CPlayer.Health;
HealthInter.Update(hp);
// flash 'em
if ( hp > LastHealth ) HealthFlash = gametic+25;
// lag
if ( hp > LastHealth )
{
for ( int i=9; i>0; i-- )
LagHealth[i] = hp;
}
LagHealth[0] = LastHealth = hp;
LagHealthInter.Update(LagHealth[9]);
for ( int i=9; i>0; i-- )
LagHealth[i] = LagHealth[i-1];
// fuel/dash
let d = Demolitionist(CPlayer.mo);
if ( d )
{
FuelInter.Update(d.dashfuel/2);
DashInter.Update((40-d.dashcooldown)*3);
}
else
{
FuelInter.Update(0);
DashInter.Update(0);
}
}
private void TickStatus()
{
// low health pulsing
if ( (CPlayer.health <= 0) || (CPlayer.health > 25) )
PulsePhase = 0;
else
{
PulsePhase--;
if ( (PulsePhase < 0) || (PulsePhase > CPlayer.health*2+25) )
PulsePhase = CPlayer.health*2+25;
}
}
private int GetRandom()
{
return (rss = (rss<<1)*35447+(rss/87));
}
private double RandomShiver()
{
int sd = GetRandom();
return ((abs(sd)%11)-5)*.1;
}
private int GetFaceTex( Demolitionist demo )
{
let facestate = demo.facestate;
let paindir = demo.paindir;
let facetimer = demo.facetimer;
let blinktime = demo.blinktime;
if ( CPlayer.Health <= 0 ) return 11;
if ( (isInvulnerable() || demo.FindInventory("InvinciballPower")) && (facestate >= FS_PAIN) ) return 12;
if ( facestate == FS_OUCH ) return 10;
if ( facestate == FS_PAIN ) return (paindir==1)?8:(paindir==-1)?9:7;
if ( facestate == FS_GRIN ) return 5;
if ( facestate == FS_EVIL ) return 6;
if ( facestate == FS_SAD ) return 17;
if ( facestate == FS_WINK ) return 18;
if ( facestate == FS_BLINK ) return ((facetimer>28)||(facetimer<2))?3:4;
switch ( blinktime )
{
case -1:
case -3:
return 3;
break;
case -2:
return 4;
break;
}
return 2;
}
private void DrawMugshot()
{
rss = MSTime()*128;
let demo = Demolitionist(CPlayer.mo);
if ( !demo ) return;
double paintime = clamp((demo.lastdamagetimer-(gametic+Fractic))/double(GameTicRate),0.,1.);
double noiz = min(demo.lastdamage*.5*paintime,3.);
Vector2 shake = (RandomShiver(),RandomShiver())*noiz;
if ( !CPlayer.mo.FindInventory("GhostPower") )
{
if ( !tagcolor ) tagcolor = CVar.GetCVar('swwm_tagcolor',CPlayer);
int facecol = tagcolor.GetInt();
if ( (facecol < 0) || (facecol > 15) ) facecol = 0;
Screen.DrawTexture(FaceTex[0],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_SrcWidth,32,DTA_SrcHeight,32,DTA_DestWidth,32,DTA_DestHeight,32,DTA_SrcX,32*(facecol%4),DTA_SrcY,32*(facecol/4));
bool raging = CPlayer.mo.FindInventory("RagekitPower");
bool angy = CPlayer.mo.FindInventory("AngeryPower");
if ( raging && angy ) Screen.DrawTexture(FaceTex[16],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
else if ( raging ) Screen.DrawTexture(FaceTex[15],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
else if ( angy ) Screen.DrawTexture(FaceTex[13],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Color,Color(255,255,0,0),DTA_Alpha,min(1.,noiz));
if ( (CPlayer.Health > 0) && (isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower")) )
Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,.8+.1*sin(gametic+fractic));
}
else
{
Screen.DrawTexture(FaceTex[0],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_SrcWidth,32,DTA_SrcHeight,32,DTA_DestWidth,32,DTA_DestHeight,32,DTA_FillColor,Color(0,0,0),DTA_Alpha,.25*(1.-min(1.,noiz)));
Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_FillColor,Color(255,0,0),DTA_Alpha,.25*min(1.,noiz));
}
Screen.DrawTexture(FaceTex[GetFaceTex(demo)],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( CPlayer.mo.FindInventory("BarrierPower") ) Screen.DrawTexture(FaceTex[14],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,.5,DTA_LegacyRenderStyle,STYLE_Add);
}
private void DrawStatus()
{
DrawMugshot();
int ox = 36;
int oy = 5;
Screen.DrawTexture(StatusTex,false,margin+ox,ss.y-(margin+22+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
String str;
double ht = clamp(HealthInter.GetValue(fractic),0,10000);
str = String.Format("%3d",clamp(round(ht),0,999));
double hw = min(ht,100);
double bhw = hw;
int hcolor = MCR_RED;
if ( round(ht) > 500 ) hcolor = MCR_YELLOW;
else if ( round(ht) > 200 ) hcolor = MCR_PURPLE;
else if ( round(ht) > 100 ) hcolor = MCR_AQUA;
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
{
Screen.DrawTexture(HealthTex[0],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(HealthTex[4],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
hcolor = MCR_WHITE;
}
else
{
Screen.DrawTexture(HealthTex[0],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(HealthTex[0],false,margin+2+ox,ss.y-(margin+20+oy),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+ox,ss.y-(margin+20+oy),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+ox,ss.y-(margin+20+oy),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+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
}
}
if ( CPlayer.mo.FindInventory("DivineSpriteEffect") )
{
double falph = clamp((ht-1000)/6000.,0.,1.);
Screen.DrawTexture(HealthTex[5],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,falph,DTA_LegacyRenderStyle,STYLE_Add);
String tst;
double alph = .1;
int trl = 9;
for ( double alph = .1; alph <= .5; alph += .1 )
{
tst = "AAA";
SWWMUtility.ObscureText(tst,(gametic-trl)/3,true);
trl--;
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_WHITE],margin+107+ox,ss.y-(margin+20+oy),tst,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,falph*alph,DTA_LegacyRenderStyle,STYLE_Add);
}
Screen.DrawText(MiniHUDFont,mhudfontcol[hcolor],margin+107+ox,ss.y-(margin+20+oy),String.Format("%3d",clamp(round(ht),0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,1.-falph);
}
else
{
Screen.DrawText(MiniHUDFont,mhudfontcol[hcolor],margin+107+ox,ss.y-(margin+20+oy),String.Format("%3d",clamp(round(ht),0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
int f = HealthFlash;
if ( f && (gametic < f) )
{
double alph = max((f-(gametic+FracTic))/25.,0.)**1.5;
Screen.DrawTexture(HealthTex[7],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,bhw,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],margin+107+ox,ss.y-(margin+20+oy),str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
if ( (CPlayer.health > 0) && (CPlayer.health <= 25) && (PulsePhase <= 15) && (hcolor != MCR_WHITE) )
{
double alph = clamp(sin((PulsePhase-FracTic)*12.),0.,1.);
Screen.DrawTexture(HealthTex[6],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_Alpha,alph);
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_REDFLASH],margin+107+ox,ss.y-(margin+20+oy),str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
ht = clamp(LagHealthInter.GetValue(fractic),0,1000);
double hwl = min(ht,100);
if ( hwl > bhw )
{
Screen.DrawTexture(HealthTex[8],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowLeftF,bhw,DTA_WindowRightF,hwl,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(HealthTex[8],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowLeftF,bhw,DTA_WindowRightF,hwl);
}
}
double ft = clamp(FuelInter.GetValue(fractic),0,120);
Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+3+ox,ss.y-(margin+7+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,ft,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+2+ox,ss.y-(margin+8+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,ft);
let d = Demolitionist(CPlayer.mo);
bool blink = (!d || (d.dashfuel > 20) || ((gametic%10) < 5));
double dt = clamp(DashInter.GetValue(fractic),0,120);
Screen.DrawTexture(DashTex,false,margin+3+ox,ss.y-(margin+4+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dt,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(DashTex,false,margin+2+ox,ss.y-(margin+5+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dt,DTA_ColorOverlay,Color(blink?0:96,0,0,0));
}
}

View file

@ -0,0 +1,386 @@
// Targeter
extend Class SWWMStatusBar
{
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 DrawInterest( Vector3 viewvec, out bool projinit )
{
String tag;
SWWMInterest poi = hnd.intpoints;
if ( !poi ) return;
do
{
// this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing
if ( !projinit )
{
projinit = true;
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh);
}
Vector3 tdir = level.Vec3Diff(ViewPos,poi.pos);
if ( viewvec dot tdir < 0 ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs2;
if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",poi.keytag);
else if ( poi.type == INT_Exit )
{
if ( (poi.trackedline.special == Teleport_EndGame)
|| ((poi.trackedline.special == Exit_Secret) && (level.nextsecretmap.Left(6) == "enDSeQ"))
|| ((poi.trackedline.special == Exit_Normal) && (level.nextmap.Left(6) == "enDSeQ")) )
tag = String.Format("\cg%s\c-",StringTable.Localize("$SWWM_EEXIT"));
else if ( poi.trackedline.special == Exit_Secret )
{
LevelInfo l = LevelInfo.FindLevelInfo(level.nextsecretmap);
if ( l && l.isValid() ) tag = String.Format("\cx%s:\c- %s\c-",StringTable.Localize("$SWWM_SEXIT"),l.LookupLevelName());
else tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT"));
}
else if ( (poi.trackedline.special == Exit_Normal) || ((poi.trackedline.special == ACS_Execute) && (poi.trackedline.Args[0] == -Int('E1M8_KNOCKOUT'))) )
{
LevelInfo l = LevelInfo.FindLevelInfo(level.nextmap);
if ( l && l.isValid() ) tag = String.Format("\cy%s:\c- %s\c-",StringTable.Localize("$SWWM_NEXIT"),l.LookupLevelName());
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
else if ( poi.trackedline.special == Teleport_NewMap )
{
LevelInfo l = LevelInfo.FindLevelByNum(poi.trackedline.Args[0]);
if ( l && l.isValid() ) tag = String.Format("\cy%s\c-%s\c-",StringTable.Localize("$SWWM_EXIT"),l.LookupLevelName());
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
else if ( ((poi.trackedline.special == ACS_Execute) || (poi.trackedline.special == ACS_ExecuteAlways)) && (poi.trackedline.Args[0] == -Int('MapFadeOut')) )
{
LevelInfo l = LevelInfo.FindLevelByNum(poi.trackedline.Args[2]);
if ( (level.levelnum != 1) && l && l.isValid() ) tag = String.Format("\cy%s\c-%s\c-",StringTable.Localize("$SWWM_EXIT"),l.LookupLevelName());
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
}
Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y-mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss2.x,DTA_VirtualHeightF,ss2.y,DTA_KeepRatio,true);
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss2.x,DTA_VirtualHeightF,ss2.y,DTA_KeepRatio,true);
}
while ( poi = poi.next );
}
private int GetItemFontColor( SWWMitemSense s )
{
let col = s.scoreitem?Font.CR_YELLOW:Font.CR_WHITE;
let i = (s.item is 'SWWMRespawnTimer')?s.item.tracer:s.item;
if ( i is 'Weapon' ) col = s.vipitem?Font.FindFontColor('VIPGold'):Font.CR_GOLD;
else if ( i is 'MagAmmo' ) col = s.vipitem?Font.FindFontColor('VIPTan'):Font.CR_TAN;
else if ( (i is 'BackpackItem') || (i is 'HammerspaceEmbiggener') ) col = Font.CR_DARKBROWN;
else if ( i is 'Ammo' ) col = s.vipitem?Font.FindFontColor('VIPBrown'):Font.CR_BROWN;
else if ( (i is 'PowerupGiver') || (i is 'AmmoFabricator') || Inventory(i).bBIGPOWERUP ) col = s.vipitem?Font.FindFontColor('VIPPurple'):Font.CR_PURPLE;
else if ( (i is 'Health') || (i is 'HealthPickup') || (i is 'SWWMHealth') ) col = Font.CR_RED;
else if ( (i is 'Armor') || (i is 'SWWMSpareArmor') ) col = Font.CR_GREEN;
else if ( i is 'PuzzleItem' ) col = Font.CR_LIGHTBLUE;
else if ( i is 'Key' ) col = Font.CR_UNTRANSLATED;
else if ( i is 'SWWMCollectible' ) col = Font.CR_PURPLE;
return col;
}
private void DrawItemSense( Vector3 viewvec, out bool projinit )
{
let demo = Demolitionist(CPlayer.mo);
if ( !demo ) return;
SWWMItemSense s = demo.itemsense;
if ( !s ) return;
do
{
if ( !s.item ) continue;
Vector3 tdir = level.Vec3Diff(ViewPos,s.pos);
if ( viewvec dot tdir < 0 ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1;
int mtime = level.allmap?(GameTicRate*2):GameTicRate;
double alph = clamp(((s.updated+mtime)-(level.maptime+fractic))/double(GameTicRate),0.,1.);
alph *= clamp(1.5-1.5*(tdir.length()/(level.allmap?1200.:800.)),0.,1.);
String tag = s.tag;
Screen.DrawText(mTinyFontOutline,GetItemFontColor(s),vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y-mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
if ( s.item is 'SWWMRespawnTimer' )
{
tag = String.Format(StringTable.Localize("$SWWM_TRESPAWN"),s.item.special2/GameTicRate);
Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()*2,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
while ( s = s.next );
}
private bool IsLegendary( Actor a )
{
for ( Inventory i=a.inv; i; i=i.inv )
{
if ( (i.GetClassName() == "LDLegendaryMonsterToken") && swwm_ldspoil ) return true;
else if ( i.GetClassName() == "LDLegendaryMonsterTransformed" ) return true;
}
return false;
}
private void DrawTrackers( Vector3 viewvec, out bool projinit )
{
let cam = players[consoleplayer].camera;
if ( !cti ) cti = ThinkerIterator.Create("SWWMQuickCombatTracker",Thinker.STAT_INVENTORY);
else cti.Reinit();
SWWMQuickCombatTracker ct;
bool onlymonsters = (swwm_targeter >= 2);
bool onlyfriends = (swwm_targeter >= 3);
int fadedist = swwm_bardist;
while ( ct = SWWMQuickCombatTracker(cti.Next()) )
{
// this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing
if ( !projinit )
{
projinit = true;
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh);
}
// ignore unowned (can happen?)
if ( !ct.Owner ) continue;
// ignore if max health is zero (SOMEHOW can happen)
if ( ct.maxhealth <= 0 ) continue;
// ignore player trackers unless voodoo dolls
if ( ct.Owner.player && (ct.Owner.player.mo == ct.Owner) ) continue;
// ignore local player or camera
if ( (ct.Owner == CPlayer.mo) || (ct.Owner == cam) ) continue;
// ignore trackers not of this player
if ( ct.myplayer != CPlayer ) continue;
// ignore non-monsters if filtering monsters
// easy check since they have empty tags
if ( onlymonsters && (ct.mytag == "") ) continue;
// ignore enemies if filtering friends
if ( onlyfriends && (!ct.Owner.IsFriend(CPlayer.mo) || ct.Owner.player) ) continue;
// ignore trackers clearly outside of player view
Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight));
Vector3 tdir = level.Vec3Diff(viewpos,smpos);
if ( viewvec dot tdir < 0 ) continue;
// ignore trackers that are too far away
double dist = tdir.length();
if ( (fadedist > 0) && (dist > fadedist*1.5) ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1;
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
double fin = clamp(ct.fadein+fractic,0.,5.)/5.;
double fout = clamp(ct.lifespan-fractic,0.,25.)/25.;
double alph = fin*fout;
if ( fadedist > 0 )
{
double df = 1.-(clamp((dist-fadedist)/fadedist,0.,.5)*2.);
alph *= df;
}
Vector2 barpos = vpos-(27,7);
if ( swwm_targettags && (ct.mytag != "") )
{
Font fnt = swwm_bigtags?mSmallFontOutline:mTinyFontOutline;
String tag = ct.mytag;
if ( IsLegendary(ct.Owner) )
{
if ( StringTable.Localize("$SWWM_LEGPREFIX") == "R" ) tag = tag..StringTable.Localize("$SWWM_LEG");
else tag = StringTable.Localize("$SWWM_LEG")..tag;
}
if ( ct.Owner.bBOSS || ct.Owner.FindInventory("BossMarker") )
{
if ( swwm_bigtags ) tag = "\cx★\c- "..tag.." \cx★\c-";
else tag = "\cx*\c- "..tag.." \cx*\c-"; // miniwi has no stars
}
// voodoo dolls aren't friends
if ( ct.Owner.IsFriend(CPlayer.mo) && !ct.Owner.player ) tag = "\cg♥\c- "..tag.." \cg♥\c-";
Screen.DrawText(fnt,Font.CR_WHITE,vpos.x-fnt.StringWidth(tag)/2,barpos.y-(fnt.GetHeight()+2),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
Screen.DrawTexture(EnemyBTex,false,barpos.x,barpos.y,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
double ht = clamp(ct.intp.GetValue(fractic),0,ct.maxhealth);
double hw = (ht*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[ct.Owner.bINVULNERABLE?1:0],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
double ohw = hw;
ht = clamp(ct.intpl.GetValue(fractic),0,ct.maxhealth);
hw = (ht*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[2],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowLeftF,ohw,DTA_WindowRightF,hw);
if ( ct.cummdamage <= 0 ) continue;
double calph = clamp(ct.cummspan-fractic,0.,20.)/20.;
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_RED],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,calph*alph);
if ( ct.cummflash <= 0 ) continue;
double falph = max((ct.cummflash-FracTic)/15.,0.)**1.5;
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_REDFLASH],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,falph*calph*alph,DTA_LegacyRenderStyle,STYLE_Add);
}
// player-owned trackers are drawn last
cti.Reinit();
while ( ct = SWWMQuickCombatTracker(cti.Next()) )
{
// this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing
if ( !projinit )
{
projinit = true;
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh);
}
// ignore unowned (can happen?)
if ( !ct.Owner ) continue;
// ignore if max health is zero (SOMEHOW can happen)
if ( ct.maxhealth <= 0 ) continue;
// ignore non-player trackers and voodoo dolls
if ( !ct.Owner.player || (ct.Owner.player.mo != ct.Owner) ) continue;
// ignore local player or camera
if ( (ct.Owner == CPlayer.mo) || (ct.Owner == cam) ) continue;
// ignore trackers not of this player
if ( ct.myplayer != CPlayer ) continue;
// ignore enemies if filtering friends
if ( onlyfriends && !ct.Owner.IsFriend(CPlayer.mo) ) continue;
// ignore trackers clearly outside of player view
Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight));
Vector3 tdir = level.Vec3Diff(viewpos,smpos);
if ( viewvec dot tdir < 0 ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1;
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
double fin = clamp(ct.fadein+fractic,0.,5.)/5.;
double fout = clamp(ct.lifespan-fractic,0.,25.)/25.;
double alph = fin*fout;
Vector2 barpos = vpos-(27,7);
Font fnt = swwm_bigtags?mSmallFontOutline:mTinyFontOutline;
int col = Font.CR_WHITE;
if ( teamplay )
{
int team = ct.Owner.player.GetTeam();
if ( team != -1 ) col = Font.FindFontColor(Teams[team].mName); // this works in practice because team names are the same as their text colors
if ( col == -1 ) col = Font.CR_WHITE;
}
Screen.DrawText(fnt,col,vpos.x-fnt.StringWidth(ct.mytag)/2,barpos.y-(fnt.GetHeight()+2),ct.mytag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
Screen.DrawTexture(EnemyBTex,false,barpos.x,barpos.y,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
double ht = clamp(ct.intp.GetValue(fractic),0,ct.maxhealth*100);
double hw = (ht*50.)/ct.maxhealth;
double ohw = hw;
if ( ct.Owner.bINVULNERABLE || (ct.Owner.player.cheats&(CF_GODMODE|CF_GODMODE2)) || ct.Owner.FindInventory("InvinciballPower") )
Screen.DrawTexture(EnemyHTex[1],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
else
{
Screen.DrawTexture(EnemyHTex[0],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
if ( ht > ct.maxhealth )
{
hw = (min(ht-ct.maxhealth,ct.maxhealth)*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[3],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
}
if ( ht > ct.maxhealth*2 )
{
hw = (min(ht-ct.maxhealth*2,ct.maxhealth*3)*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[4],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
}
if ( ht > ct.maxhealth*5 )
{
hw = (min(ht-ct.maxhealth*5,ct.maxhealth*5)*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[5],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw);
}
}
if ( ct.Owner.FindInventory("DivineSpriteEffect") )
{
double falph = clamp((ht-ct.maxhealth*10)/(ct.maxhealth*60.),0.,1.);
Screen.DrawTexture(EnemyHTex[6],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph*falph,DTA_LegacyRenderStyle,STYLE_Add);
}
else
{
ht = clamp(ct.intpl.GetValue(fractic),0,ct.maxhealth);
hw = (ht*50.)/ct.maxhealth;
Screen.DrawTexture(EnemyHTex[2],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowLeftF,ohw,DTA_WindowRightF,hw);
}
if ( ct.cummdamage <= 0 ) continue;
double calph = clamp(ct.cummspan-fractic,0.,20.)/20.;
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_RED],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,calph*alph);
if ( ct.cummflash <= 0 ) continue;
double falph = max((ct.cummflash-FracTic)/15.,0.)**1.5;
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_REDFLASH],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,falph*calph*alph,DTA_LegacyRenderStyle,STYLE_Add);
}
}
private void DrawNumbers( Vector3 viewvec, out bool projinit )
{
SWWMDamNum snum = hnd.damnums;
if ( !snum ) return;
do
{
// this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing
if ( !projinit )
{
projinit = true;
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh);
}
Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos);
if ( viewvec dot tdir < 0 ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs;
String tag = abs(snum.damage>=Actor.TELEFRAG_DAMAGE)?(snum.damage>0)?"-∞":"+∞":String.Format("%+d",-snum.damage);
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
Vector2 fo;
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));
Screen.DrawText(MiniHUDFontOutline,snum.tcolor,(vpos.x-fo.x)-(MiniHUDFontOutline.StringWidth(tag))/2,(vpos.y-fo.y)-(MiniHUDFontOutline.GetHeight())/2,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
while ( snum = snum.next );
}
private void DrawScores( Vector3 viewvec, out bool projinit )
{
SWWMScoreObj snum = hnd.scorenums;
if ( !snum ) return;
do
{
// this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing
if ( !projinit )
{
projinit = true;
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh);
}
Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos);
if ( viewvec dot tdir < 0 ) continue;
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1;
String tag = String.Format("%+d",snum.score);
double alph = clamp((snum.lifespan+fractic)/double(GameTicRate),0.,1.);
// score rises linearly
Vector2 fo = (0,snum.initialspan-(snum.lifespan-fractic));
Screen.DrawText(mTinyFontOutline,snum.tcolor,vpos.x-(fo.x+mTinyFontOutline.StringWidth(tag)/2.),vpos.y-(fo.y+(mTinyFontOutline.GetHeight()/2.)),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
// extra strings (if available)
fo.y += mTinyFontOutline.GetHeight();
for ( int i=0; i<snum.xstr.Size(); 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(mTinyFontOutline,snum.xtcolor[i],vpos.x-(fo.x+mTinyFontOutline.StringWidth(tag)/2.),vpos.y-(fo.y+(mTinyFontOutline.GetHeight()/2.)),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph);
fo.y += mTinyFontOutline.GetHeight();
}
}
while ( snum = snum.next );
}
private void DrawTarget()
{
// don't draw when dead or with automap open
if ( (CPlayer.health <= 0) || automapactive ) return;
bool projinit = false;
Vector3 viewvec = SWWMUtility.Vec3FromAngles(viewrot.x,viewrot.y);
// points of interest
if ( level.allmap && swwm_pois ) DrawInterest(viewvec,projinit);
// sensed items
DrawItemSense(viewvec,projinit);
// targetting array
if ( swwm_targeter ) DrawTrackers(viewvec,projinit);
// floating kill scores and others
if ( swwm_damnums ) DrawNumbers(viewvec,projinit);
if ( swwm_scorenums ) DrawScores(viewvec,projinit);
Screen.ClearClipRect();
}
}

View file

@ -0,0 +1,967 @@
// Minimap and stats
extend Class SWWMStatusBar
{
// quicksort (player scores)
private int partition_playerscore( Array<PlayerInfo> a, int l, int h )
{
PlayerInfo pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( pv.fragcount < a[j].fragcount )
{
i++;
PlayerInfo tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
PlayerInfo tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
return i+1;
}
private void qsort_playerscore( Array<PlayerInfo> a, int l, int h )
{
if ( l >= h ) return;
int p = partition_playerscore(a,l,h);
qsort_playerscore(a,l,p-1);
qsort_playerscore(a,p+1,h);
}
private void FlushTopStuff()
{
ScoreInter.Reset(SWWMCredits.Get(CPlayer));
}
private void TickTopStuffInterpolators()
{
ScoreInter.Update(SWWMCredits.Get(CPlayer));
// stats flashing
if ( level.killed_monsters > oldkills )
{
oldkills = level.killed_monsters;
killflash = gametic+25;
}
if ( level.found_items > olditems )
{
olditems = level.found_items;
itemflash = gametic+25;
}
if ( level.found_secrets > oldsecrets )
{
oldsecrets = level.found_secrets;
secretflash = gametic+25;
}
if ( level.total_monsters > oldtkills )
{
oldtkills = level.total_monsters;
tkillflash = gametic+25;
}
if ( level.total_items > oldtitems )
{
oldtitems = level.total_items;
titemflash = gametic+25;
}
if ( level.total_secrets > oldtsecrets )
{
oldtsecrets = level.total_secrets;
tsecretflash = gametic+25;
}
// purge expired key flashes
for ( int i=0; i<keyflash.Size(); i++ )
{
if ( keyflash[i].flashtime >= gametic ) continue;
keyflash.Delete(i--);
}
// minimap zoom interpolation
double desiredzoom = clamp(swwm_mm_zoom,.5,level.allmap?2.:1.);
if ( (minimapzoom != swwm_mm_zoom) || (oldminimapzoom != swwm_mm_zoom) )
{
oldminimapzoom = minimapzoom;
double diff = .1*(desiredzoom-minimapzoom);
minimapzoom += diff;
if ( abs(minimapzoom-desiredzoom) <= .01 )
minimapzoom = desiredzoom;
}
}
private void TickTopStuff()
{
// deathmatch stuff
if ( !deathmatch ) return;
if ( teamplay )
{
if ( teamactive.Size() != Teams.Size() ) teamactive.Resize(Teams.Size());
if ( teamscore.Size() != Teams.Size() ) teamscore.Resize(Teams.Size());
for ( int i=0; i<Teams.Size(); i++ )
{
teamactive[i] = false;
teamscore[i] = 0;
}
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] ) continue;
int team = players[i].GetTeam();
if ( team != -1 )
{
teamactive[team] = true;
teamscore[team] += players[i].fragcount;
}
}
return;
}
playercount = 0;
int highscore = int.min;
tiedscore = false;
rank = 1;
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] ) continue;
playercount++;
if ( players[i] == CPlayer ) continue;
if ( players[i].fragcount > CPlayer.fragcount )
rank += 1;
else if ( players[i].fragcount == CPlayer.fragcount )
tiedscore = true;
if ( players[i].fragcount > highscore )
highscore = players[i].fragcount;
}
if ( sortplayers.Size() != playercount ) sortplayers.Resize(playercount);
for ( int i=0, j=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] ) continue;
sortplayers[j++] = players[i];
}
// sort players by score
qsort_playerscore(sortplayers,0,playercount-1);
if ( playercount <= 1 ) highscore = CPlayer.fragcount;
lead = CPlayer.fragcount-highscore;
}
// minimap helper code
private void GetMinimapColors()
{
mm_colorset = swwm_mm_colorset;
switch ( mm_colorset )
{
case 1:
// gzdoom
mm_backcolor = am_backcolor;
mm_cdwallcolor = am_cdwallcolor;
mm_efwallcolor = am_efwallcolor;
mm_fdwallcolor = am_fdwallcolor;
mm_interlevelcolor = am_interlevelcolor;
mm_intralevelcolor = am_intralevelcolor;
mm_lockedcolor = am_lockedcolor;
mm_notseencolor = am_notseencolor;
mm_portalcolor = am_portalcolor;
mm_secretsectorcolor = am_secretsectorcolor;
mm_secretwallcolor = am_secretwallcolor;
mm_specialwallcolor = am_specialwallcolor;
mm_thingcolor = am_thingcolor;
mm_thingcolor_citem = am_thingcolor_citem;
mm_thingcolor_friend = am_thingcolor_friend;
mm_thingcolor_item = am_thingcolor_item;
mm_thingcolor_monster = am_thingcolor_monster;
mm_thingcolor_ncmonster = am_thingcolor_ncmonster;
mm_thingcolor_shootable = am_thingcolor;
mm_thingcolor_vipitem = am_unexploredsecretcolor;
mm_thingcolor_missile = am_specialwallcolor;
mm_tswallcolor = am_tswallcolor;
mm_unexploredsecretcolor = am_unexploredsecretcolor;
mm_wallcolor = am_wallcolor;
mm_yourcolor = am_yourcolor;
mm_displaylocks = true;
break;
case 2:
// doom
mm_backcolor = "00 00 00";
mm_cdwallcolor = "fc fc 00";
mm_efwallcolor = "bc 78 48";
mm_fdwallcolor = "bc 78 48";
mm_interlevelcolor = 0;
mm_intralevelcolor = 0;
mm_lockedcolor = "fc fc 00";
mm_notseencolor = "6c 6c 6c";
mm_portalcolor = "40 40 40";
mm_secretsectorcolor = 0;
mm_secretwallcolor = 0;
mm_specialwallcolor = 0;
mm_thingcolor = "74 fc 6c";
mm_thingcolor_citem = "74 fc 6c";
mm_thingcolor_friend = "74 fc 6c";
mm_thingcolor_item = "74 fc 6c";
mm_thingcolor_monster = "74 fc 6c";
mm_thingcolor_ncmonster = "74 fc 6c";
mm_thingcolor_shootable = "74 fc 6c";
mm_thingcolor_vipitem = "74 fc 6c";
mm_thingcolor_missile = "74 fc 6c";
mm_tswallcolor = "80 80 80";
mm_unexploredsecretcolor = 0;
mm_wallcolor = "fc 00 00";
mm_yourcolor = "ff ff ff";
mm_displaylocks = false;
break;
case 3:
// strife
mm_backcolor = "00 00 00";
mm_cdwallcolor = "77 73 73";
mm_efwallcolor = "37 3b 5b";
mm_fdwallcolor = "37 3b 5b";
mm_interlevelcolor = 0;
mm_intralevelcolor = 0;
mm_lockedcolor = "77 73 73";
mm_notseencolor = "6c 6c 6c";
mm_portalcolor = "40 40 40";
mm_secretsectorcolor = 0;
mm_secretwallcolor = 0;
mm_specialwallcolor = 0;
mm_thingcolor = "bb 3b 00";
mm_thingcolor_citem = "db ab 00";
mm_thingcolor_friend = "fc 00 00";
mm_thingcolor_item = "db ab 00";
mm_thingcolor_monster = "fc 00 00";
mm_thingcolor_ncmonster = "fc 00 00";
mm_thingcolor_shootable = "bb 3b 00";
mm_thingcolor_vipitem = "db ab 00";
mm_thingcolor_missile = "bb 3b 00";
mm_tswallcolor = "77 73 73";
mm_unexploredsecretcolor = 0;
mm_wallcolor = "c7 ce ce";
mm_yourcolor = "ef ef ef";
mm_displaylocks = false;
break;
case 4:
// raven
mm_backcolor = "6c 54 40";
mm_cdwallcolor = "67 3b 1f";
mm_efwallcolor = "d0 b0 85";
mm_fdwallcolor = "d0 b0 85";
mm_interlevelcolor = 0;
mm_intralevelcolor = 0;
mm_lockedcolor = "67 3b 1f";
mm_notseencolor = "00 00 00";
mm_portalcolor = "50 50 50";
mm_secretsectorcolor = 0;
mm_secretwallcolor = 0;
mm_specialwallcolor = 0;
mm_thingcolor = "ec ec ec";
mm_thingcolor_citem = "ec ec ec";
mm_thingcolor_friend = "ec ec ec";
mm_thingcolor_item = "ec ec ec";
mm_thingcolor_monster = "ec ec ec";
mm_thingcolor_ncmonster = "ec ec ec";
mm_thingcolor_shootable = "ec ec ec";
mm_thingcolor_vipitem = "ec ec ec";
mm_thingcolor_missile = "ec ec ec";
mm_tswallcolor = "58 5d 56";
mm_unexploredsecretcolor = 0;
mm_wallcolor = "4b 32 10";
mm_yourcolor = "ff ff ff";
mm_displaylocks = true;
break;
default:
// swwm
mm_backcolor = "10 10 10";
mm_cdwallcolor = "30 50 70";
mm_efwallcolor = "80 a0 c0";
mm_fdwallcolor = "50 70 90";
mm_interlevelcolor = "ff 00 60";
mm_intralevelcolor = "00 60 ff";
mm_lockedcolor = "00 90 80";
mm_notseencolor = "20 20 30";
mm_portalcolor = "40 30 20";
mm_secretsectorcolor = "80 00 ff";
mm_secretwallcolor = "60 40 80";
mm_specialwallcolor = "ff a0 00";
mm_thingcolor = "ff ff ff";
mm_thingcolor_citem = "00 ff ff";
mm_thingcolor_friend = "80 ff a0";
mm_thingcolor_item = "ff c0 00";
mm_thingcolor_monster = "ff 60 40";
mm_thingcolor_ncmonster = "a0 40 20";
mm_thingcolor_shootable = "ff a0 a0";
mm_thingcolor_vipitem = "80 60 ff";
mm_thingcolor_missile = "ff a0 20";
mm_tswallcolor = "30 20 40";
mm_unexploredsecretcolor = "40 00 80";
mm_wallcolor = "c0 e0 ff";
mm_yourcolor = "80 ff 00";
mm_displaylocks = true;
break;
}
}
private bool ShouldDisplaySpecial( int special )
{
// thanks graf/randi/whoever
switch ( special )
{
// the following have (max_args < 0)
// but we can't know this from zscript, so they're hardcoded here
case Polyobj_StartLine:
case Polyobj_ExplicitLine:
case Transfer_WallLight:
case Sector_Attach3dMidtex:
case ExtraFloor_LightOnly:
case Sector_CopyScroller:
case Scroll_Texture_Left:
case Scroll_Texture_Right:
case Scroll_Texture_Up:
case Scroll_Texture_Down:
case Plane_Copy:
case Line_SetIdentification:
case Line_SetPortal:
case Sector_Set3DFloor:
case Sector_SetContents:
case Plane_Align:
case Static_Init:
case Transfer_Heights:
case Transfer_FloorLight:
case Transfer_CeilingLight:
case Scroll_Texture_Model:
case Scroll_Texture_Offsets:
case PointPush_SetForce:
return false;
}
return true;
}
private bool CheckSectorAction( Sector s, out int special, bool useonly )
{
for ( Actor act=s.SecActTarget; act; act=act.tracer )
{
if ( (act.Health&(SectorAction.SECSPAC_Use|SectorAction.SECSPAC_UseWall) || !useonly)
&& act.special && !act.bFRIENDLY )
{
special = act.special;
return true;
}
}
return false;
}
private bool RealLineSpecial( Line l, out int special )
{
if ( special && l.activation&SPAC_PlayerActivate )
return true;
if ( CheckSectorAction(l.frontsector,special,!l.backsector) )
return true;
return (l.backsector && CheckSectorAction(l.backsector,special,false));
}
private bool ShowTriggerLine( Line l )
{
if ( am_showtriggerlines == 0 ) return false;
int special = l.special;
if ( !RealLineSpecial(l,special) ) return false;
if ( !ShouldDisplaySpecial(special) ) return false;
if ( special && (am_showtriggerlines >= 2) ) return true;
if ( !special || (special == Door_Open)
|| (special == Door_Close)
|| (special == Door_CloseWaitOpen)
|| (special == Door_Raise)
|| (special == Door_Animated)
|| (special == Generic_Door) )
return false;
return true;
}
private bool CmpFloorPlanes( Line l )
{
return (l.frontsector.floorplane.Normal == l.backsector.floorplane.Normal)
&& (l.frontsector.floorplane.D == l.backsector.floorplane.D);
}
private bool CmpCeilingPlanes( Line l )
{
return (l.frontsector.ceilingplane.Normal == l.backsector.ceilingplane.Normal)
&& (l.frontsector.ceilingplane.D == l.backsector.ceilingplane.D);
}
private int CheckSecret( Line l )
{
if ( !mm_secretsectorcolor || !mm_unexploredsecretcolor )
return 0;
if ( l.frontsector && (l.frontsector.flags&Sector.SECF_WASSECRET) )
{
if ( am_map_secrets && !(l.frontsector.flags&Sector.SECF_SECRET) ) return 1;
if ( (am_map_secrets == 2) && !(l.flags&Line.ML_SECRET) ) return 2;
}
if ( l.backsector && (l.backsector.flags&Sector.SECF_WASSECRET) )
{
if ( am_map_secrets && !(l.backsector.flags&Sector.SECF_SECRET) ) return 1;
if ( (am_map_secrets == 2) && !(l.flags&Line.ML_SECRET) ) return 2;
}
return 0;
}
private bool CheckFFBoundary( Line l )
{
int fcount = l.frontsector.Get3DFloorCount(),
bcount = l.backsector.Get3DFloorCount();
// no 3D floors, no boundary
if ( !fcount && !bcount ) return false;
int fvalid = 0, bvalid = 0;
for ( int i=0; i<fcount; i++ )
{
F3DFloor ff = l.frontsector.Get3DFloor(i);
if ( (ff.flags&F3DFloor.FF_THISINSIDE) || !(ff.flags&F3DFloor.FF_EXISTS) || (ff.alpha == 0) )
continue;
fvalid++;
}
for ( int i=0; i<bcount; i++ )
{
F3DFloor ff = l.backsector.Get3DFloor(i);
if ( (ff.flags&F3DFloor.FF_THISINSIDE) || !(ff.flags&F3DFloor.FF_EXISTS) || (ff.alpha == 0) )
continue;
bvalid++;
}
// unmatched counts, there's definitely a boundary
if ( fvalid != bvalid ) return true;
for ( int i=0; i<fcount; i++ )
{
F3DFloor ff = l.frontsector.Get3DFloor(i);
if ( (ff.flags&F3DFloor.FF_THISINSIDE) || !(ff.flags&F3DFloor.FF_EXISTS) || (ff.alpha == 0) )
continue;
bool found = false;
for ( int j=0; j<bcount; j++ )
{
F3DFloor ff2 = l.backsector.Get3DFloor(i);
if ( (ff2.flags&F3DFloor.FF_THISINSIDE) || !(ff2.flags&F3DFloor.FF_EXISTS) || (ff2.alpha == 0) )
continue;
if ( (ff.model != ff2.model) || (ff.flags != ff2.flags) )
continue;
found = true;
break;
}
// at least one mismatch between sectors, there's a boundary for sure
if ( !found ) return true;
}
// no boundary here
return false;
}
private void DrawMapLines( Vector2 basepos )
{
double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic);
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic);
Sector csec = players[consoleplayer].Camera.CurSector;
int thisgroup = csec.portalgroup;
int numgroups = level.GetPortalGroupCount();
// draw overlays first
for ( int p=numgroups-1; p >= -1; p-- )
{
if ( p == thisgroup ) continue;
foreach ( l : level.lines )
{
if ( !(l.flags&Line.ML_MAPPED) && !level.allmap && !am_cheat ) continue;
if ( (l.flags&Line.ML_DONTDRAW) && ((am_cheat == 0) || (am_cheat >= 4)) )
continue;
Vector2 rv1 = l.v1.p-cpos, rv2 = l.v2.p-cpos;
int lgroup;
if ( l.sidedef[0].flags&Side.WALLF_POLYOBJ ) lgroup = level.PointInSector(l.v1.p+l.delta/2.).portalgroup;
else lgroup = l.frontsector.portalgroup;
bool isportal = ((numgroups>0)&&(lgroup!=thisgroup));
if ( lgroup == p )
{
// portal displacement
Vector2 pofs = level.GetDisplacement(lgroup,thisgroup);
rv1 += pofs;
rv2 += pofs;
}
else if ( (p != -1) || (lgroup != thisgroup) )
continue;
Vector2 mid = (rv1+rv2)/2.;
Vector2 siz = (abs(rv1.x-rv2.x),abs(rv1.y-rv2.y))/2.;
if ( (((siz.x+zoomview)-abs(mid.x)) <= 0) || (((siz.y+zoomview)-abs(mid.y)) <= 0) )
continue;
// flip Y
rv1.y *= -1;
rv2.y *= -1;
// rotate by view
rv1 = Actor.RotateVector(rv1,ViewRot.x-90);
rv2 = Actor.RotateVector(rv2,ViewRot.x-90);
// clip to frame
bool visible;
[visible, rv1, rv2] = SWWMUtility.LiangBarsky((-1,-1)*zoomclip,(1,1)*zoomclip,rv1,rv2);
if ( !visible ) continue;
// scale to minimap frame
rv1 *= (HALFMAPSIZE/zoomclip)*hs;
rv2 *= (HALFMAPSIZE/zoomclip)*hs;
// offset to minimap center
rv1 += basepos;
rv2 += basepos;
// get the line color
Color col = mm_wallcolor;
if ( (l.flags&Line.ML_MAPPED) || am_cheat )
{
int secwit = CheckSecret(l);
int lock = SWWMUtility.GetLineLock(l);
if ( secwit == 1 ) col = mm_secretsectorcolor;
else if ( secwit == 2 ) col = mm_unexploredsecretcolor;
else if ( l.flags&Line.ML_SECRET )
{
if ( am_cheat && l.backsector && mm_secretwallcolor )
col = mm_secretwallcolor;
else col = mm_wallcolor;
}
else if ( mm_interlevelcolor
&& ((l.special == Exit_Normal)
|| (l.special == Exit_Secret)
|| (l.special == Teleport_NewMap)
|| (l.special == Teleport_EndGame)) )
col = mm_interlevelcolor;
else if ( mm_intralevelcolor &&
(l.activation&SPAC_PlayerActivate)
&& ((l.special == Teleport)
|| (l.special == Teleport_NoFog)
|| (l.special == Teleport_ZombieChanger)
|| (l.special == Teleport_Line)) )
col = mm_intralevelcolor;
else if ( mm_displaylocks
&& (lock > 0) && (lock < 256) )
{
let lcol = SWWMUtility.GetLockColor(lock);
if ( lcol ) col = lcol;
else col = mm_lockedcolor;
}
else if ( mm_specialwallcolor && ShowTriggerLine(l) )
col = mm_specialwallcolor;
else if ( l.frontsector && l.backsector )
{
if ( !CmpFloorPlanes(l) ) col = mm_fdwallcolor;
else if ( !CmpCeilingPlanes(l) ) col = mm_cdwallcolor;
else if ( CheckFFBoundary(l) ) col = mm_efwallcolor;
else
{
if ( (am_cheat == 0) || (am_cheat >= 4) )
continue;
col = mm_tswallcolor;
}
}
}
else col = mm_notseencolor;
// draw the line
if ( isportal )
{
col = Color((col.r+mm_portalcolor.r*7)/8,(col.g+mm_portalcolor.g*7)/8,(col.b+mm_portalcolor.b*7)/8);
Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs*.25),col);
}
else Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs*.5),col);
}
}
}
private void DrawMapMarkers( Vector2 basepos )
{
double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic);
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic);
Sector csec = players[consoleplayer].Camera.CurSector;
if ( !mi ) mi = ThinkerIterator.Create("MapMarker",Thinker.STAT_MAPMARKER);
else mi.Reinit();
MapMarker m;
while ( m = MapMarker(mi.Next()) )
{
if ( m.bDORMANT ) continue;
if ( m.args[1] && !(m.CurSector.moreflags&Sector.SECMF_DRAWN) ) continue;
TextureID tx;
if ( m.picnum.IsValid() ) tx = m.picnum;
else tx = m.CurState.GetSpriteTexture(1);
Vector2 sz = TexMan.GetScaledSize(tx);
Vector2 scl;
// seems to match automap scaling somewhat
if ( m.Args[2] ) scl = (m.Scale/zoomlevel)*.15;
else scl = m.Scale*.5;
sz.x *= scl.x;
sz.y *= scl.y;
double radius = max(sz.x,sz.y); // naive, I know
if ( m.args[0] )
{
// oh bother, this will be dicks
let ai = level.CreateActorIterator(m.args[0]);
Actor a;
while ( a = ai.Next() )
{
Vector2 rv = a.pos.xy-cpos;
bool isportal = false;
Sector sec = level.PointInSector(a.pos.xy);
if ( sec.portalgroup != csec.portalgroup )
{
isportal = true;
// portal displacement
rv += level.GetDisplacement(sec.portalgroup,csec.portalgroup);
}
if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) )
continue;
// flip Y
rv.y *= -1;
// rotate by view
rv = Actor.RotateVector(rv,ViewRot.x-90);
// scale to minimap frame
rv *= (HALFMAPSIZE/zoomclip)*hs;
// offset to minimap center
rv += basepos;
// draw
Screen.DrawTexture(tx,false,rv.x,rv.y,DTA_ColorOverlay,isportal?Color(128,mm_portalcolor.r,mm_portalcolor.g,mm_portalcolor.b):Color(0,0,0,0),DTA_ScaleX,hs*scl.x,DTA_ScaleY,hs*scl.y,DTA_LegacyRenderStyle,m.GetRenderStyle(),DTA_Alpha,m.Alpha,DTA_FillColor,m.FillColor,DTA_TranslationIndex,m.Translation);
}
ai.Destroy();
continue;
}
Vector2 rv = m.pos.xy-cpos;
bool isportal = false;
Sector sec = level.PointInSector(m.pos.xy);
if ( sec.portalgroup != csec.portalgroup )
{
isportal = true;
// portal displacement
rv += level.GetDisplacement(sec.portalgroup,csec.portalgroup);
}
if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) )
continue;
// flip Y
rv.y *= -1;
// rotate by view
rv = Actor.RotateVector(rv,ViewRot.x-90);
// scale to minimap frame
rv *= (HALFMAPSIZE/zoomclip)*hs;
// offset to minimap center
rv += basepos;
// draw
Screen.DrawTexture(tx,false,rv.x,rv.y,DTA_ColorOverlay,isportal?Color(128,mm_portalcolor.r,mm_portalcolor.g,mm_portalcolor.b):Color(0,0,0,0),DTA_ScaleX,hs*scl.x,DTA_ScaleY,hs*scl.y,DTA_LegacyRenderStyle,m.GetRenderStyle(),DTA_Alpha,m.Alpha,DTA_FillColor,m.FillColor,DTA_TranslationIndex,m.Translation);
}
}
private void DrawMapThings( Vector2 basepos )
{
double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic);
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic);
Sector csec = players[consoleplayer].Camera.CurSector;
bool drawmissiles = swwm_mm_missiles;
for ( SWWMSimpleTracker t=hnd.strackers; t; t=t.next )
{
if ( !drawmissiles && t.ismissile ) continue;
if ( level.allmap && (t.target is 'Key') ) continue; // don't draw keys over the actual markers they have
Color col = mm_thingcolor;
bool isitem = false;
bool plainactor = false;
Vector2 pos;
double angle;
double radius;
if ( t.target )
{
pos = SWWMUtility.LerpVector2(t.target.prev.xy,t.target.pos.xy,FracTic);
angle = t.target.angle;
radius = t.isybeam?(t.target.speed*cos(t.target.pitch-90)):t.isbeam?(t.target.speed*cos(t.target.pitch)):t.target.radius;
}
else
{
pos = t.pos.xy;
angle = t.angle;
radius = t.radius;
}
if ( t.isitem )
{
if ( t.vipitem ) col = mm_thingcolor_vipitem;
else if ( t.countitem ) col = mm_thingcolor_citem;
else col = mm_thingcolor_item;
isitem = true;
}
else if ( t.isplayer ) col = t.playercol;
else if ( t.friendly ) col = mm_thingcolor_friend;
else if ( t.countkill ) col = mm_thingcolor_monster;
else if ( t.ismonster ) col = mm_thingcolor_ncmonster;
else if ( t.ismissile ) col = mm_thingcolor_missile;
else
{
if ( t.vipitem ) col = mm_thingcolor_vipitem; // chanceboxes
else if ( t.shootable ) col = mm_thingcolor_shootable;
plainactor = true;
}
int mtime = GameTicRate;
if ( level.allmap && !t.expired && t.target ) mtime += GameTicRate*3;
Vector2 rv = pos-cpos;
bool isportal = false;
Sector sec = level.PointInSector(pos);
if ( sec.portalgroup != csec.portalgroup )
{
isportal = true;
// portal displacement
rv += level.GetDisplacement(sec.portalgroup,csec.portalgroup);
// and blend in the color too
col = Color((col.r+mm_portalcolor.r*7)/8,(col.g+mm_portalcolor.g*7)/8,(col.b+mm_portalcolor.b*7)/8);
}
if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) )
continue;
Vector2 tv[4];
int nidx;
if ( t.isbeam )
{
// oriented line
nidx = 2;
tv[0] = rv;
tv[1] = rv+Actor.RotateVector((radius,0),angle);
}
else if ( isitem )
{
// rhombus
nidx = 4;
double crad = min(radius,10);
for ( int i=0; i<4; i++ )
tv[i] = rv+Actor.RotateVector((crad,0),i*90);
}
else if ( plainactor )
{
// aabb box
nidx = 4;
tv[0] = rv+(-radius,-radius);
tv[1] = rv+(radius,-radius);
tv[2] = rv+(radius,radius);
tv[3] = rv+(-radius,radius);
}
else
{
// oriented triangle
nidx = 3;
tv[0] = rv+Actor.RotateVector((radius,0),angle);
tv[1] = rv+Actor.RotateVector((-radius*.5,radius*.7),angle);
tv[2] = rv+Actor.RotateVector((-radius*.5,-radius*.7),angle);
}
// flip Y
for ( int j=0; j<nidx; j++ ) tv[j].y *= -1;
// rotate by view
for ( int j=0; j<nidx; j++ ) tv[j] = Actor.RotateVector(tv[j],ViewRot.x-90);
bool visible, drawn;
Vector2 x0, x1;
// clip to frame
for ( int j=0; j<nidx; j++ )
{
[visible, x0, x1] = SWWMUtility.LiangBarsky((-1,-1)*zoomclip,(1,1)*zoomclip,tv[j],tv[(j+1)%nidx]);
if ( visible )
{
// scale to minimap frame
x0 *= (HALFMAPSIZE/zoomclip)*hs;
x1 *= (HALFMAPSIZE/zoomclip)*hs;
// offset to minimap center
x0 += basepos;
x1 += basepos;
// draw the line
if ( isportal ) Screen.DrawThickLine(int(x0.x),int(x0.y),int(x1.x),int(x1.y),max(1.,hs*.25),col,int(t.smoothalpha*255));
else Screen.DrawThickLine(int(x0.x),int(x0.y),int(x1.x),int(x1.y),max(1.,hs*.5),col,int(t.smoothalpha*255));
drawn = true;
}
}
if ( drawn )
{
double alph = clamp(((t.lastupdate+mtime)-level.maptime)/double(GameTicRate),0.,1.);
if ( t.isbeam ) alph *= t.target?(t.target.alpha/t.target.default.alpha):0.;
double theta = clamp(5.*FrameTime,0.,1.);
t.smoothalpha = SWWMUtility.Lerp(t.smoothalpha,alph,theta);
}
else t.smoothalpha = 0.;
}
}
private String OrdinalStr( int val, int gender )
{
String lstr = "SWWM_PLACE"..val.."_GENDER"..gender;
String str = StringTable.Localize("$"..lstr);
if ( str != lstr ) return str;
return StringTable.Localize("$SWWM_PLACE"..val);
}
private void DrawTopStuff()
{
int xx, yy = margin;
// obviously, don't draw the minimap if the automap is open
if ( !automapactive && swwm_mm_enable )
{
GetMinimapColors();
xx = int(ss.x-(margin+(HALFMAPSIZE+2)*2));
Screen.DrawTexture(MiniBox,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Vector2 basemappos = (xx+HALFMAPSIZE+2,yy+HALFMAPSIZE+2);
Screen.Dim(mm_backcolor,1.,int((basemappos.x-HALFMAPSIZE)*hs),int((basemappos.y-HALFMAPSIZE)*hs),int(HALFMAPSIZE*2*hs),int(HALFMAPSIZE*2*hs));
Screen.SetClipRect(int((basemappos.x-HALFMAPSIZE)*hs),int((basemappos.y-HALFMAPSIZE)*hs),int(HALFMAPSIZE*2*hs),int(HALFMAPSIZE*2*hs));
// draw dat stuff
DrawMapLines(basemappos*hs);
DrawMapThings(basemappos*hs);
DrawMapMarkers(basemappos*hs);
// finally, draw the player arrow
Vector2 tv[3];
tv[0] = (0,-4);
tv[1] = (-3,2);
tv[2] = (3,2);
for ( int i=0; i<3; i++ ) tv[i] = (tv[i]+basemappos)*hs;
for ( int i=0; i<3; i++ ) Screen.DrawThickLine(int(tv[i].x),int(tv[i].y),int(tv[(i+1)%3].x),int(tv[(i+1)%3].y),max(1.,hs*.5),mm_yourcolor);
Screen.ClearClipRect();
yy += ((HALFMAPSIZE+2)*2)+5;
}
// draw stats and timer when automap is open
int fstats = swwm_forcestats;
if ( automapactive || (fstats > 0) )
{
xx = int(ss.x-(margin+2));
String str;
if ( automapactive || (fstats > 1) )
{
int label = am_showmaplabel;
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);
Screen.DrawText(mSmallFontOutline,tclabel,xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += mSmallFontOutline.GetHeight()+4;
}
if ( (level.total_monsters > 0) && am_showmonsters && !deathmatch )
{
str = String.Format("\c"..tclabel_s.."K \c-%d\c"..tcextra_s.."/\c-%d",level.killed_monsters,level.total_monsters);
Screen.DrawText(MiniHUDFontOutline,(level.killed_monsters>=level.total_monsters)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( killflash && (gametic < killflash) )
{
double alph = max((killflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d/%d",level.killed_monsters,level.total_monsters);
int slashpos = str.IndexOf("/");
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
if ( tkillflash && (gametic < tkillflash) )
{
double alph = max((tkillflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d",level.total_monsters);
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
yy += MiniHUDFontOutline.GetHeight()+2;
}
if ( (level.total_items > 0) && am_showitems && !deathmatch )
{
str = String.Format("\c"..tclabel_s.."I \c-%d\c"..tcextra_s.."/\c-%d",level.found_items,level.total_items);
Screen.DrawText(MiniHUDFontOutline,(level.found_items>=level.total_items)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( itemflash && (gametic < itemflash) )
{
double alph = max((itemflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d/%d",level.found_items,level.total_items);
int slashpos = str.IndexOf("/");
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
if ( titemflash && (gametic < titemflash) )
{
double alph = max((titemflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d",level.total_items);
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
yy += MiniHUDFontOutline.GetHeight()+2;
}
if ( (level.total_secrets > 0) && am_showsecrets && !deathmatch )
{
str = String.Format("\c"..tclabel_s.."S \c-%d\c"..tcextra_s.."/\c-%d",level.found_secrets,level.total_secrets);
Screen.DrawText(MiniHUDFontOutline,(level.found_secrets>=level.total_secrets)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( secretflash && (gametic < secretflash) )
{
double alph = max((secretflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d/%d",level.found_secrets,level.total_secrets);
int slashpos = str.IndexOf("/");
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
if ( tsecretflash && (gametic < tsecretflash) )
{
double alph = max((tsecretflash-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%d",level.total_secrets);
Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
}
yy += MiniHUDFontOutline.GetHeight()+2;
}
int sec;
if ( am_showtime )
{
sec = Thinker.Tics2Seconds(level.maptime);
str = String.Format("\c"..tclabel_s.."T \c-%02d\c"..tcextra_s..":\c-%02d\c"..tcextra_s..":\c-%02d",sec/3600,(sec%3600)/60,sec%60);
Screen.DrawText(MiniHUDFontOutline,((level.sucktime>0)&&(sec>=(level.sucktime*3600)))?tcsucks:((level.partime>0)&&(sec<=level.partime))?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += MiniHUDFontOutline.GetHeight()+2;
}
// don't show total time if it's equal to map time
if ( am_showtotaltime && (level.totaltime != level.maptime) )
{
sec = Thinker.Tics2Seconds(level.totaltime);
str = String.Format("\c"..tclabel_s.."TT \c-%02d\c"..tcextra_s..":\c-%02d\c"..tcextra_s..":\c-%02d",sec/3600,(sec%3600)/60,sec%60);
Screen.DrawText(MiniHUDFontOutline,tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += MiniHUDFontOutline.GetHeight()+2;
}
yy += 3;
}
if ( deathmatch )
{
yy += 9;
if ( playercount <= 1 ) return;
xx = int(ss.x-(margin+2));
String str;
if ( teamplay )
{
// draw team scores
for ( int i=0; i<teamscore.Size(); i++ )
{
if ( !teamactive[i] ) continue;
str = String.Format("\c[MiniDemoBlue]%s \c-%d",Teams[i].mName,teamscore[i]);
Screen.DrawText(mSmallFontOutline,mhudfontcol[MCR_WHITE],xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += mSmallFont.GetHeight();
}
}
else
{
// draw rank and spread like in UT
if ( tiedscore ) str = String.Format("\cy%s \c[MiniRed]%d\c[MiniSayaHUD]/\c[MiniRed]%d\c-",StringTable.Localize("$SWWM_DMRANK"),rank,playercount);
else str = String.Format("\c[MiniDemoBlue]%s \c-%d\c[MiniIbukiHUD]/\c-%d",StringTable.Localize("$SWWM_DMRANK"),rank,playercount);
Screen.DrawText(mSmallFontOutline,mhudfontcol[MCR_WHITE],xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += mSmallFont.GetHeight();
if ( lead > 0 ) str = String.Format("\c[MiniDemoBlue]%s \c-+%d",StringTable.Localize("$SWWM_DMSPREAD"),lead);
else str = String.Format("\c[MiniDemoBlue]%s \c-%d",StringTable.Localize("$SWWM_DMSPREAD"),lead);
Screen.DrawText(mSmallFontOutline,mhudfontcol[MCR_RED],xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += mSmallFont.GetHeight()+3;
// draw top 3 players
for ( int i=0; i<min(3,playercount); i++ )
{
if ( sortplayers[i].fragcount < 0 ) str = String.Format("\c[MiniDemoBlue]#%d: \c-%s\c- \c[MiniSayaHUD](\c[MiniRed]%d\c[MiniSayaHUD])\c-",i+1,sortplayers[i].GetUserName(),sortplayers[i].fragcount);
else str = String.Format("\c[MiniDemoBlue]%s: \c-%s\c- \c[MiniIbukiHUD](\c[MiniWhite]%d\c[MiniIbukiHUD])\c-",OrdinalStr(i+1,sortplayers[i].GetGender()),sortplayers[i].GetUserName(),sortplayers[i].fragcount);
Screen.DrawText(mSmallFontOutline,mhudfontcol[MCR_WHITE],xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += mSmallFont.GetHeight();
}
}
return;
}
// draw key icons
Vector2 keypos = (ss.x-(margin+2),yy);
int colc = 0;
double colh = 0;
int n = Key.GetKeyTypeCount();
Array<Key> klist;
for ( int i=0; i<n; i++ )
{
let k = Key(CPlayer.mo.FindInventory(Key.GetKeyType(i)));
if ( !k || !k.Icon.IsValid() ) continue;
klist.Push(k);
}
int maxcolc = (gameinfo.gametype&GAME_DOOMCHEX)?6:4;
foreach ( k:klist )
{
// Hexen key icons aren't meant for this kind of HUD
TextureID icon = (k is 'HexenKey')?k.SpawnState.GetSpriteTexture(0):k.Icon;
Vector2 siz = TexMan.GetScaledSize(icon);
Screen.DrawTexture(icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_TopLeft,true);
foreach ( f:keyflash )
{
if ( !(k is f.got) ) continue;
if ( !f.flashtime || (gametic >= f.flashtime) ) continue;
double alph = max((f.flashtime-(gametic+FracTic))/25.,0.)**1.5;
Screen.DrawTexture(icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_TopLeft,true,DTA_ColorOverlay,0xFFFFC040,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph);
break;
}
keypos.x -= siz.x+2;
colh = max(colh,siz.y);
if ( ++colc == maxcolc )
{
keypos.x = ss.x-(margin+2);
keypos.y += colh+2;
colh = colc = 0;
}
}
}
override void DrawAutomapHUD( double ticFrac )
{
// do nothing, DrawTopStuff handles this
}
}

View file

@ -0,0 +1,295 @@
// Weapons and ammo
extend Class SWWMStatusBar
{
private void TickWeaponInterpolators()
{
// ammo updates
for ( int i=0; i<18; i++ )
{
let a = SWWMAmmo(CPlayer.mo.FindInventory(AmmoSlots[i]));
int amt = 0;
int maxamt = 0;
if ( a )
{
amt = a.Amount;
maxamt = a.MaxAmount;
if ( a.MagAmmoType )
{
let m = MagAmmo(CPlayer.mo.FindInventory(a.MagAmmoType));
if ( m )
{
amt *= m.ClipSize;
amt += m.Amount;
maxamt *= m.ClipSize;
}
}
}
else
{
let a = GetDefaultByType(AmmoSlots[i]);
maxamt = a.MaxAmount;
if ( a.MagAmmoType )
{
let m = GetDefaultByType(a.MagAmmoType);
maxamt *= m.ClipSize;
}
}
if ( (amt > AmmoOldAmounts[i]) && (AmmoOldAmounts[i] != int.min) )
AmmoFlash[i] = gametic+25;
AmmoOldAmounts[i] = amt;
if ( (maxamt > AmmoOldMaxAmounts[i]) && (AmmoOldMaxAmounts[i] != int.min) )
AmmoMaxFlash[i] = gametic+25;
AmmoOldMaxAmounts[i] = maxamt;
}
}
private void TickWeapons()
{
// let weapons update their own interpolators
for ( Inventory i=CPlayer.mo.inv; i; i=i.inv )
{
if ( !(i is 'SWWMWeapon') ) continue;
SWWMWeapon(i).HudTick();
}
}
// hello??? why is this function clearscope???
override void ReceivedWeapon( Weapon weapn )
{
Super.ReceivedWeapon(weapn);
int dummy, slot;
[dummy, slot] = players[consoleplayer].weapons.LocateWeapon(weapn.GetClass());
EventHandler.SendNetworkEvent("swwmweaponreceive",slot,consoleplayer);
}
private void DrawWeapons()
{
Screen.DrawTexture(WeaponTex,false,ss.x-(margin+80),ss.y-(margin+10),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
double xx = ss.x-(margin+78), yy = ss.y-(margin+8);
for ( int i=1; i<=10; i++,xx+=8 )
{
int ncolor = mhudfontcol[MCR_WHITE];
if ( !CPlayer.HasWeaponsInSlot(i%10) )
{
Screen.DrawText(MiniHUDFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(128,0,0,0));
continue;
}
bool selected = false;
bool dummy;
int slot;
SWWMGesture hasgesture = null;
SWWMItemGesture hasitemgesture = null;
if ( CPlayer.PendingWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.PendingWeapon);
else if ( CPlayer.ReadyWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.ReadyWeapon);
if ( CPlayer.PendingWeapon is 'SWWMItemGesture' ) hasitemgesture = SWWMItemGesture(CPlayer.PendingWeapon);
else if ( CPlayer.ReadyWeapon is 'SWWMItemGesture' ) hasitemgesture = SWWMItemGesture(CPlayer.ReadyWeapon);
if ( hasgesture && hasgesture.formerweapon )
{
[dummy, slot] = CPlayer.weapons.LocateWeapon(hasgesture.formerweapon.GetClass());
if ( slot == (i%10) ) selected = true;
}
else if ( hasitemgesture && hasitemgesture.gest.formerweapon )
{
[dummy, slot] = CPlayer.weapons.LocateWeapon(hasitemgesture.gest.formerweapon.GetClass());
if ( slot == (i%10) ) selected = true;
}
else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) )
{
[dummy, slot] = CPlayer.weapons.LocateWeapon(CPlayer.PendingWeapon.GetClass());
if ( slot == (i%10) ) selected = true;
}
else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon )
{
[dummy, slot] = CPlayer.weapons.LocateWeapon(CPlayer.ReadyWeapon.GetClass());
if ( slot == (i%10) ) selected = true;
}
if ( selected ) ncolor = mhudfontcol[MCR_BRASS];
else
{
bool hasammo = (i==1);
for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv )
{
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).bAMMO_OPTIONAL) || (Weapon(inv).Ammo2 && ((Weapon(inv).Ammo2.Amount > 0) || Weapon(inv).bALT_AMMO_OPTIONAL))) )
hasammo = true;
}
if ( !hasammo ) ncolor = mhudfontcol[MCR_RED];
}
Screen.DrawText(MiniHUDFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
int f = hnd.WeaponFlash[i%10];
if ( f && (gametic < f) )
{
double alph = max((f-(gametic+FracTic))/25.,0.)**1.5;
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_LegacyRenderStyle,STYLE_Add);
}
}
xx = ss.x-(margin+54);
yy = ss.y-(margin+14);
bool bDrewAmmo = false;
bool checkowned = !swwm_hudallammo;
Array<SWWMWeapon> OwnedWeapons;
if ( checkowned ) for ( Inventory i=CPlayer.mo.inv; i; i=i.inv )
{
if ( !(i is 'SWWMWeapon') ) continue;
OwnedWeapons.Push(SWWMWeapon(i));
}
String str;
for ( int i=17; i>=0; i-- )
{
let a = AmmoSlots[i];
// check if owned
if ( checkowned )
{
bool owned = false;
foreach ( w:OwnedWeapons )
{
if ( w.UsesAmmo(a) )
owned = true;
}
if ( !owned ) continue;
}
if ( !bDrewAmmo )
{
Screen.DrawTexture(AmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
bDrewAmmo = true;
}
yy -= 6;
Screen.DrawTexture(AmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 2;
let cur = SWWMAmmo(CPlayer.mo.FindInventory(a));
int amt, amax;
if ( !cur )
{
amt = 0;
amax = GetDefaultByType(a).MaxAmount;
let def = GetDefaultByType(a);
if ( def.MagAmmoType )
{
let mag = MagAmmo(CPlayer.mo.FindInventory(def.MagAmmoType));
if ( mag ) // theoretically can't happen, but still check for it
{
amt = mag.Amount;
amax = amax*mag.ClipSize+mag.MaxAmount;
}
else
{
let defmag = GetDefaultByType(def.MagAmmoType);
amax = amax*defmag.ClipSize+defmag.MaxAmount;
}
}
}
else
{
amt = cur.Amount;
amax = cur.MaxAmount;
if ( cur.MagAmmoType )
{
let mag = MagAmmo(CPlayer.mo.FindInventory(cur.MagAmmoType));
// theoretically this should never be null, but nevertheless...
if ( mag )
{
amt = amt*mag.ClipSize+mag.Amount;
amax = amax*mag.ClipSize+mag.MaxAmount;
}
else
{
let def = GetDefaultByType(cur.MagAmmoType);
amt = amt*def.ClipSize;
amax = amax*def.ClipSize+def.MaxAmount;
}
}
}
bool used = false;
if ( CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon is 'SWWMWeapon') )
used = SWWMWeapon(CPlayer.ReadyWeapon).UsesAmmo(a);
int scol = mhudfontcol[used?MCR_BRASS:MCR_WHITE];
int ncolor = (amt>0)?scol:mhudfontcol[MCR_RED];
int dcnt1 = 2-int(Log10(clamp(amt,1,999)));
int dcnt2 = 2-int(Log10(clamp(amax,1,999)));
for ( int j=0; j<dcnt1; j++ ) Screen.DrawChar(MiniHUDFont,ncolor,xx+20+j*4,yy,0x30,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(160,0,0,0));
for ( int j=0; j<dcnt2; j++ ) Screen.DrawChar(MiniHUDFont,scol,xx+38+j*4,yy,0x30,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(160,0,0,0));
str = AmmoNames[i];
Screen.DrawText(MiniHUDFont,scol,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = "/";
Screen.DrawText(MiniHUDFont,scol,xx+32,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(80,0,0,0));
str = String.Format("%3d",clamp(amt,0,999));
Screen.DrawText(MiniHUDFont,ncolor,xx+20,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = String.Format("%3d",clamp(amax,0,999));
Screen.DrawText(MiniHUDFont,scol,xx+38,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
let f = AmmoFlash[i];
if ( f && (gametic < f) )
{
double alph = max((f-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%3d",clamp(amt,0,999));
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],xx+20,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_LegacyRenderStyle,STYLE_Add);
}
f = AmmoMaxFlash[i];
if ( f && (gametic < f) )
{
double alph = max((f-(gametic+FracTic))/25.,0.)**1.5;
str = String.Format("%3d",clamp(amax,0,999));
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],xx+38,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_LegacyRenderStyle,STYLE_Add);
}
xx -= 2;
}
if ( bDrewAmmo )
{
yy -= 2;
Screen.DrawTexture(AmmoTex[0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
// score
String sstr = String.Format("%09d",int(ScoreInter.GetValue()));
xx = ss.x-(margin+48);
if ( bDrewAmmo ) yy -= 12;
else yy = ss.y-(margin+22);
Screen.DrawTexture(ScoreTex,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 10;
yy += 2;
Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_BRASS],xx,yy,sstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
int bx = bDrewAmmo?56:50;
// ammo display
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(CPlayer.ReadyWeapon).DrawWeapon(FracTic,ss.x-(margin+bx),ss.y-(margin+12),hs,ss);
else if ( CPlayer.ReadyWeapon )
{
// generic display
double xx = ss.x-(margin+bx+2), yy = ss.y-(margin+22);
String str;
int len;
if ( CPlayer.ReadyWeapon.Ammo2 && (CPlayer.ReadyWeapon.Ammo2 != CPlayer.ReadyWeapon.Ammo1) )
{
str = String.Format("%d",CPlayer.ReadyWeapon.Ammo2.Amount);
len = str.Length();
yy -= 12;
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
for ( int i=0; i<len; i++ )
{
xx -= 4;
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
Screen.DrawTexture(GenericAmmoTex[0],false,xx-2,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(MiniHUDFont,mhudfontcol[(CPlayer.ReadyWeapon.Ammo2.Amount<=0)?MCR_RED:MCR_BRASS],xx,yy+2,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 12;
}
xx = ss.x-(margin+bx+2);
if ( CPlayer.ReadyWeapon.Ammo1 )
{
str = String.Format("%d",CPlayer.ReadyWeapon.Ammo1.Amount);
len = str.Length();
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
for ( int i=0; i<len; i++ )
{
xx -= 4;
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
Screen.DrawTexture(GenericAmmoTex[0],false,xx-2,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(MiniHUDFont,mhudfontcol[(CPlayer.ReadyWeapon.Ammo1.Amount<=0)?MCR_RED:MCR_BRASS],xx,yy+2,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
}
}

View file

@ -93,6 +93,7 @@ Class SWWMStaticHandler : StaticEventHandler
}
}
SWWMHandler.ClearAllShaders();
EventHandler.SendInterfaceEvent(consoleplayer,"swwmflushhud");
// force a reset of the minimap zoom in case it's set beyond safe levels
double mmz = swwm_mm_zoom;
if ( level.allmap && (mmz >= 2.) ) mmz = 2.;
@ -209,6 +210,11 @@ Class SWWMStaticHandler : StaticEventHandler
if ( (gamestate != GS_LEVEL) || !swwm_showmaptitle ) return;
StatusBar.AttachMessage(new("DSMapTitle").Init(),-7777);
}
else if ( e.Name ~== "swwmflushud" )
{
if ( !(StatusBar is 'SWWMStatusBar') ) return;
SWWMStatusBar(StatusBar).Flush();
}
else if ( e.Name ~== "swwmaprcheck" )
{
if ( gamestate != GS_LEVEL ) return;