Add achievements menu

This commit is contained in:
fed
2023-04-09 19:11:54 +02:00
parent 00050def13
commit 74455d3eb3
61 changed files with 611 additions and 225 deletions

View File

@ -1,196 +1,2 @@
if (Engine.InFrontend()) then
return
end
local hud = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
width = 500,
height = 500,
left = 0
})
local hidetimer = LUI.UITimer.new(5000, "hide_toast")
local finishtimer = LUI.UITimer.new(6000, "notification_finished")
local animtime = 250
hud:setPriority(1000)
local isshowingachievement = false
local notificationqueue = {}
local shownotificationinternal = nil
local shownextnotification = function()
isshowingachievement = false
local data = notificationqueue[1]
if (data == nil) then
return
end
table.remove(notificationqueue, 1)
shownotificationinternal(data)
end
local createtoast = function()
local height = 80
local width = 400
local padding = 10
local leftoffset = 10
local titlefont = CoD.TextSettings.Font27
local descfont = CoD.TextSettings.Font21
local imagesize = height - padding * 2
local textoffset = padding * 2 + imagesize
local textyoffset = height / 2 - (titlefont.Height + descfont.Height) / 2
local text2yoffset = 5
local container = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
top = 100,
left = 0,
width = width,
height = height
})
container:registerAnimationState("hide", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = -1000,
width = width,
height = height
})
container:registerAnimationState("show", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = 0,
width = width,
height = height
})
container:registerAnimationState("show_right", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = 40,
width = width,
height = height
})
local bg = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
rightAnchor = true,
bottomAnchor = true,
color = {
r = 0.1,
g = 0.1,
b = 0.1,
},
alpha = 0.55
})
local image = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
top = padding,
left = padding + leftoffset,
width = imagesize,
height = imagesize,
})
local title = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
top = textyoffset,
left = textoffset + leftoffset,
font = titlefont.Font,
height = titlefont.Height
})
local desc = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
width = width - textoffset - leftoffset - padding,
alignment = LUI.Alignment.Left,
top = textyoffset + titlefont.Height + text2yoffset,
left = textoffset + leftoffset,
font = descfont.Font,
height = descfont.Height
})
container:addElement(bg)
container:addElement(image)
container:addElement(title)
container:addElement(desc)
container:addElement(LUI.DecoFrame.new(nil, LUI.DecoFrame.Grey))
container:animateToState("hide")
container:addElement(hidetimer)
container:addElement(finishtimer)
container:registerEventHandler("hide_toast", function()
LUI.UITimer.Stop(hidetimer)
container:animateToState("hide", animtime)
end)
container:registerEventHandler("notification_finished", function()
LUI.UITimer.Stop(finishtimer)
shownextnotification()
end)
hud:addElement(container)
container.image = image
container.title = title
container.desc = desc
return container
end
local toast = createtoast()
shownotificationinternal = function(data)
isshowingachievement = true
LUI.UITimer.Reset(hidetimer)
LUI.UITimer.Reset(finishtimer)
toast:animateToState("hide")
toast:animateToState("show", animtime)
toast.title:setText(data.title)
toast.desc:setText(data.description)
toast.image:setImage(data.image)
if (data.sound) then
Engine.PlaySound(data.sound)
end
end
function addnotification(data)
table.insert(notificationqueue, data)
if (not isshowingachievement) then
shownextnotification()
end
end
local addachievementnotification = function(id)
addnotification({
title = Engine.Localize("ACHIEVEMENT_EARNED"),
description = Engine.ToUpperCase(Engine.Localize("ACHIEVEMENT_NAME_" .. id)),
image = RegisterMaterial("trophy_" .. id),
sound = "ui_achievement_unlocked"
})
end
hud:registerEventHandler("earned_achievement", function(element, event)
addachievementnotification(event.id)
end)
LUI.roots.UIRoot0:addElement(hud)
require("toast")
require("menu")

View File

@ -0,0 +1,319 @@
local maincampaign = LUI.MenuBuilder.m_types_build["main_campaign"]
LUI.MenuBuilder.m_types_build["main_campaign"] = function(...)
local initlist = LUI.Options.InitScrollingList
LUI.Options.InitScrollingList = function(list)
initlist(list, nil ,{
rows = 10
})
end
local menu = maincampaign(...)
LUI.Options.InitScrollingList = initlist
return menu
end
LUI.MenuBuilder.registerType("achievements_menu", function(root, controller)
local menuwidth = 1129
local menu = LUI.MenuTemplate.new(root, {
menu_title = "@LUA_MENU_ACHIEVEMENTS",
exclusiveController = 0,
menu_width = menuwidth,
menu_top_indent = LUI.MenuTemplate.spMenuOffset,
showTopRightSmallBar = true,
uppercase_title = true
})
local itemwidth = 80
local itemspacing = 10
local maxrowelements = 1
local rowelements = 0
local newrow = function()
local currentrow = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
width = itemwidth * maxrowelements,
height = itemwidth,
})
menu.list.currentrow = currentrow
menu.list:addElement(currentrow)
menu.list.currentrow:makeFocusable()
end
newrow()
local addelement = function(element)
local container = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
width = itemwidth,
height = itemwidth,
left = rowelements * (itemwidth + itemspacing)
})
container:addElement(element)
container:makeFocusable()
menu.list.currentrow:addElement(container)
rowelements = rowelements + 1
if (rowelements == maxrowelements) then
newrow()
rowelements = 0
end
end
local achievementtable = achievements.table()
local unlockcount = 0
for i = 0, #achievementtable do
if (achievementtable[i]) then
unlockcount = unlockcount + 1
end
end
for i = 0, achievements.count() - 1 do
local trophyimage = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
width = menuwidth,
height = itemwidth,
material = RegisterMaterial("h2_btn_unfocused")
})
trophyimage:setup9SliceImage()
trophyimage:registerAnimationState("locked", {
material = RegisterMaterial("h2_btn_unfocused_locked")
})
local stroke = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
width = menuwidth,
height = itemwidth,
material = RegisterMaterial("h2_btn_focused_stroke")
})
stroke:registerAnimationState("hide", {
alpha = 0
})
stroke:registerAnimationState("show", {
alpha = 1
})
stroke:setup9SliceImage()
local glow = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
left = -20,
top = -20,
width = menuwidth + 40,
height = itemwidth + 40,
material = RegisterMaterial("h2_btn_focused_outerglow")
})
glow:registerAnimationState("hide", {
alpha = 0
})
glow:registerAnimationState("show", {
alpha = 1
})
glow:setup9SliceImage()
local pattern = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
width = menuwidth,
height = itemwidth,
material = RegisterMaterial("h2_btn_dot_pattern")
})
pattern:registerAnimationState("hide", {
alpha = 0
})
pattern:registerAnimationState("show", {
alpha = 1
})
stroke:animateToState("hide")
pattern:animateToState("hide")
glow:animateToState("hide")
local achievementcontainer = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
width = menuwidth,
height = itemwidth,
})
local image = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
top = itemspacing / 2,
left = itemspacing / 2,
width = itemwidth - itemspacing,
height = itemwidth - itemspacing,
material = RegisterMaterial("trophy_" .. i)
})
image:registerAnimationState("locked", {
topAnchor = true,
leftAnchor = true,
top = itemspacing / 2 + 15,
left = itemspacing / 2 + 15,
width = itemwidth - itemspacing - 30,
height = itemwidth - itemspacing - 30,
material = RegisterMaterial("icon_lock_mini")
})
local textwidth = menuwidth - itemwidth - itemspacing * 2
local title = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
top = itemspacing + 5,
left = itemwidth + 5,
color = {
r = 0.7,
g = 0.7,
b = 0.7,
},
width = textwidth,
font = CoD.TextSettings.Font23.Font,
height = CoD.TextSettings.Font23.Height
})
local desc = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
top = itemspacing + CoD.TextSettings.Font23.Height + 10,
left = itemwidth + 5,
width = textwidth,
alignment = LUI.Alignment.Left,
color = {
r = 0.7,
g = 0.7,
b = 0.7,
},
font = CoD.TextSettings.Font21.Font,
height = CoD.TextSettings.Font21.Height
})
local focusedtext = {
color = {r = 1, g = 1, b = 1}
}
desc:registerAnimationState("focused", focusedtext)
title:registerAnimationState("focused", focusedtext)
title:setText(Engine.ToUpperCase(Engine.Localize(achievements.getname(i))))
desc:setText(Engine.Localize(achievements.getdetails(i)))
achievementcontainer:setHandleMouse(true)
local locked = not achievementtable[i]
achievementcontainer:registerEventHandler("mouseenter", function()
Engine.PlaySound(CoD.SFX.MouseOver)
if (locked) then
trophyimage:setImage(RegisterMaterial("h2_btn_focused_locked"))
else
stroke:animateToState("show")
pattern:animateToState("show")
title:animateToState("focused")
desc:animateToState("focused")
glow:animateToState("show")
end
end)
achievementcontainer:registerEventHandler("mouseleave", function()
if (locked) then
trophyimage:setImage(RegisterMaterial("h2_btn_unfocused_locked"))
else
stroke:animateToState("hide")
pattern:animateToState("hide")
title:animateToState("default")
desc:animateToState("default")
glow:animateToState("hide")
end
end)
achievementcontainer:addElement(trophyimage)
achievementcontainer:addElement(pattern)
achievementcontainer:addElement(glow)
achievementcontainer:addElement(stroke)
achievementcontainer:addElement(image)
achievementcontainer:addElement(title)
achievementcontainer:addElement(desc)
if (locked) then
trophyimage:animateToState("locked")
image:animateToState("locked")
title:setText(Engine.Localize("@LUA_MENU_UNKNOWN_ACHIEVEMENT"))
desc:setText("")
end
addelement(achievementcontainer)
end
if (rowelements == 0) then
menu.list.currentrow:close()
end
LUI.Options.InitScrollingList(menu.list, nil, {
rows = 5
})
local createprogressbar = function()
local barwidth = menuwidth + 17
local progressbar = LUI.UIElement.new({
bottomAnchor = true,
leftAnchor = true,
width = barwidth,
bottom = -90,
height = 15
})
local bg = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
rightAnchor = true,
bottomAnchor = true,
alpha = 0.55,
color = Colors.grey_14,
})
local bar = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
bottomAnchor = true,
width = 0,
material = RegisterMaterial("h1_ui_progressbar_green")
})
progressbar.setprogress = function(fraction)
bar:registerAnimationState("progress", {
topAnchor = true,
leftAnchor = true,
bottomAnchor = true,
width = fraction * (barwidth),
})
bar:animateToState("progress", 300)
end
progressbar.setprogress(unlockcount / achievements.count())
progressbar:addElement(bg)
progressbar:addElement(bar)
progressbar:addElement(LUI.DecoFrame.new(nil, LUI.DecoFrame.Grey))
return progressbar
end
menu:addElement(createprogressbar())
menu:AddBackButton()
return menu
end)

View File

@ -0,0 +1,203 @@
if (Engine.InFrontend()) then
return
end
local hud = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
width = 500,
height = 500,
left = 0
})
local hidetimer = LUI.UITimer.new(5000, "hide_toast")
local finishtimer = LUI.UITimer.new(6000, "notification_finished")
local animtime = 250
hud:setPriority(1000)
local isshowingachievement = false
local notificationqueue = {}
local shownotificationinternal = nil
local shownextnotification = function()
isshowingachievement = false
local data = notificationqueue[1]
if (data == nil) then
return
end
table.remove(notificationqueue, 1)
shownotificationinternal(data)
end
local createtoast = function()
local height = 80
local width = 400
local padding = 10
local leftoffset = 10
local titlefont = CoD.TextSettings.Font27
local descfont = CoD.TextSettings.Font21
local imagesize = height - padding * 2
local textoffset = padding * 2 + imagesize
local textyoffset = height / 2 - (titlefont.Height + descfont.Height) / 2
local text2yoffset = 5
local container = LUI.UIElement.new({
topAnchor = true,
leftAnchor = true,
top = 100,
left = 0,
width = width,
height = height
})
container:registerAnimationState("hide", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = -1000,
width = width,
height = height
})
container:registerAnimationState("show", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = 0,
width = width,
height = height
})
container:registerAnimationState("show_right", {
topAnchor = true,
leftAnchor = true,
top = 100,
left = 40,
width = width,
height = height
})
local bg = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
rightAnchor = true,
bottomAnchor = true,
alpha = 0.55,
color = Colors.grey_14,
})
local imagebg = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
top = padding,
left = padding + leftoffset,
width = imagesize,
height = imagesize,
material = RegisterMaterial("trophy_border")
})
local image = LUI.UIImage.new({
topAnchor = true,
leftAnchor = true,
top = padding,
left = padding + leftoffset,
width = imagesize,
height = imagesize,
})
local title = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
top = textyoffset,
left = textoffset + leftoffset,
font = titlefont.Font,
height = titlefont.Height
})
local desc = LUI.UIText.new({
topAnchor = true,
leftAnchor = true,
width = width - textoffset - leftoffset - padding,
alignment = LUI.Alignment.Left,
top = textyoffset + titlefont.Height + text2yoffset,
left = textoffset + leftoffset,
font = descfont.Font,
height = descfont.Height
})
container:addElement(bg)
container:addElement(imagebg)
container:addElement(image)
container:addElement(title)
container:addElement(desc)
container:addElement(LUI.DecoFrame.new(nil, LUI.DecoFrame.Grey))
container:animateToState("hide")
container:addElement(hidetimer)
container:addElement(finishtimer)
container:registerEventHandler("hide_toast", function()
LUI.UITimer.Stop(hidetimer)
container:animateToState("hide", animtime)
end)
container:registerEventHandler("notification_finished", function()
LUI.UITimer.Stop(finishtimer)
shownextnotification()
end)
hud:addElement(container)
container.image = image
container.title = title
container.desc = desc
return container
end
local toast = createtoast()
shownotificationinternal = function(data)
isshowingachievement = true
LUI.UITimer.Reset(hidetimer)
LUI.UITimer.Reset(finishtimer)
toast:animateToState("hide")
toast:animateToState("show", animtime)
toast.title:setText(data.title)
toast.desc:setText(data.description)
toast.image:setImage(data.image)
if (data.sound) then
Engine.PlaySound(data.sound)
end
end
function addnotification(data)
table.insert(notificationqueue, data)
if (not isshowingachievement) then
shownextnotification()
end
end
local addachievementnotification = function(id)
addnotification({
title = Engine.Localize("ACHIEVEMENT_EARNED"),
description = Engine.ToUpperCase(Engine.Localize("ACHIEVEMENT_NAME_" .. id)),
image = RegisterMaterial("trophy_" .. id),
sound = "ui_achievement_unlocked"
})
end
hud:registerEventHandler("earned_achievement", function(element, event)
addachievementnotification(event.id)
end)
LUI.roots.UIRoot0:addElement(hud)

View File

@ -29,6 +29,15 @@ function string:truncate(length)
return self:sub(1, length - 3) .. "..."
end
LUI.addmenubutton("main_campaign", {
index = 6,
text = "@LUA_MENU_ACHIEVEMENTS",
description = Engine.Localize("@LUA_MENU_ACHIEVEMENTS_DESC"),
callback = function()
LUI.FlowManager.RequestAddMenu(nil, "achievements_menu")
end
})
LUI.addmenubutton("main_campaign", {
index = 6,
text = "@MENU_MODS",