457 lines
17 KiB
Text
457 lines
17 KiB
Text
// stats stab
|
|
|
|
Class DemolitionistStatsTab : DemolitionistMenuTab
|
|
{
|
|
DemolitionistMenuList lists[4];
|
|
int section;
|
|
String sname[4];
|
|
int lwidth;
|
|
SWWMStats stats;
|
|
int ofs[4], maxofs[4];
|
|
double smofs[4];
|
|
bool drag;
|
|
LevelStat clstat;
|
|
|
|
override DemolitionistMenuTab Init( DemolitionistMenu master )
|
|
{
|
|
title = "$SWWM_STATTAB";
|
|
section = 0;
|
|
lwidth = 0;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
sname[i] = StringTable.Localize("$SWWM_STATTAB"..i);
|
|
lwidth = max(lwidth,smallfont.StringWidth(sname[i]));
|
|
lists[i] = new("DemolitionistMenuList");
|
|
lists[i].selected = -1;
|
|
}
|
|
lwidth += 16; // account for padding of 8px on each side
|
|
stats = Demolitionist(players[consoleplayer].mo)?Demolitionist(players[consoleplayer].mo).mystats:null;
|
|
if ( !stats ) return Super.Init(master);
|
|
// because these types of stats don't actually change while the menu is open, we can initialize their lists ONLY ONCE here
|
|
if ( swwm_uniqstats )
|
|
{
|
|
for ( int i=0; i<stats.lstats.Size(); i++ )
|
|
{
|
|
if ( stats.lstats[i].mapname ~== level.mapname ) continue;
|
|
for ( int j=0; j<lists[2].items.Size(); j++ )
|
|
{
|
|
if ( !(DemolitionistMenuMapStatItem(lists[2].items[j]).s.mapname ~== stats.lstats[i].mapname) ) continue;
|
|
lists[2].items[j].Destroy();
|
|
lists[2].items.Delete(j);
|
|
j--;
|
|
}
|
|
lists[2].items.Push(new("DemolitionistMenuMapStatItem").Init(master,stats.lstats[i]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lists[2].items.Resize(stats.lstats.Size());
|
|
for ( int i=0; i<stats.lstats.Size(); i++ )
|
|
lists[2].items[i] = new("DemolitionistMenuMapStatItem").Init(master,stats.lstats[i]);
|
|
}
|
|
clstat = new("LevelStat");
|
|
clstat.hub = !!(level.clusterflags&level.CLUSTER_HUB);
|
|
clstat.mapname = level.mapname;
|
|
clstat.levelname = level.levelname;
|
|
int iof = clstat.levelname.IndexOf(" - by: ");
|
|
if ( iof != -1 ) clstat.levelname.Truncate(iof);
|
|
clstat.par = level.partime;
|
|
clstat.suck = level.sucktime;
|
|
lists[2].items.Push(new("DemolitionistMenuMapStatItem").Init(master,clstat));
|
|
lists[2].selected = lists[2].items.Size()-1; // so it shows the "current level" indicator
|
|
for ( int i=0; i<lists[2].items.Size(); i++ )
|
|
lists[2].items[i].ypos = i*16;
|
|
return Super.Init(master);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
for ( int i=0; i<4; i++ )
|
|
lists[i].Destroy();
|
|
}
|
|
override void OnSelect()
|
|
{
|
|
section = master.shnd.menustate.At("LastStatSection").ToInt();
|
|
smofs[section] = ofs[section];
|
|
}
|
|
override void OnDeselect()
|
|
{
|
|
master.shnd.menustate.Insert("LastStatSection",String.Format("%d",section));
|
|
smofs[section] = ofs[section];
|
|
}
|
|
|
|
private bool CmpMonsterKill( MonsterKill a, MonsterKill b )
|
|
{
|
|
if ( a.kills == b.kills )
|
|
{
|
|
// sort by name instead
|
|
String taga, tagb;
|
|
taga = GetDefaultByType(a.m).GetTag();
|
|
tagb = GetDefaultByType(b.m).GetTag();
|
|
// beautify if there's no tag
|
|
if ( taga == FallbackTag )
|
|
{
|
|
taga = a.m.GetClassName();
|
|
SWWMUtility.BeautifyClassName(taga);
|
|
}
|
|
if ( tagb == FallbackTag )
|
|
{
|
|
tagb = a.m.GetClassName();
|
|
SWWMUtility.BeautifyClassName(tagb);
|
|
}
|
|
return taga > tagb;
|
|
}
|
|
return a.kills < b.kills;
|
|
}
|
|
|
|
private int partition_mstats( Array<DemolitionistMenuListItem> a, int l, int h )
|
|
{
|
|
DemolitionistMenuListItem pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpMonsterKill(DemolitionistMenuKillItem(pv).s,DemolitionistMenuKillItem(a[j]).s) )
|
|
{
|
|
i++;
|
|
DemolitionistMenuListItem tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
DemolitionistMenuListItem tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_mstats( Array<DemolitionistMenuListItem> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_mstats(a,l,h);
|
|
qsort_mstats(a,l,p-1);
|
|
qsort_mstats(a,p+1,h);
|
|
}
|
|
|
|
override void Ticker()
|
|
{
|
|
if ( !stats ) return;
|
|
// update list contents
|
|
String str;
|
|
int w;
|
|
switch ( section )
|
|
{
|
|
case 0:
|
|
if ( lists[0].items.Size() == 0 ) // allocate first
|
|
{
|
|
for ( int i=0; i<31; i++ )
|
|
{
|
|
let li = new("DemolitionistMenuListItem").Init(master,"");
|
|
li.ypos = i*16;
|
|
lists[0].items.Push(li);
|
|
}
|
|
}
|
|
maxofs[0] = int(16*lists[0].items.Size()-(master.ws.y-46));
|
|
// oof
|
|
int thour = ((level.totaltime-stats.lastspawn)/(3600*GameTicRate));
|
|
int tmin = ((level.totaltime-stats.lastspawn)/(60*GameTicRate))%60;
|
|
int tsec = ((level.totaltime-stats.lastspawn)/GameTicRate)%60;
|
|
str = String.Format("\cx%s\c-%02d\cu:\c-%02d\cu:\c-%02d",StringTable.Localize("$SWWM_STATUPTIME"),thour,tmin,tsec);
|
|
lists[0].items[0].label = str;
|
|
if ( stats.grounddist > 32000. ) str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATONFOOT"),stats.grounddist/32000.,StringTable.Localize("$SWWM_UNIT_KILOMETER"));
|
|
else str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATONFOOT"),stats.grounddist/32.,StringTable.Localize("$SWWM_UNIT_METER"));
|
|
lists[0].items[1].label = str;
|
|
if ( stats.airdist > 32000. ) str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATFLIGHT"),stats.airdist/32000.,StringTable.Localize("$SWWM_UNIT_KILOMETER"));
|
|
else str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATFLIGHT"),stats.airdist/32.,StringTable.Localize("$SWWM_UNIT_METER"));
|
|
lists[0].items[2].label = str;
|
|
if ( stats.swimdist > 32000. ) str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATSWIM"),stats.swimdist/32000.,StringTable.Localize("$SWWM_UNIT_KILOMETER"));
|
|
else str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATSWIM"),stats.swimdist/32.,StringTable.Localize("$SWWM_UNIT_METER"));
|
|
lists[0].items[3].label = str;
|
|
if ( stats.teledist > 32000. ) str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATTELE"),stats.teledist/32000.,StringTable.Localize("$SWWM_UNIT_KILOMETER"));
|
|
else str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATTELE"),stats.teledist/32.,StringTable.Localize("$SWWM_UNIT_METER"));
|
|
lists[0].items[4].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATBOOST"),stats.boostcount);
|
|
lists[0].items[5].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDASH"),stats.dashcount);
|
|
lists[0].items[6].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSTOMP"),stats.stompcount);
|
|
lists[0].items[7].label = str;
|
|
str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATFUEL"),stats.fuelusage,StringTable.Localize("$SWWM_UNIT_LITER"));
|
|
lists[0].items[8].label = str;
|
|
str = String.Format("\cx%s\c-%g\cu%s\c-",StringTable.Localize("$SWWM_STATSPEED"),(stats.topspeed*3600.*GameTicRate)/32000.,StringTable.Localize("$SWWM_UNIT_KPH"));
|
|
lists[0].items[9].label = str;
|
|
thour = (stats.airtime/(3600*GameTicRate));
|
|
tmin = (stats.airtime/(60*GameTicRate))%60;
|
|
tsec = (stats.airtime/GameTicRate)%60;
|
|
str = String.Format("\cx%s\c-%02d\cu:\c-%02d\cu:\c-%02d",StringTable.Localize("$SWWM_STATAIRTIME"),thour,tmin,tsec);
|
|
lists[0].items[10].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATPARRY"),stats.parries);
|
|
lists[0].items[11].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATPPARRY"),stats.pparries);
|
|
lists[0].items[12].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATWPONCH"),stats.wponch);
|
|
lists[0].items[13].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATBUSTS"),stats.busts);
|
|
lists[0].items[14].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATBUTTS"),stats.buttslams);
|
|
lists[0].items[15].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATPATS"),stats.pats);
|
|
lists[0].items[16].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATKISS"),stats.smooch);
|
|
lists[0].items[17].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATFRIENDS"),stats.befriend);
|
|
lists[0].items[18].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATITEMS"),stats.items);
|
|
lists[0].items[19].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSECRETS"),stats.secrets);
|
|
lists[0].items[20].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATKILLS"),stats.kills);
|
|
lists[0].items[21].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDEATHS"),stats.deaths);
|
|
lists[0].items[22].label = str;
|
|
if ( stats.hdamagedealt > 0 ) str = str = String.Format("\cx%s\c-%d%09d",StringTable.Localize("$SWWM_STATDDEALT"),stats.hdamagedealt,stats.damagedealt);
|
|
else str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDDEALT"),stats.damagedealt);
|
|
lists[0].items[23].label = str;
|
|
if ( stats.hdamagetaken > 0 ) str = String.Format("\cx%s\c-%d%09d",StringTable.Localize("$SWWM_STATDTAKEN"),stats.hdamagetaken,stats.damagetaken);
|
|
else str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDTAKEN"),stats.damagetaken);
|
|
lists[0].items[24].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATTDEALT"),stats.topdealt);
|
|
lists[0].items[25].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATTTAKEN"),stats.toptaken);
|
|
lists[0].items[26].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATMKILL"),stats.mkill);
|
|
lists[0].items[27].label = str;
|
|
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSKILL"),stats.skill);
|
|
lists[0].items[28].label = str;
|
|
str = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_STATFAVWEAP"));
|
|
if ( stats.favweapon == -1 ) str = str.."N/A";
|
|
else if ( stats.wstats[stats.favweapon].w == 'SWWMWeapon' ) str = str..StringTable.Localize("$SWWM_YOURSELF");
|
|
else if ( stats.wstats[stats.favweapon].w == 'SWWMGesture' ) str = str..StringTable.Localize("$SWWM_DOKIDOKI");
|
|
else if ( stats.wstats[stats.favweapon].w == 'SWWMItemGesture' ) str = str..StringTable.Localize("$T_FROGGY");
|
|
else if ( stats.wstats[stats.favweapon].w == 'Weapon' ) str = str..StringTable.Localize("$SWWM_GRAVKILL");
|
|
else if ( stats.wstats[stats.favweapon].w == 'DoomWeapon' ) str = str..StringTable.Localize("$SWWM_PARRYKILL");
|
|
else
|
|
{
|
|
let def = GetDefaultByType(stats.wstats[stats.favweapon].w);
|
|
str = str..def.GetTag();
|
|
}
|
|
lists[0].items[29].label = str;
|
|
if ( stats.hhiscore > 0 ) str = String.Format("\cx%s\cu¥\c-%d%09d",StringTable.Localize("$SWWM_STATHISCORE"),stats.hhiscore,stats.hiscore);
|
|
else str = String.Format("\cx%s\cu¥\c-%09d",StringTable.Localize("$SWWM_STATHISCORE"),stats.hiscore);
|
|
lists[0].items[30].label = str;
|
|
break;
|
|
case 1:
|
|
// theoretically we can assume that the monster stats list will never shrink in the middle of gameplay, only grow
|
|
// also the array only ever has elements pushed, never inserted in-between
|
|
// if this somehow breaks, I don't know what the hell can do that
|
|
if ( lists[1].items.Size() < stats.mstats.Size() )
|
|
{
|
|
int oldindex = lists[1].items.Size();
|
|
lists[1].items.Resize(stats.mstats.Size());
|
|
for ( int i=oldindex; i<lists[1].items.Size(); i++ )
|
|
lists[1].items[i] = new("DemolitionistMenuKillItem").Init(master,stats.mstats[i]);
|
|
}
|
|
maxofs[1] = int(16*lists[1].items.Size()-(master.ws.y-46));
|
|
// update widths
|
|
w = int(master.ws.x-(18+lwidth));
|
|
if ( maxofs[1] > 0 ) w -= 8;
|
|
for ( int i=0; i<lists[1].items.Size(); i++ )
|
|
{
|
|
let k = DemolitionistMenuKillItem(lists[1].items[i]);
|
|
k.width = w;
|
|
}
|
|
// sort
|
|
qsort_mstats(lists[1].items,0,lists[1].items.Size()-1);
|
|
// update y positions after sorting
|
|
for ( int i=0; i<lists[1].items.Size(); i++ )
|
|
lists[1].items[i].ypos = i*16;
|
|
break;
|
|
case 2:
|
|
maxofs[2] = int(16*lists[2].items.Size()-(master.ws.y-46));
|
|
// update current stats
|
|
clstat.kcount = level.killed_monsters;
|
|
clstat.ktotal = level.total_monsters;
|
|
clstat.icount = level.found_items;
|
|
clstat.itotal = level.total_items;
|
|
clstat.scount = level.found_secrets;
|
|
clstat.stotal = level.total_secrets;
|
|
clstat.time = level.maptime;
|
|
// update widths
|
|
w = int(master.ws.x-(18+lwidth));
|
|
if ( maxofs[2] > 0 ) w -= 8;
|
|
int len[4], maxlen[4];
|
|
for ( int i=0; i<4; i++ ) maxlen[i] = 0;
|
|
for ( int i=0; i<lists[2].items.Size(); i++ )
|
|
{
|
|
let l = DemolitionistMenuMapStatItem(lists[2].items[i]);
|
|
l.width = w;
|
|
// and calculate "max lengths"
|
|
int sec = Thinker.Tics2Seconds(l.s.time);
|
|
str = String.Format("T %02d:%02d:%02d",sec/3600,(sec%3600)/60,sec%60);
|
|
len[0] = smallfont2.StringWidth(str);
|
|
if ( len[0] > maxlen[0] ) maxlen[0] = len[0];
|
|
str = String.Format("S %d/%d",l.s.scount,l.s.stotal);
|
|
len[1] = smallfont2.StringWidth(str);
|
|
if ( len[1] > maxlen[1] ) maxlen[1] = len[1];
|
|
str = String.Format("I %d/%d",l.s.icount,l.s.itotal);
|
|
len[2] = smallfont2.StringWidth(str);
|
|
if ( len[2] > maxlen[2] ) maxlen[2] = len[2];
|
|
str = String.Format("K %d/%d",l.s.kcount,l.s.ktotal);
|
|
len[3] = smallfont2.StringWidth(str);
|
|
if ( len[3] > maxlen[3] ) maxlen[3] = len[3];
|
|
}
|
|
// second pass to propagate the "max lengths"
|
|
for ( int i=0; i<lists[2].items.Size(); i++ )
|
|
{
|
|
let l = DemolitionistMenuMapStatItem(lists[2].items[i]);
|
|
for ( int j=0; j<4; j++ )
|
|
l.maxlen[j] = maxlen[j];
|
|
}
|
|
break;
|
|
}
|
|
// update smooth scroll
|
|
smofs[section] = (smofs[section]*.6)+(ofs[section]*.4);
|
|
if ( abs(smofs[section]-ofs[section]) < (1./master.hs) ) smofs[section] = ofs[section];
|
|
// tick the current list
|
|
lists[section].Ticker();
|
|
}
|
|
// called when sending a scroll input
|
|
// returns true if the position actually changed
|
|
// speed: how many pixels to move (either back or forward)
|
|
bool Scroll( int speed )
|
|
{
|
|
if ( maxofs[section] <= 0 ) return false;
|
|
int oldofs = ofs[section];
|
|
ofs[section] = clamp(ofs[section]+speed,0,maxofs[section]);
|
|
return (ofs[section] != oldofs);
|
|
}
|
|
// called when clicking on our scrollbar
|
|
// returns true if the position actually changed
|
|
// y: relative click position
|
|
bool SetOffset( double y )
|
|
{
|
|
if ( maxofs[section] <= 0 ) return false;
|
|
int oldofs = ofs[section];
|
|
ofs[section] = clamp(int(round((y-20.5)/((master.ws.y-41.)/maxofs[section]))),0,maxofs[section]);
|
|
return (ofs[section] != oldofs);
|
|
}
|
|
override void MenuInput( int key )
|
|
{
|
|
switch ( key )
|
|
{
|
|
case MK_LEFT:
|
|
master.MenuSound("menu/demoscroll");
|
|
smofs[section] = ofs[section];
|
|
section--;
|
|
if ( section < 0 ) section = 3;
|
|
smofs[section] = ofs[section];
|
|
break;
|
|
case MK_RIGHT:
|
|
master.MenuSound("menu/demoscroll");
|
|
smofs[section] = ofs[section];
|
|
section++;
|
|
if ( section > 3 ) section = 0;
|
|
smofs[section] = ofs[section];
|
|
break;
|
|
case MK_DOWN:
|
|
if ( Scroll(16) ) master.MenuSound("menu/demoscroll");
|
|
break;
|
|
case MK_UP:
|
|
if ( Scroll(-16) ) master.MenuSound("menu/demoscroll");
|
|
break;
|
|
}
|
|
}
|
|
override void MouseInput( Vector2 pos, int btn )
|
|
{
|
|
// global events
|
|
switch ( btn )
|
|
{
|
|
case MB_DRAG:
|
|
if ( drag ) SetOffset(pos.y);
|
|
break;
|
|
case MB_RELEASE:
|
|
drag = false;
|
|
break;
|
|
}
|
|
// mouse on left side
|
|
if ( pos.x < lwidth )
|
|
{
|
|
switch ( btn )
|
|
{
|
|
case MB_LEFT:
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
if ( pos.x < 9 ) continue;
|
|
if ( pos.x > 9+smallfont.StringWidth(sname[i]) ) continue;
|
|
if ( pos.y < 23+16*i ) continue;
|
|
if ( pos.y > 36+16*i ) continue;
|
|
if ( section != i )
|
|
{
|
|
master.MenuSound("menu/demoscroll");
|
|
smofs[section] = ofs[section];
|
|
section = i;
|
|
smofs[section] = ofs[section];
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MB_WHEELUP:
|
|
MenuInput(MK_LEFT);
|
|
break;
|
|
case MB_WHEELDOWN:
|
|
MenuInput(MK_RIGHT);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
switch ( btn )
|
|
{
|
|
case MB_LEFT:
|
|
// see if we're clicking the scrollbar (if it exists)
|
|
if ( (maxofs[section] > 0) && (pos.x > (master.ws.x-8)) )
|
|
{
|
|
SetOffset(pos.y);
|
|
master.MenuSound("menu/demoscroll");
|
|
drag = true;
|
|
break;
|
|
}
|
|
case MB_WHEELUP:
|
|
if ( Scroll(-8) ) master.MenuSound("menu/demoscroll");
|
|
break;
|
|
case MB_WHEELDOWN:
|
|
if ( Scroll(8) ) master.MenuSound("menu/demoscroll");
|
|
break;
|
|
}
|
|
}
|
|
override void Drawer()
|
|
{
|
|
if ( !stats ) return;
|
|
double xx = 9;
|
|
double yy = 23;
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
Screen.DrawText(smallfont,(i==section)?Font.CR_FIRE:Font.CR_WHITE,master.origin.x+xx,master.origin.y+yy,sname[i],DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
|
|
yy += 16;
|
|
}
|
|
master.DrawVSeparator(lwidth,14,master.ws.y-28);
|
|
if ( section == 3 )
|
|
{
|
|
// TODO achievement drawer has different margins
|
|
}
|
|
else
|
|
{
|
|
xx = lwidth+9;
|
|
yy = 23;
|
|
int cliptop = int((master.origin.y+23)*master.hs);
|
|
int clipbottom = int((master.origin.y+master.ws.y-23)*master.hs);
|
|
int clipleft = int((master.origin.x+lwidth+9)*master.hs);
|
|
int clipright = int((master.origin.x+master.ws.x-9)*master.hs);
|
|
lists[section].Drawer((xx,yy-smofs[section]),cliptop,clipbottom,clipleft,clipright);
|
|
if ( maxofs[section] > 0 )
|
|
{
|
|
xx = master.ws.x-8;
|
|
master.DrawVSeparator(xx,14,master.ws.y-28);
|
|
xx += 2;
|
|
yy = floor(smofs[section]*((master.ws.y-39)/maxofs[section]))+14;
|
|
Screen.DrawText(smallfont,Font.CR_FIRE,master.origin.x+xx,master.origin.y+yy,"▮",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
|
|
}
|
|
}
|
|
}
|
|
}
|