swwmgz_m/zscript/swwm_menu.zsc
Marisa Kirisame af1df2e18d Allow selling excess weapons/powerups.
Change of plans for one DLC weapon choice.
Various small fixes and tweaks.
Doubled price of Ynykron, since it was too cheap.
Fixed Candygun spares not being picked up in coop.
Add option to toggle menu fuzz, for streamers concerned about bitrate.
Add MAP07 enemies to the vanilla boss enhancer.
2020-05-19 14:30:35 +02:00

2394 lines
80 KiB
Text

// internal "knowledge base" and more
Class SWWMKnowledgeBaseMenu : GenericMenu
{
enum EDemoTab
{
TAB_MISSION = 0,
TAB_STATS,
TAB_INVENTORY,
TAB_KEYS,
TAB_LIBRARY,
TAB_STORE,
TAB_TRADING,
TAB_CHAT,
TAB_SECRET,
TAB_HELP
};
TextureID MainWindow, TabSeparator, WindowSeparator, WindowSeparatorH,
FancyBg, EasterEgg, LoreSeparator, LoreSeparatorW;
transient CVar lang, fuzz;
transient Font TewiFont, MPlusFont;
int curtab, oldtab;
// for scrolling
bool sub;
int sel0, sel1, sel2;
int ofs0, ofs1, ofs2; // usually equal to above, except when using mouse input
int drag; // when dragging with the mouse, which scroller to affect (1 = ofs0 and so on)
// stats
SWWMStats stats;
// inventory lists
Array<Inventory> invlist;
// lore stuff
SWWMLoreLibrary lorelib;
Array<SWWMLore> lorelist;
int oldloresiz;
// store stuff
Array<Class<Inventory> > storelist;
Array<int> storeunits;
// trading
SWWMTradeHistory tradelib;
Array<int> playerlist;
// chat history total line count (includes breaks)
int chatlines;
// temporary bottom messages, such as "not enough money"
String tmsg;
int tmsgtic;
// menu keybind
int ikey[2];
String mkey[2];
// color for chat
CVar ccol, tcol;
// for checks (duh)
Class<Inventory> lastuse;
int lastuseamt;
int checkuse;
int checkdrop;
int checksend;
// seeeeecret
int kcode;
// crimey clock stuff
int c_year, c_month, c_day, c_hour, c_minute;
// mouse stuff
Vector2 curmouse;
bool isrclick;
// returns MPlus if we're playing in Japanese, otherwise returns the requested font
Font LangFont( Font req )
{
if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]);
if ( lang.GetString() ~== "jp" ) return MPlusFont;
return req;
}
override void Init( Menu parent )
{
Super.Init(parent);
if ( (gamestate != GS_LEVEL) || (players[consoleplayer].Health <= 0) )
{
// can't open this menu outside of the game or if dead
Close();
return;
}
TewiFont = Font.GetFont('TewiShaded');
MPlusFont = Font.GetFont('MPlusShaded');
FancyBg = TexMan.CheckForTexture("graphics/tempbg.png",TexMan.Type_MiscPatch);
MainWindow = TexMan.CheckForTexture("graphics/KBase/MainWindow.png",TexMan.Type_MiscPatch);
TabSeparator = TexMan.CheckForTexture("graphics/KBase/TabSeparator.png",TexMan.Type_MiscPatch);
WindowSeparator = TexMan.CheckForTexture("graphics/KBase/WindowSeparator.png",TexMan.Type_MiscPatch);
WindowSeparatorH = TexMan.CheckForTexture("graphics/KBase/WindowSeparatorH.png",TexMan.Type_MiscPatch);
EasterEgg = TexMan.CheckForTexture("graphics/KBase/Drawing.png",TexMan.Type_MiscPatch);
LoreSeparator = TexMan.CheckForTexture("graphics/KBase/LibraryTabSeparator.png",TexMan.Type_MiscPatch);
LoreSeparatorW = TexMan.CheckForTexture("graphics/KBase/LibraryTabSeparatorJP.png",TexMan.Type_MiscPatch);
curtab = CVar.GetCVar('swwm_lasttab',players[consoleplayer]).GetInt();
int maxtab = multiplayer?TAB_CHAT:TAB_STORE;
if ( (curtab < TAB_MISSION) || (curtab > maxtab) ) curtab = TAB_MISSION;
if ( curtab == TAB_LIBRARY ) sel1 = CVar.GetCVar('swwm_lastloretab',players[consoleplayer]).GetInt();
MenuSound("menu/demoopen");
[ikey[0], ikey[1]] = Bindings.GetKeysForCommand("openmenu SWWMKnowledgeBaseMenu");
mkey[0] = Bindings.NameKeys(ikey[0],0);
mkey[1] = Bindings.NameKeys(ikey[1],0);
ccol = CVar.GetCVar("msg3color",players[consoleplayer]);
tcol = CVar.GetCVar("msg4color",players[consoleplayer]);
lorelib = SWWMLoreLibrary.Find(players[consoleplayer]);
oldloresiz = lorelib.ent.Size();
tradelib = SWWMTradeHistory.Find(players[consoleplayer]);
stats = SWWMStats.Find(players[consoleplayer]);
tmsg = "$SWWM_MAINCONTROLS";
tmsgtic = gametic+70;
if ( gameinfo.gametype&GAME_Heretic )
{
c_year = 2171;
c_month = 3;
c_day = 9;
c_hour = 9;
c_minute = 41;
}
else if ( gameinfo.gametype&GAME_Hexen )
{
c_year = 2171;
c_month = 4;
c_day = 24;
c_hour = 16;
c_minute = 41;
}
else if ( gameinfo.gametype&GAME_Strife )
{
c_year = 2173;
c_month = 7;
c_day = 12;
c_hour = 11;
c_minute = 26;
}
else // Doom
{
c_year = 2148;
c_month = 5;
c_day = 5;
c_hour = 12;
c_minute = 27;
}
}
// please don't look at this
private String CrimeTime()
{
static const int days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
bool leap_year;
int y = c_year, m = c_month, d = c_day, h = c_hour, mn = c_minute;
int addtime = level.totaltime/Thinker.TICRATE;
while ( addtime > 0 )
{
leap_year = (!(y%4) && ((y%100) || !(y%400)));
if ( addtime >= 86400 )
{
addtime -= 86400;
d++;
int md = days_in_month[m];
if ( leap_year && (m == 1) ) md++;
if ( d >= md )
{
d = 0;
m++;
if ( m > 11 )
{
m = 0;
y++;
}
}
}
else if ( addtime >= 3600 )
{
addtime -= 3600;
h++;
if ( h > 23 )
{
h = 0;
d++;
int md = days_in_month[m];
if ( leap_year && (m == 1) ) md++;
if ( d >= md )
{
d = 0;
m++;
if ( m > 11 )
{
m = 0;
y++;
}
}
}
}
else if ( addtime >= 60 )
{
addtime -= 60;
mn++;
if ( mn > 59 )
{
mn = 0;
h++;
if ( h > 23 )
{
h = 0;
d++;
int md = days_in_month[m];
if ( leap_year && (m == 1) ) md++;
if ( d >= md )
{
d = 0;
m++;
if ( m > 11 )
{
m = 0;
y++;
}
}
}
}
}
else
{
// we finished counting
addtime = 0;
}
}
return String.Format("%04d-%02d-%02d %02d:%02d",y,m+1,d+1,h,mn);
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
Font fnt = LangFont(TewiFont);
switch ( kcode )
{
case 0:
case 1:
if ( mkey == MKEY_UP ) kcode++;
else kcode = 0;
break;
case 2:
case 3:
if ( mkey == MKEY_DOWN ) kcode++;
else kcode = 0;
break;
case 4:
case 6:
if ( mkey == MKEY_LEFT ) kcode++;
else kcode = 0;
break;
case 5:
case 7:
if ( mkey == MKEY_RIGHT ) kcode++;
else kcode = 0;
break;
case 10:
if ( mkey == MKEY_ENTER )
{
MenuSound("misc/secret");
curtab = TAB_SECRET;
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
}
default:
kcode = 0;
break;
}
int maxtab = multiplayer?TAB_CHAT:TAB_STORE;
switch ( mkey )
{
case MKEY_BACK:
MenuSound("menu/democlose");
Close();
return true;
case MKEY_PAGEUP:
MenuSound("menu/demotab");
if ( (curtab <= TAB_MISSION) || (curtab > maxtab) ) curtab = maxtab;
else curtab--;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
playerlist.Clear();
return true;
case MKEY_PAGEDOWN:
MenuSound("menu/demotab");
if ( curtab < maxtab ) curtab++;
else curtab = TAB_MISSION;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
playerlist.Clear();
return true;
case MKEY_DOWN:
if ( curtab == TAB_HELP )
{
String str = StringTable.Localize("$SWWM_HELPTXT");
if ( multiplayer ) str = str..StringTable.Localize("$SWWM_HELPTXT_MP");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
if ( (l.Count() > 28) && (sel0 < l.Count()-28) )
{
MenuSound("menu/demoscroll");
sel0++;
}
}
else if ( curtab == TAB_MISSION )
{
String str = StringTable.Localize("$SWWM_MISSION_NONE");
if ( gameinfo.gametype&GAME_Doom ) str = StringTable.Localize("$SWWM_MISSION_DOOM");
else if ( gameinfo.gametype&GAME_Heretic ) str = StringTable.Localize("$SWWM_MISSION_HERETIC");
else if ( gameinfo.gametype&GAME_Hexen ) str = StringTable.Localize("$SWWM_MISSION_HEXEN");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
if ( (l.Count() > 28) && (sel0 < l.Count()-28) )
{
MenuSound("menu/demoscroll");
ofs0 = ++sel0;
}
}
else if ( (curtab == TAB_CHAT) && (StatusBar is 'SWWMStatusBar') && (sel0 > 0) )
{
MenuSound("menu/demoscroll");
ofs0 = --sel0;
}
else if ( (curtab == TAB_LIBRARY) && (lorelist.Size() > 1) )
{
if ( sub )
{
String str = StringTable.Localize(lorelist[sel0].text);
int ofs = (lang.GetString()~=="jp")?212:132;
if ( lorelist.Size() > 26 ) ofs += 8;
BrokenLines l = fnt.BreakLines(str,635-ofs);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,626-ofs);
if ( (l.Count() > 28) && (sel2 < l.Count()-28) )
{
MenuSound("menu/demoscroll");
ofs2 = ++sel2;
}
}
else
{
MenuSound("menu/demoscroll");
if ( sel0 >= lorelist.Size()-1 ) ofs0 = sel0 = 0;
else
{
sel0++;
// update ofs so selection stays on-screen
int ofs = max(ofs0-26,0);
if ( sel0 < ofs ) ofs0 = sel0+26;
else if ( sel0 > ofs+26 ) ofs0 = sel0;
}
}
}
else if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS) || ((curtab == TAB_TRADING) && sub && (sel0 != -1))) && (invlist.Size() > 1) )
{
MenuSound("menu/demoscroll");
ofs0 = ++sel0;
if ( sel0 >= invlist.Size() ) ofs0 = sel0 = 0;
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 1) )
{
MenuSound("menu/demoscroll");
ofs0 = ++sel0;
if ( sel0 >= storelist.Size() ) ofs0 = sel0 = 0;
}
else if ( curtab == TAB_TRADING )
{
if ( !sub && (playerlist.Size() > 1) )
{
// scroll through player list
MenuSound("menu/demoscroll");
ofs0 = ++sel0;
if ( sel0 >= playerlist.Size() ) ofs0 = sel0 = 0;
}
else if ( sub && (sel0 == -1) && (sel1 < tradelib.ent.Size()-28) )
{
// scroll through trading history
MenuSound("menu/demoscroll");
ofs1 = ++sel1;
}
}
return true;
case MKEY_UP:
if ( (curtab == TAB_HELP) && (sel0 > 0) )
{
MenuSound("menu/demoscroll");
ofs0 = --sel0;
}
else if ( (curtab == TAB_MISSION) && (sel0 > 0) )
{
MenuSound("menu/demoscroll");
ofs0 = --sel0;
}
else if ( (curtab == TAB_CHAT) && (StatusBar is 'SWWMStatusBar') && (sel0 < SWWMStatusBar(StatusBar).FullHistory.Size()-1) )
{
MenuSound("menu/demoscroll");
ofs0 = ++sel0;
}
else if ( (curtab == TAB_LIBRARY) && (lorelist.Size() > 1) )
{
if ( sub )
{
if ( sel2 > 0 )
{
MenuSound("menu/demoscroll");
ofs2 = --sel2;
}
}
else
{
MenuSound("menu/demoscroll");
if ( sel0 <= 0 ) ofs0 = sel0 = lorelist.Size()-1;
else
{
sel0--;
// update ofs so selection stays on-screen
int ofs = max(ofs0-26,0);
if ( sel0 < ofs ) ofs0 = sel0+26;
else if ( sel0 > ofs+26 ) ofs0 = sel0;
}
}
}
else if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS) || ((curtab == TAB_TRADING) && sub && (sel0 != -1))) && (invlist.Size() > 1) )
{
MenuSound("menu/demoscroll");
ofs0 = --sel0;
if ( sel0 < 0 ) ofs0 = sel0 = invlist.Size()-1;
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 1) )
{
MenuSound("menu/demoscroll");
ofs0 = --sel0;
if ( sel0 < 0 ) ofs0 = sel0 = storelist.Size()-1;
}
else if ( curtab == TAB_TRADING )
{
if ( !sub && (playerlist.Size() > 1) )
{
// scroll through player list
MenuSound("menu/demoscroll");
ofs0 = --sel0;
if ( sel0 < 0 ) ofs0 = sel0 = playerlist.Size()-1;
}
else if ( sub && (sel0 == -1) && (sel1 > 0) )
{
// scroll through trading history
MenuSound("menu/demoscroll");
ofs1 = --sel1;
}
}
return true;
case MKEY_RIGHT:
if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS) || ((curtab == TAB_TRADING) && sub && (sel0 != -1))) && (invlist.Size() > 21) )
{
int oldsel = sel0;
ofs0 = sel0 += 22;
if ( sel0 >= invlist.Size() ) ofs0 = sel0 = invlist.Size()-1;
if ( sel0 != oldsel ) MenuSound("menu/demoscroll");
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 21) )
{
int oldsel = sel0;
ofs0 = sel0 += 22;
if ( sel0 >= storelist.Size() ) ofs0 = sel0 = storelist.Size()-1;
if ( sel0 != oldsel ) MenuSound("menu/demoscroll");
}
else if ( curtab == TAB_LIBRARY )
{
MenuSound("menu/demoscroll");
ofs0 = sel0 = 0;
sub = false;
ofs1 = ++sel1;
if ( sel1 > LORE_LORE ) ofs1 = sel1 = LORE_ITEM;
CVar.GetCVar('swwm_lastloretab',players[consoleplayer]).SetInt(sel1);
}
else if ( (curtab == TAB_TRADING) && !sub && (playerlist.Size() > 21) ) // lol is this ever going to happen
{
int oldsel = sel0;
ofs0 = sel0 += 22;
if ( sel0 >= playerlist.Size() ) ofs0 = sel0 = playerlist.Size()-1;
if ( sel0 != oldsel ) MenuSound("menu/demoscroll");
}
return true;
case MKEY_LEFT:
if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS) || ((curtab == TAB_TRADING) && sub && (sel0 != -1))) && (invlist.Size() > 21) && (sel0-22 >= 0) )
{
MenuSound("menu/demoscroll");
ofs0 = sel0 -= 22;
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 21) && (sel0-22 >= 0) )
{
MenuSound("menu/demoscroll");
ofs0 = sel0 -= 22;
}
else if ( curtab == TAB_LIBRARY )
{
MenuSound("menu/demoscroll");
ofs0 = sel0 = 0;
sub = false;
ofs1 = --sel1;
if ( sel1 < LORE_ITEM ) ofs1 = sel1 = LORE_LORE;
CVar.GetCVar('swwm_lastloretab',players[consoleplayer]).SetInt(sel1);
}
else if ( (curtab == TAB_TRADING) && !sub && (playerlist.Size() > 21) && (sel0-22 >= 0) ) // lol is this ever going to happen
{
ofs0 = sel0 -= 22;
MenuSound("menu/demoscroll");
}
return true;
case MKEY_ENTER:
if ( (curtab == TAB_INVENTORY) && (invlist.Size() > 0) && (sel0 < invlist.Size()) )
{
// can't use this
if ( invlist[sel0] is 'Ammo' ) return true;
lastuse = invlist[sel0].GetClass();
lastuseamt = invlist[sel0].Amount;
// don't check weapons (or the lamp)
if ( !(invlist[sel0] is 'Weapon') && !(invlist[sel0] is 'SWWMLamp') )
checkuse = gametic+(multiplayer?5:1);
EventHandler.SendNetworkEvent(String.Format("swwmuseitem.%s",invlist[sel0].GetClassName()),consoleplayer);
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 0) && (sel0 < storelist.Size()) )
{
let itm = GetDefaultByType(storelist[sel0]);
let amt = storeunits[sel0];
int price = int(itm.Stamina*(1.+.5*(amt-1)));
if ( !SWWMCredits.CanTake(players[consoleplayer],price) )
{
MenuSound("menu/noinvuse");
tmsg = StringTable.Localize("$SWWM_STOREMUNS");
tmsgtic = gametic+70;
return true;
}
let cur = players[consoleplayer].mo.FindInventory(storelist[sel0]);
int camt, max;
if ( cur )
{
camt = cur.Amount;
max = cur.MaxAmount;
}
else
{
camt = 0;
max = itm.MaxAmount;
}
if ( camt >= max )
{
MenuSound("menu/noinvuse");
tmsg = StringTable.Localize("$SWWM_STOREFULL");
tmsgtic = gametic+70;
return true;
}
EventHandler.SendNetworkEvent(String.Format("swwmstoregive.%s",storelist[sel0].GetClassName()),consoleplayer,price,amt);
if ( (camt+amt) >= max ) ofs1 = sel0 = max(0,sel0-1);
MenuSound("menu/buyinv");
}
else if ( curtab == TAB_LIBRARY )
{
if ( sub )
{
MenuSound("menu/democlose");
sub = false;
}
else if ( (lorelist.Size() > 0) && (sel0 < lorelist.Size()) )
{
// mark as read
if ( !lorelist[sel0].read )
EventHandler.SendNetworkEvent(String.Format("swwmmarkloreread.%s",lorelist[sel0].tag),consoleplayer);
MenuSound("menu/demosel");
sub = true;
ofs2 = sel2 = 0;
}
}
else if ( curtab == TAB_TRADING )
{
if ( !sub && (playerlist.Size() > 0) )
{
// pick a player
MenuSound("menu/demosel");
sub = true;
ofs1 = sel1 = 0;
}
else if ( sub && (sel0 != -1) && (invlist.Size() > 0) )
{
// trade item
lastuse = invlist[sel1].GetClass();
lastuseamt = invlist[sel1].Amount;
checksend = gametic+(multiplayer?5:1);
EventHandler.SendNetworkEvent(String.Format("swwmtrade.%s",invlist[sel1].GetClassName()),consoleplayer,playerlist[sel0]);
}
}
return true;
case MKEY_CLEAR:
if ( (curtab == TAB_INVENTORY) && (invlist.Size() > 0) )
{
lastuse = invlist[sel0].GetClass();
lastuseamt = invlist[sel0].Amount;
checkdrop = gametic+(multiplayer?5:1);
EventHandler.SendNetworkEvent(String.Format("swwmdropitem.%s",invlist[sel0].GetClassName()),consoleplayer);
}
else if ( (curtab == TAB_LIBRARY) && sub )
{
MenuSound("menu/democlose");
sub = false;
}
else if ( curtab == TAB_TRADING )
{
if ( !sub )
{
// open trading history
MenuSound("menu/demosel");
sub = true;
ofs0 = sel0 = -1;
ofs1 = sel1 = 0;
}
else if ( sub )
{
// go back
MenuSound("menu/democlose");
sub = false;
ofs0 = sel0 = 0;
}
}
return true;
}
return Super.MenuEvent(mkey,fromcontroller);
}
private int rnd( double num )
{
return int(num+((num<0)?-.5:.5));
}
override bool MouseEvent( int type, int mx, int my )
{
bool res = Super.MouseEvent(type,mx,my);
Font fnt = LangFont(TewiFont);
String str;
double hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/400.)),1.);
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight())/hs;
Vector2 origin = (ss.x-640,ss.y-400)/2.;
Vector2 mpos = (mx/hs,my/hs)-origin;
int xx, yy, len;
if ( type == MOUSE_Click )
{
if ( (mpos.x < 0) || (mpos.x >= 641) || (mpos.y < 0) || (mpos.y >= 386) ) return res; // outside clickable area, ignore
else if ( mpos.y < 14 )
{
if ( isrclick ) return res;
// check which tab we're clicking
static const string tabnames[] =
{
"$SWWM_MISSTAB", "$SWWM_STATTAB", "$SWWM_INVTAB", "$SWWM_KEYTAB",
"$SWWM_KBASETAB", "$SWWM_STORETAB", "$SWWM_TRADETAB", "$SWWM_CHATTAB"
};
xx = 0;
int maxtab = multiplayer?TAB_CHAT:TAB_STORE;
for ( int i=TAB_MISSION; i<=maxtab; i++ )
{
len = fnt.StringWidth(tabnames[i])+6;
if ( (mpos.x >= xx) && (mpos.x < xx+len) )
{
if ( curtab == i ) break;
MenuSound("menu/demotab");
curtab = i;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
playerlist.Clear();
break;
}
xx += len;
}
}
else if ( (curtab == TAB_MISSION) && !isrclick )
{
// are we clicking where the scrollbar should be?
if ( mpos.x < 632 ) return res;
String str = StringTable.Localize("$SWWM_MISSION_NONE");
if ( gameinfo.gametype&GAME_Doom ) str = StringTable.Localize("$SWWM_MISSION_DOOM");
else if ( gameinfo.gametype&GAME_Heretic ) str = StringTable.Localize("$SWWM_MISSION_HERETIC");
else if ( gameinfo.gametype&GAME_Hexen ) str = StringTable.Localize("$SWWM_MISSION_HEXEN");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
drag = 1;
}
else if ( curtab == TAB_INVENTORY )
{
// check what item we clicked
if ( mpos.y < 377 )
{
if ( invlist.Size() <= 0 ) return res; // clicked nothing
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
xx = 9;
yy = 23;
int cols = 1;
for ( int i=ofs; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
// check boundary
if ( (mpos.x >= xx) && (mpos.x < xx+longest) && (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel0 != i ) MenuSound("menu/demoscroll");
sel0 = i;
ofs0 = (sel0/22)*22;
// drop on right click in inventory tab
if ( (curtab == TAB_INVENTORY) && isrclick ) MenuEvent(MKEY_CLEAR,false);
else if ( !isrclick ) MenuEvent(MKEY_ENTER,false);
return res;
}
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
}
else if ( !isrclick )
{
// check that scrollbar is present
if ( invlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
drag = 1;
}
}
else if ( (curtab == TAB_TRADING) && sub && (sel0 != -1) )
{
// check what item we clicked
if ( mpos.y < 377 )
{
if ( invlist.Size() <= 0 ) return res; // clicked nothing
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
int ofs = int(max(0,(ofs1/22)-(maxcol-1))*22);
xx = 9;
yy = 23;
int cols = 1;
for ( int i=ofs; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
// check boundary
if ( (mpos.x >= xx) && (mpos.x < xx+longest) && (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel1 != i ) MenuSound("menu/demoscroll");
sel1 = i;
ofs1 = (sel1/22)*22;
// drop on right click in inventory tab
if ( (curtab == TAB_INVENTORY) && isrclick ) MenuEvent(MKEY_CLEAR,false);
else if ( !isrclick ) MenuEvent(MKEY_ENTER,false);
return res;
}
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
}
else if ( !isrclick )
{
// check that scrollbar is present
if ( invlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
drag = 1;
}
}
else if ( (curtab == TAB_KEYS) && !isrclick )
{
// check what item we clicked
if ( mpos.y < 377 )
{
if ( invlist.Size() <= 0 ) return res; // clicked nothing
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
xx = 9;
yy = 23;
int cols = 1;
for ( int i=ofs; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
// check boundary
if ( (mpos.x >= xx) && (mpos.x < xx+longest) && (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel0 != i ) MenuSound("menu/demoscroll");
sel0 = i;
ofs0 = (sel0/22)*22;
// do nothing, we just selected it
return res;
}
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
}
else if ( !isrclick )
{
// check that scrollbar is present
if ( invlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
drag = 1;
}
}
else if ( (curtab == TAB_STORE) && !isrclick )
{
// check what item we clicked
if ( mpos.y < 377 )
{
if ( storelist.Size() <= 0 ) return res; // clicked nothing
xx = 9;
yy = 23;
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
if ( storeunits[i] > 1 ) str = String.Format("%dx %s",storeunits[i],def.GetTag());
else str = def.GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+96);
totalcol = (storelist.Size()/22)+1;
// gotta check both the tag and the price for clicking
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
int cols = 1;
for ( int i=ofs; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
// check boundary
if ( (mpos.x >= xx) && (mpos.x < xx+longest+80) && (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel0 != i ) MenuSound("menu/demoscroll");
sel0 = i;
ofs0 = (sel0/22)*22;
MenuEvent(MKEY_ENTER,false);
return res;
}
yy += 16;
if ( yy >= 370 )
{
xx += longest+96;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
}
else if ( !isrclick )
{
// check that scrollbar is present
if ( storelist.Size() <= 0 ) return res; // definitely no scrollbar
xx = 9;
yy = 23;
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
if ( storeunits[i] > 1 ) str = String.Format("%dx %s",storeunits[i],def.GetTag());
else str = def.GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+96);
totalcol = (storelist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
drag = 1;
}
}
else if ( (curtab == TAB_LIBRARY) && !isrclick )
{
double midp = (lang.GetString()~=="jp")?206:126;
if ( mpos.x < midp )
{
if ( mpos.y < 28 )
{
// switch category
if ( mpos.x < midp/2. ) MenuEvent(MKEY_LEFT,false);
else MenuEvent(MKEY_RIGHT,false);
}
else
{
// check what item we clicked
int xx = 3;
int yy = 32;
int ofs = max(0,ofs0-26);
for ( int i=ofs; i<lorelist.Size(); i++ )
{
if ( yy > 370 ) break;
// check boundary
if ( (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel0 != i ) MenuSound("menu/demoscroll");
if ( (sel0 != i) || !sub )
{
sel0 = i;
sub = false;
MenuEvent(MKEY_Enter,false);
}
return res;
}
yy += 13;
}
}
}
else if ( mpos.x < midp+8 )
{
// check that scrollbar is present
if ( lorelist.Size() <= 27 ) return res; // no scrollbar
// calculate offset
int szr = lorelist.Size()-27;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step ) step += 26;
if ( step != ofs0 ) MenuSound("menu/demoscroll");
ofs0 = step;
drag = 1;
}
else if ( sub && (mpos.x >= 632) )
{
// check that scrollbar is present
str = StringTable.Localize(lorelist[sel0].text);
int ofs = (lang.GetString()~=="jp")?212:132;
if ( lorelist.Size() > 26 ) ofs += 8;
BrokenLines l = fnt.BreakLines(str,635-ofs);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,626-ofs);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel2 ) MenuSound("menu/demoscroll");
ofs2 = sel2 = step;
drag = 3;
}
}
else if ( (curtab == TAB_TRADING) && isrclick )
{
MenuEvent(MKEY_Back,false);
}
else if ( (curtab == TAB_TRADING) && !isrclick )
{
if ( !sub )
{
// check what item we clicked
if ( mpos.y < 377 )
{
if ( playerlist.Size() <= 0 ) return res; // clicked nothing
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<playerlist.Size(); i++ )
{
str = players[playerlist[i]].GetUserName();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (playerlist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
xx = 9;
yy = 23;
int cols = 1;
for ( int i=ofs; i<playerlist.Size(); i++ )
{
str = players[playerlist[i]].GetUserName();
len = fnt.StringWidth(str);
// check text boundary
if ( (mpos.x >= xx) && (mpos.x < xx+len+1) && (mpos.y >= yy) && (mpos.y < yy+14) )
{
if ( sel0 != i ) MenuSound("menu/demoscroll");
ofs0 = sel0 = i;
MenuEvent(MKEY_Enter,false);
return res;
}
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
}
else if ( !isrclick )
{
// check that scrollbar is present (will it ever be???)
if ( playerlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<playerlist.Size(); i++ )
{
str = players[playerlist[i]].GetUserName();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (playerlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
drag = 1;
}
}
else if ( sel0 == -1 )
{
// are we clicking where the scrollbar should be?
if ( mpos.x < 632 ) return res;
if ( tradelib.ent.Size() <= 28 ) return res; // no scrollbar
// calculate offset
int szr = tradelib.ent.Size()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
drag = 1;
}
}
else if ( (curtab == TAB_CHAT) && !isrclick )
{
// are we clicking where the scrollbar should be?
if ( mpos.x < 632 ) return res;
let bar = SWWMStatusBar(StatusBar);
if ( !bar || (bar.FullHistory.Size() <= 1) ) return res; // no scrollbar
// calculate offset
int szr = bar.FullHistory.Size()-1;
int step = szr-clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
drag = 1;
}
else if ( (curtab == TAB_HELP) && !isrclick )
{
// are we clicking where the scrollbar should be?
if ( mpos.x < 632 ) return res;
int k1, k2;
[k1, k2] = bindings.GetKeysForCommand("openmenu SWWMKnowledgeBaseMenu");
String kstr = bindings.NameKeys(k1,k2);
str = String.Format(StringTable.Localize("$SWWM_HELPTXT"),kstr);
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
drag = 1;
}
}
else if ( (type == MOUSE_Move) && drag ) // scroll dragging
{
if ( curtab == TAB_MISSION )
{
String str = StringTable.Localize("$SWWM_MISSION_NONE");
if ( gameinfo.gametype&GAME_Doom ) str = StringTable.Localize("$SWWM_MISSION_DOOM");
else if ( gameinfo.gametype&GAME_Heretic ) str = StringTable.Localize("$SWWM_MISSION_HERETIC");
else if ( gameinfo.gametype&GAME_Hexen ) str = StringTable.Localize("$SWWM_MISSION_HEXEN");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
}
else if ( (curtab == TAB_INVENTORY) || ((curtab == TAB_TRADING) && sub && (sel0 != -1)) )
{
// check that scrollbar is present
if ( invlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
}
else if ( curtab == TAB_KEYS )
{
// check that scrollbar is present
if ( invlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
}
else if ( curtab == TAB_STORE )
{
// check that scrollbar is present
if ( storelist.Size() <= 0 ) return res; // definitely no scrollbar
xx = 9;
yy = 23;
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
if ( storeunits[i] > 1 ) str = String.Format("%dx %s",storeunits[i],def.GetTag());
else str = def.GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+96);
totalcol = (storelist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
}
else if ( curtab == TAB_LIBRARY )
{
if ( drag == 1 )
{
// check that scrollbar is present
if ( lorelist.Size() <= 27 ) return res; // no scrollbar
// calculate offset
int szr = lorelist.Size()-27;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step ) step += 26;
if ( step != ofs0 ) MenuSound("menu/demoscroll");
ofs0 = step;
}
else if ( drag == 3 )
{
// check that scrollbar is present
str = StringTable.Localize(lorelist[sel0].text);
int ofs = (lang.GetString()~=="jp")?212:132;
if ( lorelist.Size() > 26 ) ofs += 8;
BrokenLines l = fnt.BreakLines(str,635-ofs);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,626-ofs);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel2 ) MenuSound("menu/demoscroll");
ofs2 = sel2 = step;
}
}
else if ( curtab == TAB_TRADING )
{
if ( !sub )
{
// check that scrollbar is present (will it ever be???)
if ( playerlist.Size() <= 0 ) return res; // definitely no scrollbar
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<playerlist.Size(); i++ )
{
str = players[playerlist[i]].GetUserName();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
if ( maxcol >= totalcol ) return res; // no scrollbar
// calculate offset
int szr = totalcol-maxcol;
int step = clamp(rnd((mpos.x-5.)/(630./szr)),0,szr);
if ( step > 0 ) step += (maxcol-1);
if ( step != (ofs0/22) ) MenuSound("menu/demoscroll");
ofs0 = step*22;
}
else if ( sel0 == -1 )
{
if ( tradelib.ent.Size() <= 28 ) return res; // no scrollbar
// calculate offset
int szr = tradelib.ent.Size()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
}
}
else if ( curtab == TAB_CHAT )
{
let bar = SWWMStatusBar(StatusBar);
if ( !bar || (bar.FullHistory.Size() <= 1) ) return res; // no scrollbar
// calculate offset
int szr = bar.FullHistory.Size()-1;
int step = szr-clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
}
else if ( curtab == TAB_HELP )
{
int k1, k2;
[k1, k2] = bindings.GetKeysForCommand("openmenu SWWMKnowledgeBaseMenu");
String kstr = bindings.NameKeys(k1,k2);
str = String.Format(StringTable.Localize("$SWWM_HELPTXT"),kstr);
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
else return res; // no scrollbar
// calculate offset
int szr = l.Count()-28;
int step = clamp(rnd((mpos.y-24.)/(353./szr)),0,szr);
if ( step != sel0 ) MenuSound("menu/demoscroll");
ofs0 = sel0 = step;
}
}
else if ( type == MOUSE_Release ) drag = 0; // stop dragging any active scrolls
return res;
}
private bool CmpInventory( Inventory a, Inventory b )
{
int ta = 0, tb = 0;
if ( a is 'Weapon' ) ta = 2;
else if ( (a is 'Ammo') || (a is 'BackpackItem') || (a is 'HammerspaceEmbiggener') ) ta = 3;
else if ( (a is 'PowerupGiver') || (a is 'AmmoFabricator') || a.bBIGPOWERUP ) ta = -3;
else if ( (a is 'Health') || (a is 'HealthPickup') || (a is 'SWWMHealth') ) ta = -2;
else if ( (a is 'Armor') || (a is 'SWWMSpareArmor') ) ta = -1;
else if ( a is 'PuzzleItem' ) ta = 1;
if ( b is 'Weapon' ) tb = 2;
else if ( (b is 'Ammo') || (b is 'BackpackItem') || (b is 'HammerspaceEmbiggener') ) tb = 3;
else if ( (b is 'PowerupGiver') || (b is 'AmmoFabricator') || b.bBIGPOWERUP ) tb = -3;
else if ( (b is 'Health') || (b is 'HealthPickup') || (b is 'SWWMHealth') ) tb = -2;
else if ( (b is 'Armor') || (b is 'SWWMSpareArmor') ) tb = -1;
else if ( b is 'PuzzleItem' ) tb = 1;
return ta > tb;
}
private bool CmpInventoryClass( Class<Inventory> a, Class<Inventory> b )
{
int ta = 0, tb = 0;
let da = GetDefaultByType(a);
let db = GetDefaultByType(b);
if ( a is 'Weapon' ) ta = 2;
else if ( a is 'Ammo' ) ta = 1;
else if ( (a is 'PowerupGiver') || (a is 'AmmoFabricator') || da.bBIGPOWERUP ) ta = 3;
else if ( (a is 'Health') || (a is 'HealthPickup') || (a is 'SWWMHealth') ) ta = 5;
else if ( (a is 'Armor') || (a is 'SWWMSpareArmor') ) ta = 4;
if ( b is 'Weapon' ) tb = 2;
else if ( b is 'Ammo' ) tb = 1;
else if ( (b is 'PowerupGiver') || (b is 'AmmoFabricator') || db.bBIGPOWERUP ) tb = 3;
else if ( (b is 'Health') || (b is 'HealthPickup') || (b is 'SWWMHealth') ) tb = 5;
else if ( (b is 'Armor') || (b is 'SWWMSpareArmor') ) tb = 4;
return ta <= tb;
}
private int partition_inventory( Array<Inventory> a, int l, int h )
{
Inventory pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( CmpInventory(pv,a[j]) )
{
i++;
Inventory tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
Inventory tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
return i+1;
}
private void qsort_inventory( Array<Inventory> a, int l, int h )
{
if ( l >= h ) return;
int p = partition_inventory(a,l,h);
qsort_inventory(a,l,p-1);
qsort_inventory(a,p+1,h);
}
private int partition_store( Array<Class<Inventory> > a, Array<int> b, int l, int h )
{
Class<Inventory> pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( CmpInventoryClass(pv,a[j]) )
{
i++;
Class<Inventory> tmp = a[j];
a[j] = a[i];
a[i] = tmp;
int tmpi = b[j];
b[j] = b[i];
b[i] = tmpi;
}
}
Class<Inventory> tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
int tmpi = b[h];
b[h] = b[i+1];
b[i+1] = tmpi;
return i+1;
}
private void qsort_store( Array<Class<Inventory> > a, Array<int> b, int l, int h )
{
if ( l >= h ) return;
int p = partition_store(a,b,l,h);
qsort_store(a,b,l,p-1);
qsort_store(a,b,p+1,h);
}
override void Ticker()
{
Super.Ticker();
if ( players[consoleplayer].Health <= 0 )
{
// ded
Close();
return;
}
if ( !multiplayer && ((curtab == TAB_TRADING) || (curtab == TAB_CHAT)) )
{
MenuSound("menu/demotab");
curtab = TAB_MISSION;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
playerlist.Clear();
}
if ( curtab == TAB_INVENTORY )
{
invlist.Clear();
// alphabetically sorted inventory
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
{
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (inv is 'SWWMGesture') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) && !(inv is 'HammerspaceEmbiggener') && !(inv is 'SWWMCollectable') ) continue;
String tag = inv.GetTag();
bool greater = false;
for ( int i=0; i<invlist.Size(); i++ )
{
String tag2 = invlist[i].GetTag();
if ( tag > tag2 ) continue;
greater = true;
invlist.Insert(i,inv);
break;
}
if ( greater ) continue;
invlist.Push(inv);
}
// re-sort by category
qsort_inventory(invlist,0,invlist.Size()-1);
}
else if ( curtab == TAB_KEYS )
{
invlist.Clear();
// keys sorted by their index
int n = Key.GetKeyTypeCount();
for ( int i=0; i<n; i++ )
{
let k = Key(players[consoleplayer].mo.FindInventory(Key.GetKeyType(i)));
if ( k ) invlist.Push(k);
}
}
else if ( curtab == TAB_STORE )
{
storelist.Clear();
storeunits.Clear();
// price-sorted buyables
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let type = (Class<Inventory>)(AllActorClasses[i]);
if ( !type ) continue;
// skip chanceboxes, since they're not yet implemented
if ( type is 'Chancebox' ) continue;
// no fabricators outside of hexen
if ( !(gameinfo.gametype&GAME_Hexen) && (type is 'AmmoFabricator') ) continue;
// skip maxed items
let cur = players[consoleplayer].mo.FindInventory(type);
if ( cur && (cur.Amount >= cur.MaxAmount) ) continue;
// ignore ammo for weapons not owned
bool notownedammo = false;
if ( type is 'Ammo' )
{
notownedammo = true;
let amo = (Class<Ammo>)(type);
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.inv )
{
if ( !(inv is 'Weapon') ) continue;
if ( (Weapon(inv).AmmoType1 == amo) || (Weapon(inv).AmmoType2 == amo) )
{
notownedammo = false;
break;
}
if ( (inv is 'SWWMWeapon') && SWWMWeapon(inv).UsesAmmo(amo) )
{
notownedammo = false;
break;
}
}
}
if ( notownedammo ) continue;
let inv = GetDefaultByType(type);
// skip unimplemented weapons
if ( type is 'Weapon' )
{
let ready = inv.FindState("Ready");
if ( !ready || !ready.ValidateSpriteFrame() ) continue;
}
// ignore child ammos
if ( (type is 'Ammo') && (type.GetParentClass() != 'Ammo') ) continue;
if ( inv.Stamina <= 0 ) continue;
int amt = inv.Amount;
int price = int(inv.Stamina*(1.+.5*(amt-1)));
if ( type is 'Ammo' )
{
// get the largest affordable child pickup amount
for ( int j=0; j<AllActorClasses.Size(); j++ )
{
let type2 = (Class<Ammo>)(AllActorClasses[j]);
if ( !type2 || (type2.GetParentClass() != type) ) continue;
let inv2 = GetDefaultByType(type2);
int cprice = int(inv.Stamina*(1.+.5*(inv2.Amount-1)));
if ( (inv2.Amount > amt) && (cprice <= SWWMCredits.Get(players[consoleplayer])) )
{
price = cprice;
amt = inv2.Amount;
}
}
}
// sort by unit price
bool greater = false;
for ( int j=0; j<storelist.Size(); j++ )
{
let inv2 = GetDefaultByType(storelist[j]);
if ( inv.Stamina > inv2.Stamina ) continue;
greater = true;
storelist.Insert(j,type);
storeunits.Insert(j,amt);
break;
}
if ( greater ) continue;
storelist.Push(type);
storeunits.Push(amt);
}
// re-sort by category
qsort_store(storelist,storeunits,0,storelist.Size()-1);
}
else if ( curtab == TAB_LIBRARY )
{
// remember last position/size
SWWMLore oldone = null;
int oldsiz = lorelist.Size();
if ( lorelist.Size() > 0 ) oldone = lorelist[sel0];
// lore lore lore
lorelist.Clear();
for ( int i=0; i<lorelib.ent.Size(); i++ )
{
if ( lorelib.ent[i].tab != sel1 ) continue;
lorelist.Push(lorelib.ent[i]);
}
// readjust
if ( oldone && (lorelist.Size() != oldsiz) )
{
int idx = lorelist.Find(oldone);
if ( (idx > 0) && (idx < lorelist.Size()) )
sel0 = idx;
// update ofs so selection stays on-screen
int ofs = max(ofs0-26,0);
if ( sel0 < ofs ) ofs0 = sel0+26;
else if ( sel0 > ofs+26 ) ofs0 = sel0;
}
// add "new entries" message
if ( lorelib.ent.Size() != oldloresiz )
{
tmsg = StringTable.Localize("$SWWM_NEWLORE");
tmsgtic = gametic+70;
}
oldloresiz = lorelib.ent.Size();
}
else if ( curtab == TAB_TRADING )
{
// build player list
playerlist.Clear();
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || (i==consoleplayer) ) continue;
playerlist.Push(i);
}
// build inventory list if open
if ( sub && (sel0 != -1) )
{
invlist.Clear();
// alphabetically sorted inventory
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
{
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (inv is 'SWWMGesture') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) && !(inv is 'HammerspaceEmbiggener') && !(inv is 'SWWMCollectable') ) continue;
String tag = inv.GetTag();
bool greater = false;
for ( int i=0; i<invlist.Size(); i++ )
{
String tag2 = invlist[i].GetTag();
if ( tag > tag2 ) continue;
greater = true;
invlist.Insert(i,inv);
break;
}
if ( greater ) continue;
invlist.Push(inv);
}
// re-sort by category
qsort_inventory(invlist,0,invlist.Size()-1);
}
}
// check if use succeeded
if ( checkuse && (gametic > checkuse) )
{
checkuse = 0;
int amt = players[consoleplayer].mo.CountInv(lastuse);
if ( amt == lastuseamt )
{
tmsg = StringTable.Localize("$SWWM_INVFAIL");
tmsgtic = gametic+70;
MenuSound("menu/noinvuse");
}
else
{
MenuSound(GetDefaultByType(lastuse).UseSound);
if ( (amt == 0) && (sel0 >= invlist.Size()) )
sel0 = max(0,sel0-1);
}
}
// check if drop succeeded
if ( checkdrop && (gametic > checkdrop) )
{
checkdrop = 0;
int amt = players[consoleplayer].mo.CountInv(lastuse);
if ( amt == lastuseamt )
{
tmsg = StringTable.Localize("$SWWM_INVNDROP");
tmsgtic = gametic+70;
MenuSound("menu/noinvuse");
}
else if ( (amt == 0) && (sel0 >= invlist.Size()) )
sel0 = max(0,sel0-1);
}
// check if trade succeeded
if ( checksend && (gametic > checksend) )
{
checksend = 0;
int amt = players[consoleplayer].mo.CountInv(lastuse);
if ( amt == lastuseamt )
{
tmsg = StringTable.Localize("$SWWM_TRADEFULL");
tmsgtic = gametic+70;
MenuSound("menu/noinvuse");
}
else
{
MenuSound("menu/demosel");
if ( (amt == 0) && (sel1 >= invlist.Size()) )
sel1 = max(0,sel1-1);
}
}
}
override bool OnUiEvent( UIEvent ev )
{
switch ( ev.type )
{
case UIEvent.Type_KeyDown:
if ( ev.keychar == UiEvent.Key_F1 )
{
if ( curtab == TAB_HELP )
curtab = oldtab;
else
{
oldtab = curtab;
curtab = TAB_HELP;
}
sel0 = sel1 = sel2 = 0;
ofs0 = ofs1 = ofs2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
MenuSound("menu/demotab");
return true;
}
switch ( kcode )
{
case 8:
if ( ev.keystring ~== "B" )
kcode++;
else kcode = 0;
break;
case 9:
if ( ev.keystring ~== "A" ) kcode++;
else kcode = 0;
break;
default:
kcode = 0;
break;
}
if( (ikey[0] && (ev.keystring == mkey[0])) || (ikey[1] && (ev.keystring == mkey[1])) )
{
MenuSound("menu/democlose");
Close();
return true;
}
break;
case UIEvent.Type_WheelDown:
if ( (curtab == TAB_LIBRARY) && sub && (lorelist.Size() > 1) )
{
// special handling, need to check which side is being scrolled
double hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/400.)),1.);
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight())/hs;
Vector2 origin = (ss.x-640,ss.y-400)/2.;
Vector2 mpos = (curmouse/hs)-origin;
double midp = (lang.GetString()~=="jp")?206:126;
if ( ((lorelist.Size() > 27) && (mpos.x < midp+8)) || (mpos.x < midp) )
{
MenuSound("menu/democlose");
sub = false;
}
}
return MenuEvent(MKEY_DOWN,false);
break;
case UIEvent.Type_WheelUp:
if ( (curtab == TAB_LIBRARY) && sub && (lorelist.Size() > 1) )
{
// special handling, need to check which side is being scrolled
double hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/400.)),1.);
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight())/hs;
Vector2 origin = (ss.x-640,ss.y-400)/2.;
Vector2 mpos = (curmouse/hs)-origin;
double midp = (lang.GetString()~=="jp")?206:126;
if ( ((lorelist.Size() > 27) && (mpos.x < midp+8)) || (mpos.x < midp) )
{
MenuSound("menu/democlose");
sub = false;
}
}
return MenuEvent(MKEY_UP,false);
break;
case UIEvent.Type_LButtonDown:
isrclick = false;
return Super.OnUIEvent(ev);
break;
case UIEvent.Type_RButtonDown:
isrclick = true;
// copy over what base menus do for L click
int y = ev.MouseY;
bool res = MouseEventBack(MOUSE_Click,ev.MouseX,y);
if ( res ) y = -1;
res |= MouseEvent(MOUSE_Click,ev.MouseX,y);
if ( res ) SetCapture(true);
return false;
break;
case UIEvent.Type_RButtonUp:
// copy over what base menus do for L release
if ( mMouseCapture )
{
SetCapture(false);
int y = ev.MouseY;
bool res = MouseEventBack(MOUSE_Release,ev.MouseX,y);
if ( res ) y = -1;
res |= MouseEvent(MOUSE_Release,ev.MouseX,y);
}
return false;
break;
case UIEvent.Type_MouseMove:
// store coords
curmouse = (ev.MouseX,ev.MouseY);
break;
}
return Super.OnUIEvent(ev);
}
override void Drawer()
{
Super.Drawer();
Font fnt = LangFont(TewiFont);
String str;
double hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/400.)),1.);
Vector2 ss = (Screen.GetWidth(),Screen.GetHeight())/hs;
Vector2 origin = (ss.x-640,ss.y-400)/2.;
if ( !fuzz ) fuzz = CVar.GetCvar('swwm_fuzz',players[consoleplayer]);
if ( fuzz.GetBool() )
Screen.DrawTexture(FancyBg,false,origin.x,origin.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,.5);
Screen.DrawTexture(MainWindow,false,origin.x,origin.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// draw tabs
double xx = 3, yy = 0;
static const string tabnames[] =
{
"$SWWM_MISSTAB", "$SWWM_STATTAB", "$SWWM_INVTAB", "$SWWM_KEYTAB",
"$SWWM_KBASETAB", "$SWWM_STORETAB", "$SWWM_TRADETAB", "$SWWM_CHATTAB",
"$SWWM_SECRETTAB", "$SWWM_HELPTAB"
};
static const string ltabnames[] =
{
"$SWWM_LORETAB0", "$SWWM_LORETAB1", "$SWWM_LORETAB2"
};
int maxtab = multiplayer?TAB_CHAT:TAB_STORE;
int mx = maxtab;
if ( (curtab > TAB_CHAT) ) mx++;
for ( int i=0; i<=mx; i++ )
{
str = StringTable.Localize(tabnames[(i>maxtab)?curtab:i]);
Screen.DrawText(fnt,((i>maxtab)||(curtab==i))?Font.CR_FIRE:Font.CR_DARKGRAY,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += fnt.StringWidth(str)+2;
Screen.DrawTexture(TabSeparator,false,origin.x+xx,origin.y+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 4;
}
int muns1, muns2;
[muns1, muns2] = SWWMCredits.Get(players[consoleplayer]);
str = "\cg¥\c-";
if ( muns2 > 0 ) str.AppendFormat("%d",muns2);
str.AppendFormat("%09d",muns1);
xx = 637-TewiFont.StringWidth(str);
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// draw bottom messages
yy = 386;
if ( gametic < tmsgtic ) str = StringTable.Localize(tmsg);
else str = CrimeTime();
xx = 4;
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = "DemolitionOS v1.0";
xx = 637-fnt.StringWidth(str);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// draw contents
if ( curtab == TAB_MISSION )
{
if ( gameinfo.gametype&GAME_Doom ) str = StringTable.Localize("$SWWM_MISSION_DOOM");
else if ( gameinfo.gametype&GAME_Heretic ) str = StringTable.Localize("$SWWM_MISSION_HERETIC");
else if ( gameinfo.gametype&GAME_Hexen ) str = StringTable.Localize("$SWWM_MISSION_HEXEN");
else str = StringTable.Localize("$SWWM_MISSION_NONE");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
xx = 6;
yy = 17;
int ofs = clamp(sel0,0,max(0,l.Count()-28));
for ( int i=ofs; i<l.Count(); i++ )
{
if ( yy >= 370 ) break;
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
// scrollbar
if ( l.Count() > 28 )
{
Screen.DrawTexture(WindowSeparator,false,origin.x+631,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx = 634;
int szr = l.Count()-28;
yy = floor(ofs*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_STATS )
{
xx = 9;
yy = 23;
// wish I could use macros for this
int thour = ((level.totaltime-stats.lastspawn)/(3600*Thinker.TICRATE));
int tmin = ((level.totaltime-stats.lastspawn)/(60*Thinker.TICRATE))%60;
int tsec = ((level.totaltime-stats.lastspawn)/Thinker.TICRATE)%60;
str = String.Format("\cx%s\c-%02d\cu:\c-%02d\cu:\c-%02d",StringTable.Localize("$SWWM_STATUPTIME"),thour,tmin,tsec);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
if ( stats.grounddist > 32000. ) str = String.Format("\cx%s\c-%g\cukm\c-",StringTable.Localize("$SWWM_STATONFOOT"),stats.grounddist/32000.);
else str = String.Format("\cx%s\c-%g\cum\c-",StringTable.Localize("$SWWM_STATONFOOT"),stats.grounddist/32.);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
if ( stats.airdist > 32000. ) str = String.Format("\cx%s\c-%g\cukm\c-",StringTable.Localize("$SWWM_STATFLIGHT"),stats.airdist/32000.);
else str = String.Format("\cx%s\c-%g\cum\c-",StringTable.Localize("$SWWM_STATFLIGHT"),stats.airdist/32.);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATBOOST"),stats.boostcount);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDASH"),stats.dashcount);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSTOMP"),stats.stompcount);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%g\cul\c-",StringTable.Localize("$SWWM_STATFUEL"),stats.fuelusage/6.);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%g\cukm/h\c-",StringTable.Localize("$SWWM_STATSPEED"),stats.topspeed*32000./(3600*Thinker.TICRATE));
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
thour = (stats.airtime/(3600*Thinker.TICRATE));
tmin = (stats.airtime/(60*Thinker.TICRATE))%60;
tsec = (stats.airtime/Thinker.TICRATE)%60;
str = String.Format("\cx%s\c-%02d\cu:\c-%02d\cu:\c-%02d",StringTable.Localize("$SWWM_STATAIRTIME"),thour,tmin,tsec);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATKILLS"),stats.kills);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDEATHS"),stats.deaths);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDDEALT"),stats.damagedealt);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATDTAKEN"),stats.damagetaken);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATTDEALT"),stats.topdealt);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATTTAKEN"),stats.toptaken);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATMKILL"),stats.mkill);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSKILL"),stats.skill);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
str = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_STATFAVWEAP"));
if ( stats.favweapon == -1 ) str = str.."N/A";
else
{
let def = GetDefaultByType(stats.wstats[stats.favweapon].w);
str = str..def.GetTag();
}
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
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);
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 16;
}
else if ( (curtab == TAB_INVENTORY) || ((curtab == TAB_TRADING) && sub && (sel0 != -1)) )
{
if ( invlist.Size() <= 0 )
{
str = StringTable.Localize("$SWWM_NOINV");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
xx = 9;
yy = 23;
int longest, len;
int maxcol, totalcol, cols = 1;
// first pass, calculate longest item name
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
for ( int i=ofs; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
if ( (invlist[i] is 'Ammo') || (invlist[i].Amount > 1) || (!(invlist[i] is 'PuzzleItem') && (invlist[i].MaxAmount > 1)) ) str = String.Format("%dx %s",invlist[i].Amount,invlist[i].GetTag());
else str = invlist[i].GetTag();
int clscol = Font.CR_WHITE;
if ( invlist[i] is 'Weapon' ) clscol = Font.CR_GOLD;
else if ( (invlist[i] is 'Ammo') || (invlist[i] is 'BackpackItem') || (invlist[i] is 'HammerspaceEmbiggener') ) clscol = Font.CR_BROWN;
else if ( (invlist[i] is 'PowerupGiver') || (invlist[i] is 'AmmoFabricator') || invlist[i].bBIGPOWERUP ) clscol = Font.CR_PURPLE;
else if ( (invlist[i] is 'Health') || (invlist[i] is 'HealthPickup') || (invlist[i] is 'SWWMHealth') ) clscol = Font.CR_RED;
else if ( (invlist[i] is 'Armor') || (invlist[i] is 'SWWMSpareArmor') ) clscol = Font.CR_GREEN;
else if ( invlist[i] is 'PuzzleItem' ) clscol = Font.CR_LIGHTBLUE;
Screen.DrawText(fnt,clscol,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
if ( maxcol < totalcol )
{
// draw scrollbar
int szr = totalcol-maxcol;
xx = floor((ofs/22.)*(630./szr))+2.;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+373,"▬",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(WindowSeparatorH,false,origin.x,origin.y+377,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_KEYS )
{
if ( invlist.Size() <= 0 )
{
str = StringTable.Localize("$SWWM_NOKEYS");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
xx = 9;
yy = 23;
int longest = 0, len;
int maxcol, totalcol, cols = 1;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+24);
totalcol = (invlist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
Screen.DrawText(fnt,Font.CR_UNTRANSLATED,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
if ( maxcol < totalcol )
{
// draw scrollbar
int szr = totalcol-maxcol;
xx = floor((ofs/22.)*(630./szr))+2.;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+373,"▬",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(WindowSeparatorH,false,origin.x,origin.y+377,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_LIBRARY )
{
xx = 3;
yy = 14;
// draw the category
int twidth = (lang.GetString()~=="jp")?200:120;
str = StringTable.Localize(ltabnames[sel1]);
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+yy,"<",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx+twidth-6,origin.y+yy,">",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(fnt,Font.CR_FIRE,origin.x+xx+(twidth-fnt.StringWidth(str))/2,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// draw "unread" indicators on sides
int ltab = sel1-1;
if ( ltab < 0 ) ltab = 2;
int rtab = sel1+1;
if ( rtab > 2 ) rtab = 0;
bool lunread = false, runread = false;
for ( int i=0; i<lorelib.ent.Size(); i++ )
{
if ( lorelib.ent[i].tab == ltab ) lunread |= !lorelib.ent[i].read;
if ( lorelib.ent[i].tab == rtab ) runread |= !lorelib.ent[i].read;
}
if ( lunread ) Screen.DrawText(TewiFont,Font.CR_GOLD,origin.x+xx+6,origin.y+yy,"‼",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( runread ) Screen.DrawText(TewiFont,Font.CR_GOLD,origin.x+xx+twidth-12,origin.y+yy,"‼",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture((lang.GetString()~=="jp")?LoreSeparatorW:LoreSeparator,false,origin.x,origin.y+27,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 18;
// draw the current entries
int ofs = max(0,ofs0-26);
for ( int i=ofs; i<lorelist.Size(); i++ )
{
if ( yy > 370 ) break;
str = StringTable.Localize(lorelist[i].tag);
int len = fnt.StringWidth(str);
Screen.DrawText(fnt,(i==sel0)?Font.CR_FIRE:Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( !lorelist[i].read )
Screen.DrawText(TewiFont,Font.CR_GOLD,origin.x+xx+len,origin.y+yy," ‼",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
xx += twidth+2;
Screen.DrawTexture(WindowSeparator,false,origin.x+xx,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 3;
// scrollbar
if ( lorelist.Size() > 27 )
{
int szr = lorelist.Size()-27;
yy = floor((ofs)*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 5;
Screen.DrawTexture(WindowSeparator,false,origin.x+xx,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 3;
}
xx += 4;
// draw the entry text (if open)
if ( !sub )
{
str = StringTable.Localize("$SWWM_LOREUNSEL");
Screen.DrawText(fnt,Font.CR_FIRE,origin.x+xx+((634-xx)-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
str = StringTable.Localize(lorelist[sel0].text);
BrokenLines l = fnt.BreakLines(str,int(635-xx));
if ( l.Count() > 28 ) l = fnt.BreakLines(str,int(626-xx));
yy = 17;
ofs = clamp(sel2,0,max(0,l.Count()-28));
for ( int i=ofs; i<l.Count(); i++ )
{
if ( yy > 370 ) break;
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
// scrollbar
if ( l.Count() > 28 )
{
Screen.DrawTexture(WindowSeparator,false,origin.x+631,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx = 634;
int szr = l.Count()-28;
yy = floor(ofs*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_STORE )
{
if ( storelist.Size() <= 0 )
{
str = StringTable.Localize("$SWWM_NOSTORE");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
// draw all the stuff in the store
xx = 9;
yy = 23;
int longest = 0, len;
int maxcol, totalcol;
for ( int i=0; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
if ( (storeunits[i] > 1) || (storelist[i] is 'Ammo') ) str = String.Format("%dx %s",storeunits[i],def.GetTag());
else str = def.GetTag();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
}
maxcol = 622/(longest+96);
totalcol = (storelist.Size()/22)+1;
int ofs = int(max(0,(ofs0/22)-(maxcol-1))*22);
int cols = 1;
for ( int i=ofs; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
if ( (storeunits[i] > 1) || (storelist[i] is 'Ammo') ) str = String.Format("%dx %s",storeunits[i],def.GetTag());
else str = def.GetTag();
int clscol = Font.CR_WHITE;
if ( storelist[i] is 'Weapon' ) clscol = Font.CR_GOLD;
else if ( storelist[i] is 'Ammo' ) clscol = Font.CR_BROWN;
else if ( (storelist[i] is 'PowerupGiver') || (storelist[i] is 'AmmoFabricator') || def.bBIGPOWERUP ) clscol = Font.CR_PURPLE;
else if ( (storelist[i] is 'Health') || (storelist[i] is 'HealthPickup') || (storelist[i] is 'SWWMHealth') ) clscol = Font.CR_RED;
else if ( (storelist[i] is 'Armor') || (storelist[i] is 'SWWMSpareArmor') ) clscol = Font.CR_GREEN;
Screen.DrawText(fnt,clscol,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+96;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
xx = 9;
yy = 23;
cols = 1;
for ( int i=ofs; i<storelist.Size(); i++ )
{
if ( !storelist[i] ) continue;
let def = GetDefaultByType(storelist[i]);
int price = int(def.Stamina*(1.+.5*(storeunits[i]-1)));
str = String.Format("¥%d",price);
len = TewiFont.StringWidth(str);
int clscol = Font.CR_FIRE;
if ( (price > muns1) && (muns2 <= 0) ) clscol = Font.CR_BLACK;
Screen.DrawText(TewiFont,clscol,origin.x+xx+longest+80-len,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+96;
yy = 23;
cols++;
if ( cols > maxcol ) break;
}
}
if ( maxcol < totalcol )
{
// draw scrollbar
int szr = totalcol-maxcol;
xx = floor((ofs/22.)*(630./szr))+2.;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+373,"▬",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(WindowSeparatorH,false,origin.x,origin.y+377,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_TRADING )
{
if ( !sub )
{
if ( playerlist.Size() <= 0 )
{
str = StringTable.Localize("$SWWM_NOTRADE");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
xx = 9;
yy = 23;
int longest = 0, len;
int ofs = int(floor(max(0,sel0-44)/22.)*22);
int cols = 1;
for ( int i=ofs; i<playerlist.Size(); i++ )
{
str = players[playerlist[i]].GetUserName();
len = fnt.StringWidth(str);
if ( len > longest ) longest = len;
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+24;
yy = 23;
longest = 0;
cols++;
if ( cols > 3 ) break;
}
}
if ( playerlist.Size() > 65 )
{
// draw scrollbar
int szr = (playerlist.Size()/22)-2;
xx = floor((ofs/22)*(630./szr))+2;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+373,"▬",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(WindowSeparatorH,false,origin.x,origin.y+377,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( sub )
{
if ( sel0 == -1 )
{
if ( tradelib.ent.Size() <= 0 )
{
str = StringTable.Localize("$SWWM_NOTRADEHIST");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
xx = 6;
yy = 17;
int ofs = clamp(sel1,0,max(0,tradelib.ent.Size()-28));
for ( int i=ofs; i<tradelib.ent.Size(); i++ )
{
if ( yy >= 370 ) break;
let ent = tradelib.ent[tradelib.ent.Size()-(i+1)];
int thour = (ent.timestamp/(3600*Thinker.TICRATE));
int tmin = (ent.timestamp/(60*Thinker.TICRATE))%60;
int tsec = (ent.timestamp/Thinker.TICRATE)%60;
str = String.Format("\cu[\cc%02d\cu:\cc%02d\cu:\cc%02d\cu]\c- ",thour,tmin,tsec);
str.AppendFormat("\cd%s %s\cd: \cj%dx \cf%s\c-",ent.type?StringTable.Localize("$SWWM_TRADEFROM"):StringTable.Localize("$SWWM_TRADETO"),ent.other,ent.amt,GetDefaultByType(ent.what).GetTag());
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
// scrollbar
if ( tradelib.ent.Size() > 28 )
{
Screen.DrawTexture(WindowSeparator,false,origin.x+631,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx = 634;
int szr = tradelib.ent.Size()-28;
yy = floor(ofs*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
}
}
else if ( curtab == TAB_CHAT )
{
let bar = SWWMStatusBar(StatusBar);
if ( !bar || (bar.FullHistory.Size() <= 0) )
{
str = StringTable.Localize("$SWWM_NOCHAT");
Screen.DrawText(fnt,Font.CR_FIRE,(ss.x-fnt.StringWidth(str))/2.,(ss.y-fnt.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
int margin = TewiFont.StringWidth("[00:00:00] ");
int ofs = bar.FullHistory.Size()-(1+sel0);
xx = 3;
yy = 379;
for ( int i=ofs; i>=0; i-- )
{
int col = (bar.FullHistory[i].type==PRINT_TEAMCHAT)?tcol.GetInt():ccol.GetInt();
int thour = (bar.FullHistory[i].tic/(3600*Thinker.TICRATE));
int tmin = (bar.FullHistory[i].tic/(60*Thinker.TICRATE))%60;
int tsec = (bar.FullHistory[i].tic/Thinker.TICRATE)%60;
str = String.Format("\cu[\c-%02d\cu:\c-%02d\cu:\c-%02d\cu]\c- ",thour,tmin,tsec);
BrokenLines l = fnt.BreakLines(bar.FullHistory[i].str,626-margin);
double by = yy-13*l.Count();
if ( by < 17 ) break;
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+by,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
for ( int j=0; j<l.Count(); j++ )
Screen.DrawText(fnt,col,origin.x+xx+margin,origin.y+by+j*13,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy = by;
}
// scrollbar
if ( bar.FullHistory.Size() > 1 )
{
Screen.DrawTexture(WindowSeparator,false,origin.x+631,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx = 634;
int szr = bar.FullHistory.Size()-1;
yy = floor((szr-sel0)*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
else if ( curtab == TAB_SECRET )
{
Screen.DrawTexture(EasterEgg,false,origin.x+20,origin.y+40,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = StringTable.Localize("$SWWM_TODEMO");
Screen.DrawText(fnt,Font.CR_FIRE,origin.x+(640-fnt.StringWidth(str))/2.,origin.y+350,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
else if ( curtab == TAB_HELP )
{
// help tab
int k1, k2;
[k1, k2] = bindings.GetKeysForCommand("openmenu SWWMKnowledgeBaseMenu");
String kstr = bindings.NameKeys(k1,k2);
str = String.Format(StringTable.Localize("$SWWM_HELPTXT"),kstr);
if ( multiplayer ) str = str..StringTable.Localize("$SWWM_HELPTXT_MP");
BrokenLines l = fnt.BreakLines(str,629);
if ( l.Count() > 28 ) l = fnt.BreakLines(str,620);
xx = 6;
yy = 17;
int ofs = clamp(sel0,0,max(0,l.Count()-28));
for ( int i=ofs; i<l.Count(); i++ )
{
if ( yy >= 370 ) break;
Screen.DrawText(fnt,Font.CR_WHITE,origin.x+xx,origin.y+yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
// scrollbar
if ( l.Count() > 28 )
{
Screen.DrawTexture(WindowSeparator,false,origin.x+631,origin.y+14,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx = 634;
int szr = l.Count()-28;
yy = floor(ofs*(353./szr))+17;
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+xx,origin.y+yy,"▮",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
}
}