commit
684fe89968
@ -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
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
require("credits")
|
||||
require("mainmenu")
|
||||
|
@ -1,4 +0,0 @@
|
||||
LUI.onmenuopen("main_campaign", function(menu)
|
||||
local headertext = menu:getFirstDescendentById("header_text")
|
||||
headertext:setText("H2-MOD")
|
||||
end)
|
2
data/cdata/ui_scripts/motd/__init__.lua
Normal file
2
data/cdata/ui_scripts/motd/__init__.lua
Normal file
@ -0,0 +1,2 @@
|
||||
require("motd")
|
||||
require("featured")
|
581
data/cdata/ui_scripts/motd/featured.lua
Normal file
581
data/cdata/ui_scripts/motd/featured.lua
Normal file
@ -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)
|
||||
|
71
data/cdata/ui_scripts/motd/motd.lua
Normal file
71
data/cdata/ui_scripts/motd/motd.lua
Normal file
@ -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
|
@ -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
|
||||
|
1
data/zone_source/ara_h2_mod_font_default_bold.csv
Normal file
1
data/zone_source/ara_h2_mod_font_default_bold.csv
Normal file
@ -0,0 +1 @@
|
||||
ttf,fonts/defaultBold.otf
|
|
@ -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
|
||||
|
1
data/zone_source/h2_mod_font_bank.csv
Normal file
1
data/zone_source/h2_mod_font_bank.csv
Normal file
@ -0,0 +1 @@
|
||||
ttf,fonts/bank.ttf
|
|
1
data/zone_source/h2_mod_font_default.csv
Normal file
1
data/zone_source/h2_mod_font_default.csv
Normal file
@ -0,0 +1 @@
|
||||
ttf,fonts/default.otf
|
|
1
data/zone_source/h2_mod_font_default_bold.csv
Normal file
1
data/zone_source/h2_mod_font_default_bold.csv
Normal file
@ -0,0 +1 @@
|
||||
ttf,fonts/defaultBold.otf
|
|
1
data/zone_source/h2_mod_font_mix.csv
Normal file
1
data/zone_source/h2_mod_font_mix.csv
Normal file
@ -0,0 +1 @@
|
||||
ttf,fonts/mix.ttf
|
|
@ -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
|
||||
stringtable,font_zones.csv
|
||||
localize,branding
|
||||
|
|
21
data/zone_source/h2_mod_ui.csv
Normal file
21
data/zone_source/h2_mod_ui.csv
Normal file
@ -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
|
|
BIN
data/zonetool/fonts/mix.ttf
Normal file
BIN
data/zonetool/fonts/mix.ttf
Normal file
Binary file not shown.
@ -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,
|
|
11
data/zonetool/h2_mod_pre_gfx/font_zones.csv
Normal file
11
data/zonetool/h2_mod_pre_gfx/font_zones.csv
Normal file
@ -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
|
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"MENU_SP_CAMPAIGN": "H2-MOD"
|
||||
}
|
BIN
data/zonetool/h2_mod_ui/images/featured_panel_1.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_1.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_2.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_2.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_3.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_3.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_4.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_4.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_5.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_5.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_6.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_6.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_7.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_7.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_8.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_8.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_1.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_1.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_2.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_2.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_3.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_3.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_4.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_4.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_5.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_5.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_6.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_6.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_7.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_7.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_8.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/featured_panel_thumbnail_8.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/h1_btn_focused_rect_stroke.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/h1_btn_focused_rect_stroke.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/h1_prestige_leftright-arrow.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/h1_prestige_leftright-arrow.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/h1_ui_featured_pip_unfocused.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/h1_ui_featured_pip_unfocused.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/h2_btn_focused_rect_stroke.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/h2_btn_focused_rect_stroke.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/h2_ui_featured_pip_focused.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/h2_ui_featured_pip_focused.dds
Normal file
Binary file not shown.
BIN
data/zonetool/h2_mod_ui/images/motd_image.dds
Normal file
BIN
data/zonetool/h2_mod_ui/images/motd_image.dds
Normal file
Binary file not shown.
26
data/zonetool/h2_mod_ui/materials/featured_panel_1.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_1.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_2.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_2.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_3.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_3.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_4.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_4.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_5.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_5.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_6.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_6.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_7.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_7.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/featured_panel_8.json
Normal file
26
data/zonetool/h2_mod_ui/materials/featured_panel_8.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
26
data/zonetool/h2_mod_ui/materials/motd_image.json
Normal file
26
data/zonetool/h2_mod_ui/materials/motd_image.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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"
|
||||
}
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
||||
Subproject commit d4dfd8e86529465efc4365f27b125d90552c700e
|
||||
Subproject commit 915186f6c5c2f5a4638e5cb97ccc23d741521a64
|
@ -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()
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "mods.hpp"
|
||||
#include "fonts.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
@ -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<game::XZoneInfo>& 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<game::XZoneInfo>& 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<game::XZoneInfo>& 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<game::XZoneInfo> 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<int>(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<game::XZoneInfo> 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<int>(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);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include <utils/memory.hpp>
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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<std::string, game::TTF*> fonts;
|
||||
std::unordered_map<std::string, std::string> 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<font_replacement>& get_font_replacements()
|
||||
{
|
||||
static std::vector<font_replacement> 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<bool>("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_t> font_data;
|
||||
|
||||
game::TTF* create_font(const std::string& name, const std::string& data)
|
||||
{
|
||||
const auto font = utils::memory::get_allocator()->allocate<game::TTF>();
|
||||
font->name = utils::memory::get_allocator()->duplicate_string(name);
|
||||
font->buffer = utils::memory::get_allocator()->duplicate_string(data);
|
||||
font->len = static_cast<int>(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<game::TTF*>([&](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<void*>(name_, size);
|
||||
}
|
||||
|
||||
utils::hook::detour cl_init_renderer_hook;
|
||||
void* cl_init_renderer_stub()
|
||||
{
|
||||
load_font_replacements();
|
||||
return cl_init_renderer_hook.invoke<void*>();
|
||||
}
|
||||
|
||||
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<bool>("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<int*>(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);
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include <utils/memory.hpp>
|
||||
|
||||
namespace fonts
|
||||
{
|
||||
void add(const std::string& name, const std::string& data);
|
||||
void clear();
|
||||
void load_font_zones();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <utils/image.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/http.hpp>
|
||||
|
||||
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<void>(image, a2, a3);
|
||||
load_texture_hook.invoke<void>(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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -58,7 +58,6 @@ namespace mods
|
||||
{
|
||||
if (release_assets)
|
||||
{
|
||||
fonts::clear();
|
||||
loadscreen::clear();
|
||||
}
|
||||
|
||||
|
256
src/client/component/motd.cpp
Normal file
256
src/client/component/motd.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "motd.hpp"
|
||||
#include "console.hpp"
|
||||
#include "images.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/http.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#define MAX_FEATURED_TABS 8
|
||||
|
||||
namespace motd
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::concurrency::container<links_map_t> links;
|
||||
|
||||
utils::concurrency::container<nlohmann::json, std::recursive_mutex> marketing;
|
||||
|
||||
std::unordered_map<std::string, std::string> image_cache;
|
||||
|
||||
std::optional<std::string> 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<std::string>();
|
||||
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<std::string>();
|
||||
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<std::string>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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>([&](links_map_t& map)
|
||||
{
|
||||
return map;
|
||||
});
|
||||
}
|
||||
|
||||
int get_num_featured_tabs()
|
||||
{
|
||||
return marketing.access<nlohmann::json>([&](nlohmann::json& data)
|
||||
-> nlohmann::json
|
||||
{
|
||||
if (!data.is_object() || !data["featured"].is_array())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::min(MAX_FEATURED_TABS, static_cast<int>(data["featured"].size()));
|
||||
});
|
||||
}
|
||||
|
||||
nlohmann::json get_featured_tab(const int index)
|
||||
{
|
||||
return marketing.access<nlohmann::json>([&](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>([](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)
|
11
src/client/component/motd.hpp
Normal file
11
src/client/component/motd.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace motd
|
||||
{
|
||||
using links_map_t = std::unordered_map<std::string, std::string>;
|
||||
links_map_t get_links();
|
||||
|
||||
int get_num_featured_tabs();
|
||||
nlohmann::json get_motd();
|
||||
nlohmann::json get_featured_tab(const int index);
|
||||
}
|
@ -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<void>(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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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<std::string, std::string> 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<uint64_t>("motd_last_seen");
|
||||
if (!last_seen.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto value = static_cast<time_t>(last_seen.value());
|
||||
const auto before = std::chrono::floor<std::chrono::days>(std::chrono::system_clock::from_time_t(value));
|
||||
const auto now = std::chrono::floor<std::chrono::days>(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<uint64_t>("motd_last_seen", static_cast<uint64_t>(now));
|
||||
};
|
||||
}
|
||||
|
||||
void start()
|
||||
|
Loading…
Reference in New Issue
Block a user