diff --git a/README.md b/README.md index 39ae5668..b8c5845b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,10 @@ * Lowering graphics settings * Freeing up RAM (close programs) * Updating your GPU drivers + +**Do NOT open issues to ask for support!** +The issues tab is meant for bugs that have to be fixed or features that should be implemented. +Any issue mentioning things like "h2-mod doesn't work" with no other information included will be closed. ## Compile from source diff --git a/data/cdata/ui_scripts/branding/__init__.lua b/data/cdata/ui_scripts/branding/__init__.lua index fd1b4944..169563ff 100644 --- a/data/cdata/ui_scripts/branding/__init__.lua +++ b/data/cdata/ui_scripts/branding/__init__.lua @@ -1,2 +1 @@ require("credits") -require("mainmenu") diff --git a/data/cdata/ui_scripts/branding/mainmenu.lua b/data/cdata/ui_scripts/branding/mainmenu.lua deleted file mode 100644 index 62ac1eb1..00000000 --- a/data/cdata/ui_scripts/branding/mainmenu.lua +++ /dev/null @@ -1,4 +0,0 @@ -LUI.onmenuopen("main_campaign", function(menu) - local headertext = menu:getFirstDescendentById("header_text") - headertext:setText("H2-MOD") -end) diff --git a/data/cdata/ui_scripts/motd/__init__.lua b/data/cdata/ui_scripts/motd/__init__.lua new file mode 100644 index 00000000..6ffca475 --- /dev/null +++ b/data/cdata/ui_scripts/motd/__init__.lua @@ -0,0 +1,2 @@ +require("motd") +require("featured") diff --git a/data/cdata/ui_scripts/motd/featured.lua b/data/cdata/ui_scripts/motd/featured.lua new file mode 100644 index 00000000..ea98d739 --- /dev/null +++ b/data/cdata/ui_scripts/motd/featured.lua @@ -0,0 +1,581 @@ +motd.getfeaturedtabtitle = function(index) + return motd.getfeaturedtab(index).tab_title or "" +end + +local animmsfull = 150 +local animms = animmsfull / 2 +local minimized = false + +LUI.onmenuopen("main_campaign", function(menu) + if (mods.getloaded() ~= nil or motd.getnumfeaturedtabs() <= 0) then + return + end + + local left = 885 + local featuredcontainer = LUI.UIElement.new({ + leftAnchor = true, + topAnchor = true, + left = left, + top = 420, + }) + + featuredcontainer:registerAnimationState("hide", { + leftAnchor = true, + topAnchor = true, + left = left, + top = 570, + }) + + featuredcontainer:registerAnimationState("show", { + leftAnchor = true, + topAnchor = true, + left = left, + top = 420, + }) + + local featuredstencil = LUI.UIStencilText.new({ + leftAnchor = true, + topAnchor = true, + height = 200, + width = GenericMenuDims.menu_width_standard + (10 + 12) * 2, + }) + + local featured = LUI.UIElement.new({ + left = 20, + leftAnchor = true, + topAnchor = true, + bottomAnchor = true, + rightAnchor = true + }) + + local arrowcontainer = LUI.UIElement.new({ + leftAnchor = true, + topAnchor = true, + bottomAnchor = true, + rightAnchor = true + }) + + arrowcontainer:registerAnimationState("hide", { + alpha = 0 + }) + + arrowcontainer:registerAnimationState("show", { + alpha = 1 + }) + + featured:addElement(arrowcontainer) + + featuredstencil:registerAnimationState("hide", { + leftAnchor = true, + topAnchor = true, + height = GenericButtonSettings.Styles.FlatButton.height + 2, + width = GenericMenuDims.menu_width_standard + (10 + 12) * 2, + }) + + local istopmost = function() + return LUI.FlowManager.IsMenuTopmost(Engine.GetLuiRoot(), "main_campaign") + end + + featuredstencil:registerAnimationState("show", { + leftAnchor = true, + topAnchor = true, + height = 200, + width = GenericMenuDims.menu_width_standard + (10 + 12) * 2, + }) + + local hoverelem = LUI.UIElement.new({ + leftAnchor = true, + topAnchor = true, + top = -10, + height = 150 + GenericButtonSettings.Styles.FlatButton.height + 2 + 10, + width = GenericMenuDims.menu_width_standard + 50, + left = -25 + }) + + local header = LUI.UIElement.new({ + topAnchor = true, + leftAnchor = true, + width = GenericMenuDims.menu_width_standard, + height = GenericButtonSettings.Styles.FlatButton.height, + }) + + local headerbg = LUI.UIImage.new({ + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + alpha = 0.55, + color = Colors.grey_14, + material = RegisterMaterial("white") + }) + + local headerbutton = LUI.UIImage.new({ + leftAnchor = true, + topAnchor = true, + height = 10, + width = 10, + top = 10.5, + left = 10, + zRot = -90, + color = { + r = 0.6, + g = 0.6, + b = 0.6, + }, + material = RegisterMaterial("widg_lobby_arrow") + }) + + headerbutton:registerEventHandler("mouseenter", function() + if (not istopmost()) then + return + end + + Engine.PlaySound(CoD.SFX.MouseOver) + headerbutton:animateToState("focused") + end) + + headerbutton:registerEventHandler("mouseleave", function() + headerbutton:animateToState("unfocused") + end) + + headerbutton:registerAnimationState("down", { + zRot = -90 + }) + + headerbutton:registerAnimationState("right", { + zRot = 0 + }) + + headerbutton:registerAnimationState("focused", { + color = Colors.h2.yellow + }) + + headerbutton:registerAnimationState("unfocused", { + color = { + r = 0.6, + g = 0.6, + b = 0.6, + } + }) + + local tabcount = motd.getnumfeaturedtabs() + + headerbutton:setHandleMouse(true) + headerbutton:registerEventHandler("leftmousedown", function() + Engine.PlaySound(CoD.SFX.MenuAccept) + headerbutton:processEvent({ + name = "mouseleave" + }) + + minimized = not minimized + + if (minimized) then + featuredstencil:animateToState("hide", animms) + featuredcontainer:animateToState("hide", animms) + headerbutton:animateToState("right", animms) + arrowcontainer:animateToState("hide", animms) + else + featuredstencil:animateToState("show", animms) + featuredcontainer:animateToState("show", animms) + headerbutton:animateToState("down", animms) + + if (tabcount > 1) then + arrowcontainer:animateToState("show", animms) + end + end + end) + + if (minimized) then + featuredstencil:animateToState("hide") + featuredcontainer:animateToState("hide") + headerbutton:animateToState("right") + arrowcontainer:animateToState("hide") + end + + header:addElement(headerbg) + header:addElement(headerbutton) + + local headertext = LUI.UIText.new({ + leftAnchor = true, + left = GenericButtonSettings.Styles.FlatButton.text_padding_with_content + 10, + top = -CoD.TextSettings.Font19.Height / 2 + 1.5, + font = CoD.TextSettings.Font19.Font, + height = CoD.TextSettings.Font19.Height + }) + + local rightoffset = -15 + local pips = {} + local focusindex = 0 + + local shiftto = nil + + for i = 1, tabcount do + local pipmat = RegisterMaterial("h1_ui_featured_pip_unfocused") + local ratio = Engine.GetMaterialAspectRatio(pipmat) + local height = 14 + + local pip = LUI.UIImage.new({ + topAnchor = true, + rightAnchor = true, + top = GenericButtonSettings.Styles.FlatButton.height / 2 - height / 2, + width = ratio * height, + height = height, + material = RegisterMaterial("h1_ui_featured_pip_unfocused"), + right = rightoffset + }) + + pip:setHandleMouse(true) + pip:registerEventHandler("mouseenter", function() + if (not istopmost() or minimized) then + return + end + + Engine.PlaySound(CoD.SFX.MouseOver) + end) + + pip:registerEventHandler("leftmousedown", function() + if (not istopmost() or minimized) then + return + end + + Engine.PlaySound(CoD.SFX.MenuAccept) + shiftto(#pips - i) + end) + + pip:registerAnimationState("focused", { + material = RegisterMaterial("h2_ui_featured_pip_focused"), + }) + + pip:registerAnimationState("unfocused", { + material = RegisterMaterial("h1_ui_featured_pip_unfocused"), + }) + + table.insert(pips, pip) + header:addElement(pip) + rightoffset = rightoffset - height + end + + pips[#pips]:animateToState("focused") + + headertext:setText(Engine.ToUpperCase(Engine.Localize("@LUA_MENU_FEATURED"))) + + local content = LUI.UIElement.new({ + topAnchor = true, + leftAnchor = true, + top = GenericButtonSettings.Styles.FlatButton.height + 3, + width = GenericMenuDims.menu_width_standard, + height = 150, + }) + + local stencil = LUI.UIStencilText.new({ + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + left = 1, + }) + + local imagelist = LUI.UIHorizontalList.new( { + left = 0, + leftAnchor = true, + width = (GenericMenuDims.menu_width_standard) * tabcount, + height = 150, + spacing = 0 + } ) + + stencil:addElement(imagelist) + + local contentborder = LUI.UIImage.new({ + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + rightAnchor = true, + alpha = 0, + material = RegisterMaterial("h2_ui_btn_focused_stroke_square") + }) + + contentborder:registerAnimationState("unfocused", { + alpha = 0 + }) + + contentborder:registerAnimationState("focused", { + alpha = 1 + }) + + contentborder:setup9SliceImage() + + local shift = function() + imagelist:registerAnimationState("move", { + leftAnchor = true, + left = (focusindex) * -GenericMenuDims.menu_width_standard + }) + + imagelist:animateToState("move", animmsfull) + end + + shiftto = function(index) + local prevfocus = focusindex + focusindex = (index) % tabcount + + pips[#pips - (prevfocus)]:animateToState("unfocused") + pips[#pips - (focusindex)]:animateToState("focused") + + shift() + end + + local shiftright = function() + local prevfocus = focusindex + focusindex = (focusindex + 1) % tabcount + + pips[#pips - (prevfocus)]:animateToState("unfocused") + pips[#pips - (focusindex)]:animateToState("focused") + + shift() + end + + local shiftleft = function() + local prevfocus = focusindex + focusindex = (focusindex - 1) % tabcount + + pips[#pips - (prevfocus)]:animateToState("unfocused") + pips[#pips - (focusindex)]:animateToState("focused") + + shift() + end + + for i = 1, tabcount do + local panel = LUI.UIElement.new({ + topAnchor = true, + leftAnchor = true, + bottomAnchor = true, + width = GenericMenuDims.menu_width_standard, + }) + + local text = LUI.UIText.new({ + bottomAnchor = true, + leftAnchor = true, + rightAnchor = true, + alignment = LUI.Alignment.Center, + bottom = (-CoD.TextSettings.Font21.Height / 2) + 2, + height = CoD.TextSettings.Font21.Height, + font = CoD.TextSettings.Font21.Font, + }) + + local textbg = LUI.UIImage.new({ + bottomAnchor = true, + leftAnchor = true, + rightAnchor = true, + height = CoD.TextSettings.Font21.Height * 2, + alpha = 0.75, + material = RegisterMaterial("black") + }) + + text:setText(motd.getfeaturedtabtitle(i - 1)) + + local material = RegisterMaterial("featured_panel_thumbnail_" .. i) + local ratio = Engine.GetMaterialAspectRatio(material) + local width = GenericMenuDims.menu_width_standard + local height = width / ratio + + local contentimage = LUI.UIImage.new({ + topAnchor = true, + leftAnchor = true, + width = width, + height = height, + material = material, + }) + + panel:addElement(contentimage) + panel:addElement(textbg) + panel:addElement(text) + imagelist:addElement(panel) + end + + local autoscrolltimer = LUI.UITimer.new(3000, "autoscroll") + featured:addElement(autoscrolltimer) + featured:registerEventHandler("autoscroll", function() + if (not minimized) then + shiftright() + end + end) + + local addarrows = function() + local arrowmat = RegisterMaterial("h1_prestige_leftright_arrow") + local arrowratio = Engine.GetMaterialAspectRatio(arrowmat) + local height = 20 + local width = arrowratio * height + + local arrowleft = LUI.UIImage.new({ + leftAnchor = true, + left = -width - 10, + top = -10, + height = height, + width = width, + alpha = 0, + material = RegisterMaterial("h1_prestige_leftright_arrow") + }) + + local arrowright = LUI.UIImage.new({ + rightAnchor = true, + right = 0, + top = -10, + height = height, + width = width, + zRot = 180, + alpha = 0, + material = RegisterMaterial("h1_prestige_leftright_arrow") + }) + + local registeranimationstate = function(name, state) + arrowleft:registerAnimationState(name, state) + arrowright:registerAnimationState(name, state) + end + + registeranimationstate("pulse", { + scale = -0.1 + }) + + registeranimationstate("highlight", { + scale = 0 + }) + + registeranimationstate("focused", { + alpha = 1 + }) + + registeranimationstate("unfocused", { + alpha = 0 + }) + + arrowleft:setHandleMouse(true) + arrowright:setHandleMouse(true) + + local pulsearrow = function(arrow) + arrow:animateInSequence({ + { + "highlight", + 0 + }, + { + "pulse", + 100 + }, + { + "highlight", + 100 + } + }) + end + + arrowleft:registerEventHandler("leftmousedown", function() + if (not istopmost()) then + return + end + + pulsearrow(arrowleft) + Engine.PlaySound(CoD.SFX.MouseOver) + shiftleft() + end) + arrowright:registerEventHandler("leftmousedown", function() + if (not istopmost()) then + return + end + + pulsearrow(arrowright) + Engine.PlaySound(CoD.SFX.MouseOver) + shiftright() + end) + + arrowcontainer:addElement(arrowleft) + arrowcontainer:addElement(arrowright) + + featured.arrowleft = arrowleft + featured.arrowright = arrowright + end + + addarrows() + + if (tabcount <= 1) then + arrowcontainer:animateToState("hide") + end + + featured:registerEventHandler("focused", function() + contentborder:animateToState("focused", animms) + featured.arrowleft:animateToState("focused", animms) + featured.arrowright:animateToState("focused", animms) + LUI.UITimer.Stop(autoscrolltimer) + end) + + + featured:registerEventHandler("unfocused", function() + contentborder:animateToState("unfocused", animms) + featured.arrowleft:animateToState("unfocused", animms) + featured.arrowright:animateToState("unfocused", animms) + LUI.UITimer.Reset(autoscrolltimer) + end) + + hoverelem:setHandleMouseMove(true) + + hoverelem:registerEventHandler("mouseenter", function() + if (not istopmost()) then + return + end + + featured:processEvent({ + name = "focused", + dispatchChildren = true + }) + end) + + hoverelem:registerEventHandler("mouseleave", function() + featured:processEvent({ + name = "unfocused", + dispatchChildren = true + }) + end) + + header:addElement(headertext) + header:addElement(LUI.DecoFrame.new(nil, LUI.DecoFrame.Grey)) + + featured:addElement(header) + + content:addElement(stencil) + content:addElement(LUI.DecoFrame.new(nil, LUI.DecoFrame.Grey)) + content:addElement(contentborder) + + content:setHandleMouse(true) + + content:registerEventHandler("leftmousedown", function() + if (not istopmost() or minimized) then + return + end + + hoverelem:processEvent({ + name = "mouseleave", + }) + + Engine.PlaySound(CoD.SFX.MenuAccept) + local data = motd.getfeaturedtab(focusindex) + data.popup_image = "featured_panel_" .. (focusindex + 1) + LUI.FlowManager.RequestPopupMenu( nil, "motd_main", true, nil, false, { + popupDataQueue = {data} + }) + end) + + content:registerEventHandler("mouseenter", function() + if (not istopmost() or minimized) then + return + end + + Engine.PlaySound(CoD.SFX.MouseOver) + end) + + featured:addElement(content) + featured:addElement(hoverelem) + + featuredstencil:addElement(featured) + featuredcontainer:addElement(featuredstencil) + + menu:addElement(featuredcontainer) +end) + diff --git a/data/cdata/ui_scripts/motd/motd.lua b/data/cdata/ui_scripts/motd/motd.lua new file mode 100644 index 00000000..0750a430 --- /dev/null +++ b/data/cdata/ui_scripts/motd/motd.lua @@ -0,0 +1,71 @@ +require("LUI.common_menus.MarketingComms") +require("LUI.common_menus.MarketingPopup") + +LUI.CustomMarketingPopups = {ShowDepotOnboardingPopupIfPossible = function() end} + +LUI.MenuBuilder.registerPopupType("motd", function() + local data = motd.getmotd() + return LUI.MenuBuilder.BuildRegisteredType("motd_main", { + popupDataQueue = {data} + }) +end) + +LUI.onmenuopen("main_campaign", function(menu) + if (not motd.hasseentoday()) then + motd.sethasseentoday() + LUI.FlowManager.RequestPopupMenu(nil, "motd") + end + + menu:AddHelp({ + name = "add_button_helper_text", + button_ref = "button_alt2", + helper_text = Engine.Localize("@MENU_OPEN_MOTD"), + side = "right", + clickable = true + }, function() + LUI.FlowManager.RequestPopupMenu(nil, "motd") + end) +end) + +LUI.common_menus.MarketingPopup.OnPopupAction = function(a1, a2) + local data = a1.popupData + if (type(data.link) == "string") then + game:openlink(data.link) + end +end + +local marketingbase = LUI.MarketingPopup.Base +LUI.MarketingPopup.Base = function(a1, data, a3) + local haslink = data.popupAction ~= nil and game:islink(data.popupAction) + if (haslink) then + data.link = data.popupAction + data.popupAction = "depot" + end + + local element = marketingbase(a1, data, a3) + local blur = element:getFirstDescendentById("generic_popup_screen_overlay_blur"):getNextSibling() + local parent = blur:getFirstChild():getNextSibling():getNextSibling():getNextSibling() + local image = parent:getFirstChild() + image:close() + + local state = LUI.DeepCopy(image:getAnimationStateInC("default")) + local imagecontainer = LUI.UIStencilText.new(state) + local material = RegisterMaterial(data.image) + + local ratio = Engine.GetMaterialAspectRatio(material) + local width = 525 + local height = width / ratio + + local image = LUI.UIImage.new({ + leftAnchor = true, + topAnchor = true, + width = width, + height = height, + material = material + }) + + imagecontainer:addElement(image) + parent:addElement(imagecontainer) + + return element +end diff --git a/data/cdata/ui_scripts/settings/language.lua b/data/cdata/ui_scripts/settings/language.lua index 942c19bb..9e749a9d 100644 --- a/data/cdata/ui_scripts/settings/language.lua +++ b/data/cdata/ui_scripts/settings/language.lua @@ -24,6 +24,14 @@ local function togglecustomfonts() }) end +local function adjustverticaloffset(table, offset) + for k, v in pairs(table) do + if (table[k].y_offset ~= nil) then + table[k].y_offset = offset + end + end +end + LUI.MenuBuilder.registerType("choose_language_menu", function(a1) local menu = LUI.MenuTemplate.new(a1, { menu_title = "@LUA_MENU_CHOOSE_LANGUAGE", @@ -90,20 +98,23 @@ LUI.MenuBuilder.registerType("choose_language_menu", function(a1) end) -- fix for Y-offset in button text (russian_partial, default font) -if config.get("language") == "russian_partial" and config.get("disable_custom_fonts") then +if (config.get("language") == "russian_partial" and config.get("disable_custom_fonts")) then LUI.UIButtonText.IsOffsetedLanguage = function() return true end end -if not (config.get("disable_custom_fonts")) then +if (not (config.get("disable_custom_fonts"))) then -- fix for Y-offset in button text (global patch, custom font) + adjustverticaloffset(GenericButtonSettings.Styles, 2) + adjustverticaloffset(GenericButtonSettings.Styles.GlassButton.SubStyles, 2) + LUI.UIButtonText.IsOffsetedLanguage = function() return false end -- fix for ammo counter (polish/russian) - if not Engine.InFrontend() then + if (not Engine.InFrontend()) then local weaponinfodef = LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"] LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"] = function(...) local rus = CoD.Language.Russian @@ -131,29 +142,29 @@ if not (config.get("disable_custom_fonts")) then end -- fix for ammo counter (global patch) - if language.isnonlatin() then + if (language.isnonlatin()) then local scale = function(size) return size * 720 / 1080 end CoD.TextSettings.SP_HudAmmoStatusText = { - Font = RegisterFont("fonts/mix_gothic.ttf", 16), + Font = RegisterFont("fonts/bank.ttf", 16), Height = 16 } CoD.TextSettings.SP_HudAmmoCounterFont = { - Font = RegisterFont("fonts/mix_gothic.ttf", 34), + Font = RegisterFont("fonts/bank.ttf", 34), Height = 34 } CoD.TextSettings.HudAmmoCounterFont = { - Font = RegisterFont("fonts/mix_gothic.ttf", 105), + Font = RegisterFont("fonts/bank.ttf", 105), Height = 64 } -- forced gothic font for headers (arabic/slavic) - if language.isslavic() or language.isarabic() then + if (language.isslavic() or language.isarabic()) then CoD.TextSettings.H2TitleFont = { - Font = RegisterFont("fonts/mix_gothic.ttf", 56), + Font = RegisterFont("fonts/bank.ttf", 56), Height = scale(56) } end diff --git a/data/zone_source/ara_h2_mod_font_default_bold.csv b/data/zone_source/ara_h2_mod_font_default_bold.csv new file mode 100644 index 00000000..797f23b4 --- /dev/null +++ b/data/zone_source/ara_h2_mod_font_default_bold.csv @@ -0,0 +1 @@ +ttf,fonts/defaultBold.otf diff --git a/data/zone_source/build.txt b/data/zone_source/build.txt index a48a68d0..98e8990e 100644 --- a/data/zone_source/build.txt +++ b/data/zone_source/build.txt @@ -1,4 +1,6 @@ ara_h2_mod_common +ara_h2_mod_font_default_bold +cze_h2_mod_common deu_h2_mod_common eng_h2_mod_common eng_h2_mod_patch_af_caves @@ -6,10 +8,15 @@ ens_h2_mod_common ens_h2_mod_patch_af_caves fra_h2_mod_common h2_mod_common +h2_mod_font_bank +h2_mod_font_default +h2_mod_font_default_bold +h2_mod_font_mix h2_mod_patch_af_caves h2_mod_patch_dc_whitehouse h2_mod_patch_ending h2_mod_pre_gfx +h2_mod_ui ita_h2_mod_common jpf_h2_mod_common jpp_h2_mod_common diff --git a/data/zone_source/h2_mod_font_bank.csv b/data/zone_source/h2_mod_font_bank.csv new file mode 100644 index 00000000..4883e365 --- /dev/null +++ b/data/zone_source/h2_mod_font_bank.csv @@ -0,0 +1 @@ +ttf,fonts/bank.ttf diff --git a/data/zone_source/h2_mod_font_default.csv b/data/zone_source/h2_mod_font_default.csv new file mode 100644 index 00000000..bf5a6574 --- /dev/null +++ b/data/zone_source/h2_mod_font_default.csv @@ -0,0 +1 @@ +ttf,fonts/default.otf diff --git a/data/zone_source/h2_mod_font_default_bold.csv b/data/zone_source/h2_mod_font_default_bold.csv new file mode 100644 index 00000000..797f23b4 --- /dev/null +++ b/data/zone_source/h2_mod_font_default_bold.csv @@ -0,0 +1 @@ +ttf,fonts/defaultBold.otf diff --git a/data/zone_source/h2_mod_font_mix.csv b/data/zone_source/h2_mod_font_mix.csv new file mode 100644 index 00000000..01a85ad6 --- /dev/null +++ b/data/zone_source/h2_mod_font_mix.csv @@ -0,0 +1 @@ +ttf,fonts/mix.ttf \ No newline at end of file diff --git a/data/zone_source/h2_mod_pre_gfx.csv b/data/zone_source/h2_mod_pre_gfx.csv index d460b0f6..9f24c14b 100644 --- a/data/zone_source/h2_mod_pre_gfx.csv +++ b/data/zone_source/h2_mod_pre_gfx.csv @@ -1,5 +1,2 @@ -stringtable,font_replacements.csv -ttf,fonts/ibmplexsansarabic-semibold_custom.ttf -ttf,fonts/mix.ttf -ttf,fonts/mix_gothic.ttf -ttf,fonts/mix_open.ttf \ No newline at end of file +stringtable,font_zones.csv +localize,branding diff --git a/data/zone_source/h2_mod_ui.csv b/data/zone_source/h2_mod_ui.csv new file mode 100644 index 00000000..47bd8fa7 --- /dev/null +++ b/data/zone_source/h2_mod_ui.csv @@ -0,0 +1,21 @@ +material,h2_ui_featured_pip_focused +material,h1_ui_featured_pip_unfocused +material,h2_ui_btn_focused_stroke_square +material,h1_prestige_leftright_arrow +material,featured_panel_1 +material,featured_panel_2 +material,featured_panel_3 +material,featured_panel_4 +material,featured_panel_5 +material,featured_panel_6 +material,featured_panel_7 +material,featured_panel_8 +material,featured_panel_thumbnail_1 +material,featured_panel_thumbnail_2 +material,featured_panel_thumbnail_3 +material,featured_panel_thumbnail_4 +material,featured_panel_thumbnail_5 +material,featured_panel_thumbnail_6 +material,featured_panel_thumbnail_7 +material,featured_panel_thumbnail_8 +material,motd_image diff --git a/data/zonetool/h2_mod_pre_gfx/fonts/ibmplexsansarabic-semibold_custom.ttf b/data/zonetool/ara_h2_mod_font_default_bold/defaultBold.ttf similarity index 100% rename from data/zonetool/h2_mod_pre_gfx/fonts/ibmplexsansarabic-semibold_custom.ttf rename to data/zonetool/ara_h2_mod_font_default_bold/defaultBold.ttf diff --git a/data/zonetool/h2_mod_pre_gfx/fonts/mix_gothic.ttf b/data/zonetool/fonts/bank.ttf similarity index 100% rename from data/zonetool/h2_mod_pre_gfx/fonts/mix_gothic.ttf rename to data/zonetool/fonts/bank.ttf diff --git a/data/zonetool/h2_mod_pre_gfx/fonts/mix.ttf b/data/zonetool/fonts/default.otf similarity index 100% rename from data/zonetool/h2_mod_pre_gfx/fonts/mix.ttf rename to data/zonetool/fonts/default.otf diff --git a/data/zonetool/h2_mod_pre_gfx/fonts/mix_open.ttf b/data/zonetool/fonts/defaultBold.otf similarity index 100% rename from data/zonetool/h2_mod_pre_gfx/fonts/mix_open.ttf rename to data/zonetool/fonts/defaultBold.otf diff --git a/data/zonetool/fonts/mix.ttf b/data/zonetool/fonts/mix.ttf new file mode 100644 index 00000000..6bdf48ec Binary files /dev/null and b/data/zonetool/fonts/mix.ttf differ diff --git a/data/zonetool/h2_mod_pre_gfx/font_replacements.csv b/data/zonetool/h2_mod_pre_gfx/font_replacements.csv deleted file mode 100644 index 518f3e67..00000000 --- a/data/zonetool/h2_mod_pre_gfx/font_replacements.csv +++ /dev/null @@ -1,25 +0,0 @@ -arabic,fonts/bank.ttf,fonts/mix_gothic.ttf, -arabic,fonts/default.otf,fonts/mix.ttf, -arabic,fonts/defaultBold.otf,fonts/ibmplexsansarabic-semibold_custom.ttf, -czech,fonts/bank.ttf,fonts/mix_gothic.ttf, -czech,fonts/default.otf,fonts/mix.ttf, -czech,fonts/defaultBold.otf,fonts/mix_open.ttf, -japanese_full,fonts/default.otf,fonts/mix.ttf, -japanese_full,fonts/defaultBold.otf,fonts/mix_open.ttf, -japanese_partial,fonts/default.otf,fonts/mix.ttf, -japanese_partial,fonts/defaultBold.otf,fonts/mix_open.ttf, -korean,fonts/default.otf,fonts/mix.ttf, -korean,fonts/defaultBold.otf,fonts/mix_open.ttf, -polish,fonts/bank.ttf,fonts/mix_gothic.ttf, -polish,fonts/default.otf,fonts/mix.ttf, -polish,fonts/defaultBold.otf,fonts/mix_open.ttf, -russian,fonts/bank.ttf,fonts/mix_gothic.ttf, -russian,fonts/default.otf,fonts/mix.ttf, -russian,fonts/defaultBold.otf,fonts/mix_open.ttf, -russian_partial,fonts/bank.ttf,fonts/mix_gothic.ttf, -russian_partial,fonts/default.otf,fonts/mix.ttf, -russian_partial,fonts/defaultBold.otf,fonts/mix_open.ttf, -simplified_chinese,fonts/default.otf,fonts/mix.ttf, -simplified_chinese,fonts/defaultBold.otf,fonts/mix_open.ttf, -traditional_chinese,fonts/default.otf,fonts/mix.ttf, -traditional_chinese,fonts/defaultBold.otf,fonts/mix_open.ttf, \ No newline at end of file diff --git a/data/zonetool/h2_mod_pre_gfx/font_zones.csv b/data/zonetool/h2_mod_pre_gfx/font_zones.csv new file mode 100644 index 00000000..04b2ad25 --- /dev/null +++ b/data/zonetool/h2_mod_pre_gfx/font_zones.csv @@ -0,0 +1,11 @@ +*,h2_mod_font_mix +arabic,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold +czech,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold +japanese_full,h2_mod_font_default,h2_mod_font_default_bold +japanese_partial,h2_mod_font_default,h2_mod_font_default_bold +korean,h2_mod_font_default,h2_mod_font_default_bold +polish,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold +russian,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold +russian_partial,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold +simplified_chinese,h2_mod_font_default,h2_mod_font_default_bold +traditional_chinese,h2_mod_font_default,h2_mod_font_default_bold diff --git a/data/zonetool/h2_mod_pre_gfx/localizedstrings/branding.json b/data/zonetool/h2_mod_pre_gfx/localizedstrings/branding.json new file mode 100644 index 00000000..17699751 --- /dev/null +++ b/data/zonetool/h2_mod_pre_gfx/localizedstrings/branding.json @@ -0,0 +1,3 @@ +{ + "MENU_SP_CAMPAIGN": "H2-MOD" +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_1.dds b/data/zonetool/h2_mod_ui/images/featured_panel_1.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_1.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_2.dds b/data/zonetool/h2_mod_ui/images/featured_panel_2.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_2.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_3.dds b/data/zonetool/h2_mod_ui/images/featured_panel_3.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_3.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_4.dds b/data/zonetool/h2_mod_ui/images/featured_panel_4.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_4.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_5.dds b/data/zonetool/h2_mod_ui/images/featured_panel_5.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_5.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_6.dds b/data/zonetool/h2_mod_ui/images/featured_panel_6.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_6.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_7.dds b/data/zonetool/h2_mod_ui/images/featured_panel_7.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_7.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_8.dds b/data/zonetool/h2_mod_ui/images/featured_panel_8.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_8.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_1.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_1.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_1.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_2.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_2.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_2.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_3.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_3.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_3.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_4.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_4.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_4.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_5.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_5.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_5.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_6.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_6.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_6.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_7.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_7.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_7.dds differ diff --git a/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_8.dds b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_8.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_8.dds differ diff --git a/data/zonetool/h2_mod_ui/images/h1_btn_focused_rect_stroke.dds b/data/zonetool/h2_mod_ui/images/h1_btn_focused_rect_stroke.dds new file mode 100644 index 00000000..79ba75da Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/h1_btn_focused_rect_stroke.dds differ diff --git a/data/zonetool/h2_mod_ui/images/h1_prestige_leftright-arrow.dds b/data/zonetool/h2_mod_ui/images/h1_prestige_leftright-arrow.dds new file mode 100644 index 00000000..2ae7fc67 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/h1_prestige_leftright-arrow.dds differ diff --git a/data/zonetool/h2_mod_ui/images/h1_ui_featured_pip_unfocused.dds b/data/zonetool/h2_mod_ui/images/h1_ui_featured_pip_unfocused.dds new file mode 100644 index 00000000..b4c2ce14 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/h1_ui_featured_pip_unfocused.dds differ diff --git a/data/zonetool/h2_mod_ui/images/h2_btn_focused_rect_stroke.dds b/data/zonetool/h2_mod_ui/images/h2_btn_focused_rect_stroke.dds new file mode 100644 index 00000000..3caf1ad6 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/h2_btn_focused_rect_stroke.dds differ diff --git a/data/zonetool/h2_mod_ui/images/h2_ui_featured_pip_focused.dds b/data/zonetool/h2_mod_ui/images/h2_ui_featured_pip_focused.dds new file mode 100644 index 00000000..9ab9e9a0 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/h2_ui_featured_pip_focused.dds differ diff --git a/data/zonetool/h2_mod_ui/images/motd_image.dds b/data/zonetool/h2_mod_ui/images/motd_image.dds new file mode 100644 index 00000000..346c0f27 Binary files /dev/null and b/data/zonetool/h2_mod_ui/images/motd_image.dds differ diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_1.json b/data/zonetool/h2_mod_ui/materials/featured_panel_1.json new file mode 100644 index 00000000..d0b13c6d --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_1.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_1", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_1", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_2.json b/data/zonetool/h2_mod_ui/materials/featured_panel_2.json new file mode 100644 index 00000000..617d5d20 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_2.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_2", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_2", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_3.json b/data/zonetool/h2_mod_ui/materials/featured_panel_3.json new file mode 100644 index 00000000..d8616a18 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_3.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_3", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_3", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_4.json b/data/zonetool/h2_mod_ui/materials/featured_panel_4.json new file mode 100644 index 00000000..3f4f651c --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_4.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_4", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_4", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_5.json b/data/zonetool/h2_mod_ui/materials/featured_panel_5.json new file mode 100644 index 00000000..edd887dc --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_5.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_5", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_5", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_6.json b/data/zonetool/h2_mod_ui/materials/featured_panel_6.json new file mode 100644 index 00000000..162effdf --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_6.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_6", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_6", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_7.json b/data/zonetool/h2_mod_ui/materials/featured_panel_7.json new file mode 100644 index 00000000..8cf7f98c --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_7.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_7", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_7", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_8.json b/data/zonetool/h2_mod_ui/materials/featured_panel_8.json new file mode 100644 index 00000000..a038a347 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_8.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_8", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_8", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_1.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_1.json new file mode 100644 index 00000000..ae8e3221 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_1.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_1", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_1", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_2.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_2.json new file mode 100644 index 00000000..2ce50c6f --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_2.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_2", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_2", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_3.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_3.json new file mode 100644 index 00000000..dcccda06 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_3.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_3", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_3", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_4.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_4.json new file mode 100644 index 00000000..cd1ba066 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_4.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_4", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_4", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_5.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_5.json new file mode 100644 index 00000000..2e19349a --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_5.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_5", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_5", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_6.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_6.json new file mode 100644 index 00000000..a65a26e2 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_6.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_6", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_6", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_7.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_7.json new file mode 100644 index 00000000..7a43ffb2 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_7.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_7", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_7", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_8.json b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_8.json new file mode 100644 index 00000000..7ac9793e --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/featured_panel_thumbnail_8.json @@ -0,0 +1,26 @@ +{ + "name": "featured_panel_thumbnail_8", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "featured_panel_thumbnail_8", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/h1_prestige_leftright_arrow.json b/data/zonetool/h2_mod_ui/materials/h1_prestige_leftright_arrow.json new file mode 100644 index 00000000..e4bae2bf --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/h1_prestige_leftright_arrow.json @@ -0,0 +1,26 @@ +{ + "name": "h1_prestige_leftright_arrow", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "h1_prestige_leftright-arrow", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/h1_ui_featured_pip_unfocused.json b/data/zonetool/h2_mod_ui/materials/h1_ui_featured_pip_unfocused.json new file mode 100644 index 00000000..cb2f6a52 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/h1_ui_featured_pip_unfocused.json @@ -0,0 +1,26 @@ +{ + "name": "h1_ui_featured_pip_unfocused", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "h1_ui_featured_pip_unfocused", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/h2_ui_btn_focused_stroke_square.json b/data/zonetool/h2_mod_ui/materials/h2_ui_btn_focused_stroke_square.json new file mode 100644 index 00000000..3ae7be99 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/h2_ui_btn_focused_stroke_square.json @@ -0,0 +1,26 @@ +{ + "name": "h2_ui_btn_focused_stroke_square", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "h2_btn_focused_rect_stroke", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/h2_ui_featured_pip_focused.json b/data/zonetool/h2_mod_ui/materials/h2_ui_featured_pip_focused.json new file mode 100644 index 00000000..da2826a1 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/h2_ui_featured_pip_focused.json @@ -0,0 +1,26 @@ +{ + "name": "h2_ui_featured_pip_focused", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "h2_ui_featured_pip_focused", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/h2_mod_ui/materials/motd_image.json b/data/zonetool/h2_mod_ui/materials/motd_image.json new file mode 100644 index 00000000..ed397cd6 --- /dev/null +++ b/data/zonetool/h2_mod_ui/materials/motd_image.json @@ -0,0 +1,26 @@ +{ + "name": "motd_image", + "techniqueSet->name": "2d", + "gameFlags": 0, + "sortKey": 60, + "renderFlags": 0, + "textureAtlasRowCount": 1, + "textureAtlasColumnCount": 1, + "textureAtlasFrameBlend": 0, + "textureAtlasAsArray": 0, + "surfaceTypeBits": 0, + "cameraRegion": 12, + "materialType": 0, + "assetFlags": 0, + "constantTable": null, + "textureTable": [ + { + "image": "motd_image", + "semantic": 0, + "samplerState": 226, + "lastCharacter": 112, + "firstCharacter": 99, + "typeHash": 2695565377 + } + ] +} \ No newline at end of file diff --git a/data/zonetool/localizedstrings/english.json b/data/zonetool/localizedstrings/english.json index 07b511fc..184e3e0a 100644 --- a/data/zonetool/localizedstrings/english.json +++ b/data/zonetool/localizedstrings/english.json @@ -116,5 +116,8 @@ "LUA_MENU_SP_LOCATION_OILRIG": "LUA_MENU_SP_LOCATION_OILRIG", "LUA_MENU_SP_LOCATION_ROADKILL": "LUA_MENU_SP_LOCATION_ROADKILL", "LUA_MENU_SP_LOCATION_TRAINER": "LUA_MENU_SP_LOCATION_TRAINER", - "LUA_MENU_SP_LOCATION_MUSEUM": "LUA_MENU_SP_LOCATION_MUSEUM" + "LUA_MENU_SP_LOCATION_MUSEUM": "LUA_MENU_SP_LOCATION_MUSEUM", + + "DEPOT_GO_TO_THE_DEPOT": "Open link", + "MENU_OPEN_MOTD": "Open Message of the Day" } \ No newline at end of file diff --git a/data/zonetool/h2_mod_patch_ending/techsets/constantbuffer/2d.cbi b/data/zonetool/techsets/constantbuffer/2d.cbi similarity index 100% rename from data/zonetool/h2_mod_patch_ending/techsets/constantbuffer/2d.cbi rename to data/zonetool/techsets/constantbuffer/2d.cbi diff --git a/data/zonetool/h2_mod_patch_ending/techsets/constantbuffer/2d.cbt b/data/zonetool/techsets/constantbuffer/2d.cbt similarity index 100% rename from data/zonetool/h2_mod_patch_ending/techsets/constantbuffer/2d.cbt rename to data/zonetool/techsets/constantbuffer/2d.cbt diff --git a/data/zonetool/h2_mod_patch_ending/techsets/state/2d.statebits b/data/zonetool/techsets/state/2d.statebits similarity index 100% rename from data/zonetool/h2_mod_patch_ending/techsets/state/2d.statebits rename to data/zonetool/techsets/state/2d.statebits diff --git a/data/zonetool/h2_mod_patch_ending/techsets/state/2d.statebitsmap b/data/zonetool/techsets/state/2d.statebitsmap similarity index 100% rename from data/zonetool/h2_mod_patch_ending/techsets/state/2d.statebitsmap rename to data/zonetool/techsets/state/2d.statebitsmap diff --git a/data/zonetool/h2_mod_patch_ending/techsets/state/2d.stateinfo b/data/zonetool/techsets/state/2d.stateinfo similarity index 100% rename from data/zonetool/h2_mod_patch_ending/techsets/state/2d.stateinfo rename to data/zonetool/techsets/state/2d.stateinfo diff --git a/deps/asmjit b/deps/asmjit index d4dfd8e8..915186f6 160000 --- a/deps/asmjit +++ b/deps/asmjit @@ -1 +1 @@ -Subproject commit d4dfd8e86529465efc4365f27b125d90552c700e +Subproject commit 915186f6c5c2f5a4638e5cb97ccc23d741521a64 diff --git a/src/client/component/config.cpp b/src/client/component/config.cpp index 8d6d4ca8..bfe54b65 100644 --- a/src/client/component/config.cpp +++ b/src/client/component/config.cpp @@ -34,6 +34,7 @@ namespace config { {define_field("disable_custom_fonts", field_type::boolean, false)}, {define_field("language", field_type::string, language::get_default_language(), language::is_valid_language)}, + {define_field("motd_last_seen", field_type::number_unsigned, 0)}, }; std::string get_config_file_path() diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index 49b59f97..0bb8c80c 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -6,6 +6,7 @@ #include "command.hpp" #include "console.hpp" #include "mods.hpp" +#include "fonts.hpp" #include #include @@ -104,12 +105,14 @@ namespace fastfiles a.jmp(0x140415E29); } - bool try_load_zone(const std::string& name, bool localized, bool game = false) + bool try_add_zone(std::vector& zones, + utils::memory::allocator& allocator, const std::string& name, + bool localized, bool game = false) { if (localized) { const auto language = game::SEH_GetCurrentLanguageCode(); - try_load_zone(language + "_"s + name, false); + try_add_zone(zones, allocator, language + "_"s + name, false); } if (!fastfiles::exists(name)) @@ -118,48 +121,73 @@ namespace fastfiles } game::XZoneInfo info{}; - info.name = name.data(); + info.name = allocator.duplicate_string(name); info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM; info.freeFlags = 0; - game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC); + zones.push_back(info); return true; } - void load_mod_zones() + void add_mod_zones(std::vector& zones, utils::memory::allocator& allocator) { - try_load_zone("mod", true); + try_add_zone(zones, allocator, "mod", true); const auto mod_zones = mods::get_mod_zones(); for (const auto& zone : mod_zones) { if (zone.alloc_flags & game::DB_ZONE_COMMON) { - try_load_zone(zone.name, true); + try_add_zone(zones, allocator, zone.name, true); } } } - void load_pre_gfx_zones(game::XZoneInfo* zoneInfo, - unsigned int zoneCount, game::DBSyncMode syncMode) + void push_zones(std::vector& zones, + game::XZoneInfo* source, const size_t count) + { + for (auto i = 0; i < count; ++i) + { + zones.push_back(source[i]); + } + } + + void load_pre_gfx_zones(game::XZoneInfo* zone_info, + unsigned int zone_count, game::DBSyncMode sync_mode) { // code_pre_gfx - try_load_zone("h2_mod_pre_gfx", true); + utils::memory::allocator allocator; + std::vector zones; + try_add_zone(zones, allocator, "h2_mod_pre_gfx", true); + push_zones(zones, zone_info, zone_count); - game::DB_LoadXAssets(zoneInfo, zoneCount, syncMode); + game::DB_LoadXAssets(zones.data(), static_cast(zones.size()), sync_mode); + fonts::load_font_zones(); } - void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zoneInfo, - unsigned int zoneCount, game::DBSyncMode syncMode) + void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zone_info, + unsigned int zone_count, game::DBSyncMode sync_mode) { // code_post_gfx_mp // ui_mp // common_mp - try_load_zone("h2_mod_common", true); + utils::memory::allocator allocator; + std::vector zones; - game::DB_LoadXAssets(zoneInfo, zoneCount, syncMode); + try_add_zone(zones, allocator, "h2_mod_common", true); + for (auto i = 0u; i < zone_count; i++) + { + zones.push_back(zone_info[i]); - load_mod_zones(); + if (zone_info[i].name == "code_post_gfx"s) + { + try_add_zone(zones, allocator, "h2_mod_ui", true); + } + } + + add_mod_zones(zones, allocator); + + game::DB_LoadXAssets(zones.data(), static_cast(zones.size()), sync_mode); } constexpr unsigned int get_asset_type_size(const game::XAssetType type) @@ -432,7 +460,7 @@ namespace fastfiles add_custom_level_load_zone(load, name, size_est); } - void add_mod_zones(game::LevelLoad* load) + void add_mod_zones_to_load(game::LevelLoad* load) { const auto mod_zones = mods::get_mod_zones(); for (const auto& zone : mod_zones) @@ -450,7 +478,7 @@ namespace fastfiles a.pushad64(); a.mov(rcx, rbx); - a.call_aligned(add_mod_zones); + a.call_aligned(add_mod_zones_to_load); a.popad64(); a.mov(rcx, rdi); @@ -572,6 +600,27 @@ namespace fastfiles }); } + bool try_load_zone(const std::string& name, bool localized, bool game) + { + if (localized) + { + const auto language = game::SEH_GetCurrentLanguageCode(); + try_load_zone(language + "_"s + name, false); + } + + if (!fastfiles::exists(name)) + { + return false; + } + + game::XZoneInfo info{}; + info.name = name.data(); + info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM; + info.freeFlags = 0; + game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC); + return true; + } + class component final : public component_interface { public: @@ -631,7 +680,7 @@ namespace fastfiles } const auto name = params.get(1); - if (!try_load_zone(name, false)) + if (!fastfiles::try_load_zone(name, false)) { console::warn("loadzone: zone \"%s\" could not be found!\n", name); } diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp index be2a072c..227056d7 100644 --- a/src/client/component/fastfiles.hpp +++ b/src/client/component/fastfiles.hpp @@ -1,6 +1,7 @@ #pragma once #include "game/game.hpp" +#include namespace fastfiles { @@ -8,4 +9,5 @@ namespace fastfiles std::string get_current_fastfile(); bool exists(const std::string& zone); + bool try_load_zone(const std::string& name, bool localized, bool game = false); } diff --git a/src/client/component/fonts.cpp b/src/client/component/fonts.cpp index 097241e8..c89fe3f7 100644 --- a/src/client/component/fonts.cpp +++ b/src/client/component/fonts.cpp @@ -7,6 +7,7 @@ #include "command.hpp" #include "language.hpp" #include "config.hpp" +#include "fastfiles.hpp" #include "game/game.hpp" #include "game/dvars.hpp" @@ -41,182 +42,6 @@ namespace fonts "bankshadowmore", }; - struct font_data_t - { - std::unordered_map fonts; - std::unordered_map raw_fonts; - }; - - utils::memory::allocator font_allocator; - - game::StringTable* get_font_replacements_table() - { - if (!game::DB_XAssetExists(game::ASSET_TYPE_STRINGTABLE, "font_replacements.csv")) - { - return nullptr; - } - - return game::DB_FindXAssetHeader(game::ASSET_TYPE_STRINGTABLE, "font_replacements.csv", false).stringTable; - } - - struct font_replacement - { - const char* target_font; - const char* new_font; - }; - - std::vector& get_font_replacements() - { - static std::vector replacements = {}; - return replacements; - } - - void load_font_replacements() - { - static auto loaded = false; - if (loaded) - { - return; - } - - loaded = true; - auto& replacements = get_font_replacements(); - - const auto disabled = config::get("disable_custom_fonts"); - if (disabled.has_value() && disabled.value() && language::current() != game::LANGUAGE_CZECH) - { - return; - } - - const auto table = get_font_replacements_table(); - if (table == nullptr) - { - return; - } - - const auto current_language = language::current(); - - for (auto row = 0; row < table->rowCount; row++) - { - if (table->columnCount < 3) - { - continue; - } - - const auto row_values = &table->values[(row * table->columnCount)]; - const auto lang = row_values[0].string; - if (std::strcmp(lang, game::languages[current_language].name)) - { - continue; - } - - const auto font = utils::memory::get_allocator()->duplicate_string(row_values[1].string); - const auto replacement = utils::memory::get_allocator()->duplicate_string(row_values[2].string); - replacements.emplace_back(font, replacement); - } - - return; - } - - const char* get_font_replacement(const char* name) - { - const auto& replacements = get_font_replacements(); - for (const auto& replacement : replacements) - { - if (!std::strcmp(name, replacement.target_font)) - { - return replacement.new_font; - } - } - - return name; - } - - utils::concurrency::container font_data; - - game::TTF* create_font(const std::string& name, const std::string& data) - { - const auto font = utils::memory::get_allocator()->allocate(); - font->name = utils::memory::get_allocator()->duplicate_string(name); - font->buffer = utils::memory::get_allocator()->duplicate_string(data); - font->len = static_cast(data.size()); - font->fontFace = 0; - return font; - } - - void free_font(game::TTF* font) - { - font_allocator.free(font->buffer); - font_allocator.free(font->name); - font_allocator.free(font); - } - - game::TTF* load_font(const std::string& name) - { - return font_data.access([&](font_data_t& data_) -> game::TTF* - { - if (const auto i = data_.fonts.find(name); i != data_.fonts.end()) - { - return i->second; - } - - std::string data{}; - if (const auto i = data_.raw_fonts.find(name); i != data_.raw_fonts.end()) - { - data = i->second; - } - - if (data.empty() && !filesystem::read_file(name, &data)) - { - return nullptr; - } - - const auto material = create_font(name, data); - data_.fonts[name] = material; - - return material; - }); - } - - game::TTF* try_load_font(const std::string& name) - { - try - { - return load_font(name); - } - catch (const std::exception& e) - { - console::error("Failed to load font %s: %s\n", name.data(), e.what()); - } - - return nullptr; - } - - game::TTF* db_find_xasset_header_stub(game::XAssetType type, const char* name, int create_default) - { - auto result = try_load_font(name); - if (result == nullptr) - { - result = game::DB_FindXAssetHeader(type, name, create_default).ttf; - } - - return result; - } - - utils::hook::detour r_register_font_hook; - void* r_register_font_stub(const char* name, int size) - { - const auto name_ = get_font_replacement(name); - return r_register_font_hook.invoke(name_, size); - } - - utils::hook::detour cl_init_renderer_hook; - void* cl_init_renderer_stub() - { - load_font_replacements(); - return cl_init_renderer_hook.invoke(); - } - game::Font_s* bank_font = nullptr; utils::hook::detour ui_get_font_handle_hook; @@ -336,27 +161,47 @@ namespace fonts } } - void add(const std::string& name, const std::string& data) + void load_font_zones() { - font_data.access([&](font_data_t& data_) + const auto disabled = config::get("disable_custom_fonts"); + const auto custom_fonts_disabled = disabled.has_value() && disabled.value() && !language::is_custom(); + const auto table = game::DB_FindXAssetHeader(game::ASSET_TYPE_STRINGTABLE, "font_zones.csv", 0).stringTable; + if (table == nullptr) { - data_.raw_fonts[name] = data; - }); - } + return; + } - void clear() - { - font_data.access([&](font_data_t& data_) + const auto lang = language::current(); + const std::string lang_name = game::languages[lang].name; + for (auto row = 0; row < table->rowCount; row++) { - for (auto& font : data_.fonts) + if (table->columnCount < 3) { - free_font(font.second); + continue; } - font_allocator.clear(); - data_.fonts.clear(); - *reinterpret_cast(0x14EE3ACB8) = 0; // reset registered font count - }); + const auto row_values = &table->values[(row * table->columnCount)]; + const auto lang_value = row_values[0].string; + const auto is_replacement = lang_value != "*"s; + if (lang_value != lang_name && is_replacement) + { + continue; + } + + if (custom_fonts_disabled && is_replacement) + { + continue; + } + + for (auto col = 1; col < table->columnCount; col++) + { + const auto zone = row_values[col].string; + if (zone != nullptr) + { + fastfiles::try_load_zone(zone, true); + } + } + } } class component final : public component_interface @@ -364,10 +209,6 @@ namespace fonts public: void post_unpack() override { - utils::hook::call(0x140747096, db_find_xasset_header_stub); - r_register_font_hook.create(0x140746FE0, r_register_font_stub); - cl_init_renderer_hook.create(0x1403D5AA0, cl_init_renderer_stub); - // add custom fonts to hud elem fonts ui_asset_cache_hook.create(0x140606090, ui_asset_cache_stub); ui_get_font_handle_hook.create(0x1406058F0, ui_get_font_handle_stub); diff --git a/src/client/component/fonts.hpp b/src/client/component/fonts.hpp index c2d22869..009008eb 100644 --- a/src/client/component/fonts.hpp +++ b/src/client/component/fonts.hpp @@ -1,7 +1,9 @@ #pragma once +#include "game/game.hpp" +#include + namespace fonts { - void add(const std::string& name, const std::string& data); - void clear(); + void load_font_zones(); } diff --git a/src/client/component/images.cpp b/src/client/component/images.cpp index bc17b9d2..4f9bbd44 100644 --- a/src/client/component/images.cpp +++ b/src/client/component/images.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace images { @@ -73,7 +74,7 @@ namespace images return true; } - void load_texture_stub(game::GfxImage* image, void* a2, int* a3) + void load_texture_stub(void* a1, game::GfxImage* image) { try { @@ -87,7 +88,7 @@ namespace images console::error("Failed to load image %s: %s\n", image->name, e.what()); } - load_texture_hook.invoke(image, a2, a3); + load_texture_hook.invoke(a1, image); } int setup_texture_stub(game::GfxImage* image, void* a2, void* a3) @@ -115,7 +116,7 @@ namespace images void post_unpack() override { setup_texture_hook.create(0x1402A7940, setup_texture_stub); - load_texture_hook.create(0x1402A6690, load_texture_stub); + load_texture_hook.create(0x14074A390, load_texture_stub); } }; } diff --git a/src/client/component/mods.cpp b/src/client/component/mods.cpp index 00e1f08f..40a0b897 100644 --- a/src/client/component/mods.cpp +++ b/src/client/component/mods.cpp @@ -58,7 +58,6 @@ namespace mods { if (release_assets) { - fonts::clear(); loadscreen::clear(); } diff --git a/src/client/component/motd.cpp b/src/client/component/motd.cpp new file mode 100644 index 00000000..577ac674 --- /dev/null +++ b/src/client/component/motd.cpp @@ -0,0 +1,256 @@ +#include +#include "loader/component_loader.hpp" + +#include "motd.hpp" +#include "console.hpp" +#include "images.hpp" +#include "command.hpp" + +#include +#include +#include + +#define MAX_FEATURED_TABS 8 + +namespace motd +{ + namespace + { + utils::concurrency::container links; + + utils::concurrency::container marketing; + + std::unordered_map image_cache; + + std::optional download_image(const std::string& url) + { + if (image_cache.contains(url)) + { + return {image_cache.at(url)}; + } + + const auto res = utils::http::get_data(url); + if (res.has_value()) + { + image_cache[url] = res.value(); + } + + return res; + } + + void download_motd_image(nlohmann::json& data) + { + if (!data["motd"].is_object() || !data["motd"]["image_url"].is_string()) + { + return; + } + + const auto url = data["motd"]["image_url"].get(); + const auto image_data = download_image(url); + if (image_data.has_value()) + { + const auto& image = image_data.value(); + console::debug("Downloaded motd image\n"); + images::override_texture("motd_image", image); + } + } + + void download_featured_tabs_images(nlohmann::json& data) + { + if (!data["featured"].is_array()) + { + return; + } + + auto index = 0; + for (const auto& [key, tab] : data["featured"].items()) + { + index++; + if (index >= MAX_FEATURED_TABS + 1) + { + return; + } + + if (!tab.is_object() || !tab["image_url"].is_string()) + { + continue; + } + + const auto download_image_ = [&](const std::string& field, const std::string& image_name) + { + const auto url = tab[field].get(); + const auto image_data = download_image(url); + if (image_data.has_value()) + { + const auto& image = image_data.value(); + console::debug("Downloaded featured tab image %i\n", index); + images::override_texture(image_name + std::format("_{}", index), image); + } + }; + + download_image_("image_url", "featured_panel"); + download_image_("thumbnail_url", "featured_panel_thumbnail"); + } + } + + void download_images(nlohmann::json& data) + { + if (!data.is_object()) + { + return; + } + + download_motd_image(data); + download_featured_tabs_images(data); + } + + void init_links(links_map_t& map) + { + map = + { + {"github", "https://github.com/fedddddd/h2-mod"}, + {"donate", "https://www.paypal.com/donate/?hosted_button_id=LM5BA9UABEV4Q"}, + {"credits_1", "https://github.com/momo5502"}, + {"credits_2", "https://github.com/VladWinner"}, + {"credits_3", "https://github.com/diamante0018"}, + {"credits_4", "https://github.com/JariKCoding"}, + {"credits_5", "https://github.com/netadr"}, + {"credits_6", "https://github.com/Joelrau"}, + {"credits_7", "https://github.com/xensik"}, + {"credits_8", "https://github.com/ZoneTool/zonetool"}, + }; + } + + void add_links(nlohmann::json& data) + { + links.access([&](links_map_t& map) + { + init_links(map); + if (!data.is_object() || !data["links"].is_object()) + { + return; + } + + for (const auto& [link, url] : data["links"].items()) + { + if (!url.is_string()) + { + continue; + } + + map.insert(std::make_pair(link, url.get())); + } + }); + } + + void init(bool load_images = true) + { + links.access([](links_map_t& map) + { + init_links(map); + }); + + marketing.access([&](nlohmann::json& data) + { + image_cache.clear(); + data.clear(); + + const auto marketing_data = utils::http::get_data("https://master.fed0001.xyz/h2-mod/marketing.json"); + if (marketing_data.has_value()) + { + try + { + const auto& value = marketing_data.value(); + data = nlohmann::json::parse(value); + + add_links(data); + if (load_images) + { + download_images(data); + } + } + catch (const std::exception& e) + { + console::error("Failed to load marketing.json: %s\n", e.what()); + } + } + }); + } + } + + links_map_t get_links() + { + return links.access([&](links_map_t& map) + { + return map; + }); + } + + int get_num_featured_tabs() + { + return marketing.access([&](nlohmann::json& data) + -> nlohmann::json + { + if (!data.is_object() || !data["featured"].is_array()) + { + return 0; + } + + return std::min(MAX_FEATURED_TABS, static_cast(data["featured"].size())); + }); + } + + nlohmann::json get_featured_tab(const int index) + { + return marketing.access([&](nlohmann::json& data) + -> nlohmann::json + { + if (!data.is_object() || !data["featured"].is_array()) + { + return {}; + } + + if (index >= data["featured"].size()) + { + return {}; + } + + return data["featured"][index]; + }); + } + + nlohmann::json get_motd() + { + return marketing.access([](nlohmann::json& data) + -> nlohmann::json + { + if (!data.is_object() || !data["motd"].is_object()) + { + return {}; + } + + return data["motd"]; + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + init(); + + command::add("reloadmotd", []() + { + init(true); + }); + + command::add("reloadmotd_noimages", []() + { + init(false); + }); + } + }; +} + +REGISTER_COMPONENT(motd::component) diff --git a/src/client/component/motd.hpp b/src/client/component/motd.hpp new file mode 100644 index 00000000..4a94b751 --- /dev/null +++ b/src/client/component/motd.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace motd +{ + using links_map_t = std::unordered_map; + links_map_t get_links(); + + int get_num_featured_tabs(); + nlohmann::json get_motd(); + nlohmann::json get_featured_tab(const int index); +} diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 1bd87202..be5f8526 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -79,31 +79,6 @@ namespace patches { return game::Dvar_RegisterBool(hash, name, value, game::DVAR_FLAG_SAVED); } - - void gscr_cinematic_ingame_loop_resident_stub() - { - auto arg2 = 1.f; - auto arg1 = 1; - - const auto num_params = game::Scr_GetNumParam(); - if (!num_params) - { - game::Scr_ErrorInternal(); - } - - if (num_params >= 2) - { - arg2 = game::Scr_GetFloat(1); - } - - if (num_params >= 3) - { - arg1 = game::Scr_GetInt(2); - } - - const auto video = game::Scr_GetString(0); - utils::hook::invoke(0x14071B740, video, arg1, arg2); - } } class component final : public component_interface @@ -146,8 +121,8 @@ namespace patches // make snd_musicDisabledForCustomSoundtrack saved utils::hook::call(0x1405D05FB, register_snd_music_stub); - // Fix broken function - utils::hook::jump(0x140502140, gscr_cinematic_ingame_loop_resident_stub); + // cinematicingameloopresident -> cinematicingameloop (fix ingame cinematics) + utils::hook::jump(0x140502140, 0x1405020C0); } }; } diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index f6dc1417..9c9d6f42 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -15,6 +15,7 @@ #include "console.hpp" #include "language.hpp" #include "config.hpp" +#include "motd.hpp" #include "game/ui_scripting/execution.hpp" #include "game/scripting/execution.hpp" @@ -151,6 +152,7 @@ namespace ui_scripting { object[key] = json_to_lua(value); } + return object; } if (json.is_array()) @@ -161,6 +163,7 @@ namespace ui_scripting { array[index++] = json_to_lua(value); } + return array; } if (json.is_boolean()) @@ -331,20 +334,7 @@ namespace ui_scripting game_type["openlink"] = [](const game&, const std::string& name) { - static std::unordered_map links = - { - {"github", "https://github.com/fedddddd/h2-mod"}, - {"donate", "https://www.paypal.com/donate/?hosted_button_id=LM5BA9UABEV4Q"}, - {"credits_1", "https://github.com/momo5502"}, - {"credits_2", "https://github.com/VladWinner"}, - {"credits_3", "https://github.com/diamante0018"}, - {"credits_4", "https://github.com/JariKCoding"}, - {"credits_5", "https://github.com/netadr"}, - {"credits_6", "https://github.com/Joelrau"}, - {"credits_7", "https://github.com/xensik"}, - {"credits_8", "https://github.com/ZoneTool/zonetool"}, - }; - + const auto links = motd::get_links(); const auto link = links.find(name); if (link == links.end()) { @@ -354,6 +344,31 @@ namespace ui_scripting ShellExecuteA(nullptr, "open", link->second.data(), nullptr, nullptr, SW_SHOWNORMAL); }; + game_type["getlinkurl"] = [](const game&, const std::string& name) + -> script_value + { + const auto links = motd::get_links(); + const auto link = links.find(name); + if (link == links.end()) + { + return script_value(); + } + + return link->second; + }; + + game_type["islink"] = [](const game&, const std::string& name) + { + const auto links = motd::get_links(); + const auto link = links.find(name); + if (link == links.end()) + { + return false; + } + + return true; + }; + lua["string"]["escapelocalization"] = [](const std::string& str) { return "\x1F"s.append(str); @@ -604,6 +619,41 @@ namespace ui_scripting { config::set(key, lua_to_json(value)); }; + + auto motd_table = table(); + lua["motd"] = motd_table; + + motd_table["getnumfeaturedtabs"] = motd::get_num_featured_tabs; + motd_table["getmotd"] = []() + { + return json_to_lua(motd::get_motd()); + }; + + motd_table["getfeaturedtab"] = [](const int index) + { + return json_to_lua(motd::get_featured_tab(index)); + }; + + motd_table["hasseentoday"] = []() + { + const auto last_seen = config::get("motd_last_seen"); + if (!last_seen.has_value()) + { + return false; + } + + const auto value = static_cast(last_seen.value()); + const auto before = std::chrono::floor(std::chrono::system_clock::from_time_t(value)); + const auto now = std::chrono::floor(std::chrono::system_clock::now()); + const auto diff = std::chrono::sys_days{now} - std::chrono::sys_days{before}; + return diff.count() < 1; + }; + + motd_table["sethasseentoday"] = []() + { + const auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + config::set("motd_last_seen", static_cast(now)); + }; } void start()