Divergent/mods/Anomaly Popup Messages/gamedata/scripts/ui_popup_messages.script

355 lines
12 KiB
Plaintext
Raw Normal View History

2024-03-17 20:18:03 -04:00
-- Linear inter/extrapolation
local function lerp(a, b, f)
if a and b and f then
return a + f * (b - a)
else
return a or b or 0
end
end
local activeGUI = {}
validGUI = {
["Dialog"] = true,
}
function GUI_on_show(name)
if validGUI[name] then
activeGUI[name] = true
end
end
function GUI_on_hide(name)
if validGUI[name] then
activeGUI[name] = nil
end
end
demonized_randomizing_functions.BackEaseOutQuadratic = demonized_randomizing_functions.BackEaseOutQuadratic or function(p)
local f = (1 - p)
return 1 - (f * f - f * sin(f * M_PI))
end
function on_game_start()
RegisterScriptCallback("actor_on_first_update", start)
RegisterScriptCallback("GUI_on_show", GUI_on_show)
RegisterScriptCallback("GUI_on_hide", GUI_on_hide)
end
GUI = nil
function start()
GUI = UIPopupMessages()
end
class "UIPopupMessages" (CUIScriptWnd)
function UIPopupMessages:__init() super()
self.xml = CScriptXmlInit()
self.xml:ParseFile("ui_apm.xml")
self.dialog = self.xml:InitStatic("apm_screen", self)
-- Callbacks
RegisterScriptCallback("actor_on_net_destroy", self)
RegisterScriptCallback("on_option_change", self)
-- OPTIONS
self.options = {}
-- MCM affects these options through all instances of this class
self:InitOptions()
-- MCM affects these options only of this particular instance
self.options.pos_x = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/pos_x") or 0
self.options.pos_y = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/pos_y") or 0
--
self.window_states = {
hidden = 0,
showing = 1,
active = 2,
hiding = 3
}
self.winds = {}
get_hud():AddDialogToRender(self)
end
function UIPopupMessages:__finalize()
end
function UIPopupMessages:actor_on_net_destroy()
self:DestroyAllWindows()
if (get_hud()) then
get_hud():RemoveDialogToRender(self)
end
end
function UIPopupMessages:on_option_change()
self:InitOptions()
end
function UIPopupMessages:InitOptions()
self.options.float_height = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/float_height") or 100 -- How far up the notification floats
self.options.window_amount = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/window_amount") or 5
self.options.display_time = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/display_time") or 3000
self.options.animation_time = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/animation_time") or 500
self.options.item_shadow = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/item_shadow") or true
self.options.text_background = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/text_background") or "ui_apm_background"
self.options.shadow_alpha = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/shadow_alpha") or 120
self.options.animate_style = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/animate_style") or "CircularEaseOut"
self.options.color_r = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_r") or 238
self.options.color_g = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_g") or 155
self.options.color_b = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_b") or 23
self.options.color_r_bg = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_r_bg") or 238
self.options.color_g_bg = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_g_bg") or 155
self.options.color_b_bg = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/color_b_bg") or 23
self.options.scaling = ui_mcm and ui_mcm.get("ui_popup_messages/apm_main/scaling") or 1
end
function UIPopupMessages:UpdateOption(k, v)
self.options[k] = v
end
ScalingPresets = {
[1] = {
fontFunc = GetFontLetterica16Russian,
height = 20,
},
[2] = {
fontFunc = GetFontGraffiti19Russian,
height = 24,
},
[3] = {
fontFunc = GetFontGraffiti22Russian,
height = 27,
},
[4] = {
fontFunc = GetFontGraffiti32Russian,
height = 37,
}
}
function UIPopupMessages:AddMessage(msg, icon)
msg = msg or ("Empty Message " .. math.random(10))
local wnd = {}
wnd.wnd = self.xml:InitStatic("apm_screen:apm_wind", self.dialog)
wnd.pos = vector2():set(wnd.wnd:GetWndPos())
wnd.wnd:SetWndPos(vector2():set(
wnd.pos.x + self.options.pos_x,
wnd.pos.y + self.options.pos_y
)
)
-- wnd.wnd:SetWndSize(vector2():set(
-- wnd.wnd:GetWidth(),
-- ScalingPresets[self.options.scaling].height
-- )
-- )
local initialIconSize
if not (icon and SYS_GetParam(2, icon, "inv_grid_height")) then
wnd.icon = self.xml:InitStatic("apm_screen:apm_icon", wnd.wnd)
initialIconSize = {wnd.icon:GetWidth(), wnd.icon:GetHeight()}
wnd.icon:InitTexture(icon or "ui_icon_news_trx_communication")
wnd.icon:SetWndSize(vector2():set(
wnd.icon:GetWidth() * (ScalingPresets[self.options.scaling].height / wnd.icon:GetHeight()),
ScalingPresets[self.options.scaling].height
)
)
else
if self.options.item_shadow then
wnd.icon_sh = self.xml:InitStatic("apm_screen:apm_icon", wnd.wnd)
end
wnd.icon = self.xml:InitStatic("apm_screen:apm_icon", wnd.wnd)
initialIconSize = {wnd.icon:GetWidth(), wnd.icon:GetHeight()}
local h = SYS_GetParam(2, icon, "inv_grid_height")
local w = SYS_GetParam(2, icon, "inv_grid_width")
local wnd_x = wnd.icon:GetWidth()
local wnd_y = wnd.icon:GetHeight()
if w > h * (wnd_x / wnd_y) then
local mult = wnd_x / w
w = wnd_x
h = h * mult * (4/3)
else
local mult = wnd_y / h
w = w * mult * (3/4)
h = wnd_y
end
local h_offset = (wnd_y - h) / 2
local w_offset = (wnd_x - w) / 2
local icon_pos = wnd.icon:GetWndPos()
-- Shadow
if self.options.item_shadow then
wnd.icon_sh:InitTexture( utils_xml.get_icons_texture(icon) )
wnd.icon_sh:SetTextureRect(Frect():set( utils_xml.get_item_axis(icon, nil, true) ))
wnd.icon_sh:SetStretchTexture(true)
wnd.icon_sh:SetWndSize(vector2():set(w, h))
wnd.icon_sh:SetWndSize(vector2():set(
wnd.icon_sh:GetWidth() * (ScalingPresets[self.options.scaling].height / wnd.icon_sh:GetHeight()),
ScalingPresets[self.options.scaling].height
)
)
wnd.icon_sh:SetWndPos(vector2():set(icon_pos.x + w_offset + 3, icon_pos.y + h_offset + 3))
wnd.icon_sh:SetTextureColor( GetARGB(self.options.shadow_alpha, 20, 20, 20) )
end
-- Icon
wnd.icon:InitTexture( utils_xml.get_icons_texture(icon) )
wnd.icon:SetTextureRect(Frect():set( utils_xml.get_item_axis(icon, nil, true) ))
wnd.icon:SetStretchTexture(true)
wnd.icon:SetWndSize(vector2():set(w, h))
wnd.icon:SetWndSize(vector2():set(
wnd.icon:GetWidth() * (ScalingPresets[self.options.scaling].height / wnd.icon:GetHeight()),
ScalingPresets[self.options.scaling].height
)
)
wnd.icon:SetWndPos(vector2():set(icon_pos.x + w_offset, icon_pos.y + h_offset))
end
wnd.bg = self.xml:InitStatic("apm_screen:apm_bg", wnd.wnd)
wnd.bg:InitTexture(self.options.text_background)
wnd.bg:SetTextureColor( GetARGB(255, self.options.color_r_bg, self.options.color_g_bg, self.options.color_b_bg) )
wnd.text = self.xml:InitTextWnd("apm_screen:apm_text",wnd.wnd)
wnd.text:SetText(msg)
wnd.text:SetFont(ScalingPresets[self.options.scaling].fontFunc())
wnd.text:SetTextColor( GetARGB(255, self.options.color_r, self.options.color_g, self.options.color_b) )
wnd.text:AdjustWidthToText()
local padding = 4
local bg_end = wnd.bg:GetWndPos().x + wnd.bg:GetWidth()
wnd.bg:SetWndPos(vector2():set(bg_end - wnd.text:GetWidth() - (padding * 2), wnd.bg:GetWndPos().y))
wnd.bg:SetWndSize(vector2():set(wnd.text:GetWidth() + (padding * 2), ScalingPresets[self.options.scaling].height))
wnd.text:SetWndPos(vector2():set(wnd.bg:GetWndPos().x + padding, wnd.text:GetWndPos().y))
-- Scale whole message window
wnd.wnd:SetWndSize(vector2():set(
wnd.wnd:GetWidth() + (initialIconSize[1] * (ScalingPresets[self.options.scaling].height / wnd.wnd:GetHeight()) - initialIconSize[1]),
ScalingPresets[self.options.scaling].height
)
)
wnd.wnd:Show(false)
wnd.time_start = time_global()
wnd.time_end = time_global() + self.options.display_time + self.options.animation_time
wnd.state = self.window_states.hidden
wnd.anim_state = 0
table.insert(self.winds, 1, wnd)
self:MoveOlderMessages()
return wnd
end
function UIPopupMessages:DestroyWindow(i)
if #self.winds == 0 then return end
local wnd = table.remove(self.winds, i and clamp(i, 1, #self.winds) or #self.winds)
wnd.wnd:Show(false)
self.dialog:DetachChild(wnd.wnd)
return self
end
function UIPopupMessages:DestroyAllWindows()
while #self.winds > 0 do
self:DestroyWindow()
end
return self
end
function UIPopupMessages:MoveOlderMessages()
if #self.winds <= 1 then return self end
while #self.winds > self.options.window_amount do
self:DestroyWindow()
end
local y_offset = self.winds[1].wnd:GetWndPos().y
for i = 2, #self.winds do
local wnd = self.winds[i]
local pos = wnd.wnd:GetWndPos()
y_offset = y_offset - wnd.wnd:GetHeight()
wnd.wnd:SetWndPos(vector2():set(pos.x, y_offset))
end
return self
end
function UIPopupMessages:AnimateWindow(wnd, anim_state)
wnd.anim_state = anim_state
local anim_offset = demonized_randomizing_functions[self.options.animate_style](wnd.anim_state)
local pos = wnd.wnd:GetWndPos()
wnd.wnd:SetWndPos(vector2():set(lerp(1024, 1024 - wnd.wnd:GetWidth(), anim_offset), pos.y))
return self
end
function UIPopupMessages:SwitchTestMode(enable)
local enable = not not enable
if self.test_mode == enable then return self end
self.test_mode = enable
if not self.test_mode then
self:DestroyAllWindows()
end
return self
end
function UIPopupMessages:Update()
CUIScriptWnd.Update(self)
if self.test_mode then
self:DestroyAllWindows()
for i = 1, self.options.window_amount do
local wnd = self:AddMessage("Message Text #" .. i)
wnd.wnd:Show(true)
self:AnimateWindow(wnd, 1)
end
return
end
if (ui_inventory.GUI and ui_inventory.GUI:IsShown()) or is_not_empty(activeGUI) then
if not device():is_paused() then
for i = #self.winds, 1, -1 do
local wnd = self.winds[i]
wnd.time_end = wnd.time_end + (device().time_delta / 2)
end
end
end
for i = #self.winds, 1, -1 do
local wnd = self.winds[i]
if time_global() > wnd.time_end then
if wnd.state == self.window_states.active then
wnd.state = self.window_states.hiding
elseif wnd.state == self.window_states.hiding then
local anim_state = clamp(1 - normalize(time_global(), wnd.time_end, wnd.time_end + self.options.animation_time), 0, 1)
self:AnimateWindow(wnd, anim_state)
if anim_state == 0 then
wnd.state = self.window_states.hidden
end
else
self:DestroyWindow(i)
end
elseif time_global() > wnd.time_start then
if wnd.state == self.window_states.showing then
local anim_state = clamp(normalize(time_global(), wnd.time_start, wnd.time_start + self.options.animation_time), 0, 1)
self:AnimateWindow(wnd, anim_state)
if anim_state == 1 then
wnd.state = self.window_states.active
end
elseif wnd.state == self.window_states.active then
-- Do nothing
else
wnd.state = self.window_states.showing
wnd.wnd:Show(true)
end
end
end
end