Divergent/mods/Classes and Talents/gamedata/scripts/talents_gui.script

1150 lines
39 KiB
Plaintext
Raw Permalink Normal View History

2024-03-17 20:18:03 -04:00
local gt = game.translate_string
local gui_opened = false
local classes_ar = { "sniper", "trooper", "jugger", "monster_hunter", "merc", "assassin" }
local pick_title_ar = {
[1] = "weapons",
[2] = "outfits",
[3] = "resists",
[4] = "special",
}
local talent_types_ar = {
[1] = "offensive",
[2] = "defensive",
[3] = "endurance",
[4] = "speech",
}
local pick_stat_t = {
weapons = {
[1] = { "assault_rifle", {sniper = 2, trooper = 3, jugger = 1, monster_hunter = 2, merc = 3, assassin = 1} },
[2] = { "sniper_rifle", {sniper = 3, trooper = 1, jugger = 1, monster_hunter = 2, merc = 3, assassin = 1} },
[3] = { "shotgun", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 2, merc = 2, assassin = 1} },
[4] = { "machine_gun", {sniper = 1, trooper = 1, jugger = 3, monster_hunter = 2, merc = 2, assassin = 1} },
[5] = { "pistol", {sniper = 3, trooper = 1, jugger = 1, monster_hunter = 2, merc = 3, assassin = 3} },
[6] = { "smg", {sniper = 1, trooper = 3, jugger = 2, monster_hunter = 2, merc = 3, assassin = 3} },
},
outfits = {
[1] = { "heavy", {sniper = 1, trooper = 3, jugger = 3, monster_hunter = 3, merc = 3, assassin = 1} },
[2] = { "medium", {sniper = 3, trooper = 3, jugger = 2, monster_hunter = 3, merc = 3, assassin = 3} },
[3] = { "sci", {sniper = 1, trooper = 3, jugger = 1, monster_hunter = 2, merc = 1, assassin = 3} },
[4] = { "light", {sniper = 3, trooper = 1, jugger = 1, monster_hunter = 1, merc = 1, assassin = 3} },
},
resists = {
[1] = { "burn", {sniper = 3, trooper = 2, jugger = 1, monster_hunter = 2, merc = 2, assassin = 2} },
[2] = { "chem", {sniper = 3, trooper = 2, jugger = 1, monster_hunter = 2, merc = 2, assassin = 2} },
[3] = { "shock", {sniper = 3, trooper = 2, jugger = 1, monster_hunter = 2, merc = 2, assassin = 2} },
[4] = { "ballistic", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 1, merc = 3, assassin = 2} },
[5] = { "explosive", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 1, merc = 3, assassin = 2} },
[6] = { "rupture", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 3, merc = 1, assassin = 2} },
[7] = { "strike", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 3, merc = 1, assassin = 2} },
[8] = { "radiation", {sniper = 3, trooper = 1, jugger = 1, monster_hunter = 1, merc = 1, assassin = 1} },
[9] = { "psi", {sniper = 1, trooper = 1, jugger = 3, monster_hunter = 3, merc = 1, assassin = 1} },
},
special = {
[1] = { "speed", {sniper = 3, trooper = 2, jugger = 1, monster_hunter = 2, merc = 1, assassin = 3} },
[2] = { "weight", {sniper = 1, trooper = 2, jugger = 3, monster_hunter = 1, merc = 2, assassin = 1} },
[3] = { "crit", {sniper = 3, trooper = 2, jugger = 1, monster_hunter = 2, merc = 2, assassin = 3} },
[4] = { "melee", {sniper = 1, trooper = 1, jugger = 3, monster_hunter = 3, merc = 2, assassin = 3} },
[5] = { "expl", {sniper = 1, trooper = 2, jugger = 1, monster_hunter = 1, merc = 3, assassin = 1} },
[6] = { "disguise", {sniper = 1, trooper = 1, jugger = 1, monster_hunter = 1, merc = 2, assassin = 3} },
[7] = { "stealth", {sniper = 1, trooper = 1, jugger = 1, monster_hunter = 1, merc = 1, assassin = 3} },
},
}
local max_stats_num = 8 -- containers and strings amount
local stats_t = {
["offensive"] = {
["titles"] = { "talents_stats_damage", "talents_stats_crit" },
["sniper"] = { [1] = "sniper_rifle", [2] = "pistol", [3] = "assault_rifle" },
["trooper"] = { [1] = "assault_rifle", [2] = "smg", [3] = "shotgun" },
["jugger"] = { [1] = "shotgun", [2] = "machine_gun", [3] = "smg", [4] = "melee" },
["monster_hunter"] = { [1] = "wpns_all", [2] = "melee" },
["merc"] = { [1] = "assault_rifle", [2] = "sniper_rifle", [3] = "pistol", [4] = "smg", [5] = "shotgun", [6] = "machine_gun" },
["assassin"] = { [1] = "pistol", [2] = "smg", [3] = "melee" },
},
["defensive"] = {
["titles"] = { "talents_stats_def" },
["sniper"] = { [1] = "burn", [2] = "chem", [3] = "shock", [4] = "radiation", [5] = "ballistic", [6] = "explosive", [7] = "rupture", [8] = "strike" },
["trooper"] = { [1] = "ballistic", [2] = "explosive", [3] = "rupture", [4] = "strike", [5] = "burn", [6] = "chem", [7] = "shock" },
["jugger"] = { [1] = "ballistic", [2] = "explosive", [3] = "rupture", [4] = "strike", [5] = "psi" },
["monster_hunter"] = { [1] = "rupture", [2] = "strike", [3] = "burn", [4] = "chem", [5] = "shock", [6] = "psi", [7] = "ballistic", [8] = "explosive" },
["merc"] = { [1] = "ballistic", [2] = "explosive", [3] = "burn", [4] = "chem", [5] = "shock", [6] = "rupture", [7] = "strike", [8] = "disguise" },
["assassin"] = { [1] = "stealth", [2] = "disguise", [3] = "evade" },
},
["endurance"] = {
["titles"] = { "talents_stats_endur" },
["sniper"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
["trooper"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
["jugger"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
["monster_hunter"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
["merc"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
["assassin"] = { [1] = "speed", [2] = "weight", [3] = "stamina" },
},
}
----------------- GUI ------------------
GUI = nil
function on_key_press(k)
if k ~= talents_functions.talents_key then return end
if gui_opened then return end
CreateTimeEvent("delay_talent_var_set", "delay_talent_var_set", 0.2, function()
gui_opened = true
return true
end)
hide_hud_inventory()
if (not GUI) then
GUI = TalentsMenu()
end
if (GUI) and (not GUI:IsShown()) then
GUI:ShowDialog(true)
Register_UI("TalentsMenu", "talents_menu_xcvb")
end
end
class "TalentsMenu" (CUIScriptWnd)
function TalentsMenu:__init() super()
self:InitControls()
self:InitCallBacks()
end
function TalentsMenu:InitControls()
self:SetWndRect(Frect():set(0, 0, 1024, 768))
self:SetAutoDelete(true)
self:AllowMovement(true)
self.xml = CScriptXmlInit()
local xml = self.xml
xml:ParseFile("ui_xcvb_talents.xml")
self.picked_class_gui = "null"
self.cur_tree = "null"
-- background
self.bg = xml:InitStatic("bg", self)
-- "pick class"
self.stats_cont = {} -- main stats containers
self.pick_titles = {} -- stat titles
self.pick_strs = {} -- stat stats
self.pick_bars = {} -- stat bars
self:BuildClassMenu(xml)
-- "talents"
self.talent_conts = {} -- talent containers
self.talents = {} -- talents
-- "levels"
self.tree_conts = {} -- tree containers
self.trees = {} -- trees and levels
-- stats
self.stat_conts = {} -- stat containers
self.talent_stats = {} -- stats
self:BuildTalentsMenu(xml)
-- if class isnt picked then show "pick class" menu
if talents_functions.picked_class == "null" then
self:ShowClassMenu()
self:HideTalentsMenu()
-- if class picked then show "talents" menu
else
self:HideClassMenu()
self:ShowTalentsMenu()
end
end
function TalentsMenu:InitCallBacks()
-- pick class
for idx, class_name in ipairs(classes_ar) do
TalentsMenu["OnSelectClass_" .. class_name] = function(self)
self:OnSelectClass(class_name)
end
self:AddCallback(class_name .. "_btn", ui_events.BUTTON_CLICKED, self["OnSelectClass_" .. class_name], self)
end
self:AddCallback("pick_accept_btn", ui_events.BUTTON_CLICKED, self.OnSelectClassPick, self)
-- talent buttons
for _, typ in ipairs(talent_types_ar) do
for __, class_name in ipairs(classes_ar) do
local t = self.talents[typ][class_name]
for talent, ___ in pairs(t) do
TalentsMenu["OnSelectTalent_" .. talent] = function(self)
self:OnSelectTalent(talent)
end
self:AddCallback(talent, ui_events.BUTTON_CLICKED, self["OnSelectTalent_" .. talent], self)
end
end
end
-- tree buttons
for _, typ in ipairs(talent_types_ar) do
TalentsMenu["OnSelectTree_" .. typ] = function(self)
self:OnSelectTree(typ)
end
self:AddCallback("tree_" .. typ, ui_events.BUTTON_CLICKED, self["OnSelectTree_" .. typ], self)
end
-- respec button
self:AddCallback("talents_respec_btn", ui_events.BUTTON_CLICKED, self.OnClickRespec, self)
-- respec ver buttons
self:AddCallback("respec_btn_yes", ui_events.BUTTON_CLICKED, self.OnClickRespecYes, self)
self:AddCallback("respec_btn_no", ui_events.BUTTON_CLICKED, self.OnClickRespecNo, self)
end
---------------------------------------------------------
---------------------- Class Menu ----------------------
---------------------------------------------------------
function TalentsMenu:BuildClassMenu(xml)
self.class_main = xml:InitStatic("bg:main_pick", self.bg)
self.class_main:Show(false)
-- LEFT
self.class_left = xml:InitStatic("bg:main_pick:left", self.class_main)
-- "pick class" left cont
self.pick_class_cont = xml:InitStatic("bg:main_pick:left:pick_class_cont", self.class_left)
align_element(self, self.pick_class_cont, self.class_left, "c", "c")
self.pick_class_cont:SetWndPos(vector2():set(self.pick_class_cont:GetWndPos().x, self.pick_class_cont:GetWndPos().y - 100)) -- move a bit up
-- title
self.class_title = xml:InitTextWnd("bg:main_pick:left:pick_class_cont:class_title", self.pick_class_cont)
-- classes cont
self.classes_cont = xml:InitStatic("bg:main_pick:left:pick_class_cont:classes_cont", self.pick_class_cont)
-- sniper button/icon
self.pick_class_btns_t = {}
for _, class_name in ipairs(classes_ar) do
self.pick_class_btns_t[class_name] = {}
self.pick_class_btns_t[class_name].cont = xml:InitStatic("bg:main_pick:left:pick_class_cont:classes_cont:" .. class_name .. "_cont", self.classes_cont)
self.pick_class_btns_t[class_name].icon = xml:InitStatic("bg:main_pick:left:pick_class_cont:classes_cont:" .. class_name .. "_cont:" .. class_name .. "_icon", self.pick_class_btns_t[class_name].cont)
self.pick_class_btns_t[class_name].btn = xml:Init3tButton("bg:main_pick:left:pick_class_cont:classes_cont:" .. class_name .. "_cont:" .. class_name .. "_btn", self.pick_class_btns_t[class_name].cont)
self:Register(self.pick_class_btns_t[class_name].btn, class_name .. "_btn")
end
-- class description
self.class_descr_cont = xml:InitStatic("bg:main_pick:left:pick_class_descr_cont", self.class_left)
local pick_class_cont_pos = self.pick_class_cont:GetWndPos()
local pick_class_cont_height = self.pick_class_cont:GetHeight()
self.class_descr_cont:SetWndPos(vector2():set(pick_class_cont_pos.x - 50, pick_class_cont_pos.y + pick_class_cont_height))
self.class_descr_cont:Show(false)
-- class description text
self.class_descr_text = xml:InitTextWnd("bg:main_pick:left:pick_class_descr_cont:descr_text", self.class_descr_cont)
-- RIGHT
self.class_right = xml:InitStatic("bg:main_pick:right", self.class_main)
self.descr_cont = xml:InitStatic("bg:main_pick:right:descr_cont", self.class_right)
-- "pick class" right containers
for _, name in ipairs(classes_ar) do
self.stats_cont[name] = xml:InitStatic("bg:main_pick:right:descr_cont:pick_stats_cont", self.descr_cont)
self.stats_cont[name]:Show(false)
-- stats title
local cur_w, cur_h = 0, 0
for idx, str in ipairs(pick_title_ar) do
-- create title
self.pick_titles[idx] = xml:InitTextWnd("bg:main_pick:right:descr_cont:pick_stats_cont:stat_title", self.stats_cont[name])
self.pick_titles[idx]:SetText(gt("stat_" .. str))
-- set title position
local title_pos = vector2():set(self.pick_titles[idx]:GetWndPos())
self.pick_titles[idx]:SetWndPos(vector2():set(title_pos.x, cur_h))
-- shift Y pos by title height
cur_h = cur_h + self.pick_titles[idx]:GetHeight()
-- stats
for i, ar in ipairs(pick_stat_t[str]) do
-- create stat
self.pick_strs[i] = xml:InitTextWnd("bg:main_pick:right:descr_cont:pick_stats_cont:stat_str", self.stats_cont[name])
self.pick_strs[i]:SetText(gt("stat_" .. ar[1]))
-- set stat position
local elem_pos = vector2():set(self.pick_strs[i]:GetWndPos())
self.pick_strs[i]:SetWndPos(vector2():set(elem_pos.x, cur_h))
-- shift X pos by stat width
cur_w = self.pick_strs[i]:GetWidth()
-- create bar
local bar_val = ar[2][name]
self.pick_bars[i] = xml:InitStatic("bg:main_pick:right:descr_cont:pick_stats_cont:stat_bar", self.stats_cont[name])
self.pick_bars[i]:InitTexture("stats_bar_" .. bar_val)
-- set bar position
self.pick_bars[i]:SetWndPos(vector2():set(cur_w, cur_h))
-- shift Y pos by stat height
cur_h = cur_h + self.pick_strs[i]:GetHeight()
-- if last elem then add more gap
if i == #pick_stat_t[str] then
cur_h = cur_h + 25
end
end
end
end
-- pick button
self.pick_accept_btn = xml:Init3tButton("bg:main_pick:right:descr_cont:pick_accept_btn", self.descr_cont)
self:Register(self.pick_accept_btn, "pick_accept_btn")
self.pick_accept_btn:Enable(false)
end
function TalentsMenu:OnSelectClass(class_name)
self:ResetClassMenu()
self.picked_class_gui = class_name
self:ShowClassInfo()
end
function TalentsMenu:ResetClassMenu()
-- hide all classes stats
for name, _ in pairs(self.stats_cont) do
self.stats_cont[name]:Show(false)
end
-- remove class name
self.class_title:SetText(gt("pick_class_pick_text"))
-- remove class descr
self.class_descr_text:SetText("")
-- hide class descr container
self.class_descr_cont:Show(false)
-- remove picked class
self.picked_class_gui = "null"
-- disable pick button
self.pick_accept_btn:Enable(false)
end
function TalentsMenu:ShowClassInfo()
local name = self.picked_class_gui
-- change class title name
self.class_title:SetText(gt("pick_class_" .. name .. "_title"))
-- change class descr
self.class_descr_text:SetText(gt("pick_class_" .. name .. "_descr"))
-- show class descr container
self.class_descr_cont:Show(true)
-- show stats container
self.stats_cont[name]:Show(true)
-- enable button
self.pick_accept_btn:Enable(true)
end
function TalentsMenu:HideClassMenu()
self:ResetClassMenu()
-- hide pick class container
self.class_main:Show(false)
end
function TalentsMenu:ShowClassMenu()
self:ResetClassMenu()
-- show pick class container
self.class_main:Show(true)
end
function TalentsMenu:OnSelectClassPick()
if self.picked_class_gui and self.picked_class_gui ~= "null" then
-- set picked class
talents_functions.picked_class = self.picked_class_gui
-- send message that class was picked
local class_str = gt("pick_class_" .. self.picked_class_gui .. "_title")
news_manager.send_tip(db.actor, strformat(gt("pick_class_picked"), class_str), 0, nil, 10000)
-- hide "pick class" menu
self:HideClassMenu()
-- show "talents" menu
self:ShowTalentsMenu()
end
end
---------------------------------------------------------
--------------------- Talents Menu ---------------------
---------------------------------------------------------
function TalentsMenu:BuildTalentsMenu(xml)
self.talents_main = xml:InitStatic("bg:main_talent", self.bg)
self.talents_main:Show(false)
self.talents_left = xml:InitStatic("bg:main_talent:left", self.talents_main)
self.talents_right = xml:InitStatic("bg:main_talent:right", self.talents_main)
self.talents_descr_cont = xml:InitStatic("bg:main_talent:right:descr_cont", self.talents_right)
local gap_x, gap_y = 59, 116
local level_offset_x, level_offset_y = 30, 53
-- create left background, containers and talent table
for idx, typ in ipairs(talent_types_ar) do
-- LEFT
self.talent_conts[typ] = {}
self.talents[typ] = {}
for __, class_name in ipairs(classes_ar) do
self.talent_conts[typ][class_name] = {}
-- backgrounds
self.talent_conts[typ][class_name]["background"] = xml:InitStatic("bg:main_talent:left:talent_background", self.talents_left)
local bg_texture = class_name .. "_" .. typ
if typ == "endurance" or typ == "speech" then
bg_texture = "bg_" .. typ
end
self.talent_conts[typ][class_name]["background"]:InitTexture(bg_texture)
self.talent_conts[typ][class_name]["background"]:Show(false)
-- containers
self.talent_conts[typ][class_name]["container"] = xml:InitStatic("bg:main_talent:left:talent_container", self.talents_left)
self.talent_conts[typ][class_name]["container"]:Show(false)
-- talent table
self.talents[typ][class_name] = {}
-- create talent icons and buttons
local class_t = talents_functions.talents_table[typ][class_name]
for talent, talent_t in pairs(class_t) do
self.talents[typ][class_name][talent] = {}
local pos = { talent_t.pos.x * gap_x, talent_t.pos.y * gap_y }
-- icon [1]
self.talents[typ][class_name][talent][1] = xml:InitStatic("bg:main_talent:left:talent_container:icon", self.talent_conts[typ][class_name]["container"])
self.talents[typ][class_name][talent][1]:InitTexture("talent_" .. talent .. "_bw")
self.talents[typ][class_name][talent][1]:SetWndPos(vector2():set(pos[1], pos[2]))
-- button [2]
self.talents[typ][class_name][talent][2] = xml:Init3tButton("bg:main_talent:left:talent_container:btn", self.talent_conts[typ][class_name]["container"])
self.talents[typ][class_name][talent][2]:SetWndPos(vector2():set(pos[1], pos[2]))
self:Register(self.talents[typ][class_name][talent][2], talent)
self.talents[typ][class_name][talent][2]:Enable(false)
-- levels [3]
self.talents[typ][class_name][talent][3] = xml:InitTextWnd("bg:main_talent:left:talent_container:levels", self.talent_conts[typ][class_name]["container"])
self.talents[typ][class_name][talent][3]:SetWndPos(vector2():set(pos[1] + level_offset_x, pos[2] + level_offset_y))
self.talents[typ][class_name][talent][3]:SetText("0/0")
-- links [4]
local required_talent
for parent_talent, _ in pairs(talent_t.req) do
if parent_talent ~= "all" then required_talent = parent_talent end
end
-- get link based on pos difference
local req_pos = required_talent and talents_functions.talents_table[typ][class_name][required_talent].pos
if req_pos then
self.talents[typ][class_name][talent][4] = {}
-- create link(s)
self.talents[typ][class_name][talent][4][1] = xml:InitStatic("bg:main_talent:left:talent_container:link", self.talent_conts[typ][class_name]["container"])
self.talents[typ][class_name][talent][4][1]:InitTexture("talents_rect_bw")
-- start pos real
local start_pos_x = talent_t.pos.x * gap_x
local start_pos_y = talent_t.pos.y * gap_y
-- req pos real
local dest_pos_x = req_pos.x * gap_x
local dest_pos_y = req_pos.y * gap_y
-- default icon width/height
local def_icon_w = self.talents[typ][class_name][talent][1]:GetWidth()
local def_icon_h = self.talents[typ][class_name][talent][1]:GetHeight()
-- default link width/height
local def_link_w = self.talents[typ][class_name][talent][4][1]:GetWidth()
local def_link_h = self.talents[typ][class_name][talent][4][1]:GetHeight()
local diff_x = req_pos.x - talent_t.pos.x
local link1_pos_x = start_pos_x + (def_icon_w - def_link_w) / 2
if diff_x ~= 0 then
local link1_pos_y = dest_pos_y + (def_icon_h - def_link_h) / 2
local link1_height = start_pos_y - link1_pos_y
self.talents[typ][class_name][talent][4][1]:SetWndSize(vector2():set(def_link_w, link1_height))
self.talents[typ][class_name][talent][4][1]:SetWndPos(vector2():set(link1_pos_x, link1_pos_y))
-- create 2nd link
self.talents[typ][class_name][talent][4][2] = xml:InitStatic("bg:main_talent:left:talent_container:link", self.talent_conts[typ][class_name]["container"])
self.talents[typ][class_name][talent][4][2]:InitTexture("talents_rect_bw")
if diff_x < 0 then
local link2_pos_x = dest_pos_x + def_icon_w
local link2_pos_y = link1_pos_y
local link2_width = link1_pos_x - link2_pos_x + def_link_w
self.talents[typ][class_name][talent][4][2]:SetWndSize(vector2():set(link2_width, def_link_h))
self.talents[typ][class_name][talent][4][2]:SetWndPos(vector2():set(link2_pos_x, link2_pos_y))
else
local link2_pos_x = link1_pos_x
local link2_pos_y = link1_pos_y
local link2_width = dest_pos_x - link1_pos_x
self.talents[typ][class_name][talent][4][2]:SetWndSize(vector2():set(link2_width, def_link_h))
self.talents[typ][class_name][talent][4][2]:SetWndPos(vector2():set(link2_pos_x, link2_pos_y))
end
-- if diff_x == 0
else
local link1_pos_y = dest_pos_y + def_icon_h
local link1_height = start_pos_y - link1_pos_y
self.talents[typ][class_name][talent][4][1]:SetWndSize(vector2():set(def_link_w, link1_height))
self.talents[typ][class_name][talent][4][1]:SetWndPos(vector2():set(link1_pos_x, link1_pos_y))
end
end
end
end
-- RIGHT
self.tree_conts[typ] = xml:InitStatic("bg:main_talent:right:descr_cont:tree_container", self.talents_descr_cont)
local pos = self.tree_conts[typ]:GetWndPos()
local h = self.tree_conts[typ]:GetHeight()
local new_y = h * (idx - 1)
self.tree_conts[typ]:SetWndPos(vector2():set(pos.x, new_y))
-- create icons and descr
self.trees[typ] = {}
-- icon container and button [1]
self.trees[typ][1] = {}
self.trees[typ][1].cont = xml:InitStatic("bg:main_talent:right:descr_cont:tree_container:icon_cont", self.tree_conts[typ])
self.trees[typ][1].icon = xml:InitStatic("bg:main_talent:right:descr_cont:tree_container:icon_cont:icon", self.trees[typ][1].cont)
self.trees[typ][1].btn = xml:Init3tButton("bg:main_talent:right:descr_cont:tree_container:icon_cont:btn", self.trees[typ][1].cont)
self:Register(self.trees[typ][1].btn, "tree_" .. typ)
-- title [2]
self.trees[typ][2] = xml:InitTextWnd("bg:main_talent:right:descr_cont:tree_container:title", self.tree_conts[typ])
-- title level [3]
self.trees[typ][3] = xml:InitTextWnd("bg:main_talent:right:descr_cont:tree_container:title_level", self.tree_conts[typ])
-- bar container and bar with text [4]
self.trees[typ][4] = {}
self.trees[typ][4].cont = xml:InitStatic("bg:main_talent:right:descr_cont:tree_container:bar_cont", self.tree_conts[typ])
self.trees[typ][4].bar = xml:InitProgressBar("bg:main_talent:right:descr_cont:tree_container:bar_cont:bar", self.trees[typ][4].cont)
self.trees[typ][4].bar:SetProgressPos(0.0)
self.trees[typ][4].text = xml:InitTextWnd("bg:main_talent:right:descr_cont:tree_container:bar_cont:bar_text", self.trees[typ][4].cont)
-- points [5]
self.trees[typ][5] = xml:InitTextWnd("bg:main_talent:right:descr_cont:tree_container:points", self.tree_conts[typ])
end
-- respec button
self.respec_btn = xml:Init3tButton("bg:main_talent:right:descr_cont:respec_btn", self.talents_descr_cont)
self:Register(self.respec_btn, "talents_respec_btn")
-- stats
self.stat_conts = {}
self.stat_conts.main = xml:InitStatic("bg:main_talent:right:descr_cont:stat_container", self.talents_descr_cont)
self.stat_conts.title = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:title", self.stat_conts.main)
self.stat_conts.sum_1_title = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:sum_1_title", self.stat_conts.main)
self.stat_conts.sum_2_title = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:sum_2_title", self.stat_conts.main)
self.talent_stats = {}
for i = 1, max_stats_num do
self.talent_stats[i] = {}
-- stat name
self.talent_stats[i].name = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:name", self.stat_conts.main)
local name_pos = self.talent_stats[i].name:GetWndPos()
local name_h = self.talent_stats[i].name:GetHeight()
local name_new_y = name_h * (i - 1) + name_pos.y
self.talent_stats[i].name:SetWndPos(vector2():set(name_pos.x, name_new_y))
-- stat val 1
self.talent_stats[i].val1 = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:val1", self.stat_conts.main)
local val1_pos = self.talent_stats[i].val1:GetWndPos()
local val1_h = self.talent_stats[i].val1:GetHeight()
local val1_new_y = val1_h * (i - 1) + val1_pos.y
self.talent_stats[i].val1:SetWndPos(vector2():set(val1_pos.x, val1_new_y))
-- stat val 2
self.talent_stats[i].val2 = xml:InitTextWnd("bg:main_talent:right:descr_cont:stat_container:val2", self.stat_conts.main)
local val2_pos = self.talent_stats[i].val2:GetWndPos()
local val2_h = self.talent_stats[i].val2:GetHeight()
local val2_new_y = val2_h * (i - 1) + val2_pos.y
self.talent_stats[i].val2:SetWndPos(vector2():set(val2_pos.x, val2_new_y))
end
-- respec verification container
self.respec_cont = xml:InitStatic("bg:main_talent:right:descr_cont:respec_cont", self.talents_descr_cont)
align_element(self, self.respec_cont, self.talents_descr_cont, "c", "c")
self.respec_cont:Show(false)
-- respec text and buttons "yes" and "no"
self.respec_money = 100000
self.respec_text = xml:InitTextWnd("bg:main_talent:right:descr_cont:respec_cont:respec_text", self.respec_cont)
self.respec_text:SetText(strformat(gt("talents_respec_ver"), self.respec_money))
self.respec_btn_yes = xml:Init3tButton("bg:main_talent:right:descr_cont:respec_cont:respec_btn_yes", self.respec_cont)
self:Register(self.respec_btn_yes, "respec_btn_yes")
self.respec_btn_no = xml:Init3tButton("bg:main_talent:right:descr_cont:respec_cont:respec_btn_no", self.respec_cont)
self:Register(self.respec_btn_no, "respec_btn_no")
-- tooltip
self.talents_tooltip_cont = xml:InitStatic("bg:main_talent:right:talent_tooltip", self.talents_right)
self.talents_tooltip_name = xml:InitTextWnd("bg:main_talent:right:talent_tooltip:name", self.talents_tooltip_cont)
self.talents_tooltip_level = xml:InitTextWnd("bg:main_talent:right:talent_tooltip:levels", self.talents_tooltip_cont)
self.talents_tooltip_req = xml:InitTextWnd("bg:main_talent:right:talent_tooltip:req", self.talents_tooltip_cont)
self.talents_tooltip_descr = xml:InitTextWnd("bg:main_talent:right:talent_tooltip:descr", self.talents_tooltip_cont)
self.talents_tooltip_cont:Show(false)
end
function TalentsMenu:OnSelectTree(typ)
pr("select tree typ: %s", typ)
if self.cur_tree == typ then return end
pr("open tree: %s", typ)
-- set current tree
self.cur_tree = typ
-- reset left talents
self:ResetLeftTalents()
-- update all talents menu
self:UpdateTalentsMenu()
end
function TalentsMenu:ResetLeftTalents()
-- hide all left background and containers
for typ, t in pairs(self.talent_conts) do
for class_name, t2 in pairs(t) do
self.talent_conts[typ][class_name]["background"]:Show(false)
self.talent_conts[typ][class_name]["container"]:Show(false)
pr("reset left background and container for typ: %s || class: %s", typ, class_name)
end
end
-- show picked one
local class_name = talents_functions.picked_class
self.talent_conts[self.cur_tree][class_name]["background"]:Show(true)
self.talent_conts[self.cur_tree][class_name]["container"]:Show(true)
pr("-show left background and container for typ: %s || class: %s", self.cur_tree, class_name)
end
local picked_font = 0
function TalentsMenu:UpdateTalentsMenu()
self:UpdateTrees()
self:UpdateTalents()
self:UpdateStats()
self.respec_cont:Show(false)
if self.talents_tooltip_cont:IsShown() then
self.talents_tooltip_cont:Show(false)
end
end
function TalentsMenu:OnSelectTalent(talent)
local class_name = talents_functions.picked_class
pr("pressed talent %s", talent)
-- update other script tables
for typ, typ_t in pairs(talents_functions.talents_table) do
-- talent found and talent tree has points
local points = talents_leveling.talent_levels[typ].points
if talents_functions.talents_table[typ][class_name][talent] and points > 0 then
-- add level
talents_functions.talents_table[typ][class_name][talent].level = talents_functions.talents_table[typ][class_name][talent].level + 1
-- remove talent point
talents_leveling.talent_levels[typ].points = talents_leveling.talent_levels[typ].points - 1
-- add spent point
talents_leveling.talent_levels[typ].spent_points = talents_leveling.talent_levels[typ].spent_points + 1
-- recalc item weight
talents_functions.recalc_all_items_weight()
end
end
-- update all talents
self:UpdateTalentsMenu()
end
function TalentsMenu:UpdateTrees()
local class_name = talents_functions.picked_class
if class_name == "null" then return end
-- update trees UI
local level_t = talents_leveling.talent_levels
local exp_t = talents_leveling.typ_levels
for typ, t in pairs(level_t) do
-- update icon
self.trees[typ][1].icon:InitTexture(class_name .. "_" .. typ .. "_tree")
-- update title
self.trees[typ][2]:SetText(gt("tree_" .. typ))
-- update title level
self.trees[typ][3]:SetText(t.lvl)
-- update bar
local max_level = t.lvl >= #exp_t
local progress_val = max_level and (1.0) or (t.exp / (exp_t[t.lvl + 1]))
self.trees[typ][4].bar:SetProgressPos(progress_val)
local progress_text = max_level and (gt("tree_max_exp")) or (math.floor(t.exp) .. " / " .. (exp_t[t.lvl + 1]))
self.trees[typ][4].text:SetText(progress_text)
-- update points
local points_text = ""
if t.points > 0 then
points_text = gt("tree_points") .. " " .. t.points
end
self.trees[typ][5]:SetText(points_text)
end
end
function TalentsMenu:UpdateTalents()
local class_name = talents_functions.picked_class
if class_name == "null" then return end
-- update UI according to table
-- first iterate - update text, check requirements and enable/disable button
for typ, typ_t in pairs(talents_functions.talents_table) do
local spent_points = talents_leveling.talent_levels[typ].spent_points
for talent, t in pairs(typ_t[class_name]) do
-- update text
self.talents[typ][class_name][talent][3]:SetText(t.level .. "/" .. t.max)
-- check if requirements met
local reqs_met = size_table(t.req)
for req_name, req_val in pairs(t.req) do
-- enough points spent
if req_name == "all" then
if spent_points >= req_val then
reqs_met = reqs_met - 1
end
-- other talents requirements are picked
else
local parent_talent = typ_t[class_name][req_name]
if parent_talent.level >= req_val then
reqs_met = reqs_met - 1
end
end
end
-- 1) if reqs are met - change icon, enable button, update text, add link
if reqs_met <= 0 then
self.talents[typ][class_name][talent][1]:InitTexture("talent_" .. talent)
self.talents[typ][class_name][talent][2]:Enable(true)
if self.talents[typ][class_name][talent][4] then
for i = 1, #self.talents[typ][class_name][talent][4] do
self.talents[typ][class_name][talent][4][i]:InitTexture("talents_rect")
end
end
-- 2) if reqs arent met - change icon to bw, disable button
else
self.talents[typ][class_name][talent][1]:InitTexture("talent_" .. talent .. "_bw")
self.talents[typ][class_name][talent][2]:Enable(false)
if self.talents[typ][class_name][talent][4] then
for i = 1, #self.talents[typ][class_name][talent][4] do
self.talents[typ][class_name][talent][4][i]:InitTexture("talents_rect_bw")
end
end
end
end
end
-- second iterate - check hinders, max out, points left
for typ, typ_t in pairs(talents_functions.talents_table) do
local points = talents_leveling.talent_levels[typ].points
for talent, t in pairs(typ_t[class_name]) do
-- 3) disable button of hindered talent and make it bw (+bw link)
if t.level > 0 and t.hinder then
pr("talent: %s || lvl: %s || hinders: %s", talent, t.level, t.hinder)
self.talents[typ][class_name][t.hinder][1]:InitTexture("talent_" .. t.hinder .. "_bw")
self.talents[typ][class_name][t.hinder][2]:Enable(false)
if self.talents[typ][class_name][t.hinder][4] then
for i = 1, #self.talents[typ][class_name][t.hinder][4] do
self.talents[typ][class_name][t.hinder][4][i]:InitTexture("talents_rect_bw")
end
end
end
-- 4) disable button if talent maxed out or no points left
if points <= 0 or t.level >= t.max then
self.talents[typ][class_name][talent][2]:Enable(false)
end
-- 5) if no points left and button level 0 - change icon to bw, disable button (+bw link)
if points <= 0 and t.level <= 0 then
self.talents[typ][class_name][talent][1]:InitTexture("talent_" .. talent .. "_bw")
self.talents[typ][class_name][talent][2]:Enable(false)
if self.talents[typ][class_name][talent][4] then
for i = 1, #self.talents[typ][class_name][talent][4] do
self.talents[typ][class_name][talent][4][i]:InitTexture("talents_rect_bw")
end
end
end
end
end
end
function TalentsMenu:UpdateStats()
local class_name = talents_functions.picked_class
local cur_typ = self.cur_tree
-- clear strings first
self.stat_conts.sum_1_title:SetText("")
self.stat_conts.sum_2_title:SetText("")
for i = 1, max_stats_num do
self.talent_stats[i].name:SetText("")
self.talent_stats[i].val1:SetText("")
self.talent_stats[i].val2:SetText("")
end
-- fill new strings according to typ and class
if not stats_t[cur_typ] then return end
self.stat_conts.sum_1_title:SetText(gt(stats_t[cur_typ].titles[1]) or "")
self.stat_conts.sum_2_title:SetText(gt(stats_t[cur_typ].titles[2]) or "")
local class_stats_ar = stats_t[cur_typ][class_name]
for i = 1, max_stats_num do
if class_stats_ar[i] then
-- fill names
self.talent_stats[i].name:SetText(gt("stat_" .. class_stats_ar[i]))
-- fill values
local get_val_ar = talents_functions.calculate_stats(cur_typ, class_name, class_stats_ar[i])
-- get string
if get_val_ar then
local str1 = get_val_ar[1] .. "% (" .. get_val_ar[2] .. "%)"
local str2 = ""
if cur_typ == "offensive" and get_val_ar[3] and get_val_ar[4] then
str2 = get_val_ar[3] .. "% (" .. get_val_ar[4] .. ")"
end
-- if stat is weight then change to kg
if class_stats_ar[i] == "weight" then
str1 = get_val_ar[1] .. " " .. gt("stat_weight_kg")
-- if stat is stamina then change to % per sec
elseif class_stats_ar[i] == "stamina" then
str1 = get_val_ar[1] .. "%/" .. gt("stat_stamina_per_sec")
end
self.talent_stats[i].val1:SetText(str1)
self.talent_stats[i].val2:SetText(str2)
end
end
end
end
function TalentsMenu:HideTalentsMenu()
self.talents_main:Show(false)
end
function TalentsMenu:ShowTalentsMenu()
if talents_functions.picked_class == "null" then return end
self.talents_main:Show(true)
pr("Show talents menu")
if self.cur_tree == "null" then
self.cur_tree = "offensive"
end
-- reset left talents
self:ResetLeftTalents()
-- update all
self:UpdateTalentsMenu()
end
---------------------------------------------------------
------------------------ Respec ------------------------
---------------------------------------------------------
function TalentsMenu:OnClickRespec()
-- open new verification window
self.respec_cont:Show(true)
-- enable/disable "yes" button based on money
local has_money = db.actor:money() -1 > self.respec_money
self.respec_btn_yes:Enable(has_money)
end
function TalentsMenu:OnClickRespecYes()
db.actor:give_money(-self.respec_money)
self.respec_cont:Show(false)
-- respec
talents_functions.respec_talents()
talents_leveling.respec_levels()
-- send news
news_manager.send_tip(db.actor, gt("talents_respeced"), 0, nil, 10000)
-- hide "talents" menu
self:HideTalentsMenu()
-- show "pick class" menu
self:ShowClassMenu()
-- and close gui
self:Close()
end
function TalentsMenu:OnClickRespecNo()
self.respec_cont:Show(false)
end
-- cbs, utils and close
function TalentsMenu:Update()
CUIScriptWnd.Update(self)
-- hide
if self.talents_tooltip_cont:IsShown() then
self.talents_tooltip_cont:Show(false)
end
local typ = self.cur_tree
local class_name = talents_functions.picked_class
if (typ == "null") or (class_name == "null") then return end
-- hover icon tooltip
local talent
for tal, cont_ar in pairs(self.talents[typ][class_name]) do
if cont_ar[2]:IsShown() and cont_ar[2]:IsCursorOverWindow() then
talent = tal
break
end
end
if not talent then return end
-- bg 128, 0
-- main_talent 22, 33
-- right 436, 0
-- xD return tooltip to 0, 0
local start_x = 128+22+436
local start_y = 33
self.talents_tooltip_cont:SetWndPos(vector2():set( -start_x, -start_y ))
-- calc new pos based on cursor
local elem_height = self.talents_tooltip_cont:GetHeight()
local cursor_pos = GetCursorPosition()
local tal_t = talents_functions.talents_table[typ][class_name][talent]
local pos_y
if tal_t.pos.y <= 1 then -- pos down
pos_y = cursor_pos.y
else -- pos up
pos_y = cursor_pos.y - elem_height
end
if not pos_y then return end
-- change pos
local elem_width = self.talents_tooltip_cont:GetWidth()
local elem_pos = self.talents_tooltip_cont:GetWndPos()
self.talents_tooltip_cont:SetWndPos(vector2():set(elem_pos.x + cursor_pos.x - elem_width, elem_pos.y + pos_y))
-- change height
local height_mult = talents_functions.get_tooltip_height_mult(typ, class_name, talent)
self.talents_tooltip_cont:SetWndSize(vector2():set(200, 200 * height_mult))
-- show
self.talents_tooltip_cont:Show(true)
-- update name
self.talents_tooltip_name:SetText(gt(talent .. "_name"))
-- update levels
self.talents_tooltip_level:SetText(tal_t.level .. "/" .. tal_t.max)
-- update requirements
local req_str = talents_functions.get_tooltip_req_str(typ, class_name, talent)
self.talents_tooltip_req:SetText(req_str)
-- update description
local descr_str = talents_functions.get_tooltip_descr_str(typ, class_name, talent)
self.talents_tooltip_descr:SetText(descr_str)
end
function TalentsMenu:OnKeyboard(key, keyboard_action)
local res = CUIScriptWnd.OnKeyboard(self, key, keyboard_action)
if (res == false) then
if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
if gui_opened and (key == talents_functions.talents_key or key == DIK_keys.DIK_ESCAPE) then
self:Close()
end
end
end
return res
end
function TalentsMenu:Close()
if self:IsShown() then
self:HideDialog()
self:Show(false)
if gui_opened then
gui_opened = false
end
Unregister_UI("TalentsMenu")
end
end
function TalentsMenu:__finalize()
end
------------------------------------------
function align_element(gui, elem, cont, h, v, text_h, text_v) -- align_element(self, self.elem, self.cont, "c", "b") is bottom center
if not (gui and elem) then return end
if h and type(h) == "string" and cont then
local elem_w = elem:GetWidth()
local cont_w = cont:GetWidth()
if (elem_w <= cont_w) then
local horiz_align
if h == "l" then
horiz_align = 0
elseif h == "r" then
horiz_align = cont_w - elem_w
elseif h == "c" then
horiz_align = (cont_w - elem_w) / 2
end
if horiz_align then
local elem_pos = elem:GetWndPos()
elem:SetWndPos(vector2():set(horiz_align, elem_pos.y))
end
end
end
if v and type(v) == "string" and cont then
local elem_h = elem:GetHeight()
local cont_h = cont:GetHeight()
if (elem_h <= cont_h) then
local vert_align
if v == "t" then
vert_align = 0
elseif v == "b" then
vert_align = cont_h - elem_h
elseif v == "c" then
vert_align = (cont_h - elem_h) / 2
end
if vert_align then
local elem_pos = elem:GetWndPos()
elem:SetWndPos(vector2():set(elem_pos.x, vert_align))
end
end
end
if text_h and type(text_h) == "number" and text_h < 3 then
elem:SetTextAlignment(text_h)
end
if text_v and type(text_v) == "number" and text_h < 3 then
elem:SetVTextAlignment(text_v)
end
end
function pr(...)
if talents_functions.talents_dbg then
printf(...)
end
end
function update_talents_gui(a)
if (a and a == "UIZoom") then return end
if GUI ~= nil and talents_functions.picked_class ~= "null" then
GUI:UpdateTalentsMenu()
end
end
function on_game_start()
RegisterScriptCallback("on_key_press", on_key_press)
RegisterScriptCallback("GUI_on_show", update_talents_gui)
end