// 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; transient Font TewiFont, MPlusFont; int curtab, oldtab; // for scrolling bool sub; int sel0, sel1, sel2; // stats SWWMStats stats; // inventory lists Array invlist; // lore stuff SWWMLoreLibrary lorelib; Array lorelist; int oldloresiz; // store stuff Array > storelist; Array storeunits; // trading SWWMTradeHistory tradelib; Array 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 lastuse; int lastuseamt; int checkuse; int checkdrop; int checksend; // seeeeecret int kcode; // 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(); 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(); tradelib = SWWMTradeHistory.Find(players[consoleplayer]); stats = SWWMStats.Find(players[consoleplayer]); tmsg = "$SWWM_MAINCONTROLS"; tmsgtic = gametic+140; } 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; 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(); playerlist.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(); playerlist.Clear(); return true; case MKEY_DOWN: if ( curtab == TAB_HELP ) { String str = StringTable.Localize("$SWWM_HELPTXT"); 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"); 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 ) { String str = StringTable.Localize(lorelist[sel0].text); int ofs = fnt.StringWidth("MMMMMMMMMMMMMMMMMMMM")+12; 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"); 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; } else if ( curtab == TAB_TRADING ) { if ( !sub && (playerlist.Size() > 1) ) { // scroll through player list MenuSound("menu/demoscroll"); sel0++; if ( sel0 >= playerlist.Size() ) sel0 = 0; } else if ( sub ) { if ( (sel0 == -1) && (sel1 < tradelib.ent.Size()-28) ) { // scroll through trading history MenuSound("menu/demoscroll"); sel1++; } else if ( invlist.Size() > 1 ) { // scroll through inventory MenuSound("menu/demoscroll"); sel1++; if ( sel1 >= invlist.Size() ) sel1 = 0; } } } return true; case MKEY_UP: if ( curtab == TAB_HELP ) { if ( sel0 > 0 ) { MenuSound("menu/demoscroll"); sel0--; } } else 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; } else if ( curtab == TAB_TRADING ) { if ( !sub && (playerlist.Size() > 1) ) { // scroll through player list MenuSound("menu/demoscroll"); sel0--; if ( sel0 < 0 ) sel0 = playerlist.Size()-1; } else if ( sub ) { if ( (sel0 == -1) && (sel1 > 0) ) { // scroll through trading history MenuSound("menu/demoscroll"); sel1--; } else if ( invlist.Size() > 1 ) { // scroll through inventory MenuSound("menu/demoscroll"); sel1--; if ( sel1 < 0 ) sel1 = invlist.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; } else if ( curtab == TAB_TRADING ) { if ( !sub && (playerlist.Size() > 21) ) // lol is this ever going to happen { int oldsel = sel0; sel0 += 22; if ( sel0 >= playerlist.Size() ) sel0 = playerlist.Size()-1; if ( sel0 != oldsel ) MenuSound("menu/demoscroll"); } else if ( sub && (sel0 != -1) ) { int oldsel = sel1; sel1 += 22; if ( sel1 >= invlist.Size() ) sel1 = invlist.Size()-1; if ( sel1 != oldsel ) MenuSound("menu/demoscroll"); } } 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; } else if ( curtab == TAB_TRADING ) { if ( !sub && (playerlist.Size() > 21) ) // lol is this ever going to happen { if ( sel0-22 >= 0 ) { sel0 -= 22; MenuSound("menu/demoscroll"); } } else if ( sub && (sel0 != -1) ) { if ( sel1-22 >= 0 ) { sel1 -= 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()) ) { 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+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 ) 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; sel2 = 0; } } else if ( curtab == TAB_TRADING ) { if ( !sub && (playerlist.Size() > 0) ) { // pick a player MenuSound("menu/demosel"); sub = true; 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; sel0 = -1; sel1 = 0; } else if ( sub ) { // go back MenuSound("menu/democlose"); sub = false; sel0 = 0; } } 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 a, Class 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 tag2 ) continue; greater = true; invlist.Insert(i,inv); break; } if ( greater ) continue; invlist.Push(inv); } // re-sort by category for ( int i=0; i 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 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[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)(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[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 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 0) && CmpInventoryClass(storelist[k-1],storelist[k]) ) { Class 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 0) && (idx < lorelist.Size()) ) sel0 = idx; } // 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 tag2 ) continue; greater = true; invlist.Insert(i,inv); break; } if ( greater ) continue; invlist.Push(inv); } // re-sort by category for ( int i=0; i 0) && CmpInventory(invlist[k-1],invlist[k]) ) { Inventory tmp = invlist[k]; invlist[k] = invlist[k-1]; invlist[k-1] = tmp; k--; } j++; } } } } // 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; 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: 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(); 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.; 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 mx = (curtab>7)?9:8; for ( int i=0; i7)?curtab:i]); Screen.DrawText(fnt,((i>7)||(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 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 yy = 386; if ( gametic < tmsgtic ) { str = StringTable.Localize(tmsg); 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 = String.Format("DemolitionOS %s",StringTable.Localize("$SWWM_MODVER")); 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= 370 ) break; Screen.DrawText(fnt,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(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; 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 ) { 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 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; 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(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 longest ) longest = len; 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(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_WHITE,origin.x+xx+fnt.StringWidth("MMMMMMMMMMMMMMMMMMMM")-6,origin.y+yy,">",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); Screen.DrawText(fnt,Font.CR_FIRE,origin.x+xx+(fnt.StringWidth("MMMMMMMMMMMMMMMMMMMM")-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 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 += fnt.StringWidth("MMMMMMMMMMMMMMMMMMMM")+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(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 370 ) break; Screen.DrawText(fnt,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(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 ofs = int(floor(max(0,sel0-22)/22.)*22); int cols = 1; int collen[2]; for ( int i=ofs; i 1 ) str = String.Format("%dx %s",storeunits[i],def.GetTag()); else str = def.GetTag(); len = fnt.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(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(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 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 ) { if ( !sub ) { 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 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(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 ( 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 ) { xx = 6; yy = 17; int ofs = clamp(sel1,0,max(0,tradelib.ent.Size()-28)); for ( int i=ofs; i= 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 { xx = 9; yy = 23; int longest = 0, len; int ofs = int(floor(max(0,sel1-44)/22.)*22); int cols = 1; for ( int i=ofs; i 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; 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!=sel1)?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_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 = 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 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); 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= 370 ) break; Screen.DrawText(fnt,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); } } } } // voice selector Class OptionMenuItemSWWMVoiceOption : OptionMenuItemOptionBase { CVar mCVar; Array 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 lst; lst.Clear(); String dat = Wads.ReadLump(lmp); dat.Split(lst,"\n",0); for ( int i=0; i= 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 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; transient CVar lang; transient Font TewiFont, MPlusFont; 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; } } if ( !TewiFont ) TewiFont = Font.GetFont('Tewi'); if ( !MPlusFont ) MPlusFont = Font.GetFont('MPlus'); if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]); Font fnt = TewiFont; if ( lang.GetString() ~== "jp" ) fnt = MPlusFont; 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