swwmgz_m/zscript/swwm_menu.zsc
Marisa Kirisame d1b1a0541d Added Lead Ball ammo type to Spreadgun.
Partial implementation of Fuck Your Shit rounds, currently in progress.
Added various shader effects to some powerups, and to player damage.
Added custom view effects to player death, disabled "face attacker" because it looks weird with model-based players.
Added "untouchable" spree tracking to the Stats tab.
Implemented "emergency reboot system" for people who want a less shameful form of the Resurrect cheat. Cooldown for consecutive reboots can be configured.
Rebalanced armors.
Small language string corrections.
Adjusted pickup model sizes of some weapons.
Fixed missing punch sound (damn typos).
Fix targetter always displaying voodoo dolls.
Fix uptime breaking when loading saves, now based on total playtime rather than gametic.
Readjusted Spreadgun ammo availability.
Flush HUD interpolators alongside messages, fixes things such as the score VERY slowly counting up when loading a save.
Spare armors now only get auto-used on pickup if there is NO armor available of that type.
Added some extra visual effects to punching walls and non-bleeding actors.
Slightly altered the melee range so it's not as awkward.
Fixed punching not using flesh sounds for bleeding actors.
Pusher primary now drags the player towards their target, like the Chainsaw.
Fixed the player having no pain sounds whatsoever.
Fixed stair step anchoring not working.
The damage dealt when walljumping on a monster now also gets boosted by the Ragekit.
2020-03-04 17:05:22 +01:00

1313 lines
No EOL
45 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
};
TextureID MainWindow, TabSeparator, WindowSeparator, WindowSeparatorH,
FancyBg, EasterEgg, LoreSeparator;
Font TewiFont;
int curtab;
// for scrolling
bool sub;
int sel0, sel1, sel2;
// 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;
// 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;
// seeeeecret
int kcode;
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');
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);
curtab = CVar.GetCVar('swwm_lasttab',players[consoleplayer]).GetInt();
if ( (curtab < 0) || (curtab > 7) ) curtab = 0;
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();
stats = SWWMStats.Find(players[consoleplayer]);
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
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;
sub = false;
}
default:
kcode = 0;
break;
}
switch ( mkey )
{
case MKEY_BACK:
MenuSound("menu/democlose");
Close();
return true;
case MKEY_PAGEUP:
MenuSound("menu/demotab");
if ( (curtab <= 0) || (curtab > 7) ) curtab = 7;
else curtab--;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
return true;
case MKEY_PAGEDOWN:
MenuSound("menu/demotab");
if ( curtab < 7 ) curtab++;
else curtab = 0;
CVar.GetCVar('swwm_lasttab',players[consoleplayer]).SetInt(curtab);
sel0 = sel1 = sel2 = 0;
sub = false;
invlist.Clear();
lorelist.Clear();
storelist.Clear();
storeunits.Clear();
return true;
case MKEY_DOWN:
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 = TewiFont.BreakLines(str,629);
if ( l.Count() > 28 ) l = TewiFont.BreakLines(str,620);
if ( (l.Count() > 28) && (sel0 < l.Count()-28) )
{
MenuSound("menu/demoscroll");
sel0++;
}
}
else if ( (curtab == TAB_CHAT) && (StatusBar is 'SWWMStatusBar') && (sel0 > 0) )
{
MenuSound("menu/demoscroll");
sel0--;
}
else if ( (curtab == TAB_LIBRARY) && (lorelist.Size() > 1) )
{
if ( sub )
{
int ofs = TewiFont.StringWidth("********************")+12;
if ( lorelist.Size() > 26 ) ofs += 8;
String str = StringTable.Localize(lorelist[sel0].text);
BrokenLines l = TewiFont.BreakLines(str,635-ofs);
if ( l.Count() > 28 ) l = TewiFont.BreakLines(str,626-ofs);
if ( (l.Count() > 28) && (sel2 < l.Count()-28) )
{
MenuSound("menu/demoscroll");
sel2++;
}
}
else
{
MenuSound("menu/demoscroll");
sel0++;
if ( sel0 >= lorelist.Size() )
sel0 = 0;
}
}
else if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS)) && (invlist.Size() > 1) )
{
MenuSound("menu/demoscroll");
sel0++;
if ( sel0 >= invlist.Size() )
sel0 = 0;
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 1) )
{
MenuSound("menu/demoscroll");
sel0++;
if ( sel0 >= storelist.Size() )
sel0 = 0;
}
return true;
case MKEY_UP:
if ( curtab == TAB_MISSION )
{
if ( sel0 > 0 )
{
MenuSound("menu/demoscroll");
sel0--;
}
}
else if ( (curtab == TAB_CHAT) && (StatusBar is 'SWWMStatusBar') && (sel0 < SWWMStatusBar(StatusBar).FullHistory.Size()-1) )
{
MenuSound("menu/demoscroll");
sel0++;
}
else if ( (curtab == TAB_LIBRARY) && (lorelist.Size() > 1) )
{
if ( sub )
{
if ( sel2 > 0 )
{
MenuSound("menu/demoscroll");
sel2--;
}
}
else
{
MenuSound("menu/demoscroll");
sel0--;
if ( sel0 < 0 )
sel0 = lorelist.Size()-1;
}
}
else if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS)) && (invlist.Size() > 1) )
{
MenuSound("menu/demoscroll");
sel0--;
if ( sel0 < 0 )
sel0 = invlist.Size()-1;
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 1) )
{
MenuSound("menu/demoscroll");
sel0--;
if ( sel0 < 0 )
sel0 = storelist.Size()-1;
}
return true;
case MKEY_RIGHT:
if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS)) && (invlist.Size() > 21) )
{
int oldsel = sel0;
sel0 += 22;
if ( sel0 >= invlist.Size() ) sel0 = invlist.Size()-1;
if ( sel0 != oldsel ) MenuSound("menu/demoscroll");
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 21) )
{
int oldsel = sel0;
sel0 += 22;
if ( sel0 >= storelist.Size() ) sel0 = storelist.Size()-1;
if ( sel0 != oldsel ) MenuSound("menu/demoscroll");
}
else if ( curtab == TAB_LIBRARY )
{
MenuSound("menu/demoscroll");
sel0 = 0;
sub = false;
sel1++;
if ( sel1 > LORE_LORE )
sel1 = LORE_ITEM;
}
return true;
case MKEY_LEFT:
if ( ((curtab == TAB_INVENTORY) || (curtab == TAB_KEYS)) && (invlist.Size() > 21) )
{
if ( sel0-22 >= 0 )
{
MenuSound("menu/demoscroll");
sel0 -= 22;
}
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 21) )
{
if ( sel0-22 >= 0 )
{
MenuSound("menu/demoscroll");
sel0 -= 22;
}
}
else if ( curtab == TAB_LIBRARY )
{
MenuSound("menu/demoscroll");
sel0 = 0;
sub = false;
sel1--;
if ( sel1 < LORE_ITEM )
sel1 = LORE_LORE;
}
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+1;
EventHandler.SendNetworkEvent(String.Format("swwmuseitem.%s",invlist[sel0].GetClassName()),consoleplayer);
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 0) && (sel0 < storelist.Size()) )
{
int moni = SWWMCredits.Get(players[consoleplayer]);
let itm = GetDefaultByType(storelist[sel0]);
let amt = storeunits[sel0];
int price = int(itm.Stamina*(1.+.5*(amt-1)));
if ( moni < price )
{
MenuSound("menu/noinvuse");
tmsg = StringTable.Localize("$SWWM_STOREMUNS");
tmsgtic = gametic+35;
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+35;
return true;
}
EventHandler.SendNetworkEvent(String.Format("swwmstoregive.%s",storelist[sel0].GetClassName()),consoleplayer,price,amt);
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;
sel2 = 0;
}
}
return true;
case MKEY_CLEAR:
if ( (curtab == TAB_INVENTORY) && (invlist.Size() > 0) )
{
lastuse = invlist[sel0].GetClass();
lastuseamt = invlist[sel0].Amount;
checkdrop = gametic+1;
EventHandler.SendNetworkEvent(String.Format("swwmdropitem.%s",invlist[sel0].GetClassName()),consoleplayer);
}
else if ( (curtab == TAB_LIBRARY) && sub )
{
MenuSound("menu/democlose");
sub = false;
}
return true;
}
return Super.MenuEvent(mkey,fromcontroller);
}
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;
}
override void Ticker()
{
Super.Ticker();
if ( players[consoleplayer].Health <= 0 )
{
// ded
Close();
return;
}
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 '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
for ( int i=0; i<invlist.Size(); i++ )
{
int j = 1;
while ( j < invlist.Size() )
{
int k = j;
while ( (k > 0) && CmpInventory(invlist[k-1],invlist[k]) )
{
Inventory tmp = invlist[k];
invlist[k] = invlist[k-1];
invlist[k-1] = tmp;
k--;
}
j++;
}
}
}
else if ( curtab == TAB_KEYS )
{
invlist.Clear();
// alphabetically sorted keys
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
{
if ( !(inv is 'Key') ) 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);
}
}
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;
if ( type is 'Ammo' )
{
// get the largest 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);
if ( inv2.Amount > amt ) amt = inv2.Amount;
}
}
int price = int(inv.Stamina*(1.+.5*(amt-1)));
bool greater = false;
for ( int j=0; j<storelist.Size(); j++ )
{
let inv2 = GetDefaultByType(storelist[j]);
int price2 = int(inv2.Stamina*(1.+.5*(storeunits[j]-1)));
if ( price > price2 ) 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
for ( int i=0; i<storelist.Size(); i++ )
{
int j = 1;
while ( j < storelist.Size() )
{
int k = j;
while ( (k > 0) && CmpInventoryClass(storelist[k-1],storelist[k]) )
{
Class<Inventory> tmp = storelist[k];
storelist[k] = storelist[k-1];
storelist[k-1] = tmp;
int tmpi = storeunits[k];
storeunits[k] = storeunits[k-1];
storeunits[k-1] = tmpi;
k--;
}
j++;
}
}
}
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;
}
// add "new entries" message
if ( lorelib.ent.Size() != oldloresiz )
{
tmsg = StringTable.Localize("$SWWM_NEWLORE");
tmsgtic = gametic+35;
}
oldloresiz = lorelib.ent.Size();
}
// 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+35;
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+35;
MenuSound("menu/noinvuse");
}
else if ( (amt == 0) && (sel0 >= invlist.Size()) )
sel0 = max(0,sel0-1);
}
}
override bool OnUiEvent( UIEvent ev )
{
switch ( ev.type )
{
case UIEvent.Type_KeyDown:
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:
return MenuEvent(MKEY_DOWN,false);
break;
case UIEvent.Type_WheelUp:
return MenuEvent(MKEY_UP,false);
break;
}
return Super.OnUIEvent(ev);
}
override void Drawer()
{
Super.Drawer();
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.;
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"
};
static const string ltabnames[] =
{
"$SWWM_LORETAB0", "$SWWM_LORETAB1", "$SWWM_LORETAB2"
};
int mx = (curtab==TAB_SECRET)?9:8;
for ( int i=0; i<mx; i++ )
{
str = StringTable.Localize(tabnames[i]);
Screen.DrawText(TewiFont,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 += TewiFont.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 muns = SWWMCredits.Get(players[consoleplayer]);
str = String.Format("\cg¥\c-%09d",muns);
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
if ( gametic < tmsgtic ) str = StringTable.Localize(tmsg);
else
{
str = StringTable.Localize("$SWWM_MAINCONTROLS");
switch ( curtab )
{
case TAB_INVENTORY:
str = str..StringTable.Localize("$SWWM_LISTCONTROLS")..StringTable.Localize("$SWWM_INVCONTROLS");
break;
case TAB_KEYS:
str = str..StringTable.Localize("$SWWM_LISTCONTROLS");
break;
case TAB_MISSION:
case TAB_CHAT:
str = str..StringTable.Localize("$SWWM_TEXTCONTROLS");
break;
case TAB_STORE:
str = str..StringTable.Localize("$SWWM_LISTCONTROLS")..StringTable.Localize("$SWWM_STRCONTROLS");
break;
case TAB_TRADING:
if ( sub )
{
if ( sel1 == -1 ) str = str..StringTable.Localize("$SWWM_TEXTCONTROLS")..StringTable.Localize("$SWWM_TRADECONTROLS2");
else str = str..StringTable.Localize("$SWWM_LISTCONTROLS")..StringTable.Localize("$SWWM_TRADECONTROLS1");
}
else str = str..StringTable.Localize("$SWWM_TEXTCONTROLS")..StringTable.Localize("$SWWM_TRADECONTROLS0");
break;
case TAB_LIBRARY:
if ( sub ) str = str..StringTable.Localize("$SWWM_TEXTCONTROLS")..StringTable.Localize("$SWWM_LORECONTROLS1");
else str = str..StringTable.Localize("$SWWM_TEXTCONTROLS")..StringTable.Localize("$SWWM_LORECONTROLS0");
break;
}
}
xx = 4;
yy = 386;
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = String.Format("DemolitionOS %s",StringTable.Localize("$SWWM_MODVER"));
xx = 637-TewiFont.StringWidth(str);
Screen.DrawText(TewiFont,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 = TewiFont.BreakLines(str,629);
if ( l.Count() > 28 ) l = TewiFont.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(TewiFont,Font.CR_GREEN,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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(TewiFont,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\cu¥\c-%09d",StringTable.Localize("$SWWM_STATHISCORE"),stats.hiscore);
Screen.DrawText(TewiFont,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 )
{
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<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 = TewiFont.StringWidth(str);
if ( len > longest ) longest = len;
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(TewiFont,clscol,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(128,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 ( invlist.Size() > 65 )
{
// draw scrollbar
int szr = (invlist.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 ( curtab == TAB_KEYS )
{
xx = 9;
yy = 23;
int longest = 0, len;
int ofs = int(floor(max(0,sel0-44)/22.)*22);
int cols = 1;
for ( int i=0; i<invlist.Size(); i++ )
{
if ( !invlist[i] ) continue;
str = invlist[i].GetTag();
len = TewiFont.StringWidth(str);
if ( len > longest ) longest = len;
Screen.DrawText(TewiFont,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(128,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 ( invlist.Size() > 65 )
{
// draw scrollbar
int szr = (invlist.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 ( curtab == TAB_LIBRARY )
{
xx = 3;
yy = 14;
// draw the category
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_FIRE,origin.x+xx+(TewiFont.StringWidth("********************")-TewiFont.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,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,origin.y+yy," ‼ ",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawTexture(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,sel0-26);
for ( int i=ofs; i<lorelist.Size(); i++ )
{
if ( yy > 370 ) break;
str = StringTable.Localize(lorelist[i].tag);
if ( !lorelist[i].read ) str = str.." \cf‼\c-";
Screen.DrawText(TewiFont,(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);
yy += 13;
}
xx += TewiFont.StringWidth("********************")+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() > 26 )
{
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(TewiFont,Font.CR_FIRE,origin.x+xx+((634-xx)-TewiFont.StringWidth(str))/2.,(ss.y-TewiFont.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
str = StringTable.Localize(lorelist[sel0].text);
BrokenLines l = TewiFont.BreakLines(str,int(635-xx));
if ( l.Count() > 28 ) l = TewiFont.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(TewiFont,Font.CR_GREEN,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(TewiFont,Font.CR_FIRE,(ss.x-TewiFont.StringWidth(str))/2.,(ss.y-TewiFont.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 ofs = int(floor(max(0,sel0-22)/22.)*22);
int cols = 1;
int collen[2];
for ( int i=ofs; 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 = TewiFont.StringWidth(str);
if ( len > longest ) longest = len;
collen[cols-1] = longest;
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(TewiFont,clscol,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(128,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += longest+96;
yy = 23;
longest = 0;
cols++;
if ( cols > 2 ) 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 > muns ) clscol = Font.CR_BLACK;
Screen.DrawText(TewiFont,clscol,origin.x+xx+collen[cols-1]+80-len,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(128,0,0,0):Color(0,0,0,0));
yy += 16;
if ( yy >= 370 )
{
xx += collen[cols-1]+96;
yy = 23;
cols++;
if ( cols > 2 ) break;
}
}
if ( storelist.Size() > 43 )
{
// draw scrollbar
int szr = (storelist.Size()/22)-1;
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 )
{
str = StringTable.Localize("$SWWM_COMINGSOON");
Screen.DrawText(TewiFont,Font.CR_FIRE,(ss.x-TewiFont.StringWidth(str))/2.,(ss.y-TewiFont.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
else if ( curtab == TAB_CHAT )
{
if ( !(StatusBar is 'SWWMStatusBar') ) return;
let bar = SWWMStatusBar(StatusBar);
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 = TewiFont.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(TewiFont,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 )
{
// hidden secret tab
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(TewiFont,Font.CR_FIRE,origin.x+(640-TewiFont.StringWidth(str))/2.,origin.y+350,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
}
// voice selector
Class OptionMenuItemSWWMVoiceOption : OptionMenuItemOptionBase
{
CVar mCVar;
Array<String> types;
OptionMenuItemSWWMVoiceOption Init( String label, Name command, CVar graycheck = null, int center = 0 )
{
Super.Init(label,command,'',graycheck,center);
mCVar = CVar.FindCVar(mAction);
int lmp;
for ( lmp = Wads.FindLump("swwmvoicepack.txt"); lmp > 0; lmp = Wads.FindLump("swwmvoicepack.txt",lmp+1) )
{
Array<String> lst;
lst.Clear();
String dat = Wads.ReadLump(lmp);
dat.Split(lst,"\n",0);
for ( int i=0; i<lst.Size(); i++ )
{
if ( (lst[i].Length() <= 0) || (lst[i].GetNextCodePoint(0) == 0) || (lst[i].Left(1) == "\n") || (lst[i].Left(1) == "#") ) continue;
types.Push(lst[i]);
}
}
return self;
}
override bool SetString( int i, String newtext )
{
if ( i == OP_VALUES )
{
int cnt = types.Size();
if ( cnt >= 0 )
{
mValues = newtext;
int s = GetSelection();
if ( (s >= cnt) || (s < 0) ) s = 0;
SetSelection(s);
return true;
}
}
return false;
}
override int GetSelection()
{
int Selection = -1;
int cnt = types.Size();
if ( (cnt > 0) && mCVar )
{
String cv = mCVar.GetString();
for( int i=0; i<cnt; i++ )
{
if ( cv ~== types[i] )
{
Selection = i;
break;
}
}
}
return Selection;
}
override void SetSelection( int Selection )
{
int cnt = types.Size();
if ( (cnt > 0) && mCVar )
mCVar.SetString(types[Selection]);
}
override int Draw( OptionMenuDescriptor desc, int y, int indent, bool selected )
{
if ( mCenter ) indent = (screen.GetWidth()/2);
drawLabel(indent,y,selected?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,isGrayed());
int Selection = GetSelection();
String loc;
if ( Selection == -1 ) loc = "Unknown";
else
{
String uptxt = types[Selection];
uptxt.MakeUpper();
String str = String.Format("SWWM_VOICENAME_%s",uptxt);
loc = StringTable.Localize(str,false);
if ( str == loc ) loc = types[Selection];
}
drawValue(indent,y,OptionMenuSettings.mFontColorValue,loc,isGrayed());
return indent;
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
int cnt = types.Size();
if ( cnt > 0 )
{
int Selection = GetSelection();
if ( mkey == Menu.MKEY_Left )
{
if ( Selection == -1 ) Selection = 0;
else if ( --Selection < 0 ) Selection = cnt-1;
}
else if ( (mkey == Menu.MKEY_Right) || (mkey == Menu.MKEY_Enter) )
{
if ( ++Selection >= cnt ) Selection = 0;
}
else return OptionMenuItem.MenuEvent(mkey,fromcontroller);
SetSelection(Selection);
Menu.MenuSound("menu/change");
}
else return OptionMenuItem.MenuEvent(mkey,fromcontroller);
return true;
}
}
// option menu /w tooltips
Class SWWMOptionMenu : OptionMenu
{
private String ttip;
override void Ticker()
{
Super.Ticker();
// fetch the tooltip for whatever's selected (if any)
if ( mDesc.mSelectedItem == -1 ) return;
String mcvar = mDesc.mItems[mDesc.mSelectedItem].GetAction();
mcvar.Replace(" ","_"); // need to strip whitespace for command actions
String locstr = String.Format("TOOLTIP_%s",mcvar);
ttip = StringTable.Localize(locstr,false);
if ( ttip == locstr ) ttip = "";
}
override void Drawer()
{
Super.Drawer();
if ( ttip == "" ) return;
// re-evaluate y to check where the cursor is
int cy = 0;
int y = mDesc.mPosition;
if ( y <= 0 )
{
let font = generic_ui||!mDesc.mFont?NewSmallFont:mDesc.mFont;
if ( font && (mDesc.mTitle.Length() > 0) )
y = -y+font.GetHeight();
else y = -y;
}
int fontheight = OptionMenuSettings.mLinespacing*CleanYfac_1;
y *= CleanYfac_1;
int lastrow = Screen.GetHeight()-OptionHeight()*CleanYfac_1;
for ( int i=0; ((i < mDesc.mItems.Size()) && (y <= lastrow)); i++ )
{
// Don't scroll the uppermost items
if ( i == mDesc.mScrollTop )
{
i += mDesc.mScrollPos;
if ( i >= mDesc.mItems.Size() ) break; // skipped beyond end of menu
}
y += fontheight;
if ( mDesc.mSelectedItem == i )
{
cy = y;
break;
}
}
let fnt = Font.GetFont('Tewi');
let lines = fnt.BreakLines(ttip,CleanWidth_1-8);
int height = (8+fnt.GetHeight()*lines.Count())*CleanYFac_1;
// draw at the bottom unless the selected option could is covered by the tooltip
int ypos = Screen.GetHeight()-height;
if ( cy >= ypos ) ypos = 0;
Screen.Dim("Black",.75,0,ypos,Screen.GetWidth(),height);
ypos += 4*CleanYFac_1;
for ( int i=0; i<lines.Count(); i++ )
{
Screen.DrawText(fnt,Font.CR_WHITE,4*CleanXFac_1,ypos,lines.StringAt(i),DTA_CleanNoMove_1,true);
ypos += fnt.GetHeight()*CleanYFac_1;
}
}
}