commit
684fe89968
@ -33,6 +33,10 @@
|
|||||||
* Freeing up RAM (close programs)
|
* Freeing up RAM (close programs)
|
||||||
* Updating your GPU drivers
|
* 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
|
## Compile from source
|
||||||
|
|
||||||
- Clone the Git repo. Do NOT download it as ZIP, that won't work.
|
- Clone the Git repo. Do NOT download it as ZIP, that won't work.
|
||||||
|
@ -1,2 +1 @@
|
|||||||
require("credits")
|
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
|
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)
|
LUI.MenuBuilder.registerType("choose_language_menu", function(a1)
|
||||||
local menu = LUI.MenuTemplate.new(a1, {
|
local menu = LUI.MenuTemplate.new(a1, {
|
||||||
menu_title = "@LUA_MENU_CHOOSE_LANGUAGE",
|
menu_title = "@LUA_MENU_CHOOSE_LANGUAGE",
|
||||||
@ -90,20 +98,23 @@ LUI.MenuBuilder.registerType("choose_language_menu", function(a1)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
-- fix for Y-offset in button text (russian_partial, default font)
|
-- 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()
|
LUI.UIButtonText.IsOffsetedLanguage = function()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
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)
|
-- 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()
|
LUI.UIButtonText.IsOffsetedLanguage = function()
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- fix for ammo counter (polish/russian)
|
-- fix for ammo counter (polish/russian)
|
||||||
if not Engine.InFrontend() then
|
if (not Engine.InFrontend()) then
|
||||||
local weaponinfodef = LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"]
|
local weaponinfodef = LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"]
|
||||||
LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"] = function(...)
|
LUI.MenuBuilder.m_definitions["WeaponInfoHudDef"] = function(...)
|
||||||
local rus = CoD.Language.Russian
|
local rus = CoD.Language.Russian
|
||||||
@ -131,29 +142,29 @@ if not (config.get("disable_custom_fonts")) then
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- fix for ammo counter (global patch)
|
-- fix for ammo counter (global patch)
|
||||||
if language.isnonlatin() then
|
if (language.isnonlatin()) then
|
||||||
local scale = function(size)
|
local scale = function(size)
|
||||||
return size * 720 / 1080
|
return size * 720 / 1080
|
||||||
end
|
end
|
||||||
|
|
||||||
CoD.TextSettings.SP_HudAmmoStatusText = {
|
CoD.TextSettings.SP_HudAmmoStatusText = {
|
||||||
Font = RegisterFont("fonts/mix_gothic.ttf", 16),
|
Font = RegisterFont("fonts/bank.ttf", 16),
|
||||||
Height = 16
|
Height = 16
|
||||||
}
|
}
|
||||||
|
|
||||||
CoD.TextSettings.SP_HudAmmoCounterFont = {
|
CoD.TextSettings.SP_HudAmmoCounterFont = {
|
||||||
Font = RegisterFont("fonts/mix_gothic.ttf", 34),
|
Font = RegisterFont("fonts/bank.ttf", 34),
|
||||||
Height = 34
|
Height = 34
|
||||||
}
|
}
|
||||||
|
|
||||||
CoD.TextSettings.HudAmmoCounterFont = {
|
CoD.TextSettings.HudAmmoCounterFont = {
|
||||||
Font = RegisterFont("fonts/mix_gothic.ttf", 105),
|
Font = RegisterFont("fonts/bank.ttf", 105),
|
||||||
Height = 64
|
Height = 64
|
||||||
}
|
}
|
||||||
-- forced gothic font for headers (arabic/slavic)
|
-- forced gothic font for headers (arabic/slavic)
|
||||||
if language.isslavic() or language.isarabic() then
|
if (language.isslavic() or language.isarabic()) then
|
||||||
CoD.TextSettings.H2TitleFont = {
|
CoD.TextSettings.H2TitleFont = {
|
||||||
Font = RegisterFont("fonts/mix_gothic.ttf", 56),
|
Font = RegisterFont("fonts/bank.ttf", 56),
|
||||||
Height = scale(56)
|
Height = scale(56)
|
||||||
}
|
}
|
||||||
end
|
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_common
|
||||||
|
ara_h2_mod_font_default_bold
|
||||||
|
cze_h2_mod_common
|
||||||
deu_h2_mod_common
|
deu_h2_mod_common
|
||||||
eng_h2_mod_common
|
eng_h2_mod_common
|
||||||
eng_h2_mod_patch_af_caves
|
eng_h2_mod_patch_af_caves
|
||||||
@ -6,10 +8,15 @@ ens_h2_mod_common
|
|||||||
ens_h2_mod_patch_af_caves
|
ens_h2_mod_patch_af_caves
|
||||||
fra_h2_mod_common
|
fra_h2_mod_common
|
||||||
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_af_caves
|
||||||
h2_mod_patch_dc_whitehouse
|
h2_mod_patch_dc_whitehouse
|
||||||
h2_mod_patch_ending
|
h2_mod_patch_ending
|
||||||
h2_mod_pre_gfx
|
h2_mod_pre_gfx
|
||||||
|
h2_mod_ui
|
||||||
ita_h2_mod_common
|
ita_h2_mod_common
|
||||||
jpf_h2_mod_common
|
jpf_h2_mod_common
|
||||||
jpp_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
|
stringtable,font_zones.csv
|
||||||
ttf,fonts/ibmplexsansarabic-semibold_custom.ttf
|
localize,branding
|
||||||
ttf,fonts/mix.ttf
|
|
||||||
ttf,fonts/mix_gothic.ttf
|
|
||||||
ttf,fonts/mix_open.ttf
|
|
||||||
|
|
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_OILRIG": "LUA_MENU_SP_LOCATION_OILRIG",
|
||||||
"LUA_MENU_SP_LOCATION_ROADKILL": "LUA_MENU_SP_LOCATION_ROADKILL",
|
"LUA_MENU_SP_LOCATION_ROADKILL": "LUA_MENU_SP_LOCATION_ROADKILL",
|
||||||
"LUA_MENU_SP_LOCATION_TRAINER": "LUA_MENU_SP_LOCATION_TRAINER",
|
"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("disable_custom_fonts", field_type::boolean, false)},
|
||||||
{define_field("language", field_type::string, language::get_default_language(), language::is_valid_language)},
|
{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()
|
std::string get_config_file_path()
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "mods.hpp"
|
#include "mods.hpp"
|
||||||
|
#include "fonts.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/concurrency.hpp>
|
||||||
@ -104,12 +105,14 @@ namespace fastfiles
|
|||||||
a.jmp(0x140415E29);
|
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)
|
if (localized)
|
||||||
{
|
{
|
||||||
const auto language = game::SEH_GetCurrentLanguageCode();
|
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))
|
if (!fastfiles::exists(name))
|
||||||
@ -118,48 +121,73 @@ namespace fastfiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
game::XZoneInfo info{};
|
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.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM;
|
||||||
info.freeFlags = 0;
|
info.freeFlags = 0;
|
||||||
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC);
|
zones.push_back(info);
|
||||||
return true;
|
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();
|
const auto mod_zones = mods::get_mod_zones();
|
||||||
for (const auto& zone : mod_zones)
|
for (const auto& zone : mod_zones)
|
||||||
{
|
{
|
||||||
if (zone.alloc_flags & game::DB_ZONE_COMMON)
|
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,
|
void push_zones(std::vector<game::XZoneInfo>& zones,
|
||||||
unsigned int zoneCount, game::DBSyncMode syncMode)
|
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
|
// 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,
|
void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zone_info,
|
||||||
unsigned int zoneCount, game::DBSyncMode syncMode)
|
unsigned int zone_count, game::DBSyncMode sync_mode)
|
||||||
{
|
{
|
||||||
// code_post_gfx_mp
|
// code_post_gfx_mp
|
||||||
// ui_mp
|
// ui_mp
|
||||||
// common_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)
|
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);
|
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();
|
const auto mod_zones = mods::get_mod_zones();
|
||||||
for (const auto& zone : mod_zones)
|
for (const auto& zone : mod_zones)
|
||||||
@ -450,7 +478,7 @@ namespace fastfiles
|
|||||||
|
|
||||||
a.pushad64();
|
a.pushad64();
|
||||||
a.mov(rcx, rbx);
|
a.mov(rcx, rbx);
|
||||||
a.call_aligned(add_mod_zones);
|
a.call_aligned(add_mod_zones_to_load);
|
||||||
a.popad64();
|
a.popad64();
|
||||||
|
|
||||||
a.mov(rcx, rdi);
|
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
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -631,7 +680,7 @@ namespace fastfiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto name = params.get(1);
|
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);
|
console::warn("loadzone: zone \"%s\" could not be found!\n", name);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include <utils/memory.hpp>
|
||||||
|
|
||||||
namespace fastfiles
|
namespace fastfiles
|
||||||
{
|
{
|
||||||
@ -8,4 +9,5 @@ namespace fastfiles
|
|||||||
std::string get_current_fastfile();
|
std::string get_current_fastfile();
|
||||||
|
|
||||||
bool exists(const std::string& zone);
|
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 "command.hpp"
|
||||||
#include "language.hpp"
|
#include "language.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
@ -41,182 +42,6 @@ namespace fonts
|
|||||||
"bankshadowmore",
|
"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;
|
game::Font_s* bank_font = nullptr;
|
||||||
|
|
||||||
utils::hook::detour ui_get_font_handle_hook;
|
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()
|
const auto lang = language::current();
|
||||||
{
|
const std::string lang_name = game::languages[lang].name;
|
||||||
font_data.access([&](font_data_t& data_)
|
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();
|
const auto row_values = &table->values[(row * table->columnCount)];
|
||||||
data_.fonts.clear();
|
const auto lang_value = row_values[0].string;
|
||||||
*reinterpret_cast<int*>(0x14EE3ACB8) = 0; // reset registered font count
|
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
|
class component final : public component_interface
|
||||||
@ -364,10 +209,6 @@ namespace fonts
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
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
|
// add custom fonts to hud elem fonts
|
||||||
ui_asset_cache_hook.create(0x140606090, ui_asset_cache_stub);
|
ui_asset_cache_hook.create(0x140606090, ui_asset_cache_stub);
|
||||||
ui_get_font_handle_hook.create(0x1406058F0, ui_get_font_handle_stub);
|
ui_get_font_handle_hook.create(0x1406058F0, ui_get_font_handle_stub);
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include <utils/memory.hpp>
|
||||||
|
|
||||||
namespace fonts
|
namespace fonts
|
||||||
{
|
{
|
||||||
void add(const std::string& name, const std::string& data);
|
void load_font_zones();
|
||||||
void clear();
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <utils/image.hpp>
|
#include <utils/image.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/concurrency.hpp>
|
||||||
|
#include <utils/http.hpp>
|
||||||
|
|
||||||
namespace images
|
namespace images
|
||||||
{
|
{
|
||||||
@ -73,7 +74,7 @@ namespace images
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_texture_stub(game::GfxImage* image, void* a2, int* a3)
|
void load_texture_stub(void* a1, game::GfxImage* image)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -87,7 +88,7 @@ namespace images
|
|||||||
console::error("Failed to load image %s: %s\n", image->name, e.what());
|
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)
|
int setup_texture_stub(game::GfxImage* image, void* a2, void* a3)
|
||||||
@ -115,7 +116,7 @@ namespace images
|
|||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
setup_texture_hook.create(0x1402A7940, setup_texture_stub);
|
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)
|
if (release_assets)
|
||||||
{
|
{
|
||||||
fonts::clear();
|
|
||||||
loadscreen::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);
|
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
|
class component final : public component_interface
|
||||||
@ -146,8 +121,8 @@ namespace patches
|
|||||||
// make snd_musicDisabledForCustomSoundtrack saved
|
// make snd_musicDisabledForCustomSoundtrack saved
|
||||||
utils::hook::call(0x1405D05FB, register_snd_music_stub);
|
utils::hook::call(0x1405D05FB, register_snd_music_stub);
|
||||||
|
|
||||||
// Fix broken function
|
// cinematicingameloopresident -> cinematicingameloop (fix ingame cinematics)
|
||||||
utils::hook::jump(0x140502140, gscr_cinematic_ingame_loop_resident_stub);
|
utils::hook::jump(0x140502140, 0x1405020C0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "language.hpp"
|
#include "language.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "motd.hpp"
|
||||||
|
|
||||||
#include "game/ui_scripting/execution.hpp"
|
#include "game/ui_scripting/execution.hpp"
|
||||||
#include "game/scripting/execution.hpp"
|
#include "game/scripting/execution.hpp"
|
||||||
@ -151,6 +152,7 @@ namespace ui_scripting
|
|||||||
{
|
{
|
||||||
object[key] = json_to_lua(value);
|
object[key] = json_to_lua(value);
|
||||||
}
|
}
|
||||||
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.is_array())
|
if (json.is_array())
|
||||||
@ -161,6 +163,7 @@ namespace ui_scripting
|
|||||||
{
|
{
|
||||||
array[index++] = json_to_lua(value);
|
array[index++] = json_to_lua(value);
|
||||||
}
|
}
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.is_boolean())
|
if (json.is_boolean())
|
||||||
@ -331,20 +334,7 @@ namespace ui_scripting
|
|||||||
|
|
||||||
game_type["openlink"] = [](const game&, const std::string& name)
|
game_type["openlink"] = [](const game&, const std::string& name)
|
||||||
{
|
{
|
||||||
static std::unordered_map<std::string, std::string> links =
|
const auto links = motd::get_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 link = links.find(name);
|
const auto link = links.find(name);
|
||||||
if (link == links.end())
|
if (link == links.end())
|
||||||
{
|
{
|
||||||
@ -354,6 +344,31 @@ namespace ui_scripting
|
|||||||
ShellExecuteA(nullptr, "open", link->second.data(), nullptr, nullptr, SW_SHOWNORMAL);
|
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)
|
lua["string"]["escapelocalization"] = [](const std::string& str)
|
||||||
{
|
{
|
||||||
return "\x1F"s.append(str);
|
return "\x1F"s.append(str);
|
||||||
@ -604,6 +619,41 @@ namespace ui_scripting
|
|||||||
{
|
{
|
||||||
config::set(key, lua_to_json(value));
|
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()
|
void start()
|
||||||
|
Loading…
Reference in New Issue
Block a user