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..826e0433 --- /dev/null +++ b/data/cdata/ui_scripts/motd/featured.lua @@ -0,0 +1,493 @@ +motd.getfeaturedtabtitle = function(index) + return motd.getfeaturedtab(index).tab_title or "" +end + +local animmsfull = 150 +local animms = animmsfull / 2 + +LUI.onmenuopen("main_campaign", function(menu) + if (mods.getloaded() ~= nil or motd.getnumfeaturedtabs() <= 0) then + return + end + + local left = 866 + 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) + local minimized = false + headerbutton:registerEventHandler("leftmousedown", function() + 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) + + 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 = {} + + 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()) then + return + end + + Engine.PlaySound(CoD.SFX.MouseOver) + 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() + + 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 focusindex = 0 + local shiftright = function() + local prevfocus = focusindex + focusindex = (focusindex + 1) % tabcount + + pips[#pips - (prevfocus)]:animateToState("unfocused") + pips[#pips - (focusindex)]:animateToState("focused") + + imagelist:registerAnimationState("move", { + leftAnchor = true, + left = (focusindex) * -GenericMenuDims.menu_width_standard + }) + + imagelist:animateToState("move", animmsfull) + end + + local shiftleft = function() + local prevfocus = focusindex + focusindex = (focusindex - 1) % tabcount + + pips[#pips - (prevfocus)]:animateToState("unfocused") + pips[#pips - (focusindex)]:animateToState("focused") + + imagelist:registerAnimationState("move", { + leftAnchor = true, + left = (focusindex) * -GenericMenuDims.menu_width_standard + }) + + imagelist:animateToState("move", animmsfull) + 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") + }) + + arrowleft:registerAnimationState("focused", { + alpha = 1 + }) + + arrowleft:registerAnimationState("unfocused", { + alpha = 0 + }) + + arrowright:registerAnimationState("focused", { + alpha = 1 + }) + + arrowright:registerAnimationState("unfocused", { + alpha = 0 + }) + + arrowleft:setHandleMouse(true) + arrowright:setHandleMouse(true) + + arrowleft:registerEventHandler("leftmousedown", shiftleft) + arrowright:registerEventHandler("leftmousedown", shiftright) + + 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() + local data = motd.getfeaturedtab(focusindex) + data.popup_image = "featured_panel_" .. (focusindex + 1) + LUI.FlowManager.RequestPopupMenu( nil, "motd_main", true, nil, false, { + popupDataQueue = {data} + }) + 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..2c6f93bb --- /dev/null +++ b/data/cdata/ui_scripts/motd/motd.lua @@ -0,0 +1,76 @@ +require("LUI.common_menus.MarketingComms") +require("LUI.common_menus.MarketingPopup") +LUI.CustomMarketingPopups = {ShowDepotOnboardingPopupIfPossible = function() end} + +LUI.onmenuopen("main_campaign", function(menu) + if (not motd.hasseentoday()) then + motd.sethasseentoday() + local data = motd.getmotd() + LUI.FlowManager.RequestPopupMenu( self, "motd_main", true, nil, false, { + popupDataQueue = {data} + }) + end +end) + +local function makelink(element, link) + element:setHandleMouseMove(true) + element:setHandleMouseButton(true) + element:registerAnimationState("focused", { + color = { + r = 1, + g = 1, + b = 1 + } + }) + + local entered = false + element:registerEventHandler("mouseenter", function() + if (not entered) then + Engine.PlaySound(CoD.SFX.MouseOver) + entered = true + end + + element:animateToState("focused") + end) + + element:registerEventHandler("mouseleave", function() + entered = false + element:animateToState("default") + end) + + element:registerEventHandler("leftmousedown", function() + Engine.PlaySound(CoD.SFX.MouseClick) + game:openlink(link) + end) +end + +local marketingbase = LUI.MarketingPopup.Base +LUI.MarketingPopup.Base = function(a1, data, a3) + 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/zone_source/build.txt b/data/zone_source/build.txt index a48a68d0..e43a24fd 100644 --- a/data/zone_source/build.txt +++ b/data/zone_source/build.txt @@ -4,12 +4,14 @@ eng_h2_mod_common eng_h2_mod_patch_af_caves ens_h2_mod_common ens_h2_mod_patch_af_caves +cze_h2_mod_common fra_h2_mod_common h2_mod_common 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_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_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..50728328 100644 --- a/data/zonetool/localizedstrings/english.json +++ b/data/zonetool/localizedstrings/english.json @@ -1,4 +1,6 @@ { + "MENU_SP_CAMPAIGN": "H2-MOD", + "LOCALE_0": "English", "LOCALE_1": "French", "LOCALE_2": "German", 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/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..e5c44e9c 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -125,6 +125,29 @@ namespace fastfiles return true; } + 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_add_zone(zones, allocator, language + "_"s + name, false); + } + + if (!fastfiles::exists(name)) + { + return false; + } + + game::XZoneInfo info{}; + info.name = allocator.duplicate_string(name); + info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM; + info.freeFlags = 0; + zones.push_back(info); + return true; + } + void load_mod_zones() { try_load_zone("mod", true); @@ -138,28 +161,65 @@ namespace fastfiles } } - void load_pre_gfx_zones(game::XZoneInfo* zoneInfo, - unsigned int zoneCount, game::DBSyncMode syncMode) + void add_mod_zones(std::vector& zones, utils::memory::allocator& allocator) + { + 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_add_zone(zones, allocator, zone.name, true); + } + } + } + + 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); } - 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 +492,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 +510,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); 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/motd.cpp b/src/client/component/motd.cpp new file mode 100644 index 00000000..b9f3744a --- /dev/null +++ b/src/client/component/motd.cpp @@ -0,0 +1,203 @@ +#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 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() + { + marketing.access([&](nlohmann::json& data) + { + if (!data.is_object()) + { + return; + } + + download_motd_image(data); + download_featured_tabs_images(data); + }); + } + + void init(bool load_images = true) + { + 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); + if (load_images) + { + download_images(); + } + } + catch (const std::exception& e) + { + console::error("Failed to load marketing.json: %s\n", e.what()); + } + } + }); + } + } + + 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..d04308a5 --- /dev/null +++ b/src/client/component/motd.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace motd +{ + int get_num_featured_tabs(); + nlohmann::json get_motd(); + nlohmann::json get_featured_tab(const int index); +} diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index f6dc1417..a270ba6d 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()) @@ -604,6 +607,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()