diff --git a/res/gamedata/configs/ui/ui_console.xml b/res/gamedata/configs/ui/ui_console.xml new file mode 100644 index 00000000000..ed5f3861fe0 --- /dev/null +++ b/res/gamedata/configs/ui/ui_console.xml @@ -0,0 +1,52 @@ + + + ui\ui_console + + + + ui_inGame2_edit_box_1 + + + + + + ui_inGame2_Mp_bigbuttone + X + + + + + ui_inGame2_Mp_bigbuttone + Execute + + + + + ui_inGame2_Mp_bigbuttone + R + + + + + + + + +
+ + + diff --git a/res/gamedata/scripts/_console.script b/res/gamedata/scripts/_console.script new file mode 100644 index 00000000000..caa903b6e66 --- /dev/null +++ b/res/gamedata/scripts/_console.script @@ -0,0 +1,501 @@ +--[[ ---------------------------------------------------------------------------------------------- + Платформы: CoP v1.6.02 + Описание : Скриптовая консоль + Поддержка: 2013 © Shoker Mod + Версия : 1.0 (12.09.2013) + Автор : Shoker + Отдельное спасибо за метод отлова нажатия клавиш: Charsi, Shadows и ColR_iT +--]] ---------------------------------------------------------------------------------------------- + +--[[ + Подключение: + * Функция actor_update() на апдейт игрока или любой другой постоянно выполняющийся код + * Если нужен вызов из меню, то вставить туда код для вызова консоли + * Все изменения в ориг. скриптах игры помечены знаком --#SM+#-- + * XML-файлы с интерфейсом, сделаны под ЗП но там закоментированы текстуры под ЧН\ТЧ (правда не тестировал) +--]] + +-- Команды из мод-консоли можно также вводить через обычную игровую консоль через команду CONSOLE_COMMAND_NAME +-- Однако команда выполнится только если игра не на паузе\в меню, а если в меню, то только если мод-консоль открыта + +LOG_FILE_NAME = "gamedata\\"..user_name().."_console.log_dump" --> Файл, куда сохраняется весь текст из консоли +VAL_FILE_NAME = "gamedata\\"..user_name().."_console.values" --> Файл, куда сохраняются значения консольных переменных +MENU_KEY = DIK_keys.DIK_U --> Клавиша для открытия консоли из меню +GAME_KEY = "kU" --> Клавиша для открытия консоли из игры + +local CONSOLE_COMMAND_NAME = "mm_net_srv_name" --> Название консольной команды для ввода команд из ориг. консоли +local FUNC_SCRIPT = "_console_func" --> Скрипт, где хранятся все функции +local SAVE_TO_FILE = true --> Нужно ли сохранять текст +local LOAD_FROM_FILE = true --> Нужно ли загружать текст +local DIV = string.char(1) --> Символ-разделитель для файла лога, строки с ним не сохраняются в файл + +--\\ Возможные типы: "bol", "num", nil (строка) +VALUES_TBL = { --> Консольные переменные (Получать методами Get\SetValue) + ["flush_log"] = {value_and_def = true, types = "bol", descr_1 = "true\\false", descr_2 = "Сохранять лог на диск"}, +-- ["num_test"] = {value_and_def = 1.23, types = "num", descr_1 = "number", descr_2 = "Тест числа"}, +-- ["str_test"] = {value_and_def = "Hello Zep", types = nil, descr_1 = "string", descr_2 = "Тест строки"}, +} + + +local uiConsole = nil +local registred_commands = {} +local bBindKey = false + +--\\ Показать консоль +function Show() + InitUI() + + if not uiConsole:IsShown() then + uiConsole:ShowDialog(false) + end +end + +--\\ Скрыть консоль +function Hide() + if uiConsole then + if uiConsole:IsShown() then + uiConsole:HideDialog() + end + end +end + +--\\ Получить ссылку на консоль +function Get() + InitUI() + return uiConsole +end + +--\\ Выполнить консольную команду +function Execute(sCommand, bNoLog) + Get():OnButtonExecute(sCommand, (bNoLog or true)) +end + +local bNeedLoad = true + +--\\ Получить консольное значение +function GetVal(name) + if bNeedLoad == true then + fill_values_tbl() + bNeedLoad = false + end + + return VALUES_TBL[name].value_and_def +end + +--\\ Сохранить консольное значение +function SetVal(name, val) + if bNeedLoad == true then + fill_values_tbl() + bNeedLoad = false + end + + local tbl = VALUES_TBL[name] + + if tbl then + local set_value = _G[FUNC_SCRIPT].cast(val, tbl.types) + + if set_value == nil then + set_value = tbl.value_and_def + end + + if tbl.value_and_def ~= set_value then + tbl.value_and_def = set_value + + ----------------------- + local file = io.open( VAL_FILE_NAME, "w" ) + for cmnd, ctbl in pairs(VALUES_TBL) do + if file ~= nil then + file:write( cmnd..DIV..tostring(ctbl.value_and_def), "\n" ) + else + Get():AddString("Can't find or create values file: "..VAL_FILE_NAME, "Red") + end + end + file:close() + ----------------------- + end + else + Get():AddString("Can't finde console value with name ["..name.."]", "Red") + end +end + +--\\ Инициализировать консоль +function InitUI() + InitCommands() + if (uiConsole==nil) then + uiConsole = console_dialog() + end +end + +--\\ Инициализировать только команды +local bNeedInit = true +function InitCommands() + if bNeedInit == true then + for idx,cmnd in ipairs(_G[FUNC_SCRIPT].COMMANDS_LIST) do + registred_commands[cmnd[1]] = cmnd[2] + end + get_console():execute(CONSOLE_COMMAND_NAME.." nil") + bNeedInit = false + end +end + + + + + + + + + + + + + + + + + + +-------------------------------------------------------------------------------------------- + +--\\ Апдейт игрока +function actor_update() + InitCommands() + UpdateConsole() +end + +--\\ Апдейт консоли (как от игрока так и от интерфейса) +function UpdateConsole() + if bBindKey == false then + get_console():execute("bind_console mm_net_srv_name con.show "..GAME_KEY) + bBindKey = true + end + + local text = get_console():get_string(CONSOLE_COMMAND_NAME) + if text ~= "nil" then + Execute(text) + get_console():execute(CONSOLE_COMMAND_NAME.." nil") + end +end + +--\\ Вызвать консольную функцию из файла FUNC_SCRIPT +function ExecuteFunc(reg_func, parsed_string) + if _G[FUNC_SCRIPT][reg_func] then + _G[FUNC_SCRIPT][reg_func](parsed_string) + else + Get():AddString("Can't find registred function: "..reg_func.." ", "Red") + end +end + +--\\ Вызвать консольную функцию из файла FUNC_SCRIPT +function ExecuteValue(reg_value, value, bMsg) + if VALUES_TBL[reg_value] then + if value ~= nil then + SetVal(reg_value, value) + + if bMsg == true then + Get():AddString("Set value for "..reg_value.." ["..tostring(value).."]", "Green") + end + else + if bMsg == true then + Get():AddString(reg_value.." = "..tostring(GetVal(reg_value)).." ", "Green") + end + end + end +end + +--\\ Загрузить таблицу консольных переменных из файла +function fill_values_tbl() + local file = io.open( VAL_FILE_NAME, "r" ) + if file ~= nil then + for line in file:lines() do + if line then + local tbl = _u.string_expl(line, DIV) + + if tbl[1] ~= nil and tbl[1] ~= "" then + local tbl_val = VALUES_TBL[tbl[1]] + if tbl_val then + local last_value = tbl_val.value_and_def + tbl_val.value_and_def = _G[FUNC_SCRIPT].cast(tbl[2], tbl_val.types) + + if tbl_val.value_and_def == nil then + tbl_val.value_and_def = last_value + end + else + -- Заблокировано из за применения функции GetValue в коде консоли + -- т.к там идёт вызов функции GetVal в процессе создания консоли, которая + -- вызывает эту функцию fill_values_tbl и если код доходит до этих строчек + -- то функция Get() обращается к ещё не созданной до конца консоли и создаёт вторую (3-ю, 4-ю...) + -- консоль и так всё циклится пока игра не вылетит. + --Get():AddString("Can't finde console value with name ["..tbl[1].."]", "Red") + end + end + end + end + file:close() + else + --Get():AddString("Can't find values file: "..VAL_FILE_NAME, "Red") + end +end + +--------------------------------------------------------------------------------------------------------------- + + +class "console_dialog" (CUIScriptWnd) +function console_dialog:__init() super() + + local xml = CScriptXmlInit() + xml:ParseFile("ui_console.xml") + + self:SetWndRect(Frect():set(0,0,1024,768)) + self.form = xml:InitStatic("console", self) + + + self.editbox = xml:InitEditBox("console:edit_box", self.form) + self:Register (self.editbox, "command_box") + + self.btn_x = xml:Init3tButton("console:btn_x", self.form) + self:Register(self.btn_x, "btn_x") + + self.btn_exec = xml:Init3tButton("console:btn_execute", self.form) + self:Register(self.btn_exec, "btn_execute") + + self.btn_r = xml:Init3tButton("console:btn_r", self.form) + self:Register(self.btn_r, "btn_r") + + ctrl = CUIWindow() + xml:InitWindow ("file_item:main",0,ctrl) + + self.file_item_main_sz = vector2():set(ctrl:GetWidth(),ctrl:GetHeight()) + + xml:InitWindow ("file_item:fn",0,ctrl) + self.file_item_fn_sz = vector2():set(ctrl:GetWidth(),ctrl:GetHeight()) + + self.list_box = xml:InitListBox("console:list",self.form) + + self.list_box:ShowSelectedItem (true) + self:Register (self.list_box, "list_window") + + self:Clear() + + if LOAD_FROM_FILE then + self:LoadLog() + end + + self:ReInit() + InitCommands() + + -------------------------------------------------------------------------------- + self:AddCallback("btn_execute", ui_events.BUTTON_CLICKED, self.OnButtonExecute, self) + self:AddCallback("btn_x", ui_events.BUTTON_CLICKED, self.OnButtonX, self) + self:AddCallback("btn_r", ui_events.BUTTON_CLICKED, self.OnButtonR, self) + self:AddCallback("list_window", ui_events.WINDOW_LBUTTON_DB_CLICK, self.OnListItemDbClicked, self) +end + +function console_dialog:ReInit() + self:AddString("") + self:AddString("<<>>") + self:AddString("_______________________________") +end + +function console_dialog:Clear() + self.list_box:Clear() +end + +function console_dialog:Update() + CUIScriptWnd.Update(self) + UpdateConsole() --> Для обновления из меню +end + +class "console_item" (CUIListBoxItem) + +function console_item:__init() super() + self:SetTextColor(GetARGB(255, 170, 170, 170)) + + self.fn = self:GetTextItem() + self.fn:SetFont(GetFontLetterica18Russian()) + self.fn:SetEllipsis(true) +end + +function console_dialog:AddString(sStr, sColor, bNoFlush) + if sStr ~= nil then + if string.match(sStr, DIV) then + bNoFlush = true + end + + local _itm = console_item(self.file_item_main_sz.y) + + if sColor == nil then sColor = "White" end + _itm:SetTextColor(GetARGB(_G[FUNC_SCRIPT].ColorTbl[sColor].a, _G[FUNC_SCRIPT].ColorTbl[sColor].r, _G[FUNC_SCRIPT].ColorTbl[sColor].g, _G[FUNC_SCRIPT].ColorTbl[sColor].b)) + + _itm:SetWndSize (self.file_item_main_sz) + + _itm.fn:SetWndPos (vector2():set(0,0)) + _itm.fn:SetWndSize (self.file_item_fn_sz) + _itm.fn:SetText (sStr) + + self.list_box:AddExistingItem(_itm) + + if bNoFlush ~= true then + if SAVE_TO_FILE and GetVal("flush_log") == true then + self:Flush(sStr, sColor) + end + end + end +end + +function console_dialog:Log(text) + self:AddString(text, "Log") +end + +function console_dialog:Flush(sStr, sColor) + local sStr = tostring(sStr) + local file = io.open( LOG_FILE_NAME, "a" ) + if file ~= nil then + file:write( sColor..DIV..sStr, "\n" ) + file:close() + end +end + +function console_dialog:LoadLog(file_name, bAsText) + if file_name == nil then + file_name = LOG_FILE_NAME + end + + local file = io.open( file_name, "r" ) + if file ~= nil then + for line in file:lines() do + if line then + local tbl = {} + + if bAsText == true then + tbl[1] = "Yelow" + tbl[2] = line + else + tbl = _u.string_expl(line, DIV) + if tbl[2] == "" or tbl[2] == nil or tbl[2] == "nil" then + tbl[2] = " " + end + end + + if bAsText == true or tbl[1] == nil or _G[FUNC_SCRIPT].ColorTbl[tbl[1]] == nil then + tbl[1] = "Yelow" + end + + + self:AddString(tbl[2], tbl[1], true) + end + end + file:close() + else + self:AddString("Can't find file: "..file_name, "Red") + end +end + +------------------------------------------------------------------------------- + +function console_dialog:OnListItemDbClicked() + if self.list_box:GetSize()==0 then return end + + self:OnButtonX() + + local item = self.list_box:GetSelectedItem() + + if item then + local item_text = item.fn:GetText() + self.editbox:SetText(item_text) + end +end + +function console_dialog:OnButtonX() + self.editbox:SetText("") +end + +function console_dialog:OnButtonR() + if self.list_box:GetSize()==0 then return end + + local item = self.list_box:GetSelectedItem() + + if item then + local index = self.list_box:GetSelectedIndex() + + if index == -1 or index == nil then return end + + item = self.list_box:GetItemByIndex(index) + self.list_box:RemoveItem(item) + end +end + + +function console_dialog:OnButtonExecute(manual_text, bSilent) + local text = manual_text or self.editbox:GetText() + + if bSilent == nil then bSilent = false end + + if bSilent ~= true then + self:AddString(text, "Alpha") + end + + if text ~= "" then + ------------------------------------ + local parsed_string = _u.string_expl(text, " ") + local command_name = parsed_string[1] + local reg_func = registred_commands[command_name] + local bIsValue = VALUES_TBL[command_name] ~= nil + + parsed_string[1] = nil + if text ~= command_name and text ~= command_name.." " then + local params = string.gsub (text, command_name.." ", "") + local spaces = string.gsub (params, " ", "") + + if spaces ~= "" then + parsed_string[1] = tostring(string.gsub (text, command_name.." ", "")) + end + end + + --* Это зарегистрированная команда + if reg_func ~= nil then + if bSilent ~= true then + self:AddString("Execute command: "..command_name.." ("..reg_func..")", "Green") + end + + ExecuteFunc(reg_func, parsed_string) + end + + --* Это консольная переменная + if bIsValue then + ExecuteValue(command_name, parsed_string[1], not bSilent) + end + ------------------------------------ + end +end + +function console_dialog:OnButtonClose() + Hide() +end + +function console_dialog:OnKeyboard(dik, keyboard_action) + CUIScriptWnd.OnKeyboard(self,dik,keyboard_action) + local bNeedFocus = true + + if (dik == DIK_keys.DIK_ESCAPE) and keyboard_action == ui_events.WINDOW_KEY_PRESSED then + self:OnButtonClose() + bNeedFocus = false + end + + if dik == DIK_keys.DIK_RETURN and keyboard_action == ui_events.WINDOW_KEY_PRESSED then + self:OnButtonExecute() + bNeedFocus = false + end + + if dik == DIK_keys.DIK_LMENU and keyboard_action == ui_events.WINDOW_KEY_PRESSED then + self:OnButtonX() + bNeedFocus = false + end + + if bNeedFocus then + self.editbox:CaptureFocus(true) + end + + return true +end + diff --git a/res/gamedata/scripts/_console_func.script b/res/gamedata/scripts/_console_func.script new file mode 100644 index 00000000000..5c6750d3c6f --- /dev/null +++ b/res/gamedata/scripts/_console_func.script @@ -0,0 +1,480 @@ +--[[ ---------------------------------------------------------------------------------------------- + Платформы: CoP v1.6.02 + Описание : Скриптовая консоль (Функции) + Поддержка: 2013 © Shoker Mod + Версия : 1.0 (12.09.2013) + Авторы : Shoker, ... +--]] ---------------------------------------------------------------------------------------------- + +local FSys = getFS() + +--\\ Получить ссылку на консоль +function Get() + return _console.Get() +end + +--\\ Таблица цветов, поддерживаемых консолью +ColorTbl = { + White = {r = 255, g = 255, b = 255, a = 255}, + Red = {r = 255, g = 0, b = 0, a = 255}, + Green = {r = 0, g = 255, b = 0, a = 255}, + Blue = {r = 0, g = 0, b = 255, a = 255}, + Yelow = {r = 255, g = 216, b = 0, a = 255}, + Log = {r = 0, g = 200, b = 255, a = 255}, + Alpha = {r = 255, g = 255, b = 255, a = 120}, +} + +--\\ Все доступные команды +COMMANDS_LIST = { + {"help", "ShowHelp", "", "Все доступные команды"}, + {"list", "ShowList", "", "Все консольные переменные"}, + {"cls", "ClearList", "", "Очищает список введённых команд"}, + ---------------------[CON]--------------------------- + {"con.show", "Con_Show", "", "Открыть консоль (нужна для открытия консоли из стандартной консоли)"}, + {"con.colors", "Con_Colors", "", "Показывает все доступные цвета текста в консоли"}, + {"con.send", "Con_Send", "<текст>, <цвет*>", "Послать в консоль текст заданного цвета"}, + {"con.clean", "Con_Clean", "string*", "Очистить дамп лога\\указанный файл в папке с игрокй"}, + {"con.load", "Con_Load", "string", "Загрузить в консоль лог из указанного файла в папке gamedata (поддерживает цветное форматирование строк)"}, + {"con.load_text", "Con_LoadText", "string", "Загрузить в консоль текст из указанного файла (грузит как есть)"}, + ---------------------[LUA]--------------------------- + {"lua.do", "Lua_Execute", "string", "Выполняет lua-код, переданный в виде строки и выводит результат, если он есть."}, + {"lua.dor", "Lua_ExecuteR", "string", "Выполняет lua-код, переданный в виде строки и всегда выводит результат (добавляет return в начало кода)"}, + {"lua.dof", "Lua_ExecuteF", "string", "Загружает скриптовый файл из папки scripts и выполняет код из него"}, + {"lua.crash", "Lua_Crash", "string*", "Заставить игру вылететь с указанным текстом как причиной"}, + {"lua.exit", "Lua_Exit", "", "Закрыть игру"}, + ---------------------[FS]---------------------------- + {"fs.list", "FS_List", "string*", "Вывести список файлов по указанной маске относительно папки gamedata"}, + ---------------------[C]----------------------------- + {"c.tlp", "C_Tlp", "", "Телепортировать игрока к камере"}, + {"c.ui", "C_UI", "", "Скрыть\\Показать интерфейс и сделать игрока бессмертным (при скрытом)"}, + ---------------------[CAM]--------------------------- + {"cam.eff", "Cam_Eff", "string", "Проиграть эффект камеры (путь от папки anims)"}, + {"cam.anm", "Cam_Anm", "string", "Проиграть анимацию камеры (путь от папки anims)"}, + {"cam.anm_fix", "Cam_Anm_Fix", "string", "Проиграть анимацию камеры от некой начальной точки, зашитой в anm-файле (путь от папки anims)"}, + ---------------------[G]----------------------------- + {"g.info", "G_Info", "radius* = float", "Выводит информацию о ближайших объектах вокруг камеры в заданном радиусе (5 по умолчанию)"}, + {"g.spawn", "G_Spawn", "sec = string, x* = float, y* = float, z* = float", "Заспавнить объект на локацию с игроком в указанные координаты или перед камерой"}, + {"g.spawn_inv", "G_Spawn_Inv", "sec = string, id* = int", "Заспавнить предмет в инвентарь объекта с указанным id (если не указать id - спавн к игроку)"}, +} + +--------------------------------------------------------------------------------------------------------------- + +--[[ + * Функция cast служит для преобразования строкового значения в заданный тип, по умолчанию типов всего два - num число и bol логическое + * Каждой функции здесь передаётся параметр tbl, таблица введённых параметров, в tbl[1] хранится ВСЯ строка без учёта команды, а + в остальных каждый параметр по отдельности в порядке их ввода в консоле +--]] + +function cast(value, to_type) + if value == nil or value == "nil" then + return nil + end + + if to_type == nil then return tostring(value) end + + if to_type == "num" then + return tonumber(value) + end + + if to_type == "bol" then + if value == "1" then + return true + end + + if value == "0" then + return false + end + + return not (string.match(value, "false") ~= nil) + end +end + + +--\\ Проверка что такая секция существует +function sec_exist(sec) + local ini = system_ini() + if sec == nil then return false end + if not ini:section_exist(sec) then return false end + return true +end + +--\\ Проверка что такой файл существует +function exist(path) + if path ~= nil then + return (FSys:exist("$game_data$", path) ~= nil) + else + Get():AddString(" File name is empty", "Red") + return false + end +end + +--**************************************************************-- + +function ShowHelp() + Get():AddString("Кнопка Esc - закрыть консоль", "White") + Get():AddString("Кнопка Enter - ввести команду", "White") + Get():AddString("Кнопка Left Alt - очистить текстовое поле", "White") + + Get():AddString("", "White") + + Get():AddString("Вызов команды из стандартной консоли: mm_net_srv_name <команда> <параметры...>", "White") + Get():AddString("Параметры команд указаны в скобках, если параметр имеет знак *, значит его можно не писать\\заменить на nil", "White") + + Get():AddString("", "White") + + for idx,cmnd in ipairs(COMMANDS_LIST) do + local type_info = "" + + if cmnd[3] ~= "" then + type_info = " ("..cmnd[3]..")" + end + + Get():AddString(idx..") "..cmnd[1]..type_info, "Log") + Get():AddString(cmnd[4], "White") + end +end + +function ShowList() + for name, tbl in pairs(_console.VALUES_TBL) do + Get():AddString(name.." ("..tbl.descr_1..") = "..tostring(tbl.value_and_def), "Log") + Get():AddString(tbl.descr_2, "White") + end +end + +function ClearList() + Get():Clear() +end + + +function Con_Show() + _console.Show() +end + +function Con_Colors() + Get():AddString("-------------------------", "Log") + Get():AddString("Print colors:", "Log") + + for color, rgba in pairs(ColorTbl) do + Get():AddString(">>> "..color.." = ["..rgba.r..","..rgba.g..","..rgba.b..","..rgba.a.."]", color) + end + + Get():AddString("-------------------------", "Log") +end + +function Con_Send(tbl) + local size = #tbl + local color = "White" + local bHaveColor = false + + if tbl[size] and ColorTbl[tbl[size]] then + color = tbl[size] + bHaveColor = true + end + + if bHaveColor then + size = size - 1 + end + + if size >= 2 then + for i=2, size do + Get():AddString(tbl[i], color) + end + end +end + +function Con_Clean(tbl) + local file_name = tbl[1] or _console.LOG_FILE_NAME + local file = io.open( file_name, "w" ) + file:close() +end + +function Con_Load(tbl) + if tbl[1] == nil or tbl[1] == "" then + Get():AddString(" File name is empty", "Red") + else + local con = Get() + con:Clear() + con:LoadLog("gamedata\\"..tbl[1]) + end +end + +function Con_LoadText(tbl) + if tbl[1] == nil or tbl[1] == "" then + Get():AddString(" File name is empty", "Red") + else + local con = Get() + con:Clear() + con:LoadLog("gamedata\\"..tbl[1], true) + end +end + +function Lua_Crash(tbl) + if tbl[1] == "" or tbl[1] == nil then + tbl[1] = "nil" + end + + get_console():execute(tbl[1]) + a = nil + nil +end + +function Lua_Exit() + get_console():execute("quit") +end + +function Lua_Execute(tbl) + if tbl[1] ~= nil then + local func, msg = loadstring(tbl[1]) + if func ~= nil then + local bWork, result = pcall(func) + if bWork then + if result ~= nil then + if type(result) ~= "userdata" then + Get():AddString("Result: "..tostring(result), "Log") + else + Get():AddString("Result: UserData", "Log") + end + end + else + Get():AddString(" Bad code: "..result, "Red") + end + else + Get():AddString(" Can't compile code = "..tostring(msg), "Red") + end + else + Get():AddString(" There is no code to compile", "Red") + end +end + +function Lua_ExecuteR(tbl) + if tbl[1] ~= nil then + local func, msg = loadstring("return "..tbl[1]) + + if func ~= nil then + local bWork, result = pcall(func) + if bWork then + if result ~= nil then + if type(result) ~= "userdata" then + Get():AddString("Result: "..tostring(result), "Log") + else + Get():AddString("Result: UserData", "Log") + end + end + else + Get():AddString(" Bad code: "..result, "Red") + end + else + Get():AddString(" Can't compile code = "..tostring(msg), "Red") + end + else + Get():AddString(" There is no code to compile", "Red") + end +end + +function Lua_ExecuteF(tbl) + if tbl[1] ~= nil then + local bWork, result = pcall(dofile, "gamedata\\scripts\\"..tbl[1]..".script") + + if bWork then + if result ~= nil then + if type(result) ~= "userdata" then + Get():AddString("Result: "..tostring(result), "Log") + else + Get():AddString("Result: UserData", "Log") + end + end + else + Get():AddString(" Bad file: "..result, "Red") + end + else + Get():AddString(" There is no file to open", "Red") + end +end + +function FS_List(tbl) + local mask = tbl[1] or "*" + local flist = FSys:file_list_open_ex("$game_data$", FS.FS_ListFiles, mask) + local f_cnt = flist:Size() + + Get():AddString("-------------------------", "Log") + Get():AddString("List of files:", "Log") + + for it=0, f_cnt-1 do + local file = flist:GetAt(it) + local file_name = file:NameFull() + + Get():AddString(file_name, "Log") + end + + + Get():AddString("Total: "..tostring(f_cnt), "Log") + Get():AddString("-------------------------", "Log") +end + +function C_Tlp() + if db.actor then + db.actor:set_actor_position(device().cam_pos) + else + Get():AddString(" Game not started yet", "Red") + end +end + +local bHideUi = false +function C_UI(tbl) + if db.actor then + local bHide = not bHideUi + + if bHide then + level.hide_indicators_safe() + else + level.show_indicators() + end + + bHideUi = bHide + else + Get():AddString(" Game not started yet", "Red") + end +end + +function Cam_Eff(tbl) + if db.actor then + if tbl[1] == nil or tbl[1] == "" then + Get():AddString(" File path is empty", "Red") + else + if exist("anims\\"..tbl[1]) then + level.add_pp_effector(tbl[1], 123321, false) + else + Get():AddString(" Can't find file anims\\"..tbl[1], "Red") + end + end + else + Get():AddString(" Game not started yet", "Red") + end +end + +function Cam_Anm(tbl) + if db.actor then + if tbl[1] == nil or tbl[1] == "" then + Get():AddString(" File path is empty", "Red") + else + if exist("anims\\"..tbl[1]) then + level.add_cam_effector(tbl[1], 123321, false, "") + else + Get():AddString(" Can't find file anims\\"..tbl[1], "Red") + end + end + else + Get():AddString(" Game not started yet", "Red") + end +end + +function Cam_Anm_Fix(tbl) + if db.actor then + if tbl[1] == nil or tbl[1] == "" then + Get():AddString(" File path is empty", "Red") + else + if exist("anims\\"..tbl[1]) then + level.add_cam_effector2(tbl[1], 123321, false, "") + else + Get():AddString(" Can't find file anims\\"..tbl[1], "Red") + end + end + else + Get():AddString(" Game not started yet", "Red") + end +end + +function G_Info(tbl) + local distance = cast(tbl[2], "num") or 5 + + if db.actor then + Get():AddString("-------------------------", "Log") + Get():AddString("Search objects in radius "..tostring(distance).." ...", "Log") + local cnt = 0 + for id = 1, 65534 do + local sobj = alife():object(id) + if sobj ~= nil and sobj.parent_id == 65535 then + ----------------------------- + local lvert = game_graph():vertex(sobj.m_game_vertex_id) + local lid = lvert:level_id() + local lvl = alife():level_name(lid) + + if lvl == level.name() then + local dis = device().cam_pos:distance_to(sobj.position) + if dis <= distance then + Get():AddString(id.." = "..sobj:name().." ("..sobj:section_name()..") Distance = "..tostring(dis), "Log") + cnt = cnt + 1 + end + end + ----------------------------- + end + end + Get():AddString("Total: "..tostring(cnt), "Log") + Get():AddString("-------------------------", "Log") + else + Get():AddString(" Game not started yet", "Red") + end +end + +function G_Spawn(tbl, id) + if db.actor ~= nil then + local sec = tbl[2] + + if sec ~= nil then + if sec_exist(sec) then + local x = cast(tbl[3], "num") + local y = cast(tbl[4], "num") + local z = cast(tbl[5], "num") + + + local bToActorPos = false + + if x == nil and y == nil and z == nil then + bToActorPos = true + end + + if x == nil then x = device().cam_pos.x end + if y == nil then y = device().cam_pos.y end + if z == nil then z = device().cam_pos.z end + + local vec = vector():set(x,y,z) + + if bToActorPos then + vec = vec:add(device().cam_dir:mul(3)) + end + + if id ~= nil then + local sobj = alife():object(id) + + if sobj then + alife():create(sec, sobj.position, sobj.m_level_vertex_id, sobj.m_game_vertex_id, id) + else + Get():AddString(" There is now object with id "..tostring(id), "Red") + end + else + alife():create(sec, vec, db.actor:level_vertex_id(), db.actor:game_vertex_id()) + end + else + Get():AddString(" There is now section ["..tostring(sec).."] in system.ltx", "Red") + end + else + Get():AddString(" Section is nil", "Red") + end + else + Get():AddString(" Game not started yet", "Red") + end +end + +function G_Spawn_Inv(tbl) + local id = cast(tbl[3], "num") + + if id == nil then + if db.actor then + id = db.actor:id() + end + end + + tbl[3] = 0 + tbl[4] = 0 + tbl[5] = 0 + G_Spawn(tbl, id) +end diff --git a/res/gamedata/scripts/_u.script b/res/gamedata/scripts/_u.script new file mode 100644 index 00000000000..26a2b7c3e09 --- /dev/null +++ b/res/gamedata/scripts/_u.script @@ -0,0 +1,288 @@ +--[[ ---------------------------------------------------------------------------------------------- + Платформы: CS 1.5.10, CoP 1.6.02 + Описание : Различные утилиты для работы с данными + Поддержка: 2013 © Shoker Weapon Mod + Авторы : Shoker, <...> +--]] ---------------------------------------------------------------------------------------------- + +--[[ + TODO: + * При чтении через ltx() из ini-файла может совпасть имя секции и строка для чтения с похожей + секцией из system_ini() или любого другого ini, из за чего она буферизируется и перебьёт значения из них +--]] + +--************************************************************-- +--***********************[Ядро скрипта]***********************-- +--************************************************************-- +local _SN = script_name() + +--**************************************************************-- +--********************[Функциональная часть]********************-- +--**************************************************************-- + +--********************** Операции с векторами - Начало **********************-- +--\\ Из вектора "вперёд" возвращает вектор "вправо" и вектор "вверх" (Roll не учитывается) +--\\ Спасибо malandrinus за формулы +function get_all_direction(dir) + --* "Вправо" + local dir_right = vector() + dir_right:crossproduct(dir, vector():set(0,1,0)) + dir_right = dir_right:normalize() + + --* "Вверх" + local dir_up = vector() + dir_up:crossproduct(dir_right, dir) + dir_up = dir_up:normalize() + + return dir_right:invert(), dir_up +end + +--\\ Принимает координаты на земле и превращает их в координаты для экрана +--\\ Можно использовать в целеуказателях (malandrinus) +function point_to_hud(point) + local dev = device() + local scr_w = dev.width + local scr_h = dev.height + + local fov2 = (dev.fov/2) * (math.pi/180) + local scr_dist = 0.5 * scr_h / math.tan(fov2) + + local ppp = vector():sub(point, dev.cam_pos) + local dp = dev.cam_dir:dotproduct(ppp) + + local x = 512 + dev.cam_right:dotproduct(ppp) * scr_dist / dp * (1024/scr_w) + local y = 384 - dev.cam_top:dotproduct(ppp) * scr_dist / dp * (768/scr_h) + return x, y +end + +--\\ Вектор X,Y в углах переводит в дирекцию +function angle_to_direction(oangle) + local yaw = oangle.y + local pitch = oangle.x + return vector():setHP(yaw,pitch):normalize() +end +--********************** Операции с векторами - Конец **********************-- + + +--********************** Работа с конфигами - Начало **********************-- +local ltxBuffer = {} --> Хранит уже загруженные данные из конфигов + +--\\ Возвращает значение из секции в конфигах +-- sec - секция +-- line - строка +-- *mode - режим чтения, по умолчанию читает число с точкой ("str", "tbl1", "bol", "num", "numf") +-- *ini_file - ini-конфиг откуда надо читать, по умолчанию читает из system.ltx и подкл. к нему файлах +-- Внимание: в случае отсутствия секции\строки в конфиге - вылета не будет, так что все такие места +-- проверять соотв. функциями самим. Сделано для упрощения кода. +function ltx(sec, line, mode, ini_file) + if sec == nil then + _abort(_SN, "ltx", "sec (%s)(%s)", tostring(line), tostring(mode)) + end + + if not ltxBuffer[sec] then + ltxBuffer[sec] = {} + end + + local result = ltxBuffer[sec][line] + if result then return result end --> Нет смысла каждый раз читать из конфигов, когда достаточно 1 раз записать в таблицу + + local ini = ini_file or system_ini() + + if ltxExist(sec, line, ini) then + if mode==nil or mode=="numf" then --> число с запятой + ltxBuffer[sec][line] = ini:r_float(sec, line) + return ltxBuffer[sec][line] + end + + if mode=="bol" then --> true\false + ltxBuffer[sec][line] = ini:r_bool(sec, line) + return ltxBuffer[sec][line] + end + + if mode=="num" then --> целое число + ltxBuffer[sec][line] = ini:r_u32(sec, line) + return ltxBuffer[sec][line] + end + + if mode=="str" then --> строка + ltxBuffer[sec][line] = ini:r_string(sec, line) + return ltxBuffer[sec][line] + end + + if mode=="vec" then --> вектор + local vec = ini:r_vector(sec, line) + ltxBuffer[sec][line] = vec + return ltxBuffer[sec][line] + end + + if mode=="tbl1" then --> таблица из строки с запятыми (1 = ..., 2 = ....) + local temp = ini:r_string(sec, line) + ltxBuffer[sec][line] = string_expl(temp, ",") + return ltxBuffer[sec][line] + end + end + + -- mDbg(_SN, "ltx - no section: "..sec.." || "..line) + return nil +end +function test1() + return "yes Yes!" +end + + +--\\ Позволяет выставить значение какого либо из загруженных параметров конфига +function ltxBufferW(sec, line, value) + if not ltxBuffer[sec] then + ltxBuffer[sec] = {} + end + + ltxBuffer[sec][line] = value +end + +--\\ Возвращает имя и описание предмета +-- sec - секция предмета в конфигах +function ltxItem(sec) + local name = ltx(sec, "inv_name", "str") or "" + local descr = ltx(sec, "description", "str") or "" + + return xml(name), xml(descr) +end + +--\\ Проверяет, что такая комбинация секции-*строки существует в конфиге +-- sec - секция +-- *line - строка +-- *ini_file - ini-конфиг откуда надо читать, по умолчанию читает из system.ltx и подкл. к нему файлах +function ltxExist(sec, line, ini_file) + local ini = ini_file or system_ini() + if sec == nil then _abort(_SN, "ltxExist", "sec") end + if not ini:section_exist(sec) then return false end + if line and not ini:line_exist(sec, line) then return false end + return true +end + +--\\ Возвращает из текстового xml-файла +-- xml_id - идентификатор текста +function xml(xml_id) + return game.translate_string(xml_id) +end + +--\\ Преобразует таблицу в отформатированную строку для записи в custom data +--[[ + local value = 123 + local cd = {} + cd["test"] = {} + cd["test"]["line"] = value + cd["test"]["simple_table"] = {2,4,6,8} + cd["test"]["extended_table"] = {val1 = 1, val2 = 2, val3 = 3} + + [test] + line = 123 + simple_table = 2468 + extended_table = val1, 1, val2, 2, val3, 3 +]] +function tocdata(tTbl) + local result = "" + for sec, tData in pairs(tTbl) do + result = result.."\n["..sec.."]\n" + if type(tData) ~= "table" then + _abort(_SN, "tocdata", "tData is not table! result = %s, tData = %s", result, tostring(tData)) + else + for line, t_Param in pairs(tData) do + result = result..tostring(line).." = " + if type(t_Param) == "table" then + if table_size(t_Param) > 0 and #t_Param > 0 then + --* Скорее всего это нумерованная таблица, пакуем её без ключа + for _,p1 in pairs(t_Param) do + local first = true + if first then + result = result..tostring(p1) + first = false + else + result = result..", "..tostring(p1) + end + end + else + --* Хэш-таблица, её пишем вместе с ключами + local first = true + for p1,p2 in pairs(t_Param) do + if first then + result = result..tostring(p1)..", "..tostring(p2) + first = false + else + result = result..", "..tostring(p1)..", "..tostring(p2) + end + end + end + result = result.."\n" + else + result = result..tostring(t_Param).."\n" + end + end + end + end + + return result +end +--********************** Работа с конфигами - Конец **********************-- + +--\\ Крэшнуть игру с выводом в лог +function _abort(script_name, function_name, error_string, ...) + if script_name == nil then + script_name = "" + end + + if function_name == nil then + function_name = "" + end + + abort("%s.%s - "..error_string, script_name, function_name, ...) +end + +--\\ Вывод в лог +function log(text) + get_console():execute("load ~~ " .. tostring(text)) +end + +--\\ Подсчёт кол-ва элементов в таблице (под-таблицы считает за 1 элемент) +function table_size(tTbl) + local count = 0 + for _,_ in pairs(tTbl) do + count = count + 1 + end + + return count +end + +--! Внимание: стандартный шаблон плохо работает с "особыми" символами (например #) и разбивает строку криво +function string_expl(sStr, sDiv, Mode, bNoClear) + sStr = tostring(sStr) + if not (sStr ~= "nil" and sStr ~= '') then return {} end --> нечего разделять + local tRet = {} + local sPattern = '[%w%_]+' --> дефолтный патерн (разделение по 'словам') + if type(sDiv) == "string" then --> если задан сепаратор: разделяем по нему + if bNoClear then --> если НЕ указано 'чистить пробелы' + sPattern = '([^'..sDiv..']+)' + else --> иначе с чисткой пробелов + sPattern = '%s*([^'..sDiv..']+)%s*' + end + end + --* разделяем строку по патерну + if Mode == nil then --> обычный массив + for sValue in sStr:gmatch(sPattern) do + table.insert(tRet, sValue) + end + else + local sTypeMode = type(Mode) + if sTypeMode == "boolean" then --> таблица '[значение] = true или false' + for sValue in sStr:gmatch(sPattern) do + tRet[sValue] = Mode + end + elseif sTypeMode == "number" then --> таблица '[idx] = число или стринг' + for sValue in sStr:gmatch(sPattern) do + tRet[#tRet+1] = tonumber(sValue) or sValue + end + end + end + return tRet --> возвращаем таблицу +end + diff --git a/res/gamedata/scripts/ui_main_menu.script b/res/gamedata/scripts/ui_main_menu.script index db6b0443923..dd17a226751 100644 --- a/res/gamedata/scripts/ui_main_menu.script +++ b/res/gamedata/scripts/ui_main_menu.script @@ -344,6 +344,10 @@ function main_menu:OnKeyboard(dik, keyboard_action) --virtual function end end + if dik == _console.MENU_KEY then --#SM+#-- + _console.Show() + end + -- if dik == DIK_keys.DIK_S then -- self:OnButton_load_spawn() -- return true diff --git a/src/xrCore/NET_utils.cpp b/src/xrCore/NET_utils.cpp index 8d63bb23ed5..d3fb9b3dd74 100644 --- a/src/xrCore/NET_utils.cpp +++ b/src/xrCore/NET_utils.cpp @@ -137,7 +137,9 @@ void NET_Packet::w_seek(u32 pos, const void* p, u32 count) void NET_Packet::r_seek(u32 pos) { INI_ASSERT(r_seek) - VERIFY(pos < B.count); + //AVO: changed changed condition to <= as all net packet script utils are using r_seek(0) to read the entire packet. + VERIFY(pos <= B.count); + //VERIFY(pos < B.count); r_pos = pos; } diff --git a/src/xrEngine/xrTheora_Stream.cpp b/src/xrEngine/xrTheora_Stream.cpp index fdb8c898d4e..acadabc7781 100644 --- a/src/xrEngine/xrTheora_Stream.cpp +++ b/src/xrEngine/xrTheora_Stream.cpp @@ -201,12 +201,14 @@ bool CTheoraStream::Decode(u32 in_tm_play) if (d_frame < k_frame) { //. dbg_log ((stderr,"%04d: preroll\n",d_frame)); - VERIFY((0 != d_frame % key_rate) || - (0 == d_frame % key_rate) && theora_packet_iskeyframe(&o_packet)); + //AVO: commented out VERIFY to get COC start in Debug - something is wrong with video stream + //VERIFY((0 != d_frame % key_rate) || + // (0 == d_frame % key_rate) && theora_packet_iskeyframe(&o_packet)); continue; } - [[maybe_unused]] bool is_key = theora_packet_iskeyframe(&o_packet); - VERIFY((d_frame != k_frame) || ((d_frame == k_frame) && is_key)); + //AVO: commented out VERIFY to get COC start in Debug - something is wrong with video stream + //[[maybe_unused]] bool is_key = theora_packet_iskeyframe(&o_packet); + //VERIFY((d_frame != k_frame) || ((d_frame == k_frame) && is_key)); // real decode //. dbg_log ((stderr,"%04d: decode\n",d_frame)); [[maybe_unused]] int res = theora_decode_packetin(&t_state, &o_packet); diff --git a/src/xrGame/Actor.cpp b/src/xrGame/Actor.cpp index 1573ff6df54..e959b910a2e 100644 --- a/src/xrGame/Actor.cpp +++ b/src/xrGame/Actor.cpp @@ -77,6 +77,10 @@ #include "xrEngine/Rain.h" +//Alundaio +#include "script_hit.h" +//-Alundaio + //const u32 patch_frames = 50; //const float respawn_delay = 1.f; //const float respawn_auto = 7.f; @@ -100,7 +104,8 @@ Flags32 psActorFlags = AF_AUTOPICKUP | AF_RUN_BACKWARD | AF_IMPORTANT_SAVE | - AF_MULTI_ITEM_PICKUP + AF_MULTI_ITEM_PICKUP | + AF_USE_TRACERS }; int psActorSleepTime = 1; @@ -653,13 +658,35 @@ void CActor::Hit(SHit* pHDS) { HDS.power = 0.0f; inherited::Hit(&HDS); + return; } - float hit_power = HitArtefactsOnBelt(HDS.damage(), HDS.hit_type); - HDS.power = hit_power; + HDS.power = HitArtefactsOnBelt(HDS.damage(), HDS.hit_type); HDS.add_wound = true; if (g_Alive()) { + CScriptHit tLuaHit; + + tLuaHit.m_fPower = HDS.power; + tLuaHit.m_fImpulse = HDS.impulse; + tLuaHit.m_tDirection = HDS.direction(); + tLuaHit.m_tHitType = HDS.hit_type; + tLuaHit.m_tpDraftsman = smart_cast(HDS.who)->lua_game_object(); + + luabind::functor funct; + if (GEnv.ScriptEngine->functor("_G.CActor__BeforeHitCallback", funct)) + { + if (!funct(smart_cast(this->lua_game_object()), &tLuaHit, HDS.boneID)) + return; + } + + HDS.power = tLuaHit.m_fPower; + HDS.impulse = tLuaHit.m_fImpulse; + HDS.dir = tLuaHit.m_tDirection; + HDS.hit_type = (ALife::EHitType)(tLuaHit.m_tHitType); + //HDS.who = smart_cast(tLuaHit.m_tpDraftsman->object()); + //HDS.whoID = tLuaHit.m_tpDraftsman->ID(); + /* AVO: send script callback*/ callback(GameObject::eHit)( this->lua_game_object(), @@ -780,13 +807,13 @@ void CActor::HitMark(float P, Fvector dir, IGameObject* who_object, s16 element, void CActor::HitSignal(float perc, Fvector& vLocalDir, IGameObject* who, s16 element) { + //AVO: get bone names from IDs + //cpcstr bone_name = smart_cast(this->Visual())->LL_BoneName_dbg(element); + //Msg("Bone [%d]->[%s]", element, bone_name); + //-AVO + if (g_Alive()) { - /* AVO: to get bone names from IDs*/ - /*Log("hit info"); - Log("bone ID = %s", element); - Log("bone Name = %s", smart_cast(this->Visual())->LL_BoneName_dbg(element)); - Log("hit info END");*/ // check damage bone Fvector D; XFORM().transform_dir(D, vLocalDir); @@ -1541,7 +1568,7 @@ void CActor::shedule_Update(u32 DT) } else if (m_pVehicleWeLookingAt) { - m_sDefaultObjAction = m_sCarCharacterUseAction; + m_sDefaultObjAction = m_pVehicleWeLookingAt->m_sUseAction != nullptr ? m_pVehicleWeLookingAt->m_sUseAction : m_sCarCharacterUseAction; } else if (m_pObjectWeLookingAt && m_pObjectWeLookingAt->cast_inventory_item() && m_pObjectWeLookingAt->cast_inventory_item()->CanTake()) @@ -1928,18 +1955,19 @@ void CActor::UpdateArtefactsOnBeltAndOutfit() const auto artefact = smart_cast(it); if (artefact) { - conditions().ChangeBleeding(artefact->m_fBleedingRestoreSpeed * f_update_time); - conditions().ChangeHealth(artefact->m_fHealthRestoreSpeed * f_update_time); - conditions().ChangePower(artefact->m_fPowerRestoreSpeed * f_update_time); - conditions().ChangeSatiety(artefact->m_fSatietyRestoreSpeed * f_update_time); - if (artefact->m_fRadiationRestoreSpeed > 0.0f) + const float art_cond = artefact->GetCondition(); + conditions().ChangeBleeding((artefact->m_fBleedingRestoreSpeed * art_cond) * f_update_time); + conditions().ChangeHealth((artefact->m_fHealthRestoreSpeed * art_cond) * f_update_time); + conditions().ChangePower((artefact->m_fPowerRestoreSpeed * art_cond) * f_update_time); + conditions().ChangeSatiety((artefact->m_fSatietyRestoreSpeed * art_cond) * f_update_time); + if (artefact->m_fRadiationRestoreSpeed * art_cond > 0.0f) { - float val = artefact->m_fRadiationRestoreSpeed - conditions().GetBoostRadiationImmunity(); + float val = (artefact->m_fRadiationRestoreSpeed * art_cond) - conditions().GetBoostRadiationImmunity(); clamp(val, 0.0f, val); conditions().ChangeRadiation(val * f_update_time); } else - conditions().ChangeRadiation(artefact->m_fRadiationRestoreSpeed * f_update_time); + conditions().ChangeRadiation((artefact->m_fRadiationRestoreSpeed * art_cond) * f_update_time); } } @@ -1986,7 +2014,7 @@ float CActor::GetProtection_ArtefactsOnBelt(ALife::EHitType hit_type) { const auto artefact = smart_cast(it); if (artefact) - sum += artefact->m_ArtefactHitImmunities.AffectHit(1.0f, hit_type); + sum += artefact->m_ArtefactHitImmunities.AffectHit(1.0f, hit_type) * artefact->GetCondition(); } return sum; } @@ -2141,7 +2169,7 @@ float CActor::GetRestoreSpeed(ALife::EConditionRestoreType const& type) { const auto artefact = smart_cast(it); if (artefact) - res += artefact->m_fHealthRestoreSpeed; + res += artefact->m_fHealthRestoreSpeed * artefact->GetCondition(); } const auto outfit = GetOutfit(); @@ -2156,7 +2184,7 @@ float CActor::GetRestoreSpeed(ALife::EConditionRestoreType const& type) { const auto artefact = smart_cast(it); if (artefact) - res += artefact->m_fRadiationRestoreSpeed; + res += artefact->m_fRadiationRestoreSpeed * artefact->GetCondition(); } const auto outfit = GetOutfit(); @@ -2173,7 +2201,7 @@ float CActor::GetRestoreSpeed(ALife::EConditionRestoreType const& type) { const auto artefact = smart_cast(it); if (artefact) - res += artefact->m_fSatietyRestoreSpeed; + res += artefact->m_fSatietyRestoreSpeed * artefact->GetCondition(); } const auto outfit = GetOutfit(); @@ -2190,7 +2218,7 @@ float CActor::GetRestoreSpeed(ALife::EConditionRestoreType const& type) { const auto artefact = smart_cast(it); if (artefact) - res += artefact->m_fPowerRestoreSpeed; + res += artefact->m_fPowerRestoreSpeed * artefact->GetCondition(); } auto outfit = GetOutfit(); if (outfit) @@ -2212,7 +2240,7 @@ float CActor::GetRestoreSpeed(ALife::EConditionRestoreType const& type) { const auto artefact = smart_cast(it); if (artefact) - res += artefact->m_fBleedingRestoreSpeed; + res += artefact->m_fBleedingRestoreSpeed * artefact->GetCondition(); } const auto outfit = GetOutfit(); diff --git a/src/xrGame/Actor.h b/src/xrGame/Actor.h index 627e7d9f8a5..7b972f46bbe 100644 --- a/src/xrGame/Actor.h +++ b/src/xrGame/Actor.h @@ -254,7 +254,7 @@ class CActor : public CEntityAlive, void detach_Vehicle(); void steer_Vehicle(float angle); void attach_Vehicle(CHolderCustom* vehicle); - bool use_MountedWeapon(CHolderCustom* object); + bool use_HolderEx(CHolderCustom* object, bool bForce); virtual bool can_attach(const CInventoryItem* inventory_item) const; protected: diff --git a/src/xrGame/ActorInput.cpp b/src/xrGame/ActorInput.cpp index a303d52ad87..8046c32085d 100644 --- a/src/xrGame/ActorInput.cpp +++ b/src/xrGame/ActorInput.cpp @@ -575,8 +575,8 @@ bool CActor::use_Holder(CHolderCustom* holder) if (smart_cast(holderGO)) b = use_Vehicle(0); - else if (holderGO->CLS_ID == CLSID_OBJECT_W_STATMGUN) - b = use_MountedWeapon(0); + else if (holderGO->CLS_ID == CLSID_OBJECT_W_STATMGUN || holderGO->CLS_ID==CLSID_OBJECT_HOLDER_ENT) + b = use_HolderEx(0, false); if (inventory().ActiveItem()) { @@ -594,8 +594,8 @@ bool CActor::use_Holder(CHolderCustom* holder) if (smart_cast(holder)) b = use_Vehicle(holder); - if (holderGO->CLS_ID == CLSID_OBJECT_W_STATMGUN) - b = use_MountedWeapon(holder); + if (holderGO->CLS_ID == CLSID_OBJECT_W_STATMGUN || holderGO->CLS_ID==CLSID_OBJECT_HOLDER_ENT) + b = use_HolderEx(holder, false); if (b) { // used succesfully diff --git a/src/xrGame/ActorMountedWeapon.cpp b/src/xrGame/ActorMountedWeapon.cpp index a5da649ef44..32445018df8 100644 --- a/src/xrGame/ActorMountedWeapon.cpp +++ b/src/xrGame/ActorMountedWeapon.cpp @@ -5,36 +5,61 @@ #include "xrEngine/CameraBase.h" #include "ActorEffector.h" #include "CharacterPhysicsSupport.h" +#include "holder_custom.h" +#include "Car.h" -bool CActor::use_MountedWeapon(CHolderCustom* object) +bool CActor::use_HolderEx(CHolderCustom* object, bool bForce) { - /* - CHolderCustom* wpn =object; - if(m_holder){ - if(!wpn||(m_holder==wpn)){ + if (m_holder) + { + if (smart_cast(m_holder)) + { + detach_Vehicle(); + return true; + } + if (!m_holder->ExitLocked()) + { + if (!object || (m_holder == object)) + { m_holder->detach_Actor(); + + if (const CGameObject* go = smart_cast(m_holder)) + callback(GameObject::eDetachVehicle)(go->lua_game_object()); + character_physics_support()->movement()->CreateCharacter(); - m_holder=NULL; + m_holder = nullptr; } - return true; - }else{ - if(wpn){ - Fvector center; Center(center); - if(wpn->Use(Device.vCameraPosition, Device.vCameraDirection,center)){ - if(wpn->attach_Actor(this)){ - // destroy actor character - character_physics_support()->movement()->DestroyCharacter(); - PickupModeOff(); - m_holder=wpn; - if (pCamBobbing){ - Cameras().RemoveCamEffector(eCEBobbing); - pCamBobbing = NULL; - } - return true; - } + } + return true; + } + if (smart_cast(m_holder)) + { + attach_Vehicle(object); + return true; + } + if (object && !object->EnterLocked()) + { + Fvector center; + Center(center); + if (object->Use(Device.vCameraPosition, Device.vCameraDirection, center)) + { + if (object->attach_Actor(this)) + { + // destroy actor character + character_physics_support()->movement()->DestroyCharacter(); + + m_holder = object; + if (pCamBobbing) + { + Cameras().RemoveCamEffector(eCEBobbing); + pCamBobbing = nullptr; } + + if (const CGameObject* go = smart_cast(m_holder)) + callback(GameObject::eAttachVehicle)(go->lua_game_object()); + return true; } } - */ + } return false; } diff --git a/src/xrGame/ActorVehicle.cpp b/src/xrGame/ActorVehicle.cpp index c01994a313d..ee3074f275f 100644 --- a/src/xrGame/ActorVehicle.cpp +++ b/src/xrGame/ActorVehicle.cpp @@ -29,6 +29,10 @@ void CActor::attach_Vehicle(CHolderCustom* vehicle) if(!vehicle || m_holder) return; + CCar* car = smart_cast(vehicle); + if (!car) + return; + //PickupModeOff(); m_holder=vehicle; @@ -44,7 +48,6 @@ void CActor::attach_Vehicle(CHolderCustom* vehicle) } // temp play animation - CCar* car = smart_cast(m_holder); u16 anim_type = car->DriverAnimationType(); SVehicleAnimCollection& anims = m_vehicle_anims->m_vehicles_type_collections[anim_type]; V->PlayCycle(anims.idles[0], false); diff --git a/src/xrGame/Actor_Flags.h b/src/xrGame/Actor_Flags.h index 58f44fa36b6..e91f7678587 100644 --- a/src/xrGame/Actor_Flags.h +++ b/src/xrGame/Actor_Flags.h @@ -15,6 +15,7 @@ enum AF_MULTI_ITEM_PICKUP = (1 << 11), AF_LOADING_STAGES = (1 << 12), AF_ALWAYS_USE_ATTITUDE_SENSORS = (1 << 13), // or only when zooming if false + AF_USE_TRACERS = (1 << 14) }; extern Flags32 psActorFlags; diff --git a/src/xrGame/Actor_Movement.cpp b/src/xrGame/Actor_Movement.cpp index 2beec1b8db5..bce9faeded0 100644 --- a/src/xrGame/Actor_Movement.cpp +++ b/src/xrGame/Actor_Movement.cpp @@ -679,7 +679,7 @@ float CActor::get_additional_weight() const { CArtefact* artefact = smart_cast(*it); if (artefact) - res += artefact->AdditionalInventoryWeight(); + res += artefact->AdditionalInventoryWeight() * artefact->GetCondition(); } return res; diff --git a/src/xrGame/AmebaZone.cpp b/src/xrGame/AmebaZone.cpp index f7960f2737f..399c587a7f6 100644 --- a/src/xrGame/AmebaZone.cpp +++ b/src/xrGame/AmebaZone.cpp @@ -10,7 +10,6 @@ #include "CharacterPhysicsSupport.h" #include "entity_alive.h" - CAmebaZone::CAmebaZone() : m_fVelocityLimit(1.f) {} CAmebaZone::~CAmebaZone() {} diff --git a/src/xrGame/Artefact.cpp b/src/xrGame/Artefact.cpp index 738432662b5..e879c581c29 100644 --- a/src/xrGame/Artefact.cpp +++ b/src/xrGame/Artefact.cpp @@ -90,7 +90,7 @@ bool CArtefact::net_Spawn(CSE_Abstract* DC) StartLights(); m_CarringBoneID = u16(-1); IKinematicsAnimated* K = smart_cast(Visual()); - if (K) + if (K && K->ID_Cycle_Safe("idle")) K->PlayCycle("idle"); o_fastmode = FALSE; // start initially with fast-mode enabled diff --git a/src/xrGame/CMakeLists.txt b/src/xrGame/CMakeLists.txt index 4f7d4dcdee0..611dea1f8d8 100644 --- a/src/xrGame/CMakeLists.txt +++ b/src/xrGame/CMakeLists.txt @@ -671,6 +671,8 @@ target_sources(xrGame PRIVATE hits_store.cpp hits_store.h hits_store_inline.h + HolderEntityObject.cpp + HolderEntityObject.h holder_custom.cpp holder_custom.h holder_custom_script.cpp @@ -1615,8 +1617,6 @@ target_sources(xrGame PRIVATE weaponBM16.cpp weaponBM16.h Weapon.cpp - WeaponCustomPistolAuto.cpp - WeaponCustomPistolAuto.h WeaponCustomPistol.cpp WeaponCustomPistol.h WeaponDispersion.cpp @@ -2426,6 +2426,8 @@ target_sources(xrGame PRIVATE ui/UIRankFaction.h ui/UIRankIndicator.cpp ui/UIRankIndicator.h + ui/UIRankingsCoC.cpp + ui/UIRankingsCoC.h ui/UIRankingWnd.cpp ui/UIRankingWnd.h ui/UIScriptWnd.cpp diff --git a/src/xrGame/Car.cpp b/src/xrGame/Car.cpp index 23ffb85c1aa..31c02f0773e 100644 --- a/src/xrGame/Car.cpp +++ b/src/xrGame/Car.cpp @@ -464,7 +464,7 @@ void CCar::VisualUpdate(float fov) // OwnerActor()->Cameras().ApplyDevice(); // } // - /* if(CurrentGameUI())// + /* if(CurrentGameUI()) { CurrentGameUI()->UIMainIngameWnd->CarPanel().Show(true); CurrentGameUI()->UIMainIngameWnd->CarPanel().SetCarHealth(GetfHealth()); diff --git a/src/xrGame/Car.h b/src/xrGame/Car.h index b52a7b00028..b99fadd080f 100644 --- a/src/xrGame/Car.h +++ b/src/xrGame/Car.h @@ -534,6 +534,9 @@ class CCar : public CEntity, } bool isActiveEngine (); + + float GetRPM() const { return m_current_rpm; } + void SetRPM(float val) { m_current_rpm = val; } /***** added by Ray Twitty (aka Shadows) END *****/ diff --git a/src/xrGame/CarDamageParticles.h b/src/xrGame/CarDamageParticles.h index 3727dcd159a..47c9f192f31 100644 --- a/src/xrGame/CarDamageParticles.h +++ b/src/xrGame/CarDamageParticles.h @@ -19,8 +19,8 @@ struct CCarDamageParticles void Play2(CCar* car); /***** added by Ray Twitty (aka Shadows) START *****/ // функции для выключения партиклов дыма - void Stop1(CCar* car); - void Stop2(CCar* car); + void Stop1(CCar* car); + void Stop2(CCar* car); /***** added by Ray Twitty (aka Shadows) END *****/ void PlayWheel1(CCar* car, u16 bone_id) const; diff --git a/src/xrGame/CarScript.cpp b/src/xrGame/CarScript.cpp index b8a6f8ff997..9ee40f84919 100644 --- a/src/xrGame/CarScript.cpp +++ b/src/xrGame/CarScript.cpp @@ -35,19 +35,23 @@ SCRIPT_EXPORT(CCar, (CGameObject, CHolderCustom), .def("ExplodeTime", &CCar::ExplodeTime) .def("CarExplode", &CCar::CarExplode) /***** added by Ray Twitty (aka Shadows) START *****/ - .def("GetfFuel", &CCar::GetfFuel) - .def("SetfFuel", &CCar::SetfFuel) - .def("GetfFuelTank", &CCar::GetfFuelTank) - .def("SetfFuelTank", &CCar::SetfFuelTank) - .def("GetfFuelConsumption", &CCar::GetfFuelConsumption) - .def("SetfFuelConsumption", &CCar::SetfFuelConsumption) - .def("ChangefFuel", &CCar::ChangefFuel) - .def("ChangefHealth", &CCar::ChangefHealth) - .def("PlayDamageParticles", &CCar::PlayDamageParticles) - .def("StopDamageParticles", &CCar::StopDamageParticles) - .def("StartEngine", &CCar::StartEngine) - .def("StopEngine", &CCar::StopEngine) - .def("IsActiveEngine", &CCar::isActiveEngine) + .def("GetfFuel", &CCar::GetfFuel) + .def("SetfFuel", &CCar::SetfFuel) + .def("GetfFuelTank", &CCar::GetfFuelTank) + .def("SetfFuelTank", &CCar::SetfFuelTank) + .def("GetfFuelConsumption", &CCar::GetfFuelConsumption) + .def("SetfFuelConsumption", &CCar::SetfFuelConsumption) + .def("ChangefFuel", &CCar::ChangefFuel) + .def("ChangefHealth", &CCar::ChangefHealth) + .def("PlayDamageParticles", &CCar::PlayDamageParticles) + .def("StopDamageParticles", &CCar::StopDamageParticles) + .def("StartEngine", &CCar::StartEngine) + .def("StopEngine", &CCar::StopEngine) + .def("IsActiveEngine", &CCar::isActiveEngine) + .def("HandBreak", &CCar::HandBreak) + .def("ReleaseHandBreak", &CCar::ReleaseHandBreak) + .def("GetRPM", &CCar::GetRPM) + .def("SetRPM", &CCar::SetRPM) /***** added by Ray Twitty (aka Shadows) END *****/ .def(constructor<>()) ]; diff --git a/src/xrGame/CarWeapon.cpp b/src/xrGame/CarWeapon.cpp index ee9fc75aed3..b8142373f8b 100644 --- a/src/xrGame/CarWeapon.cpp +++ b/src/xrGame/CarWeapon.cpp @@ -212,8 +212,8 @@ void CCarWeapon::FireEnd() void CCarWeapon::OnShot() { - FireBullet( - m_fire_pos, m_fire_dir, fireDispersionBase, *m_Ammo, m_object->ID(), m_object->ID(), SendHitAllowed(m_object)); + FireBullet(m_fire_pos, m_fire_dir, fireDispersionBase, + *m_Ammo, m_object->ID(), m_object->ID(), SendHitAllowed(m_object), ::Random.randI(0,30)); StartShotParticles(); diff --git a/src/xrGame/Entity.cpp b/src/xrGame/Entity.cpp index ff52793bb46..5c90db4acbb 100644 --- a/src/xrGame/Entity.cpp +++ b/src/xrGame/Entity.cpp @@ -253,21 +253,20 @@ void CEntity::net_Destroy() void CEntity::KillEntity(u16 whoID, bool bypass_actor_check) { - if (GameID() == eGameIDSingle && this->ID() == Actor()->ID()) + if (IsGameTypeSingle() && this->ID() == Actor()->ID()) { - //AVO: allow scripts to process actor condition and prevent actor's death or kill him if desired. - //IMPORTANT: if you wish to kill actor you need to call db.actor:kill(level:object_by_id(whoID), true) in actor_before_death callback, to ensure all objects are properly destroyed - // this will bypass below if block and go to normal KillEntity routine. + Actor()->use_HolderEx(nullptr, true); #ifdef ACTOR_BEFORE_DEATH_CALLBACK + //AVO: allow scripts to process actor condition and prevent actor's death or kill him if desired. + //IMPORTANT: if you wish to kill actor you need to call db.actor:kill(level:object_by_id(whoID), true) in actor_before_death callback, to ensure all objects are properly destroyed + // this will bypass below if block and go to normal KillEntity routine. if (bypass_actor_check == false) { Actor()->callback(GameObject::eActorBeforeDeath)(whoID); return; } + //-AVO #endif - //-AVO - Actor()->detach_Vehicle(); - Actor()->use_MountedWeapon(nullptr); } if (whoID != ID()) { diff --git a/src/xrGame/GameObject.cpp b/src/xrGame/GameObject.cpp index 60aece96f3a..88434e7c69c 100644 --- a/src/xrGame/GameObject.cpp +++ b/src/xrGame/GameObject.cpp @@ -450,6 +450,7 @@ bool CGameObject::net_Spawn(CSE_Abstract* DC) cNameSect_set(E->s_name); if (E->name_replace()[0]) cName_set(E->name_replace()); + bool demo_spectator = false; if (Level().IsDemoPlayStarted() && E->ID == u16(-1)) @@ -461,11 +462,12 @@ bool CGameObject::net_Spawn(CSE_Abstract* DC) { //Alundaio: //R_ASSERT(Level().Objects.net_Find(E->ID) == nullptr); - if (Level().Objects.net_Find(E->ID) != nullptr) + if (const auto obj = Level().Objects.net_Find(E->ID)) { - GEnv.ScriptEngine->script_log(LuaMessageType::Error, "CGameObject:net_Spawn() | Level().Objects.net_Find(E->ID) != nullptr (This mean object already exist on level by this ID) ID=%s s_name=%s", E->ID, E->s_name.c_str()); + Msg("! ERROR: CGameObject:net_spawn() Object with ID[%u] already exists! self=%s other=%s", E->ID, cName().c_str(), obj->cName().c_str()); return false; } + //-Alundaio } setID(E->ID); @@ -713,57 +715,57 @@ void CGameObject::spawn_supplies() for (u32 k = 0, j; spawn_ini()->r_line("spawn", k, &N, &V); k++) { VERIFY(xr_strlen(N)); - if (pSettings->section_exist(N)) //Alundaio: Validate section exists - { - j = 1; - p = 1.f; + if (!pSettings->section_exist(N)) //Alundaio: Validate section exists + continue; - float f_cond = 1.0f; - if (V && xr_strlen(V)) - { - int n = _GetItemCount(V); - string16 temp; - if (n > 0) - j = atoi(_GetItem(V, 0, temp)); // count - - if (NULL != strstr(V, "prob=")) - p = (float)atof(strstr(V, "prob=") + 5); - if (fis_zero(p)) - p = 1.f; - if (!j) - j = 1; - if (NULL != strstr(V, "cond=")) - f_cond = (float)atof(strstr(V, "cond=") + 5); - bScope = (NULL != strstr(V, "scope")); - bSilencer = (NULL != strstr(V, "silencer")); - bLauncher = (NULL != strstr(V, "launcher")); - } - for (u32 i = 0; i < j; ++i) - { - if (::Random.randF(1.f) < p) - { - CSE_Abstract* A = Level().spawn_item(N, Position(), ai_location().level_vertex_id(), ID(), true); + j = 1; + p = 1.f; - CSE_ALifeInventoryItem* pSE_InventoryItem = smart_cast(A); - if (pSE_InventoryItem) - pSE_InventoryItem->m_fCondition = f_cond; + float f_cond = 1.0f; + if (V && xr_strlen(V)) + { + int n = _GetItemCount(V); + string16 temp; + if (n > 0) + j = atoi(_GetItem(V, 0, temp)); // count + + if (NULL != strstr(V, "prob=")) + p = (float)atof(strstr(V, "prob=") + 5); + if (fis_zero(p)) + p = 1.f; + if (!j) + j = 1; + if (NULL != strstr(V, "cond=")) + f_cond = (float)atof(strstr(V, "cond=") + 5); + bScope = (NULL != strstr(V, "scope")); + bSilencer = (NULL != strstr(V, "silencer")); + bLauncher = (NULL != strstr(V, "launcher")); + } + for (u32 i = 0; i < j; ++i) + { + if (::Random.randF(1.f) < p) + { + CSE_Abstract* A = Level().spawn_item(N, Position(), ai_location().level_vertex_id(), ID(), true); - CSE_ALifeItemWeapon* W = smart_cast(A); - if (W) - { - if (W->m_scope_status == ALife::eAddonAttachable) - W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonScope, bScope); - if (W->m_silencer_status == ALife::eAddonAttachable) - W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonSilencer, bSilencer); - if (W->m_grenade_launcher_status == ALife::eAddonAttachable) - W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonGrenadeLauncher, bLauncher); - } + CSE_ALifeInventoryItem* pSE_InventoryItem = smart_cast(A); + if (pSE_InventoryItem) + pSE_InventoryItem->m_fCondition = f_cond; - NET_Packet P; - A->Spawn_Write(P, TRUE); - Level().Send(P, net_flags(TRUE)); - F_entity_Destroy(A); + CSE_ALifeItemWeapon* W = smart_cast(A); + if (W) + { + if (W->m_scope_status == ALife::eAddonAttachable) + W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonScope, bScope); + if (W->m_silencer_status == ALife::eAddonAttachable) + W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonSilencer, bSilencer); + if (W->m_grenade_launcher_status == ALife::eAddonAttachable) + W->m_addon_flags.set(CSE_ALifeItemWeapon::eWeaponAddonGrenadeLauncher, bLauncher); } + + NET_Packet P; + A->Spawn_Write(P, TRUE); + Level().Send(P, net_flags(TRUE)); + F_entity_Destroy(A); } } } diff --git a/src/xrGame/GameTask.h b/src/xrGame/GameTask.h index 223e56d7dc8..930005bf45d 100644 --- a/src/xrGame/GameTask.h +++ b/src/xrGame/GameTask.h @@ -110,11 +110,11 @@ class SGameTaskObjective : public ISerializable protected: virtual void ChangeStateCallback(); - void CreateMapLocation(bool on_load); public: void RemoveMapLocations(bool notify); void ChangeMapLocation(pcstr new_map_location, u16 new_map_object_id); + void CreateMapLocation(bool on_load); // Made public only for Lua export // for scripting access auto GetType_script() const { return m_task_type; } diff --git a/src/xrGame/GameTask_script.cpp b/src/xrGame/GameTask_script.cpp index ab01da239b7..5bd95580e8b 100644 --- a/src/xrGame/GameTask_script.cpp +++ b/src/xrGame/GameTask_script.cpp @@ -58,6 +58,8 @@ SCRIPT_EXPORT(CGameTask, (), .def("get_type", &SGameTaskObjective::GetType_script) .def("set_type", &SGameTaskObjective::SetType_script) + .def("get_map_location", +[](const SGameTaskObjective* self) -> pcstr { return self->m_map_location.c_str(); }) + .def("get_map_object_id", +[](const SGameTaskObjective* self) -> u16 { return self->m_map_object_id; }) .def("set_map_hint", &SGameTaskObjective::SetMapHint_script) .def("set_map_location", &SGameTaskObjective::SetMapLocation_script) .def("set_map_object_id", &SGameTaskObjective::SetMapObjectID_script) @@ -66,6 +68,7 @@ SCRIPT_EXPORT(CGameTask, (), .def("remove_map_locations", &SGameTaskObjective::RemoveMapLocations) .def("change_map_location", &SGameTaskObjective::ChangeMapLocation) + .def("create_map_location", &SGameTaskObjective::CreateMapLocation) .def("add_complete_info", &SGameTaskObjective::AddCompleteInfo_script) .def("add_complete_func", &SGameTaskObjective::AddCompleteFunc_script) diff --git a/src/xrGame/HelicopterWeapon.cpp b/src/xrGame/HelicopterWeapon.cpp index 917578c6f32..40ecdbd35fb 100644 --- a/src/xrGame/HelicopterWeapon.cpp +++ b/src/xrGame/HelicopterWeapon.cpp @@ -143,7 +143,7 @@ void CHelicopter::OnShot() fire_dir.sub(enemy_pos, fire_pos).normalize_safe(); }; - FireBullet(fire_pos, fire_dir, fireDispersionBase, m_CurrentAmmo, ID(), ID(), OnServer()); + FireBullet(fire_pos, fire_dir, fireDispersionBase, m_CurrentAmmo, ID(), ID(), OnServer(), ::Random.randI(0,30)); StartShotParticles(); if (m_bLightShotEnabled) diff --git a/src/xrGame/HolderEntityObject.cpp b/src/xrGame/HolderEntityObject.cpp new file mode 100644 index 00000000000..ae494550132 --- /dev/null +++ b/src/xrGame/HolderEntityObject.cpp @@ -0,0 +1,234 @@ +#include "StdAfx.h" + +#include "HolderEntityObject.h" + +#include "Actor.h" +#include "ActorEffector.h" +#include "CameraFirstEye.h" +#include "Level.h" + +#include "Include/xrRender/Kinematics.h" + +#include "xrPhysics/PhysicsShell.h" + +void CHolderEntityObject::BoneCallbackX(CBoneInstance* B) +{ +} + +void CHolderEntityObject::BoneCallbackY(CBoneInstance* B) +{ +} + +CHolderEntityObject::CHolderEntityObject() + : camera(xr_new(this, CCameraBase::flRelativeLink | CCameraBase::flPositionRigid | CCameraBase::flDirectionRigid)) +{ + camera->Load("holder_entity_object_cam"); +} + +CHolderEntityObject::~CHolderEntityObject() +{ + xr_delete(camera); +} + +void CHolderEntityObject::SetBoneCallbacks() +{ + m_pPhysicsShell->EnabledCallbacks(false); +} + +void CHolderEntityObject::ResetBoneCallbacks() +{ + m_pPhysicsShell->EnabledCallbacks(true); +} + +void CHolderEntityObject::Load(LPCSTR section) +{ + inheritedPH::Load(section); + m_bAllowWeapon = pSettings->r_bool(section, "allow_weapon"); + m_bExitLocked = pSettings->r_bool(section, "lock_exit"); + m_bEnterLocked = pSettings->r_bool(section, "lock_enter"); + + m_exit_position = READ_IF_EXISTS(pSettings, r_fvector3, section, "exit_pos", Fvector().set(0.0f, 0.0f, 0.0f)); + m_camera_position = READ_IF_EXISTS(pSettings, r_fvector3, section, "camera_pos", Fvector().set(0.0f, 0.0f, 0.0f)); + m_camera_angle = READ_IF_EXISTS(pSettings, r_fvector3, section, "camera_angle", Fvector().set(0.0f, 0.0f, 0.0f)); + m_sUseAction = READ_IF_EXISTS(pSettings, r_string, section, "use_action_hint", nullptr); +} + +bool CHolderEntityObject::net_Spawn(CSE_Abstract* DC) +{ + if (!inheritedPH::net_Spawn(DC)) + return false; + + IKinematics* K = smart_cast(Visual()); + xr_vector fixed_bones; + fixed_bones.push_back(K->LL_GetBoneRoot()); + PPhysicsShell() = P_build_Shell(this, false, fixed_bones); + + processing_activate(); + setVisible(true); + setEnabled(true); + return true; +} + +void CHolderEntityObject::net_Destroy() +{ + inheritedPH::net_Destroy(); + processing_deactivate(); +} + +void CHolderEntityObject::net_Export(NET_Packet& P) // export to server +{ + inheritedPH::net_Export(P); +} + +void CHolderEntityObject::net_Import(NET_Packet& P) // import from server +{ + inheritedPH::net_Import(P); +} + +void CHolderEntityObject::attach_actor_script(bool bForce) +{ + Actor()->use_HolderEx(this, bForce); +} + +void CHolderEntityObject::detach_actor_script(bool bForce) +{ + Actor()->use_HolderEx(nullptr, bForce); +} + +void CHolderEntityObject::UpdateCL() +{ + inheritedPH::UpdateCL(); + + if (OwnerActor() && OwnerActor()->IsMyCamera()) + { + cam_Update(Device.fTimeDelta, g_fov); + OwnerActor()->Cameras().UpdateFromCamera(Camera()); + OwnerActor()->Cameras().ApplyDevice(); + } +} + +void CHolderEntityObject::Hit(SHit* pHDS) +{ + if (!Owner()) + inheritedPH::Hit(pHDS); +} + +void CHolderEntityObject::cam_Update(float dt, float fov) +{ + Fvector P; + + XFORM().transform_tiny(P, m_camera_position); + + if (OwnerActor()) + { + // rotate head + OwnerActor()->Orientation().yaw = -Camera()->yaw; + OwnerActor()->Orientation().pitch = -Camera()->pitch; + } + + Camera()->f_fov = fov; + Camera()->Update(P, m_camera_angle); + Level().Cameras().UpdateFromCamera(Camera()); +} + +void CHolderEntityObject::renderable_Render(u32 context_id, IRenderable* root) +{ + inheritedPH::renderable_Render(context_id, root); +} + +void CHolderEntityObject::Action(u16 id, u32 flags) +{ + inheritedHolder::Action(id, flags); + /* + switch (id) + { + case kWPN_FIRE: + { + if (flags == CMD_START) + FireStart(); + else + FireEnd(); + break; + } + } + */ +} + +void CHolderEntityObject::SetParam(int id, Fvector2 val) +{ + inheritedHolder::SetParam(id, val); +} + +bool CHolderEntityObject::attach_Actor(CGameObject* actor) +{ + inheritedHolder::attach_Actor(actor); + SetBoneCallbacks(); + return true; +} + +void CHolderEntityObject::detach_Actor() +{ + inheritedHolder::detach_Actor(); + ResetBoneCallbacks(); +} + +void CHolderEntityObject::OnMouseMove(int dx, int dy) +{ + if (Remote()) + return; + CCameraBase* C = camera; + float scale = (C->f_fov / g_fov) * psMouseSens * psMouseSensScale / 50.f; + if (dx) + { + const float d = float(dx) * scale; + C->Move((d < 0) ? kLEFT : kRIGHT, _abs(d)); + } + if (dy) + { + const float d = ((psMouseInvert.test(1)) ? -1 : 1) * float(dy) * scale * 3.f / 4.f; + C->Move((d > 0) ? kUP : kDOWN, _abs(d)); + } +} + +void CHolderEntityObject::OnKeyboardPress(int dik) +{ + if (Remote()) + return; + + switch (dik) + { + case kWPN_FIRE: + break; + } +} + +void CHolderEntityObject::OnKeyboardRelease(int dik) +{ + if (Remote()) + return; + switch (dik) + { + case kWPN_FIRE: + break; + } +} + +void CHolderEntityObject::OnKeyboardHold(int dik) +{ +} + +void CHolderEntityObject::OnControllerPress(int cmd, float x, float y) +{ +} + +void CHolderEntityObject::OnControllerRelease(int cmd, float x, float y) +{ +} + +void CHolderEntityObject::OnControllerHold(int cmd, float x, float y) +{ +} + +void CHolderEntityObject::OnControllerAttitudeChange(Fvector change) +{ +} diff --git a/src/xrGame/HolderEntityObject.h b/src/xrGame/HolderEntityObject.h new file mode 100644 index 00000000000..f1f7b2a7153 --- /dev/null +++ b/src/xrGame/HolderEntityObject.h @@ -0,0 +1,79 @@ +#pragma once + +#include "holder_custom.h" +#include "PhysicsShellHolder.h" + +class CCameraBase; + +class CHolderEntityObject final : public CPhysicsShellHolder, public CHolderCustom +{ + typedef CPhysicsShellHolder inheritedPH; + typedef CHolderCustom inheritedHolder; + +private: + CCameraBase* camera; + + static void BoneCallbackX(CBoneInstance* B); + static void BoneCallbackY(CBoneInstance* B); + void SetBoneCallbacks(); + void ResetBoneCallbacks(); + +public: + //casts + CHolderCustom* cast_holder_custom() override { return this; } + +public: + //general + CHolderEntityObject(); + ~CHolderEntityObject() override; + + void Load(pcstr section) override; + + bool net_Spawn(CSE_Abstract* DC) override; + void net_Destroy() override; + void net_Export(NET_Packet& P) override; // export to server + void net_Import(NET_Packet& P) override; // import from server + + void UpdateCL() override; + + void Hit(SHit* pHDS) override; + +private: + //shooting + Fvector3 m_camera_position{}; + Fvector3 m_exit_position{}; + Fvector3 m_camera_angle{}; + + Fvector2 m_lim_x_rot{}, m_lim_y_rot{}; //in bone space + bool m_bAllowWeapon; + +public: + //HolderCustom + bool Use(const Fvector& pos, const Fvector& dir, const Fvector& foot_pos) override { return !Owner(); }; + void OnMouseMove(int x, int y) override; + void OnKeyboardPress(int dik) override; + void OnKeyboardRelease(int dik) override; + void OnKeyboardHold(int dik) override; + void OnControllerPress(int cmd, float x, float y) override; + void OnControllerRelease(int cmd, float x, float y) override; + void OnControllerHold(int cmd, float x, float y) override; + void OnControllerAttitudeChange(Fvector change) override; + CInventory* GetInventory() override { return nullptr; }; + void cam_Update(float dt, float fov = 90.0f) override; + + void renderable_Render(u32 context_id, IRenderable* root) override; + + void attach_actor_script(bool bForce = false); + void detach_actor_script(bool bForce = false); + + bool attach_Actor(CGameObject* actor) override; + void detach_Actor() override; + bool allowWeapon() const override { return m_bAllowWeapon; }; + bool HUDView() const override { return true; }; + Fvector ExitPosition() override { return m_exit_position; }; + + CCameraBase* Camera() override { return camera; }; + + void Action(u16 id, u32 flags) override; + void SetParam(int id, Fvector2 val) override; +}; diff --git a/src/xrGame/HudItem.cpp b/src/xrGame/HudItem.cpp index 0cecb3cf54e..57af3628972 100644 --- a/src/xrGame/HudItem.cpp +++ b/src/xrGame/HudItem.cpp @@ -143,6 +143,12 @@ void CHudItem::OnStateSwitch(u32 S, u32 oldState) void CHudItem::OnAnimationEnd(u32 state) { + if (const auto actor = smart_cast(object().H_Parent())) + { + actor->callback(GameObject::eActorHudAnimationEnd)( + smart_cast(this)->lua_game_object(), + hud_sect.c_str(), m_current_motion.c_str(), state, animation_slot()); + } switch (state) { case eBore: { SwitchState(eIdle); diff --git a/src/xrGame/HudSound.cpp b/src/xrGame/HudSound.cpp index a8a14a4189d..a3656c11e21 100644 --- a/src/xrGame/HudSound.cpp +++ b/src/xrGame/HudSound.cpp @@ -99,9 +99,17 @@ void HUD_SOUND_ITEM::PlaySound( hud_snd.m_activeSnd = &hud_snd.sounds[index]; - hud_snd.m_activeSnd->snd.play_at_pos(const_cast(parent), - flags & sm_2D ? Fvector().set(0, 0, 0) : position, flags, hud_snd.m_activeSnd->delay); - + if (hud_snd.m_b_exclusive) + { + hud_snd.m_activeSnd->snd.play_at_pos(const_cast(parent), + flags & sm_2D ? Fvector().set(0, 0, 0) : position, flags, hud_snd.m_activeSnd->delay); + } + else + { + Fvector pos = flags & sm_2D ? Fvector{} : position; + hud_snd.m_activeSnd->snd.play_no_feedback(const_cast(parent), + flags, hud_snd.m_activeSnd->delay, &pos, nullptr, nullptr, nullptr); + } hud_snd.m_activeSnd->snd.set_volume(hud_snd.m_activeSnd->volume * (b_hud_mode ? psHUDSoundVolume : 1.0f)); } @@ -145,8 +153,8 @@ void HUD_SOUND_COLLECTION::PlaySound( if (sound_item.m_b_exclusive) HUD_SOUND_ITEM::StopSound(sound_item); - HUD_SOUND_ITEM* snd_item = FindSoundItem(alias, true); - HUD_SOUND_ITEM::PlaySound(*snd_item, position, parent, hud_mode, looped, index); + if (const auto snd_item = FindSoundItem(alias, false)) + HUD_SOUND_ITEM::PlaySound(*snd_item, position, parent, hud_mode, looped, index); } void HUD_SOUND_COLLECTION::StopSound(LPCSTR alias) @@ -157,8 +165,8 @@ void HUD_SOUND_COLLECTION::StopSound(LPCSTR alias) void HUD_SOUND_COLLECTION::SetPosition(LPCSTR alias, const Fvector& pos) { - HUD_SOUND_ITEM* snd_item = FindSoundItem(alias, true); - if (snd_item->playing()) + HUD_SOUND_ITEM* snd_item = FindSoundItem(alias, false); + if (snd_item && snd_item->playing()) snd_item->set_position(pos); } diff --git a/src/xrGame/Inventory.cpp b/src/xrGame/Inventory.cpp index 7d4888ec2bb..032041f9b7f 100644 --- a/src/xrGame/Inventory.cpp +++ b/src/xrGame/Inventory.cpp @@ -1083,6 +1083,12 @@ bool CInventory::Eat(PIItem pIItem) pItemToEat->object().cNameSect().c_str()); #endif // MP_LOGGING + luabind::functor funct; + if (GEnv.ScriptEngine->functor("_G.CInventory__eat", funct)) + { + if (!funct(smart_cast(pItemToEat->object().H_Parent())->lua_game_object(), smart_cast(pIItem)->lua_game_object())) + return false; + } CActor* pActor = smart_cast(Level().CurrentControlEntity()); if (pActor && pActor->m_inventory == this) @@ -1096,7 +1102,6 @@ bool CInventory::Eat(PIItem pIItem) CurrentGameUI()->GetActorMenu().SetCurrentItem(nullptr); } - if (pItemToEat->Empty()) { if (!pItemToEat->CanDelete()) @@ -1283,13 +1288,24 @@ u32 CInventory::BeltMaxWidth() const return m_iMaxBelt; } -void CInventory::AddAvailableItems(TIItemContainer& items_container, bool for_trade) const +void CInventory::AddAvailableItems(TIItemContainer& items_container, bool for_trade, bool bOverride /*= false*/) const { for (TIItemContainer::const_iterator it = m_ruck.begin(); m_ruck.end() != it; ++it) { PIItem pIItem = *it; if (!for_trade || pIItem->CanTrade()) + { + if (bOverride) + { + luabind::functor funct; + if (GEnv.ScriptEngine->functor("actor_menu_inventory.CInventory_ItemAvailableToTrade", funct)) + { + if (!funct(m_pOwner->cast_game_object()->lua_game_object(), pIItem->cast_game_object()->lua_game_object())) + continue; + } + } items_container.push_back(pIItem); + } } if (m_bBeltUseful) @@ -1298,7 +1314,18 @@ void CInventory::AddAvailableItems(TIItemContainer& items_container, bool for_tr { PIItem pIItem = *it; if (!for_trade || pIItem->CanTrade()) + { + if (bOverride) + { + luabind::functor funct; + if (GEnv.ScriptEngine->functor("actor_menu_inventory.CInventory_ItemAvailableToTrade", funct)) + { + if (!funct(m_pOwner->cast_game_object()->lua_game_object(), pIItem->cast_game_object()->lua_game_object())) + continue; + } + } items_container.push_back(pIItem); + } } } @@ -1312,7 +1339,18 @@ void CInventory::AddAvailableItems(TIItemContainer& items_container, bool for_tr if (item && (!for_trade || item->CanTrade())) { if (!SlotIsPersistent(I) || item->BaseSlot() == GRENADE_SLOT) + { + if (bOverride) + { + luabind::functor funct; + if (GEnv.ScriptEngine->functor("actor_menu_inventory.CInventory_ItemAvailableToTrade", funct)) + { + if (!funct(m_pOwner->cast_game_object()->lua_game_object(), item->cast_game_object()->lua_game_object())) + continue; + } + } items_container.push_back(item); + } } } } diff --git a/src/xrGame/Inventory.h b/src/xrGame/Inventory.h index e14c354b5ad..4d3ce630826 100644 --- a/src/xrGame/Inventory.h +++ b/src/xrGame/Inventory.h @@ -132,7 +132,7 @@ class CInventory public: //возвращает РІСЃРµ РєСЂРѕРјРµ PDA РІ слоте Рё болта - void AddAvailableItems(TIItemContainer& items_container, bool for_trade) const; + void AddAvailableItems(TIItemContainer& items_container, bool for_trade, bool bOverride = false) const; float GetMaxWeight() const { return m_fMaxWeight; } void SetMaxWeight(float weight) { m_fMaxWeight = weight; } diff --git a/src/xrGame/Level_Bullet_Manager.cpp b/src/xrGame/Level_Bullet_Manager.cpp index 29872c6fd09..f94eec1fb00 100644 --- a/src/xrGame/Level_Bullet_Manager.cpp +++ b/src/xrGame/Level_Bullet_Manager.cpp @@ -35,7 +35,7 @@ float g_bullet_time_factor = 1.f; SBullet::SBullet(const Fvector& position, const Fvector& direction, float starting_speed, float power, /*float power_critical,*/ float impulse, u16 sender_id, u16 sendersweapon_id, ALife::EHitType e_hit_type, - float maximum_distance, const CCartridge& cartridge, float const air_resistance_factor, bool SendHit) + float maximum_distance, const CCartridge& cartridge, float const air_resistance_factor, bool SendHit, int iShotNum /*= 0*/) { bullet_pos = position; speed = max_speed = starting_speed; @@ -67,6 +67,11 @@ SBullet::SBullet(const Fvector& position, const Fvector& direction, float starti bullet_material_idx = cartridge.bullet_material_idx; VERIFY(u16(-1) != bullet_material_idx); + //Alundaio: Tracer for every 5th bullet + if (flags.allow_tracer && cartridge.m_4to1_tracer && iShotNum % 5 != 0) + flags.allow_tracer = false; + //-Alundaio + flags.allow_tracer = !!cartridge.m_flags.test(CCartridge::cfTracer); flags.allow_ricochet = !!cartridge.m_flags.test(CCartridge::cfRicochet); flags.explosive = !!cartridge.m_flags.test(CCartridge::cfExplosive); @@ -176,7 +181,7 @@ void CBulletManager::Clear() void CBulletManager::AddBullet(const Fvector& position, const Fvector& direction, float starting_speed, float power, //. float power_critical, float impulse, u16 sender_id, u16 sendersweapon_id, ALife::EHitType e_hit_type, float maximum_distance, - const CCartridge& cartridge, float const air_resistance_factor, bool SendHit, bool AimBullet) + const CCartridge& cartridge, float const air_resistance_factor, bool SendHit, bool AimBullet, int iShotNum /*= 0*/) { // Always called in Primary thread // Uncomment below if you will change the behaviour @@ -189,7 +194,7 @@ void CBulletManager::AddBullet(const Fvector& position, const Fvector& direction // u32 CurID = Level().CurrentControlEntity()->ID(); // u32 OwnerID = sender_id; SBullet& bullet = m_Bullets.emplace_back(position, direction, starting_speed, power, /*power_critical,*/ impulse, sender_id, - sendersweapon_id, e_hit_type, maximum_distance, cartridge, air_resistance_factor, SendHit); + sendersweapon_id, e_hit_type, maximum_distance, cartridge, air_resistance_factor, SendHit, iShotNum); // bullet.frame_num = Device.dwFrame; bullet.flags.aim_bullet = AimBullet; if (!IsGameTypeSingle()) @@ -853,6 +858,8 @@ void CBulletManager::Render() SBullet* bullet = &sbullet; if (!bullet->flags.allow_tracer) continue; + if (!psActorFlags.test(AF_USE_TRACERS)) + continue; if (!bullet->CanBeRenderedNow()) continue; diff --git a/src/xrGame/Level_Bullet_Manager.h b/src/xrGame/Level_Bullet_Manager.h index df2d72f57c9..67c9fe8a213 100644 --- a/src/xrGame/Level_Bullet_Manager.h +++ b/src/xrGame/Level_Bullet_Manager.h @@ -83,7 +83,7 @@ struct SBullet public: SBullet(const Fvector& position, const Fvector& direction, float start_speed, float power, /*float power_critical,*/ float impulse, u16 sender_id, u16 sendersweapon_id, ALife::EHitType e_hit_type, - float maximum_distance, const CCartridge& cartridge, float const air_resistance_factor, bool SendHit); + float maximum_distance, const CCartridge& cartridge, float const air_resistance_factor, bool SendHit, int iShotNum = 0); bool CanBeRenderedNow() const { return (Device.dwFrame > init_frame_num); } }; @@ -207,7 +207,7 @@ class CBulletManager void AddBullet(const Fvector& position, const Fvector& direction, float starting_speed, float power, /*float power_critical,*/ float impulse, u16 sender_id, u16 sendersweapon_id, ALife::EHitType e_hit_type, float maximum_distance, const CCartridge& cartridge, float const air_resistance_factor, bool SendHit, - bool AimBullet = false); + bool AimBullet = false, int iShotNum = 0); void CommitEvents(); // @ the start of frame void CommitRenderSet(); // @ the end of frame diff --git a/src/xrGame/Level_input.cpp b/src/xrGame/Level_input.cpp index 051199fc076..afa0ac05c41 100644 --- a/src/xrGame/Level_input.cpp +++ b/src/xrGame/Level_input.cpp @@ -111,8 +111,10 @@ void CLevel::IR_OnMouseMove(int dx, int dy) extern bool g_block_pause; // Lain: added TEMP!!! +#ifdef DEBUG extern float g_separate_factor; extern float g_separate_radius; +#endif #include "xrScriptEngine/script_engine.hpp" #include "ai_space.h" @@ -214,6 +216,13 @@ void CLevel::IR_OnKeyboardPress(int key) if (game && game->OnKeyboardPress(GetBindedAction(key))) return; + luabind::functor funct; + if (GEnv.ScriptEngine->functor("level_input.on_key_press", funct)) + { + if (funct(key, _curr)) + return; + } + if (_curr == kQUICK_SAVE && IsGameTypeSingle()) { Console->Execute("save"); diff --git a/src/xrGame/ScriptXMLInit.cpp b/src/xrGame/ScriptXMLInit.cpp index 46911dba27a..d7646ed0089 100644 --- a/src/xrGame/ScriptXMLInit.cpp +++ b/src/xrGame/ScriptXMLInit.cpp @@ -8,6 +8,7 @@ #include "xrUICore/ComboBox/UIComboBox.h" #include "xrUICore/TabControl/UITabControl.h" #include "xrUICore/Windows/UIFrameWindow.h" +#include "xrUICore/Hint/UIHint.h" #include "ui/UILabel.h" #include "ui/ServerList.h" #include "ui/UIMapList.h" @@ -49,6 +50,14 @@ void CScriptXmlInit::InitWindow(LPCSTR path, int index, CUIWindow* pWnd) CUIXmlInit::InitWindow(m_xml, path, index, pWnd); } +UIHint* CScriptXmlInit::InitHint(pcstr path, CUIWindow* parent) +{ + UIHint* pWnd = xr_new(); + pWnd->init_from_xml(m_xml, path); + _attach_child(pWnd, parent); + return pWnd; +} + CUIFrameWindow* CScriptXmlInit::InitFrame(LPCSTR path, CUIWindow* parent) { CUIFrameWindow* pWnd = xr_new(path); @@ -271,6 +280,7 @@ SCRIPT_EXPORT(CScriptXmlInit, (), .def("ParseFile", &CScriptXmlInit::ParseFile) .def("ParseShTexInfo", &CScriptXmlInit::ParseShTexInfo) .def("InitWindow", &CScriptXmlInit::InitWindow) + .def("InitHint", &CScriptXmlInit::InitHint) .def("InitFrame", &CScriptXmlInit::InitFrame) .def("InitFrameLine", &CScriptXmlInit::InitFrameLine) .def("InitEditBox", &CScriptXmlInit::InitEditBox) diff --git a/src/xrGame/ScriptXMLInit.h b/src/xrGame/ScriptXMLInit.h index 737816abe4d..7db15ebc382 100644 --- a/src/xrGame/ScriptXMLInit.h +++ b/src/xrGame/ScriptXMLInit.h @@ -28,6 +28,7 @@ class CUIScrollView; class CUIListWnd; class CUIListBox; class CUIProgressBar; +class UIHint; class CScriptXmlInit { @@ -35,6 +36,7 @@ class CScriptXmlInit void ParseFile(LPCSTR xml_file); void ParseShTexInfo(pcstr xml_file); void InitWindow(LPCSTR path, int index, CUIWindow* pWnd); + UIHint* InitHint(pcstr path, CUIWindow* parent); CUIFrameWindow* InitFrame(LPCSTR path, CUIWindow* parent); CUIFrameLineWnd* InitFrameLine(LPCSTR path, CUIWindow* parent); CUIEditBox* InitEditBox(LPCSTR path, CUIWindow* parent); @@ -63,6 +65,8 @@ class CScriptXmlInit CUIListBox* InitListBox(LPCSTR path, CUIWindow* parent); CUIProgressBar* InitProgressBar(LPCSTR path, CUIWindow* parent); + CUIXml& GetXml() { return m_xml; } + protected: CUIXml m_xml; }; diff --git a/src/xrGame/ShootingObject.cpp b/src/xrGame/ShootingObject.cpp index 59fd266e501..0693acfd559 100644 --- a/src/xrGame/ShootingObject.cpp +++ b/src/xrGame/ShootingObject.cpp @@ -40,18 +40,19 @@ void CShootingObject::Load(LPCSTR section) //время затрачиваемое РЅР° выстрел fOneShotTime = pSettings->r_float(section, "rpm"); + //Alundaio: Two-shot burst rpm; used for Abakan/AN-94 - modeShotTime = READ_IF_EXISTS(pSettings, r_float, section, "rpm_mode_2", fOneShotTime); + fModeShotTime = READ_IF_EXISTS(pSettings, r_float, section, "rpm_mode_2", fOneShotTime); VERIFY(fOneShotTime > 0.f); fOneShotTime = 60.f / fOneShotTime; - modeShotTime = 60.f / modeShotTime; + fModeShotTime = 60.f / fModeShotTime; //Cycle down RPM after first 2 shots; used for Abakan/AN-94 if (pSettings->line_exist(section, "cycle_down")) - cycleDown = pSettings->r_bool(section, "cycle_down") ? true : false; + bCycleDown = pSettings->r_bool(section, "cycle_down") ? true : false; else - cycleDown = false; + bCycleDown = false; //Alundaio: END LoadFireParams(section); @@ -444,7 +445,7 @@ bool CShootingObject::SendHitAllowed(IGameObject* pUser) extern void random_dir(Fvector& tgt_dir, const Fvector& src_dir, float dispersion); void CShootingObject::FireBullet(const Fvector& pos, const Fvector& shot_dir, float fire_disp, - const CCartridge& cartridge, u16 parent_id, u16 weapon_id, bool send_hit) + const CCartridge& cartridge, u16 parent_id, u16 weapon_id, bool send_hit, int iShotNum /*= 0*/) { Fvector dir; random_dir(dir, shot_dir, fire_disp); @@ -504,7 +505,7 @@ void CShootingObject::FireBullet(const Fvector& pos, const Fvector& shot_dir, fl Level().BulletManager().AddBullet(pos, dir, m_fStartBulletSpeed * cur_silencer_koef.bullet_speed, l_fHitPower * cur_silencer_koef.hit_power, fHitImpulse * cur_silencer_koef.hit_impulse, parent_id, weapon_id, - ALife::eHitTypeFireWound, fireDistance, cartridge, m_air_resistance_factor, send_hit, aim_bullet); + ALife::eHitTypeFireWound, fireDistance, cartridge, m_air_resistance_factor, send_hit, aim_bullet, iShotNum); } void CShootingObject::FireStart() { bWorking = true; } void CShootingObject::FireEnd() { bWorking = false; } diff --git a/src/xrGame/ShootingObject.h b/src/xrGame/ShootingObject.h index ec9762b133c..36c508592fb 100644 --- a/src/xrGame/ShootingObject.h +++ b/src/xrGame/ShootingObject.h @@ -46,7 +46,7 @@ class CShootingObject : public IAnticheatDumpable virtual void LoadFireParams(LPCSTR section); //сила выстрела virtual bool SendHitAllowed(IGameObject* pUser); virtual void FireBullet(const Fvector& pos, const Fvector& dir, float fire_disp, const CCartridge& cartridge, - u16 parent_id, u16 weapon_id, bool send_hit); + u16 parent_id, u16 weapon_id, bool send_hit, int iShotNum = 0); void SetBulletSpeed(float new_speed) { m_fStartBulletSpeed = new_speed; } float GetBulletSpeed() { return m_fStartBulletSpeed; } virtual void FireStart(); @@ -61,8 +61,8 @@ class CShootingObject : public IAnticheatDumpable bool bWorking{}; float fOneShotTime{}; - float modeShotTime; - bool cycleDown; + float fModeShotTime; + bool bCycleDown; Fvector4 fvHitPower{}; Fvector4 fvHitPowerCritical{}; float fHitImpulse; diff --git a/src/xrGame/UIDialogHolder.cpp b/src/xrGame/UIDialogHolder.cpp index 9732c081fe7..4838bef9be1 100644 --- a/src/xrGame/UIDialogHolder.cpp +++ b/src/xrGame/UIDialogHolder.cpp @@ -41,7 +41,7 @@ void CDialogHolder::StartMenu(CUIDialogWnd* pDialog, bool bDoHideIndicators) AddDialogToRender(pDialog); SetMainInputReceiver(pDialog, false); - if (UseIndicators()) + if (UseIndicators() && !m_input_receivers.empty()) //Alundaio { bool b = !!psHUD_Flags.test(HUD_CROSSHAIR_RT); m_input_receivers.back().m_flags.set(recvItem::eCrosshair, b); @@ -82,7 +82,7 @@ void CDialogHolder::StopMenu(CUIDialogWnd* pDialog) if (TopInputReceiver() == pDialog) { - if (UseIndicators()) + if (UseIndicators() && !m_input_receivers.empty()) //Alundaio { bool b = !!m_input_receivers.back().m_flags.test(recvItem::eCrosshair); psHUD_Flags.set(HUD_CROSSHAIR_RT, b); diff --git a/src/xrGame/UIGameCustom.cpp b/src/xrGame/UIGameCustom.cpp index 6ecbbb3b687..6b3106cdba3 100644 --- a/src/xrGame/UIGameCustom.cpp +++ b/src/xrGame/UIGameCustom.cpp @@ -227,8 +227,12 @@ void CUIGameCustom::ShowMessagesWindow() bool CUIGameCustom::ShowPdaMenu() { HideActorMenu(); - PdaMenu->ShowDialog(true); - return true; + if (!PdaMenu->IsShown()) + { + PdaMenu->ShowDialog(true); + return true; + } + return false; } void CUIGameCustom::HidePdaMenu() diff --git a/src/xrGame/Weapon.cpp b/src/xrGame/Weapon.cpp index c556cb13eba..391adfab3e8 100644 --- a/src/xrGame/Weapon.cpp +++ b/src/xrGame/Weapon.cpp @@ -1703,6 +1703,14 @@ const CInventoryItem* CWeapon::can_kill(const xr_vector& ite bool CWeapon::ready_to_kill() const { + //Alundaio + const auto io = smart_cast(H_Parent()); + if (!io) + return false; + + if (!io->inventory().ActiveItem() || io->inventory().ActiveItem()->object().ID() != ID()) + return false; + //-Alundaio return ( !IsMisfire() && ((GetState() == eIdle) || (GetState() == eFire) || (GetState() == eFire2)) && GetAmmoElapsed()); } diff --git a/src/xrGame/WeaponAmmo.cpp b/src/xrGame/WeaponAmmo.cpp index dd07aaef61e..70d4ec4da8d 100644 --- a/src/xrGame/WeaponAmmo.cpp +++ b/src/xrGame/WeaponAmmo.cpp @@ -56,6 +56,9 @@ void CCartridge::Load(LPCSTR section, u8 LocalAmmoType) m_flags.set(cfMagneticBeam, TRUE); } + if (pSettings->line_exist(section, "4to1_tracer")) + m_4to1_tracer = pSettings->r_bool(section, "4to1_tracer");; + if (pSettings->line_exist(section, "can_be_unlimited")) m_flags.set(cfCanBeUnlimited, pSettings->r_bool(section, "can_be_unlimited")); @@ -104,6 +107,10 @@ void CWeaponAmmo::Load(LPCSTR section) else cartridge_param.kAirRes = pSettings->r_float(BULLET_MANAGER_SECTION, "air_resistance_k"); m_tracer = !!pSettings->r_bool(section, "tracer"); + + if (pSettings->line_exist(section, "4to1_tracer")) + m_4to1_tracer = pSettings->r_bool(section, "4to1_tracer");; + cartridge_param.buckShot = pSettings->r_s32(section, "buck_shot"); cartridge_param.impair = pSettings->r_float(section, "impair"); cartridge_param.fWallmarkSize = pSettings->r_float(section, "wm_size"); @@ -167,6 +174,7 @@ bool CWeaponAmmo::Get(CCartridge& cartridge) cartridge.param_s = cartridge_param; cartridge.m_flags.set(CCartridge::cfTracer, m_tracer); + cartridge.m_4to1_tracer = m_4to1_tracer; cartridge.bullet_material_idx = GMLib.GetMaterialIdx(WEAPON_MATERIAL_NAME); cartridge.m_InvShortName = NameShort(); --m_boxCurr; diff --git a/src/xrGame/WeaponAmmo.h b/src/xrGame/WeaponAmmo.h index d2df35b84f4..b6f732367c0 100644 --- a/src/xrGame/WeaponAmmo.h +++ b/src/xrGame/WeaponAmmo.h @@ -42,6 +42,7 @@ class CCartridge : public IAnticheatDumpable SCartridgeParam param_s; u8 m_LocalAmmoType; + bool m_4to1_tracer{}; u16 bullet_material_idx; Flags8 m_flags; @@ -81,6 +82,7 @@ class CWeaponAmmo : public CInventoryItemObject u16 m_boxSize; u16 m_boxCurr; bool m_tracer; + bool m_4to1_tracer{}; public: virtual CInventoryItem* can_make_killing(const CInventory* inventory) const; diff --git a/src/xrGame/WeaponAutomaticShotgun.h b/src/xrGame/WeaponAutomaticShotgun.h index f477b6ccd32..f280930cb8b 100644 --- a/src/xrGame/WeaponAutomaticShotgun.h +++ b/src/xrGame/WeaponAutomaticShotgun.h @@ -25,7 +25,7 @@ class CWeaponAutomaticShotgun : public CWeaponMagazined void PlayAnimCloseWeapon(); virtual bool Action(u16 cmd, u32 flags); - //virtual int GetCurrentFireMode() { return m_aFireModes[m_iCurFireMode]; } //AVO: this is already implemented in parent class (CWeaponMagazined) + protected: virtual void OnAnimationEnd(u32 state); void TriStateReload(); diff --git a/src/xrGame/WeaponCustomPistolAuto.cpp b/src/xrGame/WeaponCustomPistolAuto.cpp deleted file mode 100644 index 59de9453a63..00000000000 --- a/src/xrGame/WeaponCustomPistolAuto.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "StdAfx.h" -#include "WeaponCustomPistolAuto.h" - -CWeaponCustomPistolAuto::CWeaponCustomPistolAuto() : CWeaponMagazined(SOUND_TYPE_WEAPON_PISTOL) {} - -CWeaponCustomPistolAuto::~CWeaponCustomPistolAuto() {} - -void CWeaponCustomPistolAuto::switch2_Fire() -{ - m_bFireSingleShot = true; - //bWorking = false; - m_iShotNum = 0; - m_bStopedAfterQueueFired = false; -} - -void CWeaponCustomPistolAuto::FireEnd() -{ - //if (fShotTimeCounter <= 0) - { - //SetPending(false); - inherited::FireEnd(); - } -} - -void CWeaponCustomPistolAuto::PlayAnimReload() -{ - inherited::PlayAnimReload(); -} diff --git a/src/xrGame/WeaponCustomPistolAuto.h b/src/xrGame/WeaponCustomPistolAuto.h deleted file mode 100644 index eae1fc6ab99..00000000000 --- a/src/xrGame/WeaponCustomPistolAuto.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "WeaponMagazined.h" - -class CWeaponCustomPistolAuto: public CWeaponMagazined -{ - using inherited = CWeaponMagazined; - -public: - CWeaponCustomPistolAuto(); - virtual ~CWeaponCustomPistolAuto(); - //int GetCurrentFireMode() override { return 1; }; - -protected: - void FireEnd() override; - void switch2_Fire() override; - void PlayAnimReload() override; -}; diff --git a/src/xrGame/WeaponFire.cpp b/src/xrGame/WeaponFire.cpp index fbbe67b9104..c977be39918 100644 --- a/src/xrGame/WeaponFire.cpp +++ b/src/xrGame/WeaponFire.cpp @@ -111,7 +111,7 @@ void CWeapon::FireTrace(const Fvector& P, const Fvector& D) //выстерлить пулю (СЃ учетом возможной стрельбы РґСЂРѕР±СЊСЋ) for (int i = 0; i < l_cartridge.param_s.buckShot; ++i) { - FireBullet(P, D, fire_disp, l_cartridge, H_Parent()->ID(), ID(), SendHit); + FireBullet(P, D, fire_disp, l_cartridge, H_Parent()->ID(), ID(), SendHit, iAmmoElapsed); } StartShotParticles(); diff --git a/src/xrGame/WeaponMagazined.cpp b/src/xrGame/WeaponMagazined.cpp index a6bad977fab..8686e63552e 100644 --- a/src/xrGame/WeaponMagazined.cpp +++ b/src/xrGame/WeaponMagazined.cpp @@ -56,8 +56,7 @@ void CWeaponMagazined::net_Destroy() { inherited::net_Destroy(); } bool CWeaponMagazined::WeaponSoundExist(pcstr section, pcstr sound_name) const { pcstr str; - bool sec_exist = process_if_exists_set(section, sound_name, &CInifile::r_string, str, true); - if (sec_exist) + if (process_if_exists_set(section, sound_name, &CInifile::r_string, str, true)) return true; #ifdef DEBUG Msg("~ [WARNING] ------ Sound [%s] does not exist in [%s]", sound_name, section); @@ -72,14 +71,14 @@ void CWeaponMagazined::Load(LPCSTR section) inherited::Load(section); // Sounds - m_sounds.LoadSound(section, "snd_draw", "sndShow", false, m_eSoundShow); - m_sounds.LoadSound(section, "snd_holster", "sndHide", false, m_eSoundHide); + m_sounds.LoadSound(section, "snd_draw", "sndShow", true, m_eSoundShow); + m_sounds.LoadSound(section, "snd_holster", "sndHide", true, m_eSoundHide); //Alundaio: LAYERED_SND_SHOOT m_layered_sounds.LoadSound(section, "snd_shoot", "sndShot", false, m_eSoundShot); //-Alundaio - m_sounds.LoadSound(section, "snd_empty", "sndEmptyClick", false, m_eSoundEmptyClick); + m_sounds.LoadSound(section, "snd_empty", "sndEmptyClick", true, m_eSoundEmptyClick); m_sounds.LoadSound(section, "snd_reload", "sndReload", true, m_eSoundReload); if (WeaponSoundExist(section, "snd_reload_empty")) @@ -87,7 +86,7 @@ void CWeaponMagazined::Load(LPCSTR section) if (WeaponSoundExist(section, "snd_reload_misfire")) m_sounds.LoadSound(section, "snd_reload_misfire", "sndReloadMisfire", true, m_eSoundReloadMisfire); - m_sSndShotCurrent = "sndShot"; + m_sSndShotCurrent = IsSilencerAttached() ? "sndSilencerShot" : "sndShot"; //Р·РІСѓРєРё Рё партиклы глушителя, если такой есть if (m_eSilencerStatus == ALife::eAddonAttachable || m_eSilencerStatus == ALife::eAddonPermanent) @@ -99,8 +98,6 @@ void CWeaponMagazined::Load(LPCSTR section) //Alundaio: LAYERED_SND_SHOOT Silencer m_layered_sounds.LoadSound(section, "snd_silncer_shot", "sndSilencerShot", false, m_eSoundShot); - if (WeaponSoundExist(section, "snd_silncer_shot_actor")) - m_layered_sounds.LoadSound(section, "snd_silncer_shot_actor", "sndSilencerShotActor", false, m_eSoundShot); //-Alundaio } @@ -169,12 +166,9 @@ void CWeaponMagazined::FireStart() else // misfire { // Alundaio - CGameObject* object = smart_cast(H_Parent()); - if (object) + if (const auto object = smart_cast(H_Parent())) { - auto& cb = object->callback(GameObject::eOnWeaponJammed); - if (cb) - cb(object->lua_game_object(), this->lua_game_object()); + object->callback(GameObject::eOnWeaponJammed)(object->lua_game_object(), this->lua_game_object()); } if (smart_cast(this->H_Parent()) && (Level().CurrentViewEntity() == H_Parent())) @@ -258,6 +252,12 @@ bool CWeaponMagazined::IsAmmoAvailable() void CWeaponMagazined::OnMagazineEmpty() { + if (IsGameTypeSingle() && ParentIsActor()) + { + int AC = GetSuitableAmmoTotal(); + Actor()->callback(GameObject::eOnWeaponMagazineEmpty)(lua_game_object(), AC); + } + if (GetState() == eIdle) { OnEmptyClick(); @@ -297,6 +297,12 @@ void CWeaponMagazined::UnloadMagazine(bool spawn_ammo) VERIFY((u32)iAmmoElapsed == m_magazine.size()); + if (IsGameTypeSingle() && ParentIsActor()) + { + int AC = GetSuitableAmmoTotal(); + Actor()->callback(GameObject::eOnWeaponMagazineEmpty)(lua_game_object(), AC); + } + if (!spawn_ammo) return; @@ -550,8 +556,8 @@ void CWeaponMagazined::state_Fire(float dt) //Alundaio: Use fModeShotTime instead of fOneShotTime if current fire mode is 2-shot burst //Alundaio: Cycle down RPM after two shots; used for Abakan/AN-94 - if (GetCurrentFireMode() == 2 || (cycleDown == true && m_iShotNum <= 1)) - fShotTimeCounter = modeShotTime; + if (GetCurrentFireMode() == 2 || (bCycleDown == true && m_iShotNum <= 1)) + fShotTimeCounter = fModeShotTime; else fShotTimeCounter = fOneShotTime; //Alundaio: END @@ -677,43 +683,34 @@ void CWeaponMagazined::switch2_Idle() void CWeaponMagazined::switch2_Fire() { CInventoryOwner* io = smart_cast(H_Parent()); - -#ifdef DEBUG if (!io) return; - // VERIFY2(io, make_string("no inventory owner, item %s", *cName())); CInventoryItem* ii = smart_cast(this); + if (ii != io->inventory().ActiveItem()) + { + Msg("~ WARNING: Not an active item, item %s, owner %s, active item %s", + cName().c_str(), H_Parent()->cName().c_str(), + io->inventory().ActiveItem() ? io->inventory().ActiveItem()->object().cName().c_str() : "no_active_item"); + return; + } +#ifdef DEBUG if (ii != io->inventory().ActiveItem()) Msg("! not an active item, item %s, owner %s, active item %s", *cName(), *H_Parent()->cName(), io->inventory().ActiveItem() ? *io->inventory().ActiveItem()->object().cName() : "no_active_item"); if (!(io && (ii == io->inventory().ActiveItem()))) { - CAI_Stalker* stalker = smart_cast(H_Parent()); - if (stalker) + if (const auto stalker = smart_cast(H_Parent())) { stalker->planner().show(); stalker->planner().show_current_world_state(); stalker->planner().show_target_world_state(); } } -#else - if (!io) - return; #endif // DEBUG - // - // VERIFY2( - // io && (ii == io->inventory().ActiveItem()), - // make_string( - // "item[%s], parent[%s]", - // *cName(), - // H_Parent() ? *H_Parent()->cName() : "no_parent" - // ) - // ); - m_bStopedAfterQueueFired = false; m_bFireSingleShot = true; m_iShotNum = 0; @@ -750,10 +747,12 @@ void CWeaponMagazined::PlayReloadSound() else { if (iAmmoElapsed == 0) + { if (m_sounds.FindSoundItem("sndReloadEmpty", false)) PlaySound("sndReloadEmpty", get_LastFP()); else PlaySound("sndReload", get_LastFP()); + } else PlaySound("sndReload", get_LastFP()); } @@ -1171,16 +1170,12 @@ void CWeaponMagazined::OnZoomIn() PlayAnimIdle(); // Alundaio - CGameObject* object = smart_cast(H_Parent()); - if (object) + if (const auto object = smart_cast(H_Parent())) { - auto& cb = object->callback(GameObject::eOnWeaponZoomIn); - if (cb) - cb(object->lua_game_object(), this->lua_game_object()); + object->callback(GameObject::eOnWeaponZoomIn)(object->lua_game_object(), this->lua_game_object()); } - CActor* pActor = smart_cast(H_Parent()); - if (pActor) + if (CActor* pActor = smart_cast(H_Parent())) { CEffectorZoomInertion* S = smart_cast(pActor->Cameras().GetCamEffector(eCEZoom)); if (!S) @@ -1203,17 +1198,12 @@ void CWeaponMagazined::OnZoomOut() PlayAnimIdle(); //Alundaio - CGameObject* object = smart_cast(H_Parent()); - if (object) + if (const auto object = smart_cast(H_Parent())) { - auto& cb = object->callback(GameObject::eOnWeaponZoomOut); - if (cb) - cb(object->lua_game_object(), this->lua_game_object()); + object->callback(GameObject::eOnWeaponZoomOut)(object->lua_game_object(), this->lua_game_object()); } - CActor* pActor = smart_cast(H_Parent()); - - if (pActor) + if (CActor* pActor = smart_cast(H_Parent())) pActor->Cameras().RemoveCamEffector(eCEZoom); } @@ -1537,5 +1527,5 @@ void CWeaponMagazined::FireBullet(const Fvector& pos, const Fvector& shot_dir, f SetBulletSpeed(m_fOldBulletSpeed); } } - inherited::FireBullet(pos, shot_dir, fire_disp, cartridge, parent_id, weapon_id, send_hit); + inherited::FireBullet(pos, shot_dir, fire_disp, cartridge, parent_id, weapon_id, send_hit, GetAmmoElapsed()); } diff --git a/src/xrGame/WeaponMagazinedWGrenade.cpp b/src/xrGame/WeaponMagazinedWGrenade.cpp index 4c646432fd5..8382acb95e5 100644 --- a/src/xrGame/WeaponMagazinedWGrenade.cpp +++ b/src/xrGame/WeaponMagazinedWGrenade.cpp @@ -30,7 +30,7 @@ void CWeaponMagazinedWGrenade::Load(LPCSTR section) CRocketLauncher::Load(section); //// Sounds - m_sounds.LoadSound(section, "snd_shoot_grenade", "sndShotG", false, m_eSoundShot); + m_sounds.LoadSound(section, "snd_shoot_grenade", "sndShotG", true, m_eSoundShot); m_sounds.LoadSound(section, "snd_reload_grenade", "sndReloadG", true, m_eSoundReload); m_sounds.LoadSound(section, "snd_switch", "sndSwitch", true, m_eSoundReload); @@ -658,12 +658,12 @@ void CWeaponMagazinedWGrenade::PlayAnimIdle() { case state::idle: { - PlayHUDMotion("anm_idle_g", "anim_idle_g", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_g", "anim_idle_g", true, nullptr, GetState()); break; } case state::sprint: { - PlayHUDMotion("anm_idle_sprint_g", "anim_idle_g", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_sprint_g", "anim_idle_g", true, nullptr, GetState()); break; } case state::crouch: @@ -677,7 +677,7 @@ void CWeaponMagazinedWGrenade::PlayAnimIdle() } case state::moving: { - PlayHUDMotion("anm_idle_moving_g", "anim_idle_g", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_moving_g", "anim_idle_g", true, nullptr, GetState()); break; } } // switch (act_state) @@ -688,12 +688,12 @@ void CWeaponMagazinedWGrenade::PlayAnimIdle() { case state::idle: { - PlayHUDMotion("anm_idle_w_gl", "anim_idle_gl", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_w_gl", "anim_idle_gl", true, nullptr, GetState()); break; } case state::sprint: { - PlayHUDMotion("anm_idle_sprint_w_gl", "anim_idle_sprint", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_sprint_w_gl", "anim_idle_sprint", true, nullptr, GetState()); break; } case state::crouch: @@ -707,7 +707,7 @@ void CWeaponMagazinedWGrenade::PlayAnimIdle() } case state::moving: { - PlayHUDMotion("anm_idle_moving_w_gl", "anim_idle_gl", TRUE, nullptr, GetState()); + PlayHUDMotion("anm_idle_moving_w_gl", "anim_idle_gl", true, nullptr, GetState()); break; } } // switch (act_state) @@ -925,7 +925,7 @@ bool CWeaponMagazinedWGrenade::GetBriefInfo(II_BriefInfo& info) return false; */ string32 int_str; - int ae = GetAmmoElapsed(); + const int ae = GetAmmoElapsed(); xr_sprintf(int_str, "%d", ae); info.cur_ammo._set(int_str); if (HasFireModes()) @@ -941,9 +941,7 @@ bool CWeaponMagazinedWGrenade::GetBriefInfo(II_BriefInfo& info) if (m_pInventory->ModifyFrame() <= m_BriefInfo_CalcFrame) return false; - GetSuitableAmmoTotal(); - - const u32 at_size = m_bGrenadeMode ? m_ammoTypes2.size() : m_ammoTypes.size(); + const size_t at_size = m_bGrenadeMode ? m_ammoTypes2.size() : m_ammoTypes.size(); if (unlimited_ammo() || at_size == 0) { info.fmj_ammo._set("--"); @@ -958,30 +956,27 @@ bool CWeaponMagazinedWGrenade::GetBriefInfo(II_BriefInfo& info) info.ap_ammo._set(""); info.third_ammo._set(""); - int total = 0; if (at_size >= 1) { const int fmj = m_bGrenadeMode ? GetAmmoCount2(0) : GetAmmoCount(0); xr_sprintf(int_str, "%d", fmj); info.fmj_ammo._set(int_str); - total += fmj; } if (at_size >= 2) { const int ap = m_bGrenadeMode ? GetAmmoCount2(1) : GetAmmoCount(1); xr_sprintf(int_str, "%d", ap); info.ap_ammo._set(int_str); - total += ap; } if (at_size >= 3) { const int third = m_bGrenadeMode ? GetAmmoCount2(2) : GetAmmoCount(2); xr_sprintf(int_str, "%d", third); info.third_ammo._set(int_str); - total += third; } - xr_sprintf(int_str, "%d", total); + const int ac = GetSuitableAmmoTotal(); + xr_sprintf(int_str, "%d", ac - ae); info.total_ammo = int_str; //-Alundaio } diff --git a/src/xrGame/WeaponPistol.cpp b/src/xrGame/WeaponPistol.cpp index a41cc4de262..c0e9ab1817a 100644 --- a/src/xrGame/WeaponPistol.cpp +++ b/src/xrGame/WeaponPistol.cpp @@ -84,11 +84,6 @@ void CWeaponPistol::PlayAnimAim() inherited::PlayAnimAim(); } -void CWeaponPistol::PlayAnimReload() -{ - inherited::PlayAnimReload(); //AVO: refactored to use grand-parent (CWeaponMagazined) function -} - void CWeaponPistol::PlayAnimHide() { VERIFY(GetState() == eHiding); @@ -116,10 +111,6 @@ void CWeaponPistol::PlayAnimShoot() void CWeaponPistol::switch2_Reload() { inherited::switch2_Reload(); } void CWeaponPistol::OnAnimationEnd(u32 state) { inherited::OnAnimationEnd(state); } -void CWeaponPistol::OnShot() -{ - inherited::OnShot(); //Alundaio: not changed from inherited, so instead of copying changes from weaponmagazined, we just do this -} void CWeaponPistol::UpdateSounds() { diff --git a/src/xrGame/WeaponPistol.h b/src/xrGame/WeaponPistol.h index e3f81f13200..82eba06b6bf 100644 --- a/src/xrGame/WeaponPistol.h +++ b/src/xrGame/WeaponPistol.h @@ -13,7 +13,6 @@ class CWeaponPistol : public CWeaponCustomPistol virtual void switch2_Reload(); - virtual void OnShot(); virtual void OnAnimationEnd(u32 state); virtual void net_Destroy(); virtual void OnH_B_Chield(); @@ -24,7 +23,6 @@ class CWeaponPistol : public CWeaponCustomPistol virtual void PlayAnimIdleMoving(); virtual void PlayAnimIdleSprint(); virtual void PlayAnimHide(); - virtual void PlayAnimReload(); virtual void PlayAnimShoot(); virtual void PlayAnimBore(); virtual void PlayAnimAim(); diff --git a/src/xrGame/WeaponRevolver.cpp b/src/xrGame/WeaponRevolver.cpp index 18d43e6c2cb..62f5ff4c9fe 100644 --- a/src/xrGame/WeaponRevolver.cpp +++ b/src/xrGame/WeaponRevolver.cpp @@ -98,7 +98,6 @@ void CWeaponRevolver::PlayAnimReload() PlayHUDMotion("anm_reload_5", true, this, state); else PlayHUDMotion("anm_reload", true, this, state); - } diff --git a/src/xrGame/WeaponStatMgun.cpp b/src/xrGame/WeaponStatMgun.cpp index e8d90c7c80d..d3f3adc6fb2 100644 --- a/src/xrGame/WeaponStatMgun.cpp +++ b/src/xrGame/WeaponStatMgun.cpp @@ -62,7 +62,7 @@ void CWeaponStatMgun::ResetBoneCallbacks() m_pPhysicsShell->EnabledCallbacks(TRUE); } -void CWeaponStatMgun::Load(LPCSTR section) +void CWeaponStatMgun::Load(cpcstr section) { inheritedPH::Load(section); inheritedShooting::Load(section); @@ -74,6 +74,15 @@ void CWeaponStatMgun::Load(LPCSTR section) camRelaxSpeed = pSettings->r_float(section, "cam_relax_speed"); camRelaxSpeed = _abs(deg2rad(camRelaxSpeed)); + m_overheat_enabled = pSettings->read_if_exists(section, "overheat_enabled", false); + m_overheat_time_quant = pSettings->read_if_exists(section, "overheat_time_quant", 0.025f); + m_overheat_decr_quant = pSettings->read_if_exists(section, "overheat_decr_quant", 0.002f); + m_overheat_threshold = pSettings->read_if_exists(section, "overheat_threshold", 110.f); + m_overheat_particles = pSettings->read_if_exists(section, "overheat_particles", "damage_fx\\burn_creatures00"); + + m_bEnterLocked = pSettings->read_if_exists(section, "lock_enter", false); + m_bExitLocked = pSettings->read_if_exists(section, "lock_exit", false); + VERIFY(!fis_zero(camMaxAngle)); VERIFY(!fis_zero(camRelaxSpeed)); } @@ -129,6 +138,12 @@ bool CWeaponStatMgun::net_Spawn(CSE_Abstract* DC) void CWeaponStatMgun::net_Destroy() { + if (p_overheat) + { + if (p_overheat->IsPlaying()) + p_overheat->Stop(false); + CParticlesObject::Destroy(p_overheat); + } inheritedPH::net_Destroy(); processing_deactivate(); } diff --git a/src/xrGame/WeaponStatMgun.h b/src/xrGame/WeaponStatMgun.h index e2cb598f77e..6ceaa4336ad 100644 --- a/src/xrGame/WeaponStatMgun.h +++ b/src/xrGame/WeaponStatMgun.h @@ -62,6 +62,15 @@ class CWeaponStatMgun : public CPhysicsShellHolder, public CHolderCustom, public float camRelaxSpeed; float camMaxAngle; + bool m_firing_disabled{}; + bool m_overheat_enabled{}; + float m_overheat_value{}; + float m_overheat_time_quant{}; + float m_overheat_decr_quant{}; + float m_overheat_threshold{}; + shared_str m_overheat_particles; + CParticlesObject* p_overheat{}; + protected: void UpdateBarrelDir(); virtual const Fvector& get_CurrentFirePoint(); diff --git a/src/xrGame/WeaponStatMgunFire.cpp b/src/xrGame/WeaponStatMgunFire.cpp index 52b57f74d40..afc7bbb90e7 100644 --- a/src/xrGame/WeaponStatMgunFire.cpp +++ b/src/xrGame/WeaponStatMgunFire.cpp @@ -12,6 +12,9 @@ const Fvector& CWeaponStatMgun::get_CurrentFirePoint() { return m_fire_pos; } const Fmatrix& CWeaponStatMgun::get_ParticlesXFORM() { return m_fire_bone_xform; } void CWeaponStatMgun::FireStart() { + if (m_firing_disabled) + return; + m_dAngle.set(0.0f, 0.0f); inheritedShooting::FireStart(); } @@ -31,12 +34,64 @@ void CWeaponStatMgun::UpdateFire() inheritedShooting::UpdateFlameParticles(); inheritedShooting::UpdateLight(); + if (m_overheat_enabled) + { + m_overheat_value -= m_overheat_decr_quant; + if (m_overheat_value < 100.f) + { + if (p_overheat) + { + if (p_overheat->IsPlaying()) + p_overheat->Stop(false); + CParticlesObject::Destroy(p_overheat); + } + if (m_firing_disabled) + m_firing_disabled = false; + } + else { + if (p_overheat) + { + Fmatrix pos; + pos.set(get_ParticlesXFORM()); + pos.c.set(get_CurrentFirePoint()); + p_overheat->SetXFORM(pos); + } + } + } + if (!IsWorking()) { clamp(fShotTimeCounter, 0.0f, flt_max); + clamp(m_overheat_value, 0.0f, m_overheat_threshold); return; } + if (m_overheat_enabled) + { + m_overheat_value += m_overheat_time_quant; + clamp(m_overheat_value, 0.0f, m_overheat_threshold); + + if (m_overheat_value >= 100.f) + { + if (!p_overheat) + { + p_overheat = CParticlesObject::Create(m_overheat_particles.c_str(),FALSE); + Fmatrix pos; + pos.set(get_ParticlesXFORM()); + pos.c.set(get_CurrentFirePoint()); + p_overheat->SetXFORM(pos); + p_overheat->Play(false); + } + + if (m_overheat_value >= m_overheat_threshold) + { + m_firing_disabled = true; + FireEnd(); + return; + } + } + } + if (fShotTimeCounter <= 0) { OnShot(); @@ -53,7 +108,7 @@ void CWeaponStatMgun::OnShot() { VERIFY(Owner()); - FireBullet(m_fire_pos, m_fire_dir, fireDispersionBase, *m_Ammo, Owner()->ID(), ID(), SendHitAllowed(Owner())); + FireBullet(m_fire_pos, m_fire_dir, fireDispersionBase, *m_Ammo, Owner()->ID(), ID(), SendHitAllowed(Owner()), ::Random.randI(0,30)); StartShotParticles(); diff --git a/src/xrGame/accumulative_states.h b/src/xrGame/accumulative_states.h index 55f7ac28636..34b7994fd7e 100644 --- a/src/xrGame/accumulative_states.h +++ b/src/xrGame/accumulative_states.h @@ -1,6 +1,8 @@ #ifndef ACCUMULATIVE_STATES_INCLUDED #define ACCUMULATIVE_STATES_INCLUDED +#include + namespace award_system { enum enum_accumulative_player_values diff --git a/src/xrGame/action_base.h b/src/xrGame/action_base.h index 6a81559729d..319e9227061 100644 --- a/src/xrGame/action_base.h +++ b/src/xrGame/action_base.h @@ -47,9 +47,9 @@ class CActionBase : public GraphEngineSpace::CWorldOperator mutable edge_value_type m_weight; bool m_first_time; -#ifdef LOG_ACTION public: - LPCSTR m_action_name; + pcstr m_action_name{}; +#ifdef LOG_ACTION bool m_use_log; bool m_switched; diff --git a/src/xrGame/action_base_inline.h b/src/xrGame/action_base_inline.h index 8c51701068a..04974c82ac3 100644 --- a/src/xrGame/action_base_inline.h +++ b/src/xrGame/action_base_inline.h @@ -25,9 +25,9 @@ void CBaseAction::init(_object_type* object, LPCSTR action_name) m_object = object; m_weight = edge_value_type(1); + m_action_name = action_name; #ifdef LOG_ACTION m_use_log = false; - m_action_name = action_name; m_switched = false; // if (xr_strlen(m_action_name)) // debug_log (eActionStateConstructed); diff --git a/src/xrGame/action_planner_inline.h b/src/xrGame/action_planner_inline.h index 3a98aa02040..247d551acb6 100644 --- a/src/xrGame/action_planner_inline.h +++ b/src/xrGame/action_planner_inline.h @@ -69,26 +69,29 @@ void CPlanner::update() } } #endif + //Alundaio: debug action + static bool bDbgAct = strstr(Core.Params, "-dbgact") != NULL; #ifdef LOG_ACTION if (this->m_failed) { // printing current world state show(); - - Msg("! ERROR : there is no action sequence, which can transfer current world state to the target one"); - Msg("Time : %6d", Device.dwTimeGlobal); - Msg("Object : %s", object_name()); - + Msg("! ERROR: there is no action sequence, which can transfer current world state to the target one: action[%s] object[%s], time[%6d]", + object_name(), current_action().m_action_name, Device.dwTimeGlobal); show_current_world_state(); show_target_world_state(); - // VERIFY2 (!this->m_failed,"Problem solver couldn't build a valid path - verify your - //conditions, - // effects and goals!"); } +#else + if (bDbgAct && this->m_failed && current_action().m_action_name) + Msg("! ERROR: there is no action sequence, which can transfer current world state to the target one: action[%s]", current_action().m_action_name); #endif THROW(!this->solution().empty()); + //Alundaio: + if (this->solution().empty()) + return; + //-Alundaio if (initialized()) { @@ -96,6 +99,9 @@ void CPlanner::update() { current_action().finalize(); m_current_action_id = this->solution().front(); + //Alundaio: More detailed logging for initializing action + if (bDbgAct) + Msg("DEBUG: Action [%s] initializing", current_action().m_action_name); current_action().initialize(); } } @@ -103,9 +109,17 @@ void CPlanner::update() { m_initialized = true; m_current_action_id = this->solution().front(); + //Alundaio: More detailed logging for initializing action + if (bDbgAct) + Msg("DEBUG: Action [%s] initializing", current_action().m_action_name); current_action().initialize(); } + //Alundaio: More detailed logging for executing action; Knowing the last executing action before a crash can be very useful for debugging + if (bDbgAct) + Msg("DEBUG: Action [%s] executing", current_action().m_action_name); + //-Alundaio: Debug Action + current_action().execute(); } diff --git a/src/xrGame/ai/monsters/monster_sound_memory.h b/src/xrGame/ai/monsters/monster_sound_memory.h index 310a1d5b3c8..23f82c0f270 100644 --- a/src/xrGame/ai/monsters/monster_sound_memory.h +++ b/src/xrGame/ai/monsters/monster_sound_memory.h @@ -65,7 +65,7 @@ typedef struct tagSoundElement } TSoundDangerValue ConvertSoundType(ESoundTypes stype); - void CalcValue(TTime cur_time, Fvector cur_pos) + void CalcValue(TTime cur_time, const Fvector& cur_pos) { value = FACTOR_SOUND_TYPE * u32(NONE_DANGEROUS_SOUND - WEAPON_SHOOTING) - iFloor(FACTOR_DISTANCE * cur_pos.distance_to(position)) - diff --git a/src/xrGame/ai/phantom/phantom.cpp b/src/xrGame/ai/phantom/phantom.cpp index ef7fe6eb50b..e171b5c2028 100644 --- a/src/xrGame/ai/phantom/phantom.cpp +++ b/src/xrGame/ai/phantom/phantom.cpp @@ -76,12 +76,12 @@ bool CPhantom::net_Spawn(CSE_Abstract* DC) SwitchToState(stBirth); // initial state (changed on load method in inherited::) + OBJ->set_killer_id(u16(-1)); // Alundaio: Hack to prevent strange crash with dynamic phantoms + // inherited if (!inherited::net_Spawn(DC)) return FALSE; - OBJ->set_killer_id(u16(-1)); // Alundaio: Hack to prevent strange crash with dynamic phantoms - m_enemy = Level().CurrentEntity(); VERIFY(m_enemy); @@ -294,7 +294,7 @@ void CPhantom::Hit(SHit* pHDS) SwitchToState(stShoot); if (g_Alive()) { - SetfHealth(-1.f); + //SetfHealth(-1.f); // inherited::Hit (P,dir,who,element,p_in_object_space,impulse/100.f, hit_type); inherited::Hit(pHDS); } @@ -354,8 +354,14 @@ void CPhantom::PsyHit(const IGameObject* object, float value) //--------------------------------------------------------------------- // Core events -void CPhantom::save(NET_Packet& output_packet) { output_packet.w_s32(s32(m_CurState)); } -void CPhantom::load(IReader& input_packet) { SwitchToState(EState(input_packet.r_s32())); } +void CPhantom::save(NET_Packet& output_packet) +{ + //output_packet.w_s32(s32(m_CurState)); +} +void CPhantom::load(IReader& input_packet) +{ + //SwitchToState(EState(input_packet.r_s32())); +} void CPhantom::net_Export(NET_Packet& P) // export to server { // export diff --git a/src/xrGame/ai/stalker/ai_stalker_fire.cpp b/src/xrGame/ai/stalker/ai_stalker_fire.cpp index 5cdd52ee4bb..0d3778f7ae7 100644 --- a/src/xrGame/ai/stalker/ai_stalker_fire.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_fire.cpp @@ -49,6 +49,7 @@ #include "stalker_planner.h" #include "stalker_decision_space.h" #include "script_game_object.h" +#include "script_game_object_impl.h" #include "Inventory.h" #include "trajectories.h" @@ -229,6 +230,14 @@ void CAI_Stalker::Hit(SHit* pHDS) SHit HDS = *pHDS; HDS.add_wound = true; + //AVO: get bone names from IDs + //if (HDS.whoID == 0) // if shot by actor + //{ + // pcstr bone_name = smart_cast(Visual())->LL_BoneName_dbg(HDS.boneID); + // Msg("Bone [%d]->[%s]", HDS.boneID, bone_name); + //} + //-AVO + float hit_power = HDS.power * m_fRankImmunity; if (m_boneHitProtection && HDS.hit_type == ALife::eHitTypeFireWound) @@ -405,7 +414,22 @@ void CAI_Stalker::update_best_item_info() void CAI_Stalker::update_best_item_info_impl() { + luabind::functor funct; + if (GEnv.ScriptEngine->functor("ai_stalker.update_best_weapon", funct)) + { + CGameObject* cur_itm = smart_cast(m_best_item_to_kill); + CScriptGameObject* GO = funct(lua_game_object(),cur_itm ? cur_itm->lua_game_object() : nullptr); + CInventoryItem* bw = GO ? smart_cast(&GO->object()): nullptr; + if (bw) + { + m_best_item_to_kill = bw; + m_best_ammo = bw; + return; + } + } + ai().ef_storage().alife_evaluation(false); + /* Alundaio: This is what causes stalkers to switch weapons during combat; It's stupid if (m_item_actuality && m_best_item_to_kill && m_best_item_to_kill->can_kill()) { if (!memory().enemy().selected()) @@ -419,6 +443,7 @@ void CAI_Stalker::update_best_item_info_impl() if (fsimilar(value, m_best_item_value)) return; } + */ // initialize parameters m_item_actuality = true; diff --git a/src/xrGame/ai_debug.h b/src/xrGame/ai_debug.h index 5e29378f905..6d76a14e1ca 100644 --- a/src/xrGame/ai_debug.h +++ b/src/xrGame/ai_debug.h @@ -14,7 +14,6 @@ #define aiMotion (1 << 2) #define aiFrustum (1 << 3) #define aiFuncs (1 << 4) -#define aiALife (1 << 5) #define aiGOAP (1 << 7) #define aiCover (1 << 8) #define aiAnimation (1 << 9) @@ -40,6 +39,7 @@ #endif // DEBUG #if defined(DEBUG) || !defined(MASTER_GOLD) +#define aiALife (1 << 5) #define aiIgnoreActor (1 << 24) #define aiObstaclesAvoiding (1 << 28) #define aiObstaclesAvoidingStatic (1 << 29) diff --git a/src/xrGame/alife_dynamic_object.cpp b/src/xrGame/alife_dynamic_object.cpp index 01e4bdea3d4..24ee197fba0 100644 --- a/src/xrGame/alife_dynamic_object.cpp +++ b/src/xrGame/alife_dynamic_object.cpp @@ -41,7 +41,14 @@ void CSE_ALifeDynamicObject::on_before_register() {} #include "Level.h" #include "map_manager.h" -void CSE_ALifeDynamicObject::on_unregister() { Level().MapManager().OnObjectDestroyNotify(ID); } +void CSE_ALifeDynamicObject::on_unregister() +{ + luabind::functor funct; + if (GEnv.ScriptEngine->functor("_G.CSE_ALifeDynamicObject_on_unregister", funct)) + funct(ID); + Level().MapManager().OnObjectDestroyNotify(ID); +} + void CSE_ALifeDynamicObject::switch_online() { R_ASSERT(!m_bOnline); diff --git a/src/xrGame/alife_object.cpp b/src/xrGame/alife_object.cpp index d16dd09c8f5..080ce80d135 100644 --- a/src/xrGame/alife_object.cpp +++ b/src/xrGame/alife_object.cpp @@ -32,14 +32,15 @@ void CSE_ALifeObject::spawn_supplies(LPCSTR ini_string) // No need to spawn ammo, this will automatically spawn 1 box for weapon and if ammo_type is specified it will spawn that type // count is used only for ammo boxes (ie wpn_pm = 3) will spawn 3 boxes, not 3 wpn_pm // Usage: to create random weapon loadouts - if (ini.section_exist("spawn_loadout")) + static constexpr cpcstr LOADOUT_SECTION = "spawn_loadout"; + if (ini.section_exist(LOADOUT_SECTION)) { pcstr itmSection, V; xr_vector OnlyOne; - pcstr lname = *ai().game_graph().header().level(ai().game_graph().vertex(m_tGraphID)->level_id()).name(); + pcstr lname = ai().game_graph().header().level(ai().game_graph().vertex(m_tGraphID)->level_id()).name().c_str(); - for (u32 k = 0; ini.r_line("spawn_loadout", k, &itmSection, &V); k++) + for (u32 k = 0; ini.r_line(LOADOUT_SECTION, k, &itmSection, &V); k++) { // If level= then only spawn items if object on that level if (strstr(V, "level=") != nullptr) @@ -56,7 +57,7 @@ void CSE_ALifeObject::spawn_supplies(LPCSTR ini_string) if (!OnlyOne.empty()) { s32 sel = Random.randI(0, OnlyOne.size()); - if (ini.r_line("spawn_loadout", OnlyOne.at(sel), &itmSection, &V)) + if (ini.r_line(LOADOUT_SECTION, OnlyOne.at(sel), &itmSection, &V)) { VERIFY(xr_strlen(itmSection)); if (pSettings->section_exist(itmSection)) @@ -116,8 +117,7 @@ void CSE_ALifeObject::spawn_supplies(LPCSTR ini_string) alife().spawn_item(ammoSec, o_Position, m_tNodeID, m_tGraphID, ID); } } - CSE_ALifeInventoryItem* IItem = smart_cast(E); - if (IItem) + if (const auto IItem = smart_cast(E)) IItem->m_fCondition = f_cond; } } diff --git a/src/xrGame/alife_simulator_script.cpp b/src/xrGame/alife_simulator_script.cpp index 2fdb5de572d..4076474e732 100644 --- a/src/xrGame/alife_simulator_script.cpp +++ b/src/xrGame/alife_simulator_script.cpp @@ -30,16 +30,22 @@ STORY_PAIRS story_ids; SPAWN_STORY_PAIRS spawn_story_ids; CALifeSimulator* alife() { return (const_cast(ai().get_alife())); } -CSE_ALifeDynamicObject* alife_object(const CALifeSimulator* self, ALife::_OBJECT_ID object_id) + +bool valid_object_id(const CALifeSimulator* self, ALife::_OBJECT_ID object_id) { VERIFY(self); - return (self->objects().object(object_id, true)); + return (object_id != 0xffff); } -bool valid_object_id(const CALifeSimulator* self, ALife::_OBJECT_ID object_id) +CSE_ALifeDynamicObject* alife_object(const CALifeSimulator* self, ALife::_OBJECT_ID object_id) { VERIFY(self); - return (object_id != 0xffff); + if (!valid_object_id(self, object_id)) + { + Log("! alife():object(id): invalid id specified"); + return nullptr; + } + return (self->objects().object(object_id, true)); } CSE_ALifeDynamicObject* alife_object(const CALifeSimulator* self, pcstr name) @@ -184,6 +190,32 @@ CSE_Abstract* CALifeSimulator__spawn_item2(CALifeSimulator* self, LPCSTR section return (self->server().Process_spawn(packet, clientID)); } +//Alundaio: Allows to call alife():register(se_obj) manually afterward so that packet editing can be done safely when spawning object with a parent +CSE_Abstract* CALifeSimulator__spawn_item3(CALifeSimulator* self, pcstr section, const Fvector& position, + u32 level_vertex_id, GameGraph::_GRAPH_ID game_vertex_id, + ALife::_OBJECT_ID id_parent, bool reg = true) +{ + if (reg) + return CALifeSimulator__spawn_item2(self, section, position, level_vertex_id, game_vertex_id, id_parent); + + if (id_parent == ALife::_OBJECT_ID(-1)) + return (self->spawn_item(section, position, level_vertex_id, game_vertex_id, id_parent)); + + const auto object = ai().alife().objects().object(id_parent, true); + if (!object) + { + Msg("! invalid parent id [%d] specified", id_parent); + return nullptr; + } + + if (!object->m_bOnline) + return (self->spawn_item(section, position, level_vertex_id, game_vertex_id, id_parent)); + + CSE_Abstract* item = self->spawn_item(section, position, level_vertex_id, game_vertex_id, id_parent, false); + + return item; +} + CSE_Abstract* CALifeSimulator__spawn_ammo(CALifeSimulator* self, LPCSTR section, const Fvector& position, u32 level_vertex_id, GameGraph::_GRAPH_ID game_vertex_id, ALife::_OBJECT_ID id_parent, int ammo_to_spawn) { @@ -309,17 +341,15 @@ void teleport_object(CALifeSimulator* alife, ALife::_OBJECT_ID id, GameGraph::_G { alife->teleport_object(id, game_vertex_id, level_vertex_id, position); } -//-Alundaio -void iterate_objects(const CALifeSimulator* self, luabind::functor functor) +void IterateInfo(const CALifeSimulator* alife, const ALife::_OBJECT_ID& id, const luabind::functor& functor) { - THROW(self); - for (const auto& it : self->objects().objects()) - { - CSE_ALifeDynamicObject* obj = it.second; - if (functor(obj)) - return; - } + const auto known_info = registry(alife, id); + if (!known_info) + return; + + for (const auto& it : *known_info) + functor(id, it.info_id); } CSE_Abstract* reprocess_spawn(CALifeSimulator* self, CSE_Abstract* object) @@ -340,6 +370,7 @@ CSE_Abstract* reprocess_spawn(CALifeSimulator* self, CSE_Abstract* object) return self->server().Process_spawn(packet, clientID); } + CSE_Abstract* try_to_clone_object(CALifeSimulator* self, CSE_Abstract* object, pcstr section, const Fvector& position, u32 level_vertex_id, GameGraph::_GRAPH_ID game_vertex_id, ALife::_OBJECT_ID id_parent, bool bRegister = true) @@ -387,15 +418,17 @@ xr_vector& get_children(const CALifeSimulator* self, CSE_Abstract* object) VERIFY(self); return object->children; } +//-Alundaio -void IterateInfo(const CALifeSimulator* alife, const ALife::_OBJECT_ID& id, const luabind::functor& functor) +void iterate_objects(const CALifeSimulator* self, luabind::functor functor) { - const auto known_info = registry(alife, id); - if (!known_info) - return; - - for (const auto& it : *known_info) - functor(id, it.info_id); + THROW(self); + for (const auto& it : self->objects().objects()) + { + CSE_ALifeDynamicObject* obj = it.second; + if (functor(obj)) + return; + } } void set_start_position(Fvector& pos) @@ -443,6 +476,7 @@ SCRIPT_EXPORT(CALifeSimulator, (), .def("create", &CALifeSimulator__create) .def("create", &CALifeSimulator__spawn_item2) .def("create", &CALifeSimulator__spawn_item) + .def("create", &CALifeSimulator__spawn_item3) .def("create_ammo", &CALifeSimulator__spawn_ammo) .def("release", &CALifeSimulator__release) .def("spawn_id", &CALifeSimulator__spawn_id) @@ -456,7 +490,6 @@ SCRIPT_EXPORT(CALifeSimulator, (), (&CALifeSimulator::set_switch_distance)) //Alundaio: renamed to set_switch_distance from switch_distance //Alundaio: extend alife simulator exports .def("teleport_object", &teleport_object) - //Alundaio: END .def("iterate_objects", &iterate_objects) .def("iterate_info", &IterateInfo) .def("clone_weapon", (CSE_Abstract* (*)(CALifeSimulator*, CSE_Abstract*, pcstr, const Fvector&, u32, @@ -467,6 +500,7 @@ SCRIPT_EXPORT(CALifeSimulator, (), .def("set_objects_per_update", &set_objects_per_update) .def("set_process_time", &set_process_time) .def("get_children", &get_children, return_stl_iterator()), + //Alundaio: END def("alife", &alife), def("set_start_position", &set_start_position), diff --git a/src/xrGame/alife_storage_manager.cpp b/src/xrGame/alife_storage_manager.cpp index 0c10232c4ef..a04a41d5083 100644 --- a/src/xrGame/alife_storage_manager.cpp +++ b/src/xrGame/alife_storage_manager.cpp @@ -55,6 +55,12 @@ void CALifeStorageManager::save(LPCSTR save_name_no_check, bool update_name) } } + //Alundaio: To get the savegame fname to make our own custom save states + luabind::functor funct1; + if (GEnv.ScriptEngine->functor("alife_storage_manager.CALifeStorageManager_before_save", funct1)) + funct1((pcstr)m_save_name); + //-Alundaio + u32 source_count; u32 dest_count; void* dest_data; @@ -90,12 +96,24 @@ void CALifeStorageManager::save(LPCSTR save_name_no_check, bool update_name) Msg("* Game %s is successfully saved to file '%s'", m_save_name, temp); #endif // DEBUG + //Alundaio: To get the savegame fname to make our own custom save states + luabind::functor funct2; + if (GEnv.ScriptEngine->functor("alife_storage_manager.CALifeStorageManager_save", funct2)) + funct2((pcstr)m_save_name); + //-Alundaio + if (!update_name) xr_strcpy(m_save_name, saveBackup); } void CALifeStorageManager::load(void* buffer, const u32& buffer_size, LPCSTR file_name) { + //Alundaio: So we can get the fname to make our own custom save states + luabind::functor funct; + if (GEnv.ScriptEngine->functor("alife_storage_manager.CALifeStorageManager_load", funct)) + funct(file_name); + //-Alundaio + IReader source(buffer, buffer_size); header().load(source); time_manager().load(source); diff --git a/src/xrGame/alife_switch_manager.cpp b/src/xrGame/alife_switch_manager.cpp index 1a24ecfb295..6837e602eb5 100644 --- a/src/xrGame/alife_switch_manager.cpp +++ b/src/xrGame/alife_switch_manager.cpp @@ -61,10 +61,11 @@ void CALifeSwitchManager::add_online(CSE_ALifeDynamicObject* object, bool update server().Process_spawn(tNetPacket, clientID, FALSE, l_tpAbstract); object->s_flags._and (u16(-1) ^ M_SPAWN_UPDATE); - R_ASSERT3(!object->used_ai_locations() || ai().level_graph().valid_vertex_id(object->m_tNodeID), - "Invalid vertex for object ", object->name_replace()); + //Alundaio: Workaround for crash with corpses that end up outside AI map + //R_ASSERT3(!object->used_ai_locations() || ai().level_graph().valid_vertex_id(object->m_tNodeID), + // "Invalid vertex for object ", object->name_replace()); -#ifdef DEBUG +#ifndef MASTER_GOLD if (psAI_Flags.test(aiALife)) Msg("[LSS] Spawning object [%s][%s][%d]", object->name_replace(), *object->s_name, object->ID); #endif diff --git a/src/xrGame/alife_update_manager.cpp b/src/xrGame/alife_update_manager.cpp index 339bbfeb8f8..a4552ae2be2 100644 --- a/src/xrGame/alife_update_manager.cpp +++ b/src/xrGame/alife_update_manager.cpp @@ -136,6 +136,10 @@ bool CALifeUpdateManager::change_level(NET_Packet& net_packet) if (m_changing_level) return (false); + luabind::functor funct; + if (GEnv.ScriptEngine->functor("_G.CALifeUpdateManager__on_before_change_level", funct)) + funct(&net_packet); + // prepare_objects_for_save (); // we couldn't use prepare_objects_for_save since we need // get updates from client diff --git a/src/xrGame/console_commands.cpp b/src/xrGame/console_commands.cpp index 680dd543bbe..44570706fad 100644 --- a/src/xrGame/console_commands.cpp +++ b/src/xrGame/console_commands.cpp @@ -2205,6 +2205,7 @@ void CCC_RegisterCommands() CMD3(CCC_Mask, "g_important_save", &psActorFlags, AF_IMPORTANT_SAVE); CMD3(CCC_Mask, "g_loading_stages", &psActorFlags, AF_LOADING_STAGES); CMD3(CCC_Mask, "g_always_use_attitude_sensors", &psActorFlags, AF_ALWAYS_USE_ATTITUDE_SENSORS); + CMD3(CCC_Mask, "g_use_tracers", &psActorFlags, AF_USE_TRACERS); CMD4(CCC_Integer, "g_inv_highlight_equipped", &g_inv_highlight_equipped, 0, 1); CMD4(CCC_Integer, "g_first_person_death", &g_first_person_death, 0, 1); diff --git a/src/xrGame/game_object_space.h b/src/xrGame/game_object_space.h index 7e31cd11226..0419aee13d0 100644 --- a/src/xrGame/game_object_space.h +++ b/src/xrGame/game_object_space.h @@ -54,6 +54,9 @@ enum ECallbackType : u32 eInvBoxItemTake, eWeaponNoAmmoAvailable, + //Alundaio: added defines + eActorHudAnimationEnd, + //AVO: custom callbacks // Input eKeyPress, @@ -69,19 +72,18 @@ enum ECallbackType : u32 eItemToBelt, eItemToSlot, eItemToRuck, + // weapon + eOnWeaponZoomIn, + eOnWeaponZoomOut, + eOnWeaponJammed, + eOnWeaponMagazineEmpty, // Actor eActorBeforeDeath, - //-AVO - // vehicle eAttachVehicle, eDetachVehicle, eUseVehicle, - - // weapon - eOnWeaponZoomIn, - eOnWeaponZoomOut, - eOnWeaponJammed, + //-AVO eDummy = u32(-1), }; diff --git a/src/xrGame/holder_custom.h b/src/xrGame/holder_custom.h index 01ee9449ee4..17022f62873 100644 --- a/src/xrGame/holder_custom.h +++ b/src/xrGame/holder_custom.h @@ -14,6 +14,14 @@ class CHolderCustom protected: CGameObject* Owner() { return m_owner; } CActor* OwnerActor() { return m_ownerActor; } + +protected: + bool m_bEnterLocked{}; + bool m_bExitLocked{}; + +public: + shared_str m_sUseAction; + public: CHolderCustom() { @@ -42,6 +50,10 @@ class CHolderCustom virtual void cam_Update(float dt, float fov = 90.0f) = 0; + bool EnterLocked() const { return m_bEnterLocked; } + bool ExitLocked() const { return m_bExitLocked; } + void SetEnterLocked(bool v) { m_bEnterLocked = v; } + void SetExitLocked(bool v) { m_bExitLocked = v; } virtual bool Use(const Fvector& pos, const Fvector& dir, const Fvector& foot_pos) = 0; virtual bool attach_Actor(CGameObject* actor); virtual void detach_Actor(); diff --git a/src/xrGame/holder_custom_script.cpp b/src/xrGame/holder_custom_script.cpp index 7f4908289a0..b76564cfcac 100644 --- a/src/xrGame/holder_custom_script.cpp +++ b/src/xrGame/holder_custom_script.cpp @@ -11,8 +11,9 @@ SCRIPT_EXPORT(CHolderCustom, (), class_("holder") .def("engaged", &CHolderCustom::Engaged) .def("Action", &CHolderCustom::Action) - // .def("SetParam", (void (CHolderCustom::*)(int,Fvector2)) - //&CHolderCustom::SetParam) + // .def("SetParam", (void (CHolderCustom::*)(int,Fvector2))&CHolderCustom::SetParam) .def("SetParam", (void (CHolderCustom::*)(int, Fvector)) & CHolderCustom::SetParam) + .def("SetEnterLocked", &CHolderCustom::SetEnterLocked) + .def("SetExitLocked", &CHolderCustom::SetExitLocked) ]; }); diff --git a/src/xrGame/inventory_item.cpp b/src/xrGame/inventory_item.cpp index b8548a4ac83..a2ebae0de28 100644 --- a/src/xrGame/inventory_item.cpp +++ b/src/xrGame/inventory_item.cpp @@ -119,6 +119,8 @@ void CInventoryItem::Load(LPCSTR section) // Added by Axel, to enable optional condition use on any item m_flags.set(FUsingCondition, READ_IF_EXISTS(pSettings, r_bool, section, "use_condition", false)); + m_highlight_equipped = READ_IF_EXISTS(pSettings, r_bool, section, "highlight_equipped", false); + if (BaseSlot() != NO_ACTIVE_SLOT || Belt()) { m_flags.set(FRuckDefault, pSettings->read_if_exists(section, "default_to_ruck", true)); diff --git a/src/xrGame/inventory_item.h b/src/xrGame/inventory_item.h index 496a810a482..be5a755b0eb 100644 --- a/src/xrGame/inventory_item.h +++ b/src/xrGame/inventory_item.h @@ -154,6 +154,7 @@ class CInventoryItem : public CAttachableItem, shared_str m_name; shared_str m_nameShort; shared_str m_nameComplex; + bool m_highlight_equipped; SInvItemPlace m_ItemCurrPlace; @@ -288,9 +289,7 @@ class CInventoryItem : public CAttachableItem, bool has_upgrade_group_by_upgrade_id(const shared_str& upgrade_id); void add_upgrade(const shared_str& upgrade_id, bool loading); bool get_upgrades_str(string2048& res) const; -#ifdef GAME_OBJECT_EXTENDED_EXPORTS Upgrades_type get_upgrades() { return m_upgrades; } //Alundaio -#endif bool equal_upgrades(Upgrades_type const& other_upgrades) const; diff --git a/src/xrGame/inventory_upgrade.h b/src/xrGame/inventory_upgrade.h index d47a730702b..2b0a3316988 100644 --- a/src/xrGame/inventory_upgrade.h +++ b/src/xrGame/inventory_upgrade.h @@ -74,7 +74,7 @@ struct functor3 : public functor2 enum EMaxProps { - max_properties_count = 3, + max_properties_count = 4, }; class Upgrade : public UpgradeBase diff --git a/src/xrGame/level_script.cpp b/src/xrGame/level_script.cpp index bda80dcc7cc..62711bf91e8 100644 --- a/src/xrGame/level_script.cpp +++ b/src/xrGame/level_script.cpp @@ -739,14 +739,13 @@ IC static void CLevel_Export(lua_State* luaState) [ //Alundaio: Extend level namespace exports def("send", &g_send) , //allow the ability to send netpacket to level - //def("ray_pick",g_ray_pick), def("get_target_obj", &g_get_target_obj), //intentionally named to what is in xray extensions def("get_target_dist", &g_get_target_dist), def("get_target_element", &g_get_target_element), //Can get bone cursor is targeting def("spawn_item", &spawn_section), def("get_active_cam", &get_active_cam), def("set_active_cam", &set_active_cam), - def("get_start_time", +[]() { return xrTime(Level().GetStartGameTime()); }), + def("get_start_time", +[]() -> xrTime { return xrTime(Level().GetStartGameTime()); }), def("valid_vertex", +[](u32 level_vertex_id) { return ai().level_graph().valid_vertex_id(level_vertex_id); @@ -863,34 +862,34 @@ IC static void CLevel_Export(lua_State* luaState) module(luaState) [ class_("ray_pick") - .def(constructor<>()) - .def(constructor()) - .def("set_position", &CRayPick::set_position) - .def("set_direction", &CRayPick::set_direction) - .def("set_range", &CRayPick::set_range) - .def("set_flags", &CRayPick::set_flags) - .def("set_ignore_object", &CRayPick::set_ignore_object) - .def("query", &CRayPick::query) - .def("get_result", &CRayPick::get_result) - .def("get_object", &CRayPick::get_object) - .def("get_distance", &CRayPick::get_distance) - .def("get_element", &CRayPick::get_element), + .def(constructor<>()) + .def(constructor()) + .def("set_position", &CRayPick::set_position) + .def("set_direction", &CRayPick::set_direction) + .def("set_range", &CRayPick::set_range) + .def("set_flags", &CRayPick::set_flags) + .def("set_ignore_object", &CRayPick::set_ignore_object) + .def("query", &CRayPick::query) + .def("get_result", &CRayPick::get_result) + .def("get_object", &CRayPick::get_object) + .def("get_distance", &CRayPick::get_distance) + .def("get_element", &CRayPick::get_element), class_("rq_result") - .def_readonly("object", &script_rq_result::O) - .def_readonly("range", &script_rq_result::range) - .def_readonly("element", &script_rq_result::element) - .def(constructor<>()), + .def_readonly("object", &script_rq_result::O) + .def_readonly("range", &script_rq_result::range) + .def_readonly("element", &script_rq_result::element) + .def(constructor<>()), class_>("rq_target") - .enum_("targets") - [ - value("rqtNone", int(collide::rqtNone)), - value("rqtObject", int(collide::rqtObject)), - value("rqtStatic", int(collide::rqtStatic)), - value("rqtShape", int(collide::rqtShape)), - value("rqtObstacle", int(collide::rqtObstacle)), - value("rqtBoth", int(collide::rqtBoth)), - value("rqtDyn", int(collide::rqtDyn)) - ] + .enum_("targets") + [ + value("rqtNone", int(collide::rqtNone)), + value("rqtObject", int(collide::rqtObject)), + value("rqtStatic", int(collide::rqtStatic)), + value("rqtShape", int(collide::rqtShape)), + value("rqtObstacle", int(collide::rqtObstacle)), + value("rqtBoth", int(collide::rqtBoth)), + value("rqtDyn", int(collide::rqtDyn)) + ] ]; module(luaState) diff --git a/src/xrGame/property_evaluator.h b/src/xrGame/property_evaluator.h index 314c9474a3a..d69f2d25304 100644 --- a/src/xrGame/property_evaluator.h +++ b/src/xrGame/property_evaluator.h @@ -24,7 +24,7 @@ class CPropertyEvaluator _object_type* m_object; CPropertyStorage* m_storage; #if 1//def LOG_ACTION //Alundaio: m_evaluator_name - LPCSTR m_evaluator_name; + pcstr m_evaluator_name; #endif public: diff --git a/src/xrGame/purchase_list.cpp b/src/xrGame/purchase_list.cpp index 93630048020..cce4ab77cd0 100644 --- a/src/xrGame/purchase_list.cpp +++ b/src/xrGame/purchase_list.cpp @@ -27,12 +27,21 @@ void CPurchaseList::process(CInifile& ini_file, LPCSTR section, CInventoryOwner& auto E = S.Data.cend(); for (; I != E; ++I) { - VERIFY3((*I).second.size(), "PurchaseList : cannot handle lines in section without values", section); + if (I->second.empty()) + continue; + + if (!pSettings->section_exist(I->first)) + continue; + + //VERIFY3(I->second.size(), "PurchaseList : cannot handle lines in section without values", section); string256 temp0, temp1; - THROW3(_GetItemCount(*(*I).second) == 2, "Invalid parameters in section", section); - process(game_object, (*I).first, atoi(_GetItem(*(*I).second, 0, temp0)), - (float)atof(_GetItem(*(*I).second, 1, temp1))); + //THROW3(_GetItemCount(I->second.c_str()) == 2, "Invalid parameters in section", section); + + cpcstr count = _GetItem(I->second.c_str(), 0, temp0); + cpcstr prob = _GetItemCount(I->second.c_str()) >= 2 ? _GetItem(I->second.c_str(), 1, temp1) : "1.0f"; + + process(game_object, I->first, atoi(count), (float)atof(prob)); } } diff --git a/src/xrGame/script_game_object.cpp b/src/xrGame/script_game_object.cpp index 4a667c27c02..b687cbd0073 100644 --- a/src/xrGame/script_game_object.cpp +++ b/src/xrGame/script_game_object.cpp @@ -348,7 +348,8 @@ void CScriptGameObject::SetAmmoElapsed(int ammo_elapsed) int CScriptGameObject::GetAmmoCount(u8 type) { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return 0; + if (!weapon) + return 0; if (type < weapon->m_ammoTypes.size()) return weapon->GetAmmoCount_forType(weapon->m_ammoTypes[type]); @@ -359,7 +360,8 @@ int CScriptGameObject::GetAmmoCount(u8 type) void CScriptGameObject::SetAmmoType(u8 type) { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return; + if (!weapon) + return; weapon->SetAmmoType(type); } @@ -367,7 +369,8 @@ void CScriptGameObject::SetAmmoType(u8 type) u8 CScriptGameObject::GetAmmoType() { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return 255; + if (!weapon) + return 255; return weapon->GetAmmoType(); } @@ -375,7 +378,8 @@ u8 CScriptGameObject::GetAmmoType() void CScriptGameObject::SetMainWeaponType(u32 type) { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return; + if (!weapon) + return; weapon->set_ef_main_weapon_type(type); } @@ -383,7 +387,8 @@ void CScriptGameObject::SetMainWeaponType(u32 type) void CScriptGameObject::SetWeaponType(u32 type) { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return; + if (!weapon) + return; weapon->set_ef_weapon_type(type); } @@ -391,7 +396,8 @@ void CScriptGameObject::SetWeaponType(u32 type) u32 CScriptGameObject::GetMainWeaponType() { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return 255; + if (!weapon) + return 255; return weapon->ef_main_weapon_type(); } @@ -399,7 +405,8 @@ u32 CScriptGameObject::GetMainWeaponType() u32 CScriptGameObject::GetWeaponType() { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return 255; + if (!weapon) + return 255; return weapon->ef_weapon_type(); } @@ -407,7 +414,8 @@ u32 CScriptGameObject::GetWeaponType() bool CScriptGameObject::HasAmmoType(u8 type) { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return false; + if (!weapon) + return false; return type < weapon->m_ammoTypes.size(); } @@ -415,7 +423,8 @@ bool CScriptGameObject::HasAmmoType(u8 type) u8 CScriptGameObject::GetWeaponSubstate() { CWeapon* weapon = smart_cast(&object()); - if (!weapon) return 255; + if (!weapon) + return 255; return weapon->m_sub_state; } @@ -676,9 +685,6 @@ pcstr CScriptGameObject::get_smart_cover_description() const return smart_cover_object->get_cover().get_description()->table_id().c_str(); } -void CScriptGameObject::set_visual_name(LPCSTR visual) { object().cNameVisual_set(visual); } -LPCSTR CScriptGameObject::get_visual_name() const { return object().cNameVisual().c_str(); } - void CScriptGameObject::PhantomSetEnemy(CScriptGameObject* enemy) { CPhantom* phant = smart_cast(&object()); @@ -688,7 +694,7 @@ void CScriptGameObject::PhantomSetEnemy(CScriptGameObject* enemy) phant->SetEnemy(&enemy->object()); } -//Allows to force use an object if passed obj is the actor +// Allows to force use an object if passed obj is the actor bool CScriptGameObject::Use(CScriptGameObject* obj) { bool ret = object().use(&obj->object()); @@ -697,30 +703,24 @@ bool CScriptGameObject::Use(CScriptGameObject* obj) if (!actor) return ret; - CInventoryOwner* pActorInv = smart_cast(actor); - if (!pActorInv) - return ret; - CUIActorMenu& ActorMenu = CurrentGameUI()->GetActorMenu(); - CInventoryBox* pBox = smart_cast(&object()); - if (pBox) + if (const auto box = smart_cast(&object())) { - ActorMenu.SetActor(pActorInv); - ActorMenu.SetInvBox(pBox); + ActorMenu.SetActor(actor); + ActorMenu.SetInvBox(box); ActorMenu.SetMenuMode(mmDeadBodySearch); ActorMenu.ShowDialog(true); return true; } - else - { - CInventoryOwner* pOtherOwner = smart_cast(&object()); - if (!pOtherOwner) - return ret; - /* + CInventoryOwner* pOtherOwner = smart_cast(&object()); + if (!pOtherOwner) + return ret; + + /* CEntityAlive* e = smart_cast(pOtherOwner); if (e && e->g_Alive()) { @@ -729,16 +729,13 @@ bool CScriptGameObject::Use(CScriptGameObject* obj) } */ - ActorMenu.SetActor(pActorInv); - ActorMenu.SetPartner(pOtherOwner); - - ActorMenu.SetMenuMode(mmDeadBodySearch); - ActorMenu.ShowDialog(true); + ActorMenu.SetActor(actor); + ActorMenu.SetPartner(pOtherOwner); - return true; - } + ActorMenu.SetMenuMode(mmDeadBodySearch); + ActorMenu.ShowDialog(true); - return false; + return true; } void CScriptGameObject::StartTrade(CScriptGameObject* obj) @@ -747,17 +744,13 @@ void CScriptGameObject::StartTrade(CScriptGameObject* obj) if (!actor) return; - CInventoryOwner* pActorInv = smart_cast(actor); - if (!pActorInv) - return; - CInventoryOwner* pOtherOwner = smart_cast(&object()); if (!pOtherOwner) return; CUIActorMenu& ActorMenu = CurrentGameUI()->GetActorMenu(); - ActorMenu.SetActor(pActorInv); + ActorMenu.SetActor(actor); ActorMenu.SetPartner(pOtherOwner); ActorMenu.SetMenuMode(mmTrade); @@ -770,17 +763,13 @@ void CScriptGameObject::StartUpgrade(CScriptGameObject* obj) if (!actor) return; - CInventoryOwner* pActorInv = smart_cast(actor); - if (!pActorInv) - return; - CInventoryOwner* pOtherOwner = smart_cast(&object()); if (!pOtherOwner) return; CUIActorMenu& ActorMenu = CurrentGameUI()->GetActorMenu(); - ActorMenu.SetActor(pActorInv); + ActorMenu.SetActor(actor); ActorMenu.SetPartner(pOtherOwner); ActorMenu.SetMenuMode(mmUpgrade); diff --git a/src/xrGame/script_game_object.h b/src/xrGame/script_game_object.h index eb9da6b8eb5..761a9af6cc4 100644 --- a/src/xrGame/script_game_object.h +++ b/src/xrGame/script_game_object.h @@ -191,11 +191,7 @@ class CScriptGameObject _DECLARE_FUNCTION10(Squad, int); _DECLARE_FUNCTION10(Group, int); - // XXX: this is a workaround, since luabind can't determine default function arguments... - // There is more places, not only this one - // Look here: https://github.com/qweasdd136963/OXR_CoC/commit/c37d8f4e49c92fe226a5958954cc9a6a1ab18c93 - void Kill(CScriptGameObject* who) { Kill(who, false); } - void Kill(CScriptGameObject* who, bool bypass_actor_check /*= false*/ /*AVO: added for actor before death callback*/); + void Kill(CScriptGameObject* who, bool bypass_actor_check = false); // CEntityAlive _DECLARE_FUNCTION10(GetFOV, float); @@ -359,8 +355,8 @@ class CScriptGameObject bool IsInvUpgradeEnabled(); void ActorLookAtPoint(Fvector point); - void IterateInventory(luabind::functor functor, luabind::adl::object object); - void IterateInventoryBox(luabind::functor functor, luabind::adl::object object); + void IterateInventory(luabind::functor functor, luabind::adl::object object); + void IterateInventoryBox(luabind::functor functor, luabind::adl::object object); void MarkItemDropped(CScriptGameObject* item); bool MarkedDropped(CScriptGameObject* item); void UnloadMagazine(); @@ -421,6 +417,7 @@ class CScriptGameObject void SetCharacterRank(int); void ChangeCharacterRank(int); void ChangeCharacterReputation(int); + void SetCharacterReputation(int); void SetCharacterCommunity(LPCSTR, int, int); u32 GetInventoryObjectCount() const; @@ -794,7 +791,45 @@ class CScriptGameObject bool is_door_blocked_by_npc() const; bool is_weapon_going_to_be_strapped(CScriptGameObject const* object) const; -#ifdef GAME_OBJECT_EXTENDED_EXPORTS + //AVO: functions for object testing + //_DECLARE_FUNCTION10(IsGameObject, bool); + //_DECLARE_FUNCTION10(IsCar, bool); + //_DECLARE_FUNCTION10(IsHeli, bool); + //_DECLARE_FUNCTION10(IsHolderCustom, bool); + _DECLARE_FUNCTION10(IsEntityAlive, bool); + _DECLARE_FUNCTION10(IsInventoryItem, bool); + _DECLARE_FUNCTION10(IsInventoryOwner, bool); + _DECLARE_FUNCTION10(IsActor, bool); + _DECLARE_FUNCTION10(IsCustomMonster, bool); + _DECLARE_FUNCTION10(IsWeapon, bool); + //_DECLARE_FUNCTION10(IsMedkit, bool); + //_DECLARE_FUNCTION10(IsEatableItem, bool); + //_DECLARE_FUNCTION10(IsAntirad, bool); + _DECLARE_FUNCTION10(IsCustomOutfit, bool); + _DECLARE_FUNCTION10(IsScope, bool); + _DECLARE_FUNCTION10(IsSilencer, bool); + _DECLARE_FUNCTION10(IsGrenadeLauncher, bool); + _DECLARE_FUNCTION10(IsWeaponMagazined, bool); + _DECLARE_FUNCTION10(IsSpaceRestrictor, bool); + _DECLARE_FUNCTION10(IsStalker, bool); + _DECLARE_FUNCTION10(IsAnomaly, bool); + _DECLARE_FUNCTION10(IsMonster, bool); + //_DECLARE_FUNCTION10(IsExplosive, bool); + //_DECLARE_FUNCTION10(IsScriptZone, bool); + //_DECLARE_FUNCTION10(IsProjector, bool); + _DECLARE_FUNCTION10(IsTrader, bool); + _DECLARE_FUNCTION10(IsHudItem, bool); + //_DECLARE_FUNCTION10(IsFoodItem, bool); + _DECLARE_FUNCTION10(IsArtefact, bool); + _DECLARE_FUNCTION10(IsAmmo, bool); + //_DECLARE_FUNCTION10(IsMissile, bool); + //_DECLARE_FUNCTION10(IsPhysicsShellHolder, bool); + //_DECLARE_FUNCTION10(IsGrenade, bool); + //_DECLARE_FUNCTION10(IsBottleItem, bool); + //_DECLARE_FUNCTION10(IsTorch, bool); + _DECLARE_FUNCTION10(IsWeaponGL, bool); + _DECLARE_FUNCTION10(IsInventoryBox, bool); + // Alundaio void inactualize_level_path(); void inactualize_game_path(); @@ -812,12 +847,13 @@ class CScriptGameObject u8 GetRestrictionType(); void SetRestrictionType(u8 type); - //CWeaponAmmo - u16 AmmoGetCount(); - void AmmoSetCount(u16 count); - u16 AmmoBoxSize(); + void RemoveDanger(const CDangerObject& dobject); + + void RemoveMemorySoundObject(const MemorySpace::CSoundObject& memory_object); + void RemoveMemoryHitObject(const MemorySpace::CHitObject& memory_object); + void RemoveMemoryVisibleObject(const MemorySpace::CVisibleObject& memory_object); - //Weapon + // Weapon void Weapon_AddonAttach(CScriptGameObject* item); void Weapon_AddonDetach(pcstr item_section); bool HasAmmoType(u8 type); @@ -830,7 +866,12 @@ class CScriptGameObject u8 GetWeaponSubstate(); u8 GetAmmoType(); - //Weapon & Outfit + // CWeaponAmmo + u16 AmmoGetCount(); + void AmmoSetCount(u16 count); + u16 AmmoBoxSize(); + + // Weapon & Outfit bool AddUpgrade(pcstr upgrade); bool InstallUpgrade(pcstr upgrade); bool HasUpgrade(pcstr upgrade) const; @@ -839,11 +880,12 @@ class CScriptGameObject bool CanAddUpgrade(pcstr upgrade) const; bool CanInstallUpgrade(pcstr upgrade) const; void IterateInstalledUpgrades(luabind::functor functor); + bool WeaponInGrenadeMode(); //Car CScriptGameObject* GetAttachedVehicle(); - void AttachVehicle(CScriptGameObject* veh); - void DetachVehicle(); + void AttachVehicle(CScriptGameObject* veh, bool bForce = false); + void DetachVehicle(bool bForce = false); //Any class that is derived from CHudItem u32 PlayHudMotion(pcstr M, bool mixIn, u32 state); @@ -854,9 +896,12 @@ class CScriptGameObject bool IsBoneVisible(pcstr bone_name); void SetBoneVisible(pcstr bone_name, bool bVisibility, bool bRecursive = true); - //Anything with PPhysicShell (ie. car, actor, stalker, monster, heli) + // CAI_Stalker + void ResetBoneProtections(pcstr imm_sect, pcstr bone_sect); + // Anything with PPhysicShell (ie. car, actor, stalker, monster, heli) void ForceSetPosition(Fvector pos, bool bActivate = false); + // Artefacts float GetArtefactHealthRestoreSpeed(); float GetArtefactRadiationRestoreSpeed(); float GetArtefactSatietyRestoreSpeed(); @@ -869,53 +914,38 @@ class CScriptGameObject void SetArtefactPowerRestoreSpeed(float value); void SetArtefactBleedingRestoreSpeed(float value); - void RemoveDanger(const CDangerObject& dobject); - - void RemoveMemorySoundObject(const MemorySpace::CSoundObject& memory_object); - void RemoveMemoryHitObject(const MemorySpace::CHitObject& memory_object); - void RemoveMemoryVisibleObject(const MemorySpace::CVisibleObject& memory_object); - - //CAI_Stalker - void ResetBoneProtections(pcstr imm_sect, pcstr bone_sect); - - //Eatable items + // Eatable items void SetRemainingUses(u8 value); u8 GetRemainingUses(); u8 GetMaxUses(); - //Phantom + // Phantom void PhantomSetEnemy(CScriptGameObject*); - //Actor + + // Actor float GetActorMaxWeight() const; void SetActorMaxWeight(float max_weight); - float GetActorMaxWalkWeight() const; void SetActorMaxWalkWeight(float max_walk_weight); - float GetAdditionalMaxWeight() const; void SetAdditionalMaxWeight(float add_max_weight); - float GetAdditionalMaxWalkWeight() const; void SetAdditionalMaxWalkWeight(float add_max_walk_weight); - float GetTotalWeight() const; float Weight() const; float GetActorJumpSpeed() const; void SetActorJumpSpeed(float jump_speed); - float GetActorSprintKoef() const; void SetActorSprintKoef(float sprint_koef); - float GetActorRunCoef() const; void SetActorRunCoef(float run_coef); - float GetActorRunBackCoef() const; void SetActorRunBackCoef(float run_back_coef); void SetCharacterIcon(pcstr iconName); //-Alundaio -#endif // GAME_OBJECT_EXTENDED_EXPORTS + doors::door* m_door; }; diff --git a/src/xrGame/script_game_object2.cpp b/src/xrGame/script_game_object2.cpp index 5d5dbdf6f0d..e667aa544aa 100644 --- a/src/xrGame/script_game_object2.cpp +++ b/src/xrGame/script_game_object2.cpp @@ -81,8 +81,15 @@ CScriptGameObject* CScriptGameObject::best_weapon() } else { - CGameObject* game_object = object_handler->best_weapon() ? &object_handler->best_weapon()->object() : 0; - return (game_object ? game_object->lua_game_object() : 0); + //Alundaio: extra security + CGameObject* game_object = object_handler->best_weapon() ? &object_handler->best_weapon()->object() : nullptr; + if (!game_object) + return nullptr; + + if (!game_object->H_Parent() || game_object->H_Parent()->ID() != object().ID()) + return nullptr; + //-Alundaio + return game_object->lua_game_object(); } } @@ -610,3 +617,6 @@ void CScriptGameObject::ResetBoneProtections(pcstr imm_sect, pcstr bone_sect) stalker->ResetBoneProtections(imm_sect, bone_sect); } + +void CScriptGameObject::set_visual_name(pcstr visual) { object().cNameVisual_set(visual); } +pcstr CScriptGameObject::get_visual_name() const { return object().cNameVisual().c_str(); } diff --git a/src/xrGame/script_game_object3.cpp b/src/xrGame/script_game_object3.cpp index e7d7a72b1e5..6f7c7904f26 100644 --- a/src/xrGame/script_game_object3.cpp +++ b/src/xrGame/script_game_object3.cpp @@ -39,7 +39,6 @@ #include "stalker_decision_space.h" #include "space_restriction_manager.h" //Alundaio -#ifdef GAME_OBJECT_EXTENDED_EXPORTS #include "Artefact.h" #include "holder_custom.h" #include "Actor.h" @@ -48,9 +47,10 @@ #include "eatable_item.h" #include "xrScriptEngine/script_callback_ex.h" #include "xrEngine/Feel_Touch.h" +#include "WeaponAmmo.h" +#include "WeaponMagazinedWGrenade.h" #include "level_path_manager.h" #include "game_path_manager.h" -#endif //-Alundaio namespace MemorySpace @@ -1263,7 +1263,6 @@ bool CScriptGameObject::is_weapon_going_to_be_strapped(CScriptGameObject const* } //Alundaio: Taken from Radium -#ifdef GAME_OBJECT_EXTENDED_EXPORTS u16 CScriptGameObject::AmmoGetCount() { CWeaponAmmo* ammo = smart_cast(&object()); @@ -1383,22 +1382,21 @@ void CScriptGameObject::SetArtefactBleedingRestoreSpeed(float value) artefact->SetBleedingPower(value); } -void CScriptGameObject::AttachVehicle(CScriptGameObject* veh) +void CScriptGameObject::AttachVehicle(CScriptGameObject* veh, bool bForce) { - CActor* actor = smart_cast(&object()); - if (actor) + if (CActor* actor = smart_cast(&object())) { - CHolderCustom* vehicle = veh->object().cast_holder_custom();//smart_cast(veh->object()); - if (vehicle) - actor->attach_Vehicle(vehicle); + if (CHolderCustom* vehicle = veh->object().cast_holder_custom()) + actor->use_HolderEx(vehicle, bForce); } } -void CScriptGameObject::DetachVehicle() +void CScriptGameObject::DetachVehicle(bool bForce) { - CActor* actor = smart_cast(&object()); - if (actor) - actor->detach_Vehicle(); + if (CActor* actor = smart_cast(&object())) + { + actor->use_HolderEx(nullptr, bForce); + } } CScriptGameObject* CScriptGameObject::GetAttachedVehicle() @@ -1420,13 +1418,12 @@ CScriptGameObject* CScriptGameObject::GetAttachedVehicle() u32 CScriptGameObject::PlayHudMotion(pcstr M, bool mixIn, u32 state) { - CWeapon* Weapon = object().cast_weapon(); - if (Weapon) + if (CWeapon* weapon = object().cast_weapon()) { - if (!Weapon->isHUDAnimationExist(M)) + if (!weapon->isHUDAnimationExist(M)) return 0; - return Weapon->PlayHUDMotion(M, mixIn, Weapon, state); + return weapon->PlayHUDMotion(M, mixIn, weapon, state); } CHudItem* itm = object().cast_inventory_item()->cast_hud_item(); @@ -1448,32 +1445,34 @@ void CScriptGameObject::SwitchState(u32 state) return; } - CInventoryItem* IItem = object().cast_inventory_item(); - if (IItem) + if (CInventoryItem* IItem = object().cast_inventory_item()) { - CHudItem* itm = IItem->cast_hud_item(); - if (itm) + if (CHudItem* itm = IItem->cast_hud_item()) itm->SwitchState(state); } } u32 CScriptGameObject::GetState() { - CWeapon* Weapon = object().cast_weapon(); - if (Weapon) - return Weapon->GetState(); + if (const auto weapon = object().cast_weapon()) + return weapon->GetState(); - CInventoryItem* IItem = object().cast_inventory_item(); - if (IItem) + if (CInventoryItem* IItem = object().cast_inventory_item()) { - CHudItem* itm = IItem->cast_hud_item(); - if (itm) + if (const auto itm = IItem->cast_hud_item()) return itm->GetState(); } return 65535; } +bool CScriptGameObject::WeaponInGrenadeMode() +{ + if (const auto wpn = smart_cast(&object())) + return wpn->m_bGrenadeMode; + return false; +} + void CScriptGameObject::SetBoneVisible(pcstr bone_name, bool bVisibility, bool bRecursive) { IKinematics* k = object().Visual()->dcast_PKinematics(); @@ -1505,7 +1504,7 @@ bool CScriptGameObject::IsBoneVisible(pcstr bone_name) float CScriptGameObject::GetLuminocityHemi() { - CGameObject* e = smart_cast(&object()); + CGameObject* e = &object(); if (!e || !e->renderable_ROS()) return 0; return e->renderable_ROS()->get_luminocity_hemi(); @@ -1513,7 +1512,7 @@ float CScriptGameObject::GetLuminocityHemi() float CScriptGameObject::GetLuminocity() { - CGameObject* e = smart_cast(&object()); + CGameObject* e = &object(); if (!e || !e->renderable_ROS()) return 0; return e->renderable_ROS()->get_luminocity(); @@ -1525,8 +1524,7 @@ void CScriptGameObject::ForceSetPosition(Fvector pos, bool bActivate) if (!sh) return; - CPhysicsShell* shell = sh->PPhysicsShell(); - if (shell) + if (CPhysicsShell* shell = sh->PPhysicsShell()) { if (bActivate) sh->activate_physic_shell(); @@ -1540,8 +1538,10 @@ void CScriptGameObject::ForceSetPosition(Fvector pos, bool bActivate) sh->character_physics_support()->ForceTransform(M); } else - GEnv.ScriptEngine->script_log(LuaMessageType::Error, "force_set_position: object %s has no physics shell!", - *object().cName()); + { + GEnv.ScriptEngine->script_log(LuaMessageType::Error, + "force_set_position: object %s has no physics shell!", object().cName().c_str()); + } } void CScriptGameObject::SetRemainingUses(u8 value) @@ -1585,15 +1585,11 @@ u8 CScriptGameObject::GetMaxUses() void CScriptGameObject::IterateFeelTouch(luabind::functor functor) { - Feel::Touch* touch = smart_cast(&object()); - if (touch) + if (Feel::Touch* touch = smart_cast(&object())) { for (const auto& game_object : touch->feel_touch) { - // XXX Xottab_DUTY: Do we need this cast from IGameObject* to IGameObject* ? - IGameObject* o = smart_cast(game_object); - if (o) - functor(game_object->ID()); + functor(game_object->ID()); } } } @@ -1610,8 +1606,7 @@ u32 CScriptGameObject::GetSpatialType() u8 CScriptGameObject::GetRestrictionType() { - CSpaceRestrictor* restr = smart_cast(&object()); - if (restr) + if (const auto restr = smart_cast(&object())) return restr->m_space_restrictor_type; return -1; @@ -1619,13 +1614,11 @@ u8 CScriptGameObject::GetRestrictionType() void CScriptGameObject::SetRestrictionType(u8 type) { - CSpaceRestrictor* restr = smart_cast(&object()); - if (restr) + if (const auto restr = smart_cast(&object())) { restr->m_space_restrictor_type = type; if (type != RestrictionSpace::eRestrictorTypeNone) Level().space_restriction_manager().register_restrictor(restr, RestrictionSpace::ERestrictorTypes(type)); } } -#endif //-Alundaio diff --git a/src/xrGame/script_game_object4.cpp b/src/xrGame/script_game_object4.cpp index 5805bd1963b..f41416176ae 100644 --- a/src/xrGame/script_game_object4.cpp +++ b/src/xrGame/script_game_object4.cpp @@ -24,6 +24,26 @@ #include "Artefact.h" #include "stalker_sound_data.h" +// AVO: for functions for testing object class +//#include "car.h" +//#include "helicopter.h" +#include "Actor.h" +#include "CustomOutfit.h" +//#include "CustomZone.h" +#include "ai/monsters/basemonster/base_monster.h" +//#include "Artifact.h" +//#include "medkit.h" +//#include "antirad.h" +#include "Scope.h" +#include "Silencer.h" +#include "Torch.h" +#include "GrenadeLauncher.h" +#include "searchlight.h" +//#include "WeaponAmmo.h" +//#include "Grenade.h" +//#include "BottleItem.h" +#include "WeaponMagazinedWGrenade.h" + class CWeapon; ////////////////////////////////////////////////////////////////////////// @@ -317,7 +337,7 @@ void CScriptGameObject::start_particles(LPCSTR pname, LPCSTR bone) return; IKinematics* K = smart_cast(object().Visual()); - R_ASSERT(K); + R_ASSERT1_CURE(K, true, { return; }); u16 play_bone = K->LL_BoneID(bone); R_ASSERT(play_bone != BI_NONE); @@ -335,7 +355,7 @@ void CScriptGameObject::stop_particles(LPCSTR pname, LPCSTR bone) return; IKinematics* K = smart_cast(object().Visual()); - R_ASSERT(K); + R_ASSERT1_CURE(K, true, { return; }); u16 play_bone = K->LL_BoneID(bone); R_ASSERT(play_bone != BI_NONE); @@ -347,7 +367,6 @@ void CScriptGameObject::stop_particles(LPCSTR pname, LPCSTR bone) LuaMessageType::Error, "Cant stop particles, bone [%s] is not visible now", bone); } -#ifdef GAME_OBJECT_EXTENDED_EXPORTS //AVO: directly set entity health instead of going through normal health property which operates on delta void CScriptGameObject::SetHealthEx(float hp) { @@ -357,4 +376,51 @@ void CScriptGameObject::SetHealthEx(float hp) obj->SetfHealth(hp); } //-AVO -#endif + +// AVO: functions for testing object class +// Credits: KD +#define TEST_OBJECT_CLASS(funcname, classname)\ + bool funcname() const\ + {\ + if (smart_cast(&object()))\ + return true;\ + return false;\ + } + +//TEST_OBJECT_CLASS(CScriptGameObject::IsGameObject, CGameObject) +//TEST_OBJECT_CLASS(CScriptGameObject::IsCar, CCar) +//TEST_OBJECT_CLASS(CScriptGameObject::IsHeli, CHelicopter) +//TEST_OBJECT_CLASS(CScriptGameObject::IsHolderCustom, CHolderCustom) +TEST_OBJECT_CLASS(CScriptGameObject::IsEntityAlive, CEntityAlive) +TEST_OBJECT_CLASS(CScriptGameObject::IsInventoryItem, CInventoryItem) +TEST_OBJECT_CLASS(CScriptGameObject::IsInventoryOwner, CInventoryOwner) +TEST_OBJECT_CLASS(CScriptGameObject::IsActor, CActor) +TEST_OBJECT_CLASS(CScriptGameObject::IsCustomMonster, CCustomMonster) +TEST_OBJECT_CLASS(CScriptGameObject::IsWeapon, CWeapon) +//TEST_OBJECT_CLASS(CScriptGameObject::IsMedkit, CMedkit) +//TEST_OBJECT_CLASS(CScriptGameObject::IsEatableItem, CEatableItem) +//TEST_OBJECT_CLASS(CScriptGameObject::IsAntirad, CAntirad) +TEST_OBJECT_CLASS(CScriptGameObject::IsCustomOutfit, CCustomOutfit) +TEST_OBJECT_CLASS(CScriptGameObject::IsScope, CScope) +TEST_OBJECT_CLASS(CScriptGameObject::IsSilencer, CSilencer) +TEST_OBJECT_CLASS(CScriptGameObject::IsGrenadeLauncher, CGrenadeLauncher) +TEST_OBJECT_CLASS(CScriptGameObject::IsWeaponMagazined, CWeaponMagazined) +TEST_OBJECT_CLASS(CScriptGameObject::IsSpaceRestrictor, CSpaceRestrictor) +TEST_OBJECT_CLASS(CScriptGameObject::IsStalker, CAI_Stalker) +TEST_OBJECT_CLASS(CScriptGameObject::IsAnomaly, CCustomZone) +TEST_OBJECT_CLASS(CScriptGameObject::IsMonster, CBaseMonster) +//TEST_OBJECT_CLASS(CScriptGameObject::IsExplosive, CExplosive) +//TEST_OBJECT_CLASS(CScriptGameObject::IsScriptZone, CScriptZone) +//TEST_OBJECT_CLASS(CScriptGameObject::IsProjector, CProjector) +TEST_OBJECT_CLASS(CScriptGameObject::IsTrader, CAI_Trader) +TEST_OBJECT_CLASS(CScriptGameObject::IsHudItem, CHudItem) +//TEST_OBJECT_CLASS(CScriptGameObject::IsFoodItem, CFoodItem) +TEST_OBJECT_CLASS(CScriptGameObject::IsArtefact, CArtefact) +TEST_OBJECT_CLASS(CScriptGameObject::IsAmmo, CWeaponAmmo) +//TEST_OBJECT_CLASS(CScriptGameObject::IsMissile, CMissile) +//TEST_OBJECT_CLASS(CScriptGameObject::IsPhysicsShellHolder, CPhysicsShellHolder) +//TEST_OBJECT_CLASS(CScriptGameObject::IsGrenade, CGrenade) +//TEST_OBJECT_CLASS(CScriptGameObject::IsBottleItem, CBottleItem) +//TEST_OBJECT_CLASS(CScriptGameObject::IsTorch, CTorch) +TEST_OBJECT_CLASS(CScriptGameObject::IsWeaponGL, CWeaponMagazinedWGrenade) +TEST_OBJECT_CLASS(CScriptGameObject::IsInventoryBox, CInventoryBox) diff --git a/src/xrGame/script_game_object_inventory_owner.cpp b/src/xrGame/script_game_object_inventory_owner.cpp index b36b6d54899..f5e699ce6bd 100644 --- a/src/xrGame/script_game_object_inventory_owner.cpp +++ b/src/xrGame/script_game_object_inventory_owner.cpp @@ -53,7 +53,6 @@ #include "CustomOutfit.h" #include "ActorBackpack.h" #include "inventory_item_impl.h" -#include "Inventory.h" #include "xrServer_Objects_ALife_Items.h" #include "xrServerEntities/inventory_space.h" //-Alundaio @@ -289,7 +288,7 @@ void CScriptGameObject::ForEachInventoryItems(const luabind::functor& func } // 1 -void CScriptGameObject::IterateInventory(luabind::functor functor, luabind::object object) +void CScriptGameObject::IterateInventory(luabind::functor functor, luabind::object object) { CInventoryOwner* inventory_owner = smart_cast(&this->object()); if (!inventory_owner) @@ -299,14 +298,15 @@ void CScriptGameObject::IterateInventory(luabind::functor functor, luabind return; } - TIItemContainer::iterator I = inventory_owner->inventory().m_all.begin(); - TIItemContainer::iterator E = inventory_owner->inventory().m_all.end(); + TIItemContainer::iterator I = inventory_owner->inventory().m_all.begin(); + TIItemContainer::iterator E = inventory_owner->inventory().m_all.end(); for (; I != E; ++I) - functor(object, (*I)->object().lua_game_object()); + if (functor(object, (*I)->object().lua_game_object()) == true) + return; } #include "InventoryBox.h" -void CScriptGameObject::IterateInventoryBox(luabind::functor functor, luabind::object object) +void CScriptGameObject::IterateInventoryBox(luabind::functor functor, luabind::object object) { CInventoryBox* inventory_box = smart_cast(&this->object()); if (!inventory_box) @@ -320,9 +320,9 @@ void CScriptGameObject::IterateInventoryBox(luabind::functor functor, luab xr_vector::const_iterator E = inventory_box->m_items.end(); for (; I != E; ++I) { - CGameObject* GO = smart_cast(Level().Objects.net_Find(*I)); - if (GO) - functor(object, GO->lua_game_object()); + if (const auto GO = smart_cast(Level().Objects.net_Find(*I))) + if (functor(object, GO->lua_game_object()) == true) + return; } } @@ -755,6 +755,18 @@ void CScriptGameObject::ChangeCharacterReputation(int char_rep) pInventoryOwner->ChangeReputation(char_rep); } +void CScriptGameObject::SetCharacterReputation(int char_rep) +{ + CInventoryOwner* pInventoryOwner = smart_cast(&object()); + + if (!pInventoryOwner) + { + GEnv.ScriptEngine->script_log(LuaMessageType::Error, "SetCharacterReputation available only for InventoryOwner"); + return; + } + pInventoryOwner->SetReputation(char_rep); +} + LPCSTR CScriptGameObject::CharacterCommunity() { CInventoryOwner* pInventoryOwner = smart_cast(&object()); @@ -1755,7 +1767,6 @@ bool CScriptGameObject::is_door_blocked_by_npc() const //Alundaio: Methods for exporting the ability to detach/attach addons for magazined weapons -#ifdef GAME_OBJECT_EXTENDED_EXPORTS void CScriptGameObject::Weapon_AddonAttach(CScriptGameObject* item) { auto weapon = smart_cast(&object()); @@ -2227,5 +2238,4 @@ void CScriptGameObject::SetCharacterIcon(pcstr iconName) } return pInventoryOwner->SetIcon(iconName); } -#endif //-Alundaio diff --git a/src/xrGame/script_game_object_script.cpp b/src/xrGame/script_game_object_script.cpp index de392ee1d56..640131fdf5e 100644 --- a/src/xrGame/script_game_object_script.cpp +++ b/src/xrGame/script_game_object_script.cpp @@ -92,6 +92,8 @@ SCRIPT_EXPORT(CScriptGameObject, (), value("take_item_from_box", int(GameObject::eInvBoxItemTake)), value("weapon_no_ammo", int(GameObject::eWeaponNoAmmoAvailable)), + //Alundaio: + value("hud_animation_end", int(GameObject::eActorHudAnimationEnd)), //AVO: custom callbacks // Input value("key_press", int(GameObject::eKeyPress)), @@ -102,23 +104,22 @@ SCRIPT_EXPORT(CScriptGameObject, (), value("controller_press", int(GameObject::eControllerPress)), value("controller_release", int(GameObject::eControllerRelease)), value("controller_hold", int(GameObject::eControllerHold)), - // Inventory - value("item_to_belt", int(GameObject::eItemToBelt)), - value("item_to_slot", int(GameObject::eItemToSlot)), - value("item_to_ruck", int(GameObject::eItemToRuck)), // Actor value("actor_before_death", int(GameObject::eActorBeforeDeath)), - //-AVO - - // vehicle + // Vehicle value("on_attach_vehicle", int(GameObject::eAttachVehicle)), value("on_detach_vehicle", int(GameObject::eDetachVehicle)), value("on_use_vehicle", int(GameObject::eUseVehicle)), - - // weapon + // Weapon value("weapon_jammed", int(GameObject::eOnWeaponJammed)), value("weapon_zoom_in", int(GameObject::eOnWeaponZoomIn)), value("weapon_zoom_out", int(GameObject::eOnWeaponZoomOut)), + value("weapon_magazine_empty", int(GameObject::eOnWeaponMagazineEmpty)), + // Inventory + value("item_to_belt", int(GameObject::eItemToBelt)), + value("item_to_slot", int(GameObject::eItemToSlot)), + value("item_to_ruck", int(GameObject::eItemToRuck)), + //-AVO value("map_location_added", int(GameObject::eMapLocationAdded)) ], diff --git a/src/xrGame/script_game_object_script2.cpp b/src/xrGame/script_game_object_script2.cpp index fdf38acfcc3..fd4bfd10c61 100644 --- a/src/xrGame/script_game_object_script2.cpp +++ b/src/xrGame/script_game_object_script2.cpp @@ -106,7 +106,6 @@ luabind::class_& script_register_game_object1(luabind::class_ .def("group", &CScriptGameObject::Group) .def("change_team", (void (CScriptGameObject::*)(u8, u8, u8))(&CScriptGameObject::ChangeTeam)) .def("set_visual_memory_enabled", &CScriptGameObject::SetVisualMemoryEnabled) - // XXX: this is a workaround, since luabind can't determine default function arguments... .def("kill", (void (CScriptGameObject::*)(CScriptGameObject*))&CScriptGameObject::Kill) .def("kill", (void (CScriptGameObject::*)(CScriptGameObject*, bool))(&CScriptGameObject::Kill)) .def("hit", &CScriptGameObject::Hit) diff --git a/src/xrGame/script_game_object_script3.cpp b/src/xrGame/script_game_object_script3.cpp index bce41d611bf..9494f81ced8 100644 --- a/src/xrGame/script_game_object_script3.cpp +++ b/src/xrGame/script_game_object_script3.cpp @@ -283,7 +283,9 @@ luabind::class_& script_register_game_object2(luabind::class_ .def("character_icon", &CScriptGameObject::CharacterIcon) .def("character_rank", &CScriptGameObject::CharacterRank) .def("set_character_rank", &CScriptGameObject::SetCharacterRank) + .def("change_character_rank", &CScriptGameObject::ChangeCharacterRank) .def("character_reputation", &CScriptGameObject::CharacterReputation) + .def("set_character_reputation", &CScriptGameObject::SetCharacterReputation) .def("change_character_reputation", &CScriptGameObject::ChangeCharacterReputation) .def("character_community", &CScriptGameObject::CharacterCommunity) .def("set_character_community", &CScriptGameObject::SetCharacterCommunity) @@ -434,13 +436,12 @@ luabind::class_& script_register_game_object2(luabind::class_ .def("start_particles", &CScriptGameObject::start_particles) .def("stop_particles", &CScriptGameObject::stop_particles) - //Alundaio: Extended exports - //For Car + // Alundaio: Extended exports + // For Car .def("attach_vehicle", &CScriptGameObject::AttachVehicle) .def("detach_vehicle", &CScriptGameObject::DetachVehicle) .def("get_attached_vehicle", &CScriptGameObject::GetAttachedVehicle) -#ifdef GAME_OBJECT_EXTENDED_EXPORTS .def("reset_bone_protections", &CScriptGameObject::ResetBoneProtections) .def("iterate_feel_touch", &CScriptGameObject::IterateFeelTouch) .def("get_luminocity_hemi", &CScriptGameObject::GetLuminocityHemi) @@ -456,16 +457,16 @@ luabind::class_& script_register_game_object2(luabind::class_ .def("remove_memory_visible_object", &CScriptGameObject::RemoveMemoryVisibleObject) .def("remove_memory_hit_object", &CScriptGameObject::RemoveMemoryHitObject) - //For Ammo + // For Ammo .def("ammo_get_count", &CScriptGameObject::AmmoGetCount) .def("ammo_set_count", &CScriptGameObject::AmmoSetCount) .def("ammo_box_size", &CScriptGameObject::AmmoBoxSize) - //For Weapons + // For Weapons .def("weapon_addon_attach", &CScriptGameObject::Weapon_AddonAttach) .def("weapon_addon_detach", &CScriptGameObject::Weapon_AddonDetach) - //For Weapon & Outfit + // For Weapon & Outfit .def("add_upgrade", &CScriptGameObject::AddUpgrade) .def("install_upgrade", &CScriptGameObject::InstallUpgrade) .def("has_upgrade", &CScriptGameObject::HasUpgrade) @@ -474,24 +475,25 @@ luabind::class_& script_register_game_object2(luabind::class_ .def("can_install_upgrade", &CScriptGameObject::CanInstallUpgrade) .def("can_add_upgrade", &CScriptGameObject::CanAddUpgrade) .def("iterate_installed_upgrades", &CScriptGameObject::IterateInstalledUpgrades) + .def("weapon_in_grenade_mode", &CScriptGameObject::WeaponInGrenadeMode) // For CHudItem .def("play_hud_motion", &CScriptGameObject::PlayHudMotion) .def("switch_state", &CScriptGameObject::SwitchState) .def("get_state", &CScriptGameObject::GetState) + // For EatableItem .def("set_remaining_uses", &CScriptGameObject::SetRemainingUses) .def("get_remaining_uses", &CScriptGameObject::GetRemainingUses) .def("get_max_uses", &CScriptGameObject::GetMaxUses) + // Phantom .def("phantom_set_enemy", &CScriptGameObject::PhantomSetEnemy) + // Actor .def("set_character_icon", &CScriptGameObject::SetCharacterIcon) -#endif - //-Alundaio -#ifdef GAME_OBJECT_CASTING_EXPORTS - // Casting objects + // Casting .def("cast_GameObject", &ObjectCast) .def("cast_Car", &ObjectCast) .def("cast_Heli", &ObjectCast) @@ -528,8 +530,46 @@ luabind::class_& script_register_game_object2(luabind::class_ //.def("cast_Torch", &ObjectCast) //.def("cast_WeaponMagazinedWGrenade", &ObjectCast) //.def("cast_InventoryBox", &ObjectCast) -#endif // GAME_OBJECT_CASTING_EXPORTS + //-Alundaio + //AVO: additional functions + //.def("is_game_object", &CScriptGameObject::IsGameObject) + //.def("is_car", &CScriptGameObject::IsCar) + //.def("is_helicopter", &CScriptGameObject::IsHeli) + //.def("is_holder", &CScriptGameObject::IsHolderCustom) + .def("is_entity_alive", &CScriptGameObject::IsEntityAlive) + .def("is_inventory_item", &CScriptGameObject::IsInventoryItem) + .def("is_inventory_owner", &CScriptGameObject::IsInventoryOwner) + .def("is_actor", &CScriptGameObject::IsActor) + .def("is_custom_monster", &CScriptGameObject::IsCustomMonster) + .def("is_weapon", &CScriptGameObject::IsWeapon) + //.def("is_medkit", &CScriptGameObject::IsMedkit) + //.def("is_eatable_item", &CScriptGameObject::IsEatableItem) + //.def("is_antirad", &CScriptGameObject::IsAntirad) + .def("is_outfit", &CScriptGameObject::IsCustomOutfit) + .def("is_scope", &CScriptGameObject::IsScope) + .def("is_silencer", &CScriptGameObject::IsSilencer) + .def("is_grenade_launcher", &CScriptGameObject::IsGrenadeLauncher) + .def("is_weapon_magazined", &CScriptGameObject::IsWeaponMagazined) + .def("is_space_restrictor", &CScriptGameObject::IsSpaceRestrictor) + .def("is_stalker", &CScriptGameObject::IsStalker) + .def("is_anomaly", &CScriptGameObject::IsAnomaly) + .def("is_monster", &CScriptGameObject::IsMonster) + //.def("is_explosive", &CScriptGameObject::IsExplosive) + //.def("is_script_zone", &CScriptGameObject::IsScriptZone) + //.def("is_projector", &CScriptGameObject::IsProjector) + .def("is_trader", &CScriptGameObject::IsTrader) + .def("is_hud_item", &CScriptGameObject::IsHudItem) + //.def("is_food_item", &CScriptGameObject::IsFoodItem) + .def("is_artefact", &CScriptGameObject::IsArtefact) + .def("is_ammo", &CScriptGameObject::IsAmmo) + //.def("is_missile", &CScriptGameObject::IsMissile) + //.def("is_physics_shell_holder", &CScriptGameObject::IsPhysicsShellHolder) + //.def("is_grenade", &CScriptGameObject::IsGrenade) + //.def("is_bottle_item", &CScriptGameObject::IsBottleItem) + //.def("is_torch", &CScriptGameObject::IsTorch) + .def("is_weapon_gl", &CScriptGameObject::IsWeaponGL) + .def("is_inventory_box", &CScriptGameObject::IsInventoryBox) .def("is_on_belt", &CScriptGameObject::IsOnBelt) .def("item_on_belt", &CScriptGameObject::ItemOnBelt) diff --git a/src/xrGame/script_game_object_use.cpp b/src/xrGame/script_game_object_use.cpp index 90b3f72be8f..44a642f88dc 100644 --- a/src/xrGame/script_game_object_use.cpp +++ b/src/xrGame/script_game_object_use.cpp @@ -59,7 +59,7 @@ int CScriptGameObject::clsid() const { return (object().clsid()); } LPCSTR CScriptGameObject::Name() const { return (*object().cName()); } shared_str CScriptGameObject::cName() const { return (object().cName()); } LPCSTR CScriptGameObject::Section() const { return (*object().cNameSect()); } -void CScriptGameObject::Kill(CScriptGameObject* who, bool bypass_actor_check /*AVO: added for actor before death callback*/) +void CScriptGameObject::Kill(CScriptGameObject* who, bool bypass_actor_check) { CEntity* l_tpEntity = smart_cast(&object()); if (psActorFlags.test(AF_GODMODE) && !!l_tpEntity->cast_actor()) diff --git a/src/xrGame/script_movement_action.h b/src/xrGame/script_movement_action.h index cd7fefbbd8a..e229170f7ca 100644 --- a/src/xrGame/script_movement_action.h +++ b/src/xrGame/script_movement_action.h @@ -114,7 +114,7 @@ class CScriptMovementAction : public CScriptAbstractAction IC void SetMovementType(const MonsterSpace::EMovementType tMovementType); IC void SetPathType(const DetailPathManager::EDetailPathType tPathType); void SetObjectToGo(CScriptGameObject* tpObjectToGo); - IC void SetPatrolPath(const CPatrolPath* path, shared_str path_name); + IC void SetPatrolPath(const CPatrolPath* path, const shared_str& path_name); IC void SetPosition(const Fvector& tPosition); IC void SetSpeed(float fSpeed); IC void SetPatrolStart(EPatrolStartType tPatrolPathStart); diff --git a/src/xrGame/script_movement_action_inline.h b/src/xrGame/script_movement_action_inline.h index 7e5d0a1fefa..7c2c7e3a097 100644 --- a/src/xrGame/script_movement_action_inline.h +++ b/src/xrGame/script_movement_action_inline.h @@ -76,7 +76,7 @@ IC void CScriptMovementAction::SetPathType(const DetailPathManager::EDetailPathT m_bCompleted = false; } -IC void CScriptMovementAction::SetPatrolPath(const CPatrolPath* path, shared_str path_name) +IC void CScriptMovementAction::SetPatrolPath(const CPatrolPath* path, const shared_str& path_name) { m_path = path; m_path_name = path_name; diff --git a/src/xrGame/sight_manager.cpp b/src/xrGame/sight_manager.cpp index 75f56ab576d..754ab6fe5a4 100644 --- a/src/xrGame/sight_manager.cpp +++ b/src/xrGame/sight_manager.cpp @@ -65,7 +65,7 @@ void CSightManager::vfValidateAngleDependency(float x1, float& x2, float x3) BOOL g_ai_dbg_sight = 0; #endif // #ifdef DEBUG -float g_ai_aim_min_speed = PI_DIV_8 / 2.f; +float g_ai_aim_min_speed = 0.24f; // PI_DIV_8 / 2.f; //Alundaio float g_ai_aim_min_angle = PI_DIV_8 / 2.f; float g_ai_aim_max_angle = PI_DIV_4; BOOL g_ai_aim_use_smooth_aim = 1; diff --git a/src/xrGame/space_restrictor.cpp b/src/xrGame/space_restrictor.cpp index c2287aeb4ce..44f031cb5fd 100644 --- a/src/xrGame/space_restrictor.cpp +++ b/src/xrGame/space_restrictor.cpp @@ -23,6 +23,7 @@ //Alundaio #include "RadioactiveZone.h" +#include "ZoneCampfire.h" BOOL g_ai_die_in_anomaly = 0; //-Alundaio @@ -67,8 +68,9 @@ bool CSpaceRestrictor::net_Spawn(CSE_Abstract* data) if (!result) return (FALSE); - CCustomZone* zone = smart_cast(this); - if (g_ai_die_in_anomaly == 0 || !zone || smart_cast(zone)) + //Alundaio: zone visible for ai if g_ai_die_in_anomaly = 1 unless it's Radioactive Zone or Campfire + CCustomZone* zone = smart_cast(this); + if (g_ai_die_in_anomaly == 0 || !zone || smart_cast(zone) || smart_cast(zone)) spatial.type &= ~STYPE_VISIBLEFORAI; setEnabled(FALSE); diff --git a/src/xrGame/stalker_animation_manager_update.cpp b/src/xrGame/stalker_animation_manager_update.cpp index b31cb94c2e8..6a7b4881850 100644 --- a/src/xrGame/stalker_animation_manager_update.cpp +++ b/src/xrGame/stalker_animation_manager_update.cpp @@ -229,12 +229,14 @@ void CStalkerAnimationManager::update() catch (...) { Msg("! error in stalker with visual %s and ID %u", *object().cNameVisual(), object().ID()); + /* avo: prevent game from crashing */ head().reset(); torso().reset(); legs().reset(); global().reset(); return; // throw; + /* avo: end */ } STOP_PROFILE } diff --git a/src/xrGame/stalker_animation_torso.cpp b/src/xrGame/stalker_animation_torso.cpp index b6934c0587c..21ebc1b65e1 100644 --- a/src/xrGame/stalker_animation_torso.cpp +++ b/src/xrGame/stalker_animation_torso.cpp @@ -30,13 +30,15 @@ MotionID CStalkerAnimationManager::aim_animation( if (slot != 2) return (animation[6].A[index]); -#if 1 // def DEBUG if (animation[6].A.size() < 7) { + //Alundaio: No need for message as many npcs have special danger move and very few don't +#ifndef MASTER_GOLD Msg("! cannot find special danger animations for object with visual %s", object().cNameVisual().c_str()); +#endif + //-Alundaio return (animation[6].A[index]); } -#endif // DEBUG switch (index) { diff --git a/src/xrGame/stalker_combat_actions.cpp b/src/xrGame/stalker_combat_actions.cpp index 4546cc063e8..b9d980931a8 100644 --- a/src/xrGame/stalker_combat_actions.cpp +++ b/src/xrGame/stalker_combat_actions.cpp @@ -434,6 +434,7 @@ void CStalkerActionKillEnemy::execute() #endif // TEST_MENTAL_STATE inherited::execute(); + //Alundaio: Prevent Stalkers from shooting at walls for prolonged periods due to kill if not visible const CEntityAlive* enemy = object().memory().enemy().selected(); if (enemy && enemy->g_Alive()) @@ -538,10 +539,6 @@ void CStalkerActionTakeCover::execute() object().brain().affect_cover(true); } - //. Add fire here - // if (object().memory().visual().visible_now(object().memory().enemy().selected()) && object().can_kill_enemy()) - // if (object().memory().visual().visible_now(object().memory().enemy().selected())) - if (object().movement().path_completed()) // && (object().memory().enemy().selected()->Position().distance_to_sqr(object().Position()) >= 10.f)) { object().best_cover_can_try_advance(); @@ -820,7 +817,6 @@ void CStalkerActionDetourEnemy::initialize() //#ifndef SILENT_COMBAT //Alundaio: Added sanity to make sure enemy exists if (object().memory().enemy().selected() && object().memory().enemy().selected()->human_being() && object().agent_manager().member().group_behaviour()) - //Alundaio: END //object().sound().play(eStalkerSoundNeedBackup); object().sound().play(eStalkerSoundDetour); //#endif @@ -1064,31 +1060,38 @@ void CStalkerActionSuddenAttack::execute() //Alundaio: Removed check to allow stalkers to sneak up on enemy even if they are in a group. //if (object().agent_manager().member().combat_members().size() > 1) - // m_storage->set_property(eWorldPropertyUseSuddenness, false); - //-Alundaio + // m_storage->set_property(eWorldPropertyUseSuddenness,false); + //Alundaio: END const CEntityAlive* enemy = object().memory().enemy().selected(); if (!enemy) + { + m_storage->set_property(eWorldPropertyUseSuddenness, false); return; + } CMemoryInfo mem_object = object().memory().memory(enemy); + if (!mem_object.m_object) + { + m_storage->set_property(eWorldPropertyUseSuddenness, false); return; + } - //Alundaio: Don't aim at ceiling or floor - bool visible_now = object().memory().visual().visible_now(enemy); - + const bool visible_now = object().memory().visual().visible_now(enemy); if (visible_now) object().sight().setup(CSightAction(enemy, true)); else { //Alundaio: Prevent stalkers from staring at floor or ceiling for this action u32 const level_time = object().memory().visual().visible_object_time_last_seen(mem_object.m_object); - if (Device.dwTimeGlobal >= level_time + 3000 && _abs( - object().Position().y - mem_object.m_object_params.m_position.y) > 3.5f) + if (Device.dwTimeGlobal >= level_time + 3000 && + _abs(object().Position().y - mem_object.m_object_params.m_position.y) > 3.5f) { - Fvector3 Vpos = { - mem_object.m_object_params.m_position.x, object().Position().y + 1.f, + const Fvector3 Vpos = + { + mem_object.m_object_params.m_position.x, + object().Position().y + 1.f, mem_object.m_object_params.m_position.z }; object().sight().setup(CSightAction(SightManager::eSightTypePosition, Vpos, true)); @@ -1102,11 +1105,13 @@ void CStalkerActionSuddenAttack::execute() if (object().movement().accessible(mem_object.m_object_params.m_level_vertex_id)) object().movement().set_level_dest_vertex(mem_object.m_object_params.m_level_vertex_id); else + { object().movement().set_nearest_accessible_position( ai().level_graph().vertex_position(mem_object.m_object_params.m_level_vertex_id), mem_object.m_object_params.m_level_vertex_id); + } - if (!visible_now) + /*if (!visible_now) { u32 target_vertex_id = object().movement().level_path().dest_vertex_id(); if (object().ai_location().level_vertex_id() == target_vertex_id) @@ -1114,9 +1119,9 @@ void CStalkerActionSuddenAttack::execute() m_storage->set_property(eWorldPropertyUseSuddenness, false); return; } - } + }*/ - float distance = object().Position().distance_to(mem_object.m_object_params.m_position); + const float distance = object().Position().distance_to(mem_object.m_object_params.m_position); if (distance >= 15.f) { object().movement().set_body_state(eBodyStateStand); @@ -1253,7 +1258,9 @@ void CStalkerActionCriticalHit::initialize() min_queue_interval, max_queue_interval); } else + { object().set_goal(eObjectActionIdle, object().best_weapon()); + } } object().sight().setup(CSightAction(SightManager::eSightTypeCurrentDirection, true, true)); diff --git a/src/xrGame/stalker_combat_planner.cpp b/src/xrGame/stalker_combat_planner.cpp index 738da893b4f..dca32c58ef0 100644 --- a/src/xrGame/stalker_combat_planner.cpp +++ b/src/xrGame/stalker_combat_planner.cpp @@ -464,6 +464,7 @@ void CStalkerCombatPlanner::add_actions() add_condition(action, eWorldPropertyUseSuddenness, true); add_condition(action, eWorldPropertyEnemyWounded, false); add_condition(action, eWorldPropertyInSmartCover, false); + add_condition(action, eWorldPropertyEnemy, true); add_effect(action, eWorldPropertyEnemy, false); add_operator(eWorldOperatorSuddenAttack, action); diff --git a/src/xrGame/trade2.cpp b/src/xrGame/trade2.cpp index ebafec3d4db..05e2d958e98 100644 --- a/src/xrGame/trade2.cpp +++ b/src/xrGame/trade2.cpp @@ -63,7 +63,7 @@ bool CTrade::CanTrade() return true; } -void CTrade::TransferItem(CInventoryItem* pItem, bool bBuying, bool bFree) +void CTrade::TransferItem(CInventoryItem* pItem, bool bBuying, bool bFree /*= false*/) { // СЃСѓРјРјР° сделки учитывая ценовой коэффициент // актер цену РЅРµ РіРѕРІРѕСЂРёС‚ РЅРёРєРѕРіРґР°, РІСЃРµ делают Р·Р° него @@ -137,7 +137,7 @@ CInventory& CTrade::GetTradeInv(SInventoryOwner owner) CTrade* CTrade::GetPartnerTrade() { return pPartner.inv_owner->GetTrade(); } CInventory* CTrade::GetPartnerInventory() { return &GetTradeInv(pPartner); } CInventoryOwner* CTrade::GetPartner() { return pPartner.inv_owner; } -u32 CTrade::GetItemPrice(PIItem pItem, bool b_buying, bool bFree) +u32 CTrade::GetItemPrice(PIItem pItem, bool b_buying, bool bFree /*= false*/) { if (bFree) return 0; @@ -217,6 +217,9 @@ u32 CTrade::GetItemPrice(PIItem pItem, bool b_buying, bool bFree) clamp(action_factor, _min(trade_factors.enemy_factor(), trade_factors.friend_factor()), _max(trade_factors.enemy_factor(), trade_factors.friend_factor())); + if (action_factor == 0) + return 0; + // computing deficit_factor // float deficit_factor = partner.inv_owner->deficit_factor(pItem->object().cNameSect()); constexpr float deficit_factor = 1.f; diff --git a/src/xrGame/trade_parameters_inline.h b/src/xrGame/trade_parameters_inline.h index 4984a3fc596..d94d6f98b17 100644 --- a/src/xrGame/trade_parameters_inline.h +++ b/src/xrGame/trade_parameters_inline.h @@ -77,6 +77,9 @@ IC void CTradeParameters::process(_action_type type, CInifile& ini_file, const s auto E = S.Data.cend(); for (; I != E; ++I) { + if (!pSettings->section_exist(I->first)) + continue; + if (!(*I).second.size()) { _action.disable((*I).first); @@ -84,9 +87,11 @@ IC void CTradeParameters::process(_action_type type, CInifile& ini_file, const s } string256 temp0, temp1; - THROW3(_GetItemCount(*(*I).second) == 2, "Invalid parameters in section", *section); - _action.enable((*I).first, CTradeFactors((float)atof(_GetItem(*(*I).second, 0, temp0)), - (float)atof(_GetItem(*(*I).second, 1, temp1)))); + //THROW3(_GetItemCount(I->second.c_str()) == 2, "Invalid parameters in section", section.c_str()); + cpcstr param1 = _GetItem(I->second.c_str(), 0, temp0); + cpcstr param2 = _GetItemCount(I->second.c_str()) >= 2 ? _GetItem(I->second.c_str(), 1, temp1) : param1; + + _action.enable(I->first, CTradeFactors((float)atof(param1), (float)atof(param2))); } } diff --git a/src/xrGame/ui/Restrictions.cpp b/src/xrGame/ui/Restrictions.cpp index e975af7e93e..df0c4a877cf 100644 --- a/src/xrGame/ui/Restrictions.cpp +++ b/src/xrGame/ui/Restrictions.cpp @@ -31,13 +31,14 @@ u32 get_rank(const shared_str& section) } } + //R_ASSERT3(res != -1, "cannot find rank for", section.c_str()); if (res == -1) { - Msg("Setting rank to 0. Cannot find rank for: [%s]", section.c_str()); + Msg("! Setting rank to 0. Cannot find rank for: [%s]", section.c_str()); // Xottab_DUTY: I'm not sure if it's save to leave it -1 res = 0; } - //R_ASSERT3(res != -1, "cannot find rank for", section.c_str()); + return res; } diff --git a/src/xrGame/ui/UIActorMenu.cpp b/src/xrGame/ui/UIActorMenu.cpp index 1b21d757926..a776c525eab 100644 --- a/src/xrGame/ui/UIActorMenu.cpp +++ b/src/xrGame/ui/UIActorMenu.cpp @@ -159,6 +159,7 @@ void CUIActorMenu::SetMenuMode(EMenuMode mode) InitActorInfo(); if (m_currMenuMode != mmUndefined && m_currMenuMode != mmInventory) InitPartnerInfo(); + highlight_equipped(); CurModeToScript(); } // if @@ -526,6 +527,8 @@ void CUIActorMenu::UpdateItemsPlace() UpdateOutfit(); UpdateActor(); } + + highlight_equipped(); } // ================================================================ @@ -868,6 +871,25 @@ void CUIActorMenu::highlight_weapons_for_addon(PIItem addon_item, CUIDragDropLis } // for i } +void CUIActorMenu::highlight_equipped() const +{ + // Highlight 'equipped' items in actor bag + CUIDragDropListEx* slot_list = m_pLists[eInventoryBagList]; + u32 const cnt = slot_list->ItemsCount(); + for (u32 i = 0; i < cnt; ++i) + { + CUICellItem* ci = slot_list->GetItemIdx(i); + const auto item = static_cast(ci->m_pData); + if (!item) + continue; + + if (item->m_highlight_equipped && item->m_pInventory && item->m_pInventory->ItemFromSlot(item->BaseSlot()) == item) + ci->m_select_equipped = true; + else + ci->m_select_equipped = false; + } +} + // ------------------------------------------------------------------- void CUIActorMenu::ClearAllLists() @@ -981,9 +1003,10 @@ bool CUIActorMenu::CanSetItemToList(PIItem item, CUIDragDropListEx* l, u16& ret_ void CUIActorMenu::HighlightSectionInSlot(pcstr section, EDDListType type, u16 slot_id /*= 0*/) { CUIDragDropListEx* slot_list = GetListByType(type); - if (!slot_list) slot_list = m_pLists[eInventoryBagList]; + if (!slot_list) + return; u32 const cnt = slot_list->ItemsCount(); for (u32 i = 0; i < cnt; ++i) @@ -1008,9 +1031,10 @@ void CUIActorMenu::HighlightForEachInSlot(const luabind::functor& functor, return; CUIDragDropListEx* slot_list = GetListByType(type); - if (!slot_list) slot_list = m_pLists[eInventoryBagList]; + if (!slot_list) + return; u32 const cnt = slot_list->ItemsCount(); for (u32 i = 0; i < cnt; ++i) diff --git a/src/xrGame/ui/UIActorMenu.h b/src/xrGame/ui/UIActorMenu.h index ecf76bcd22f..a5fe42487ad 100644 --- a/src/xrGame/ui/UIActorMenu.h +++ b/src/xrGame/ui/UIActorMenu.h @@ -222,6 +222,7 @@ class CUIActorMenu final : public CUIDialogWnd, public CUIWndCallback void highlight_weapons_for_ammo(PIItem ammo_item, CUIDragDropListEx* ddlist); bool highlight_addons_for_weapon(PIItem weapon_item, CUICellItem* ci); void highlight_weapons_for_addon(PIItem addon_item, CUIDragDropListEx* ddlist); + void highlight_equipped() const; protected: void Construct(); @@ -393,12 +394,17 @@ class CUIActorMenu final : public CUIDialogWnd, public CUIWndCallback IC UIHint* get_hint_wnd() { return m_hint_wnd; } - CScriptGameObject* GetCurrentItemAsGameObject(); - void HighlightSectionInSlot(pcstr section, EDDListType type, u16 slot_id = 0); - void HighlightForEachInSlot(const luabind::functor& functor, EDDListType type, u16 slot_id); + //AxelDominator && Alundaio consumable use condition + void RefreshCurrentItemCell(); - void RefreshCurrentItemCell(); - void DonateCurrentItem(CUICellItem* cell_item); //Alundaio: Donate item via context menu while in trade menu + CScriptGameObject* GetCurrentItemAsGameObject(); + void HighlightSectionInSlot(pcstr section, EDDListType type, u16 slot_id = 0); + void HighlightForEachInSlot(const luabind::functor& functor, EDDListType type, u16 slot_id); + bool ToSlotScript(CScriptGameObject* GO, bool force_place, u16 slot_id); + bool ToBeltScript(CScriptGameObject* GO, bool b_use_cursor_pos); + + //-AxelDominator && Alundaio consumable use condition + void DonateCurrentItem(CUICellItem* cell_item); //Alundaio: Donate item via context menu while in trade menu pcstr GetDebugType() override { return "CUIActorMenu"; } }; // class CUIActorMenu diff --git a/src/xrGame/ui/UIActorMenuDeadBodySearch.cpp b/src/xrGame/ui/UIActorMenuDeadBodySearch.cpp index 2369b0a8320..9c7c7fb2768 100644 --- a/src/xrGame/ui/UIActorMenuDeadBodySearch.cpp +++ b/src/xrGame/ui/UIActorMenuDeadBodySearch.cpp @@ -64,7 +64,7 @@ void CUIActorMenu::InitDeadBodySearchMode() TIItemContainer items_list; if (m_pPartnerInvOwner) { - m_pPartnerInvOwner->inventory().AddAvailableItems(items_list, false); // true + m_pPartnerInvOwner->inventory().AddAvailableItems(items_list, false, m_pPartnerInvOwner->is_alive()); UpdatePartnerBag(); } else @@ -87,7 +87,7 @@ void CUIActorMenu::InitDeadBodySearchMode() CBaseMonster* monster = smart_cast(m_pPartnerInvOwner); // only for partner, box = no, monster = no - if (m_pPartnerInvOwner && !monster) + if (m_pPartnerInvOwner && !monster && !m_pPartnerInvOwner->is_alive()) { CInfoPortionWrapper known_info_registry; known_info_registry.registry().init(m_pPartnerInvOwner->object_id()); diff --git a/src/xrGame/ui/UIActorMenuInventory.cpp b/src/xrGame/ui/UIActorMenuInventory.cpp index c6a93120948..0d1ec74e450 100644 --- a/src/xrGame/ui/UIActorMenuInventory.cpp +++ b/src/xrGame/ui/UIActorMenuInventory.cpp @@ -34,6 +34,7 @@ #include "CustomDetector.h" #include "PDA.h" #include "actor_defs.h" +#include "script_game_object_impl.h" void move_item_from_to(u16 from_id, u16 to_id, u16 what_id); @@ -466,8 +467,15 @@ void CUIActorMenu::InitInventoryContents(CUIDragDropListEx* pBagList, bool onlyB InitCellForSlot(ARTEFACT_SLOT); if (!m_pActorInvOwner->inventory().SlotIsPersistent(PDA_SLOT)) InitCellForSlot(PDA_SLOT); - if (!m_pActorInvOwner->inventory().SlotIsPersistent(TORCH_SLOT)) - InitCellForSlot(TORCH_SLOT); //Alundaio: TODO find out why this crash when you unequip + //if (!m_pActorInvOwner->inventory().SlotIsPersistent(TORCH_SLOT)) + // InitCellForSlot(TORCH_SLOT); // Alundaio: TODO find out why this crash when you unequip + + //for custom slots that exist past LAST_SLOT + for (u16 i = SLOTS_COUNT; i <= m_pActorInvOwner->inventory().LastSlot(); ++i) + { + if (!m_pActorInvOwner->inventory().SlotIsPersistent(i)) + InitCellForSlot(i); + } //-Alundaio curr_list = m_pLists[eInventoryBeltList]; @@ -507,6 +515,30 @@ bool CUIActorMenu::TryActiveSlot(CUICellItem* itm) return false; } +bool CUIActorMenu::ToSlotScript(CScriptGameObject* GO, bool force_place, u16 slot_id) +{ + CInventoryItem* iitem = smart_cast(GO->object().dcast_GameObject()); + + if (!iitem || !m_pActorInvOwner->inventory().InRuck(iitem)) + return false; + + CUIDragDropListEx* invlist = GetListByType(iActorBag); + CUICellContainer* c = invlist->GetContainer(); + auto& child_list = c->GetChildWndList(); + + for (CUIWindow* it : child_list) + { + CUICellItem* i = static_cast(it); + PIItem pitm = static_cast(i->m_pData); + if (pitm == iitem) + { + ToSlot(i, force_place, slot_id); + return true; + } + } + return false; +} + bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) { CUIDragDropListEx* old_owner = itm->OwnerList(); @@ -546,7 +578,7 @@ bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) } } - [[maybe_unused]] bool result = !b_own_item || m_pActorInvOwner->inventory().Slot(slot_id, iitem); + [[maybe_unused]] const bool result = !b_own_item || m_pActorInvOwner->inventory().Slot(slot_id, iitem); VERIFY(result); CUICellItem* i = old_owner->RemoveItem(itm, (old_owner == new_owner)); @@ -681,6 +713,30 @@ bool CUIActorMenu::ToBag(CUICellItem* itm, bool b_use_cursor_pos) return false; } +bool CUIActorMenu::ToBeltScript(CScriptGameObject* GO, bool b_use_cursor_pos) +{ + CInventoryItem* iitem = smart_cast(GO->object().dcast_GameObject()); + + if (!iitem || !m_pActorInvOwner->inventory().InRuck(iitem)) + return false; + + CUIDragDropListEx* invlist = GetListByType(iActorBag); + CUICellContainer* c = invlist->GetContainer(); + auto child_list = c->GetChildWndList(); + + for (CUIWindow* it : child_list) + { + CUICellItem* i = static_cast(it); + PIItem pitm = static_cast(i->m_pData); + if (pitm == iitem) + { + ToBelt(i, b_use_cursor_pos); + return true; + } + } + return false; +} + bool CUIActorMenu::ToBelt(CUICellItem* itm, bool b_use_cursor_pos) { PIItem iitem = (PIItem)itm->m_pData; @@ -767,7 +823,7 @@ CUIDragDropListEx* CUIActorMenu::GetSlotList(u16 slot_idx) case ARTEFACT_SLOT: case BINOCULAR_SLOT: - case GRENADE_SLOT: // fake + default: if (m_currMenuMode == mmTrade) { return m_pLists[eTradeActorBagList]; @@ -934,8 +990,8 @@ void CUIActorMenu::PropertiesBoxForSlots(PIItem item, bool& b_show) bool bAlreadyDressed = false; u16 cur_slot = item->BaseSlot(); - if (!pOutfit && !pHelmet && cur_slot != NO_ACTIVE_SLOT && !inv.SlotIsPersistent(cur_slot) && m_pActorInvOwner-> - inventory().ItemFromSlot(cur_slot) != item /*&& inv.CanPutInSlot(item, cur_slot)*/) + if (!pOutfit && !pHelmet && cur_slot != NO_ACTIVE_SLOT && !inv.SlotIsPersistent(cur_slot) && + inv.ItemFromSlot(cur_slot) != item /*&& inv.CanPutInSlot(item, cur_slot)*/) { m_UIPropertiesBox->AddItem("st_move_to_slot", NULL, INVENTORY_TO_SLOT_ACTION); b_show = true; @@ -952,7 +1008,8 @@ void CUIActorMenu::PropertiesBoxForSlots(PIItem item, bool& b_show) { if (!pHelmet) { - if (m_currMenuMode == mmDeadBodySearch) + const bool has_translation = StringTable().translate("st_unequip", nullptr); + if (m_currMenuMode == mmDeadBodySearch || !has_translation) m_UIPropertiesBox->AddItem("st_move_to_bag", nullptr, INVENTORY_TO_BAG_ACTION); else m_UIPropertiesBox->AddItem("st_unequip", nullptr, INVENTORY_TO_BAG_ACTION); @@ -1138,7 +1195,7 @@ void CUIActorMenu::PropertiesBoxForUsing(PIItem item, bool& b_show) shared_str section_name = GO->cNameSect(); //ability to set eat string from settings - act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "default_use_text", 0); + act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "default_use_text", nullptr); if (act_str) { m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT_ACTION); @@ -1174,35 +1231,67 @@ void CUIActorMenu::PropertiesBoxForUsing(PIItem item, bool& b_show) } //1st Custom Use action - act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use1_text", 0); - if (act_str) + pcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use1_functor", nullptr); + if (functor_name) { - m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT2_ACTION); - b_show = true; + luabind::functor funct1; + if (GEnv.ScriptEngine->functor(functor_name, funct1)) + { + act_str = funct1(GO->lua_game_object()); + if (act_str) + { + m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT2_ACTION); + b_show = true; + } + } } - //2nd Custom Use action - act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use2_text", 0); - if (act_str) + // 2nd Custom Use action + functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use2_functor", nullptr); + if (functor_name) { - m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT3_ACTION); - b_show = true; + luabind::functor funct1; + if (GEnv.ScriptEngine->functor(functor_name, funct1)) + { + act_str = funct1(GO->lua_game_object()); + if (act_str) + { + m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT3_ACTION); + b_show = true; + } + } } - //3rd Custom Use action - act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use3_text", 0); - if (act_str) + // 3rd Custom Use action + functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use3_functor", nullptr); + if (functor_name) { - m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT4_ACTION); - b_show = true; + luabind::functor funct1; + if (GEnv.ScriptEngine->functor(functor_name, funct1)) + { + act_str = funct1(GO->lua_game_object()); + if (act_str) + { + m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT4_ACTION); + b_show = true; + } + } } - //4th Custom Use action - act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use4_text", 0); - if (act_str) + // 4th Custom Use action + functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use4_functor", nullptr); + if (functor_name) { - m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT5_ACTION); - b_show = true; + luabind::functor funct1; + if (GEnv.ScriptEngine->functor(functor_name, funct1)) + { + act_str = funct1(GO->lua_game_object()); + if (act_str) + { + m_UIPropertiesBox->AddItem(act_str, nullptr, INVENTORY_EAT5_ACTION); + b_show = true; + } + } } } @@ -1247,8 +1336,11 @@ void CUIActorMenu::PropertiesBoxForRepair(PIItem item, bool& b_show) //Alundaio: Ability to donate item during trade void CUIActorMenu::PropertiesBoxForDonate(PIItem item, bool& b_show) { - m_UIPropertiesBox->AddItem("st_donate", nullptr, INVENTORY_DONATE_ACTION); - b_show = true; + if (!item->IsQuestItem()) + { + m_UIPropertiesBox->AddItem("st_donate", nullptr, INVENTORY_DONATE_ACTION); + b_show = true; + } } //-Alundaio @@ -1271,9 +1363,8 @@ void CUIActorMenu::ProcessPropertiesBoxClicked(CUIWindow* w, void* d) case INVENTORY_EAT_ACTION: TryUseItem(cell_item); break; case INVENTORY_EAT2_ACTION: { - CGameObject* GO = smart_cast(item); - const pcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use1_functor", 0); - if (functor_name) + const CGameObject* GO = smart_cast(item); + if (cpcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use1_action_functor", nullptr)) { luabind::functor funct1; if (GEnv.ScriptEngine->functor(functor_name, funct1)) @@ -1286,9 +1377,8 @@ void CUIActorMenu::ProcessPropertiesBoxClicked(CUIWindow* w, void* d) } case INVENTORY_EAT3_ACTION: { - CGameObject* GO = smart_cast(item); - const pcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use2_functor", 0); - if (functor_name) + const CGameObject* GO = smart_cast(item); + if (cpcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use2_action_functor", nullptr)) { luabind::functor funct2; if (GEnv.ScriptEngine->functor(functor_name, funct2)) @@ -1301,9 +1391,8 @@ void CUIActorMenu::ProcessPropertiesBoxClicked(CUIWindow* w, void* d) } case INVENTORY_EAT4_ACTION: { - CGameObject* GO = smart_cast(item); - const pcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use3_functor", 0); - if (functor_name) + const CGameObject* GO = smart_cast(item); + if (cpcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use3_action_functor", nullptr)) { luabind::functor funct3; if (GEnv.ScriptEngine->functor(functor_name, funct3)) @@ -1316,9 +1405,8 @@ void CUIActorMenu::ProcessPropertiesBoxClicked(CUIWindow* w, void* d) } case INVENTORY_EAT5_ACTION: { - CGameObject* GO = smart_cast(item); - const pcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use4_functor", 0); - if (functor_name) + const CGameObject* GO = smart_cast(item); + if (cpcstr functor_name = READ_IF_EXISTS(pSettings, r_string, GO->cNameSect(), "use4_action_functor", nullptr)) { luabind::functor funct4; if (GEnv.ScriptEngine->functor(functor_name, funct4)) diff --git a/src/xrGame/ui/UIActorMenu_action.cpp b/src/xrGame/ui/UIActorMenu_action.cpp index 9665c7b9c92..22e546ee4b1 100644 --- a/src/xrGame/ui/UIActorMenu_action.cpp +++ b/src/xrGame/ui/UIActorMenu_action.cpp @@ -254,8 +254,10 @@ bool CUIActorMenu::OnItemDbClick(CUICellItem* itm) ToBag(itm, false); } else if (!ToSlot(itm, false, iitem_to_place->BaseSlot())) + { if (!ToBelt(itm, false)) ToSlot(itm, true, iitem_to_place->BaseSlot()); + } break; } case iActorBelt: @@ -319,6 +321,16 @@ bool CUIActorMenu::OnItemFocusReceive(CUICellItem* itm) itm->m_selected = true; set_highlight_item(itm); + + luabind::functor funct1; + if (GEnv.ScriptEngine->functor("actor_menu_inventory.CUIActorMenu_OnItemFocusReceive", funct1)) + { + PIItem _iitem = (PIItem)itm->m_pData; + + const CGameObject* GO = _iitem ? smart_cast(_iitem) : nullptr; + if (GO) + funct1(GO->lua_game_object()); + } return true; } @@ -331,6 +343,16 @@ bool CUIActorMenu::OnItemFocusLost(CUICellItem* itm) InfoCurItem(NULL); clear_highlight_lists(); + luabind::functor funct1; + if (GEnv.ScriptEngine->functor("actor_menu_inventory.CUIActorMenu_OnItemFocusLost", funct1)) + { + PIItem _iitem = (PIItem)itm->m_pData; + + const CGameObject* GO = _iitem ? smart_cast(_iitem) : nullptr; + if (GO) + funct1(GO->lua_game_object()); + } + return true; } diff --git a/src/xrGame/ui/UIActorMenu_script.cpp b/src/xrGame/ui/UIActorMenu_script.cpp index 1ba0054ef09..c0a28730a6c 100644 --- a/src/xrGame/ui/UIActorMenu_script.cpp +++ b/src/xrGame/ui/UIActorMenu_script.cpp @@ -135,6 +135,8 @@ SCRIPT_EXPORT(CUIActorMenu, (CUIDialogWnd), .def("IsShown", &CUIActorMenu::IsShown) .def("ShowDialog", &CUIActorMenu::ShowDialog) .def("HideDialog", &CUIActorMenu::HideDialog) + .def("ToSlot", &CUIActorMenu::ToSlotScript) + .def("ToBelt", &CUIActorMenu::ToBeltScript) ]; using namespace luabind; @@ -159,7 +161,9 @@ SCRIPT_EXPORT(CUIPdaWnd, (CUIDialogWnd), .def("IsShown", &CUIPdaWnd::IsShown) .def("ShowDialog", &CUIPdaWnd::ShowDialog) .def("HideDialog", &CUIPdaWnd::HideDialog) - .def("SetActiveSubdialog", &CUIPdaWnd::SetActiveSubdialog_script) + .def("SetActiveSubdialog", +[](CUIPdaWnd* self, pcstr section) { self->SetActiveSubdialog(section); }) + .def("SetActiveDialog", &CUIPdaWnd::SetActiveDialog) + .def("GetActiveDialog", &CUIPdaWnd::GetActiveDialog) .def("GetActiveSection", &CUIPdaWnd::GetActiveSection) .def("GetTabControl", &CUIPdaWnd::GetTabControl) ]; diff --git a/src/xrGame/ui/UICellCustomItems.cpp b/src/xrGame/ui/UICellCustomItems.cpp index 8db40782a01..da179462e93 100644 --- a/src/xrGame/ui/UICellCustomItems.cpp +++ b/src/xrGame/ui/UICellCustomItems.cpp @@ -10,6 +10,8 @@ namespace detail { +static constexpr pcstr ICON_LAYER_FIELD = "icon_layer"; + struct is_helper_pred { bool operator()(CUICellItem* child) { return child->IsHelper(); } @@ -30,6 +32,43 @@ CUIInventoryCellItem::CUIInventoryCellItem(CInventoryItem* itm) inherited::SetTextureRect(rect); inherited::SetStretchTexture(true); + + //Alundaio; Layered icon + for (u8 i = 0; i < 255; ++i) + { + string32 layer_str; + xr_sprintf(layer_str, "%u%s", i, detail::ICON_LAYER_FIELD); + if (!pSettings->line_exist(itm->m_section_id, layer_str)) + break; + + cpcstr section = pSettings->r_string(itm->m_section_id, layer_str); + if (!section) + continue; + + string32 temp; + const Fvector2 offset + { + pSettings->r_float(itm->m_section_id, strconcat(temp, layer_str, "_x")), + pSettings->r_float(itm->m_section_id, strconcat(temp, layer_str, "_y")) + }; + + cpcstr field_scale = strconcat(temp, layer_str, "_scale"); + const float scale = pSettings->read_if_exists(itm->m_section_id, field_scale, 1.0f); + + //cpcstr field_color = strconcat(temp, layer_str, "_color"); + //const u32 color = READ_IF_EXISTS(pSettings, r_color, itm->m_section_id, field_color, 0); + + CreateLayer(section, offset, scale); + } + //-Alundaio +} + +void CUIInventoryCellItem::OnAfterChild(CUIDragDropListEx* parent_list) +{ + for (SIconLayer* layer : m_layers) + { + layer->m_icon = InitLayer(layer->m_icon, layer->m_name, layer->offset, parent_list->GetVerticalPlacement(), layer->m_scale); + } } bool CUIInventoryCellItem::EqualTo(CUICellItem* itm) @@ -61,11 +100,136 @@ bool CUIInventoryCellItem::IsHelperOrHasHelperChild() CUIDragItem* CUIInventoryCellItem::CreateDragItem() { - return IsHelperOrHasHelperChild() ? NULL : inherited::CreateDragItem(); + if (IsHelperOrHasHelperChild()) + return nullptr; + + CUIDragItem* i = inherited::CreateDragItem(); + + for (const SIconLayer* layer : m_layers) + { + CUIStatic* s = xr_new("Layer"); + s->SetAutoDelete(true); + s->SetShader(InventoryUtilities::GetEquipmentIconsShader()); + InitLayer(s, layer->m_name, layer->offset, false, layer->m_scale); + s->SetTextureColor(i->wnd()->GetTextureColor()); + i->wnd()->AttachChild(s); + } + + return i; +} + +void CUIInventoryCellItem::SetTextureColor(u32 color) +{ + inherited::SetTextureColor(color); + for (const SIconLayer* layer : m_layers) + { + if (layer->m_icon) + layer->m_icon->SetTextureColor(color); + } } bool CUIInventoryCellItem::IsHelper() { return object()->is_helper_item(); } void CUIInventoryCellItem::SetIsHelper(bool is_helper) { object()->set_is_helper(is_helper); } + +//Alundaio +void CUIInventoryCellItem::RemoveLayer(const SIconLayer* layer) +{ + for (auto it = m_layers.begin(); m_layers.end() != it; ++it) + { + if ((*it) == layer) + { + DetachChild((*it)->m_icon); + m_layers.erase(it); + break; + } + } +} + +void CUIInventoryCellItem::CreateLayer(pcstr section, Fvector2 offset, float scale) +{ + SIconLayer* layer = xr_new(); + layer->m_name = section; + layer->offset = offset; + //layer->m_color = color; + layer->m_scale = scale; + m_layers.push_back(layer); +} + +CUIStatic* CUIInventoryCellItem::InitLayer(CUIStatic* s, pcstr section, + Fvector2 addon_offset, bool b_rotate, float scale) +{ + if (!s) + { + s = xr_new("Layer"); + s->SetAutoDelete(true); + AttachChild(s); + s->SetShader(InventoryUtilities::GetEquipmentIconsShader()); + s->SetTextureColor(GetTextureColor()); + } + + Fvector2 base_scale; + + if (Heading()) + { + base_scale.x = (GetHeight() / (INV_GRID_WIDTHF * m_grid_size.x)) * scale; + base_scale.y = (GetWidth() / (INV_GRID_HEIGHTF * m_grid_size.y)) * scale; + } + else + { + base_scale.x = (GetWidth() / (INV_GRID_WIDTHF * m_grid_size.x)) * scale; + base_scale.y = (GetHeight() / (INV_GRID_HEIGHTF * m_grid_size.y)) * scale; + } + Fvector2 cell_size + { + pSettings->r_float(section, "inv_grid_width") * INV_GRID_WIDTHF, + pSettings->r_float(section, "inv_grid_height") * INV_GRID_HEIGHTF + }; + + Frect tex_rect + { + pSettings->r_float(section, "inv_grid_x") * INV_GRID_WIDTHF, + pSettings->r_float(section, "inv_grid_y") * INV_GRID_HEIGHTF + }; + + tex_rect.rb.add(tex_rect.lt, cell_size); + + cell_size.mul(base_scale); + + if (b_rotate) + { + s->SetWndSize(Fvector2{ cell_size.y, cell_size.x }); + + const Fvector2 new_offset + { + addon_offset.y * base_scale.x, + GetHeight() - addon_offset.x * base_scale.x - cell_size.x + }; + addon_offset = new_offset; + addon_offset.x *= UICore::get_current_kx(); + } + else + { + s->SetWndSize(cell_size); + addon_offset.mul(base_scale); + } + + s->SetWndPos(addon_offset); + s->SetTextureRect(tex_rect); + s->SetStretchTexture(true); + + s->EnableHeading(b_rotate); + + if (b_rotate) + { + s->SetHeading(GetHeading()); + const Fvector2 offs{ 0.0f, s->GetWndSize().y }; + s->SetHeadingPivot(Fvector2{ 0.0f, 0.0f }, /*Fvector2{ 0.0f, 0.0f }*/offs, true); + } + + return s; +} +//-Alundaio + void CUIInventoryCellItem::Update() { inherited::Update(); @@ -83,6 +247,12 @@ void CUIInventoryCellItem::Update() } SetTextureColor(color); + + for (SIconLayer* layer : m_layers) + { + layer->m_icon = InitLayer(layer->m_icon, layer->m_name, layer->offset, Heading(), layer->m_scale); + layer->m_icon->SetTextureColor(color); + } } void CUIInventoryCellItem::UpdateItemText() diff --git a/src/xrGame/ui/UICellCustomItems.h b/src/xrGame/ui/UICellCustomItems.h index 765dfe98680..bdc2655a8d0 100644 --- a/src/xrGame/ui/UICellCustomItems.h +++ b/src/xrGame/ui/UICellCustomItems.h @@ -2,10 +2,21 @@ #include "UICellItem.h" #include "Weapon.h" +struct SIconLayer +{ + pcstr m_name; + CUIStatic* m_icon; + Fvector2 offset; + //u32 m_color; + float m_scale; +}; + class CUIInventoryCellItem : public CUICellItem { typedef CUICellItem inherited; + xr_vector m_layers; + public: CUIInventoryCellItem(CInventoryItem* itm); @@ -18,6 +29,15 @@ class CUIInventoryCellItem : public CUICellItem void Update(); CInventoryItem* object() { return (CInventoryItem*)m_pData; } + //Alundaio + void OnAfterChild(CUIDragDropListEx* parent_list) override; + void SetTextureColor(u32 color) override; + + void RemoveLayer(const SIconLayer* layer); + void CreateLayer(pcstr name, Fvector2 offset, float scale); + CUIStatic* InitLayer(CUIStatic* s, pcstr section, Fvector2 addon_offset, bool b_rotate, float scale); + //-Alundaio + pcstr GetDebugType() override { return "CUIInventoryCellItem"; } }; diff --git a/src/xrGame/ui/UICellItem.cpp b/src/xrGame/ui/UICellItem.cpp index 1e2997c3bf3..9df84efd5e9 100644 --- a/src/xrGame/ui/UICellItem.cpp +++ b/src/xrGame/ui/UICellItem.cpp @@ -226,7 +226,7 @@ void CUICellItem::UpdateConditionProgressBar() if (eitm) { const u8 max_uses = eitm->GetMaxUses(); - if (max_uses > 1) + if (max_uses > 0) { const u8 remaining_uses = eitm->GetRemainingUses(); diff --git a/src/xrGame/ui/UICellItem.h b/src/xrGame/ui/UICellItem.h index f07254b0092..8c8c8925a81 100644 --- a/src/xrGame/ui/UICellItem.h +++ b/src/xrGame/ui/UICellItem.h @@ -86,6 +86,7 @@ class CUICellItem : public CUIStatic bool m_b_destroy_childs; bool m_selected; bool m_select_armament; + bool m_select_equipped{}; bool m_cur_mark; bool m_has_upgrade; }; diff --git a/src/xrGame/ui/UIDialogWnd.cpp b/src/xrGame/ui/UIDialogWnd.cpp index 132dcd8f341..e0c17835af9 100644 --- a/src/xrGame/ui/UIDialogWnd.cpp +++ b/src/xrGame/ui/UIDialogWnd.cpp @@ -80,6 +80,6 @@ void CUIDialogWnd::ShowDialog(bool bDoHideIndicators) void CUIDialogWnd::HideDialog() { - if (IsShown()) + if (GetHolder() && IsShown()) GetHolder()->StopDialog(this); } diff --git a/src/xrGame/ui/UIDragDropListEx.cpp b/src/xrGame/ui/UIDragDropListEx.cpp index ae8f760dd46..4bba28ea491 100644 --- a/src/xrGame/ui/UIDragDropListEx.cpp +++ b/src/xrGame/ui/UIDragDropListEx.cpp @@ -8,6 +8,8 @@ #include "Inventory.h" //-Alundaio +extern int g_inv_highlight_equipped; + CUIDragItem* CUIDragDropListEx::m_drag_item = NULL; void CUICell::Clear() @@ -650,11 +652,14 @@ bool CUICellContainer::AddSimilar(CUICellItem* itm) return false; //Alundaio: Don't stack equipped items - extern int g_inv_highlight_equipped; - if (g_inv_highlight_equipped) + PIItem iitem = (PIItem)itm->m_pData; + if (iitem && iitem->m_pInventory) { - const PIItem iitem = static_cast(itm->m_pData); - if (iitem && iitem->m_pInventory && iitem->m_pInventory->ItemFromSlot(iitem->BaseSlot()) == iitem) + if (g_inv_highlight_equipped) + if (iitem->m_pInventory->ItemFromSlot(iitem->BaseSlot()) == iitem) + return false; + + if (pSettings->line_exist(iitem->m_section_id, "dont_stack") && pSettings->r_bool(iitem->m_section_id, "dont_stack")) return false; } //-Alundaio @@ -673,19 +678,20 @@ CUICellItem* CUICellContainer::FindSimilar(CUICellItem* itm) { for (auto& it : m_ChildWndList) { - // XXX: Xottab_DUTY: find out why different casts used for different configurations - // and maybe use only one cast #ifdef DEBUG auto i = smart_cast(it); #else auto i = (CUICellItem*)it; #endif //Alundaio: Don't stack equipped items - extern int g_inv_highlight_equipped; - if (g_inv_highlight_equipped) + PIItem iitem = (PIItem)i->m_pData; + if (iitem && iitem->m_pInventory) { - auto iitem = static_cast(i->m_pData); - if (iitem && iitem->m_pInventory && iitem->m_pInventory->ItemFromSlot(iitem->BaseSlot()) == iitem) + if (g_inv_highlight_equipped) + if (iitem->m_pInventory->ItemFromSlot(iitem->BaseSlot()) == iitem) + continue; + + if (pSettings->line_exist(iitem->m_section_id, "dont_stack") && pSettings->r_bool(iitem->m_section_id, "dont_stack")) continue; } //-Alundaio @@ -1078,18 +1084,8 @@ void CUICellContainer::Draw() select_mode = 1; else if (ui_cell.m_item->m_select_armament) select_mode = 3; - else - { - //Alundaio: Highlight equipped items - extern int g_inv_highlight_equipped; - if (g_inv_highlight_equipped) - { - PIItem iitem = static_cast(ui_cell.m_item->m_pData); - if (iitem && iitem->m_pInventory && iitem->m_pInventory->ItemFromSlot(iitem->BaseSlot()) == iitem) - select_mode = 2; - } - //-Alundaio - } + else if (ui_cell.m_item->m_select_equipped && g_inv_highlight_equipped) + select_mode = 2; } Fvector2 tp; diff --git a/src/xrGame/ui/UIInventoryUtilities.cpp b/src/xrGame/ui/UIInventoryUtilities.cpp index 17b818c0a20..672124bf6c3 100644 --- a/src/xrGame/ui/UIInventoryUtilities.cpp +++ b/src/xrGame/ui/UIInventoryUtilities.cpp @@ -331,9 +331,10 @@ LPCSTR InventoryUtilities::GetTimePeriodAsString(pstr _buff, u32 buff_sz, ALife: int cnt = 0; _buff[0] = 0; - if (month1 != month2) - cnt = xr_sprintf( - _buff + cnt, buff_sz - cnt, "%d %s ", month2 - month1, *StringTable().translate("ui_st_months")); + u8 yrdiff = ((year2 - year1) * 12); + + if (month1 != month2 || yrdiff > 0) + cnt = xr_sprintf(_buff + cnt, buff_sz - cnt, "%d %s", month2 + (yrdiff - month1), *CStringTable().translate("ui_st_months")); if (!cnt && day1 != day2) cnt = xr_sprintf(_buff + cnt, buff_sz - cnt, "%d %s", day2 - day1, *StringTable().translate("ui_st_days")); diff --git a/src/xrGame/ui/UIItemInfo.cpp b/src/xrGame/ui/UIItemInfo.cpp index eb93af24b81..d613444d4d0 100644 --- a/src/xrGame/ui/UIItemInfo.cpp +++ b/src/xrGame/ui/UIItemInfo.cpp @@ -280,7 +280,7 @@ void CUIItemInfo::InitItem(CUICellItem* pCellItem, CInventoryItem* pCompareItem, } TryAddConditionInfo(*pInvItem, pCompareItem); TryAddWpnInfo(*pInvItem, pCompareItem); - TryAddArtefactInfo(pInvItem->object().cNameSect()); + TryAddArtefactInfo(*pInvItem); TryAddOutfitInfo(*pInvItem, pCompareItem); TryAddUpgradeInfo(*pInvItem); TryAddBoosterInfo(*pInvItem); @@ -350,14 +350,14 @@ void CUIItemInfo::TryAddWpnInfo(CInventoryItem& pInvItem, CInventoryItem* pCompa } } -void CUIItemInfo::TryAddArtefactInfo(const shared_str& af_section) +void CUIItemInfo::TryAddArtefactInfo(CInventoryItem& pInvItem) { if (!UIArtefactParams) return; - if (UIArtefactParams->Check(af_section)) + if (UIArtefactParams->Check(pInvItem.object().cNameSect())) { - UIArtefactParams->SetInfo(af_section); + UIArtefactParams->SetInfo(pInvItem); UIDesc->AddWindow(UIArtefactParams, false); } } diff --git a/src/xrGame/ui/UIItemInfo.h b/src/xrGame/ui/UIItemInfo.h index 2335b6e70dc..0479347c5bb 100644 --- a/src/xrGame/ui/UIItemInfo.h +++ b/src/xrGame/ui/UIItemInfo.h @@ -43,7 +43,7 @@ class CUIItemInfo final : public CUIWindow void TryAddConditionInfo(CInventoryItem& pInvItem, CInventoryItem* pCompareItem); void TryAddWpnInfo(CInventoryItem& pInvItem, CInventoryItem* pCompareItem); - void TryAddArtefactInfo(const shared_str& af_section); + void TryAddArtefactInfo(CInventoryItem& pInvItem); void TryAddOutfitInfo(CInventoryItem& pInvItem, CInventoryItem* pCompareItem); void TryAddUpgradeInfo(CInventoryItem& pInvItem); void TryAddBoosterInfo(CInventoryItem& pInvItem); diff --git a/src/xrGame/ui/UIMap.cpp b/src/xrGame/ui/UIMap.cpp index 196ff37f51e..9e88f0ac3b3 100644 --- a/src/xrGame/ui/UIMap.cpp +++ b/src/xrGame/ui/UIMap.cpp @@ -552,9 +552,7 @@ void CUILevelMap::SendMessage(CUIWindow* pWnd, s16 msg, void* pData) } } else if (msg == MAP_HIDE_HINT) - { MapWnd()->HideHint(pWnd); - } else if (msg == MAP_SELECT_SPOT) MapWnd()->SpotSelected(pWnd); else if (msg == MAP_SELECT_SPOT2) diff --git a/src/xrGame/ui/UIMapWnd.cpp b/src/xrGame/ui/UIMapWnd.cpp index d60f258202e..5b254347114 100644 --- a/src/xrGame/ui/UIMapWnd.cpp +++ b/src/xrGame/ui/UIMapWnd.cpp @@ -597,7 +597,7 @@ void CUIMapWnd::ActivatePropertiesBox(CUIWindow* w) luabind::functor funct; if (GEnv.ScriptEngine->functor("pda.property_box_add_properties", funct)) { - funct(m_UIPropertiesBox, m_cur_location->ObjectID(), (LPCSTR)m_cur_location->GetLevelName().c_str(), m_cur_location); + funct(m_UIPropertiesBox, m_cur_location->ObjectID(), (LPCSTR)m_cur_location->GetLevelName().c_str(), m_cur_location->GetHint()); } // Только для меток РёРіСЂРѕРєР° diff --git a/src/xrGame/ui/UIMapWnd.h b/src/xrGame/ui/UIMapWnd.h index 1407512fe4d..2df2673de0b 100644 --- a/src/xrGame/ui/UIMapWnd.h +++ b/src/xrGame/ui/UIMapWnd.h @@ -19,6 +19,7 @@ class CMapSpot; class CGameTask; class CUIXml; class UIHint; +class CUIPropertiesBox; using GAME_MAPS = xr_map; diff --git a/src/xrGame/ui/UIOutfitInfo.cpp b/src/xrGame/ui/UIOutfitInfo.cpp index 56e77d070aa..356d377e672 100644 --- a/src/xrGame/ui/UIOutfitInfo.cpp +++ b/src/xrGame/ui/UIOutfitInfo.cpp @@ -10,32 +10,18 @@ #include "player_hud.h" #include "UIHelper.h" -constexpr cpcstr immunity_names[] = +constexpr std::tuple immunity_names[] = { - "burn_immunity", - "shock_immunity", - "chemical_burn_immunity", - "radiation_immunity", - "telepatic_immunity", - "wound_immunity", - "fire_wound_immunity", - "strike_immunity", - "explosion_immunity", - nullptr -}; - -constexpr cpcstr immunity_st_names[] = -{ - "ui_inv_outfit_burn_protection", - "ui_inv_outfit_shock_protection", - "ui_inv_outfit_chemical_burn_protection", - "ui_inv_outfit_radiation_protection", - "ui_inv_outfit_telepatic_protection", - "ui_inv_outfit_wound_protection", - "ui_inv_outfit_fire_wound_protection", - "ui_inv_outfit_strike_protection", - "ui_inv_outfit_explosion_protection", - nullptr + // { hit type, "immunity", "immunity text" } + { ALife::eHitTypeBurn, "burn_immunity", "ui_inv_outfit_burn_protection" }, + { ALife::eHitTypeShock, "shock_immunity", "ui_inv_outfit_shock_protection" }, + { ALife::eHitTypeChemicalBurn, "chemical_burn_immunity", "ui_inv_outfit_chemical_burn_protection" }, + { ALife::eHitTypeRadiation, "radiation_immunity", "ui_inv_outfit_radiation_protection" }, + { ALife::eHitTypeTelepatic, "telepatic_immunity", "ui_inv_outfit_telepatic_protection" }, + { ALife::eHitTypeStrike, "strike_immunity", "ui_inv_outfit_strike_protection" }, + { ALife::eHitTypeWound, "wound_immunity", "ui_inv_outfit_wound_protection" }, + { ALife::eHitTypeExplosion, "explosion_immunity", "ui_inv_outfit_explosion_protection" }, + { ALife::eHitTypeFireWound, "fire_wound_immunity", "ui_inv_outfit_fire_wound_protection" }, }; CUIOutfitImmunity::CUIOutfitImmunity() @@ -47,23 +33,23 @@ CUIOutfitImmunity::CUIOutfitImmunity() m_magnitude = 1.0f; } -bool CUIOutfitImmunity::InitFromXml(CUIXml& xml_doc, LPCSTR base_str, u32 hit_type) +bool CUIOutfitImmunity::InitFromXml(CUIXml& xml_doc, pcstr base_str, pcstr immunity, pcstr immunity_text) { CUIXmlInit::InitWindow(xml_doc, base_str, 0, this); string256 buf; - strconcat(sizeof(buf), buf, base_str, ":", immunity_names[hit_type]); + strconcat(sizeof(buf), buf, base_str, ":", immunity); if (!CUIXmlInit::InitWindow(xml_doc, buf, 0, this, false)) return false; CUIXmlInit::InitStatic(xml_doc, buf, 0, &m_name); - m_name.TextItemControl()->SetTextST(immunity_st_names[hit_type]); + m_name.TextItemControl()->SetTextST(immunity_text); - strconcat(sizeof(buf), buf, base_str, ":", immunity_names[hit_type], ":progress_immunity"); + strconcat(sizeof(buf), buf, base_str, ":", immunity, ":progress_immunity"); m_progress.InitFromXml(xml_doc, buf); - strconcat(sizeof(buf), buf, base_str, ":", immunity_names[hit_type], ":static_value"); + strconcat(sizeof(buf), buf, base_str, ":", immunity, ":static_value"); if (xml_doc.NavigateToNode(buf, 0) && !CallOfPripyatMode) { CUIXmlInit::InitStatic(xml_doc, buf, 0, &m_value); @@ -92,7 +78,7 @@ void CUIOutfitImmunity::SetProgressValue(float cur, float comp) // =========================================================================================== void CUIOutfitInfo::InitFromXml(CUIXml& xml_doc) { - LPCSTR base_str = "outfit_info"; + const LPCSTR base_str = "outfit_info"; CUIXmlInit::InitWindow(xml_doc, base_str, 0, this); @@ -104,51 +90,49 @@ void CUIOutfitInfo::InitFromXml(CUIXml& xml_doc) strconcat(sizeof(buf), buf, base_str, ":", "prop_line"); m_Prop_line = UIHelper::CreateStatic(xml_doc, buf, this, false); - Fvector2 pos; - pos.set(0.0f, 0.0f); + Fvector2 pos{}; if (m_Prop_line) pos.set(0.0f, m_Prop_line->GetWndPos().y + m_Prop_line->GetWndSize().y); else if (m_caption) pos.set(0.0f, m_caption->GetWndSize().y); - for (u32 i = 0; i < max_count; ++i) + for (const auto [hit_type, immunity, immunity_text] : immunity_names) { - auto immunity = xr_new(); - if (!immunity->InitFromXml(xml_doc, base_str, i)) + auto item = xr_new(); + if (!item->InitFromXml(xml_doc, base_str, immunity, immunity_text)) { - xr_delete(immunity); + xr_delete(item); continue; } - immunity->SetAutoDelete(true); - AttachChild(immunity); - immunity->SetWndPos(pos); - pos.y += immunity->GetWndSize().y; - - m_items[i] = immunity; + item->SetAutoDelete(true); + AttachChild(item); + item->SetWndPos(pos); + pos.y += item->GetWndSize().y; + m_items[hit_type] = item; } + pos.x = GetWndSize().x; SetWndSize(pos); } void CUIOutfitInfo::UpdateInfo(CCustomOutfit* cur_outfit, CCustomOutfit* slot_outfit) { - CActor* actor = smart_cast(Level().CurrentViewEntity()); + const CActor* actor = smart_cast(Level().CurrentViewEntity()); if (!actor || !cur_outfit) { return; } - for (u32 i = 0; i < max_count; ++i) + for (auto& [hit_type, item] : m_items) { - if (!m_items[i]) + if (!item) continue; - if (i == ALife::eHitTypeFireWound) + if (hit_type == ALife::eHitTypeFireWound) continue; - ALife::EHitType hit_type = (ALife::EHitType)i; - float max_power = actor->conditions().GetZoneMaxPower(hit_type); + const float max_power = actor->conditions().GetZoneMaxPower(hit_type); float cur = cur_outfit->GetDefHitTypeProtection(hit_type); cur /= max_power; // = 0..1 @@ -159,10 +143,10 @@ void CUIOutfitInfo::UpdateInfo(CCustomOutfit* cur_outfit, CCustomOutfit* slot_ou slot = slot_outfit->GetDefHitTypeProtection(hit_type); slot /= max_power; // = 0..1 } - m_items[i]->SetProgressValue(cur, slot); + item->SetProgressValue(cur, slot); } - if (m_items[ALife::eHitTypeFireWound]) + if (const auto& fireWoundItem = m_items[ALife::eHitTypeFireWound]) { IKinematics* ikv = smart_cast(actor->Visual()); VERIFY(ikv); @@ -185,31 +169,30 @@ void CUIOutfitInfo::UpdateInfo(CCustomOutfit* cur_outfit, CCustomOutfit* slot_ou // slot += slot_outfit->GetBoneArmor(spine_bone); //} } - float max_power = actor->conditions().GetMaxFireWoundProtection(); + const float max_power = actor->conditions().GetMaxFireWoundProtection(); cur /= max_power; slot /= max_power; - m_items[ALife::eHitTypeFireWound]->SetProgressValue(cur, slot); + fireWoundItem->SetProgressValue(cur, slot); } } void CUIOutfitInfo::UpdateInfo(CHelmet* cur_helmet, CHelmet* slot_helmet) { - CActor* actor = smart_cast(Level().CurrentViewEntity()); + const CActor* actor = smart_cast(Level().CurrentViewEntity()); if (!actor || !cur_helmet) { return; } - for (u32 i = 0; i < max_count; ++i) + for (auto& [hit_type, item] : m_items) { - if (!m_items[i]) + if (!item) continue; - if (i == ALife::eHitTypeFireWound) + if (hit_type == ALife::eHitTypeFireWound) continue; - ALife::EHitType hit_type = (ALife::EHitType)i; - float max_power = actor->conditions().GetZoneMaxPower(hit_type); + const float max_power = actor->conditions().GetZoneMaxPower(hit_type); float cur = cur_helmet->GetDefHitTypeProtection(hit_type); cur /= max_power; // = 0..1 @@ -220,18 +203,18 @@ void CUIOutfitInfo::UpdateInfo(CHelmet* cur_helmet, CHelmet* slot_helmet) slot = slot_helmet->GetDefHitTypeProtection(hit_type); slot /= max_power; // = 0..1 } - m_items[i]->SetProgressValue(cur, slot); + item->SetProgressValue(cur, slot); } - if (m_items[ALife::eHitTypeFireWound]) + if (const auto& fireWoundItem = m_items[ALife::eHitTypeFireWound]) { IKinematics* ikv = smart_cast(actor->Visual()); VERIFY(ikv); - u16 spine_bone = ikv->LL_BoneID("bip01_head"); + const u16 spine_bone = ikv->LL_BoneID("bip01_head"); - float cur = cur_helmet->GetBoneArmor(spine_bone) * cur_helmet->GetCondition(); - float slot = (slot_helmet) ? slot_helmet->GetBoneArmor(spine_bone) * slot_helmet->GetCondition() : cur; + const float cur = cur_helmet->GetBoneArmor(spine_bone) * cur_helmet->GetCondition(); + const float slot = (slot_helmet) ? slot_helmet->GetBoneArmor(spine_bone) * slot_helmet->GetCondition() : cur; - m_items[ALife::eHitTypeFireWound]->SetProgressValue(cur, slot); + fireWoundItem->SetProgressValue(cur, slot); } } diff --git a/src/xrGame/ui/UIOutfitInfo.h b/src/xrGame/ui/UIOutfitInfo.h index a36743a8684..72a632a6a3f 100644 --- a/src/xrGame/ui/UIOutfitInfo.h +++ b/src/xrGame/ui/UIOutfitInfo.h @@ -14,7 +14,7 @@ class CUIOutfitImmunity final : public CUIWindow public: CUIOutfitImmunity(); - bool InitFromXml(CUIXml& xml_doc, LPCSTR base_str, u32 hit_type); + bool InitFromXml(CUIXml& xml_doc, pcstr base_str, pcstr immunity, pcstr immunity_text); void SetProgressValue(float cur, float comp); pcstr GetDebugType() override { return "CUIOutfitImmunity"; } @@ -41,13 +41,7 @@ class CUIOutfitInfo final : public CUIWindow pcstr GetDebugType() override { return "CUIOutfitInfo"; } protected: - enum - { - max_count = ALife::eHitTypeMax - 3 - }; - CUIStatic* m_caption{}; CUIStatic* m_Prop_line{}; - CUIOutfitImmunity* m_items[max_count]{}; - + xr_unordered_map m_items; }; // class CUIOutfitInfo diff --git a/src/xrGame/ui/UIPdaWnd.cpp b/src/xrGame/ui/UIPdaWnd.cpp index 2f069eb67b8..198d5af6151 100644 --- a/src/xrGame/ui/UIPdaWnd.cpp +++ b/src/xrGame/ui/UIPdaWnd.cpp @@ -162,8 +162,8 @@ void CUIPdaWnd::SendMessage(CUIWindow* pWnd, s16 msg, void* pData) } default: { - R_ASSERT(m_pActiveDialog); - m_pActiveDialog->SendMessage(pWnd, msg, pData); + if (m_pActiveDialog) + m_pActiveDialog->SendMessage(pWnd, msg, pData); } }; } @@ -175,20 +175,24 @@ void CUIPdaWnd::Show(bool status) { InventoryUtilities::SendInfoToActor("ui_pda"); - if (!m_pActiveDialog) + if (!m_sActiveSection.empty()) + SetActiveSubdialog(m_sActiveSection); + else { - if (pUIMapWnd && !pUITaskWnd) - SetActiveSubdialog("eptMap"); - else - SetActiveSubdialog("eptTasks"); + cpcstr subdialog = pUIMapWnd && !pUITaskWnd ? "eptMap" : "eptTasks"; + SetActiveSubdialog(subdialog); + UITabControl->SetActiveTab(subdialog); } - m_pActiveDialog->Show(true); } else { InventoryUtilities::SendInfoToActor("ui_pda_hide"); CurrentGameUI()->UIMainIngameWnd->SetFlashIconState_(CUIMainIngameWnd::efiPdaTask, false); - m_pActiveDialog->Show(false); + if (m_pActiveDialog) + { + m_pActiveDialog->Show(false); + m_pActiveDialog = pUITaskWnd; //hack for script window + } g_btnHint->Discard(); g_statHint->Discard(); } @@ -197,12 +201,12 @@ void CUIPdaWnd::Show(bool status) void CUIPdaWnd::Update() { inherited::Update(); - m_pActiveDialog->Update(); + + if (m_pActiveDialog) + m_pActiveDialog->Update(); if (m_clock) - { m_clock->SetText(GetGameTimeAsString(InventoryUtilities::etpTimeToMinutes).c_str()); - } if (pUILogsWnd) Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(pUILogsWnd, &CUILogsWnd::PerformWork)); @@ -210,12 +214,13 @@ void CUIPdaWnd::Update() void CUIPdaWnd::SetActiveSubdialog(const shared_str& section) { - if (m_sActiveSection == section) - return; + //if (m_sActiveSection == section) + // return; if (m_pActiveDialog) { - UIMainPdaFrame->DetachChild(m_pActiveDialog); + if (UIMainPdaFrame->IsChild(m_pActiveDialog)) + UIMainPdaFrame->DetachChild(m_pActiveDialog); m_pActiveDialog->Show(false); } @@ -241,8 +246,7 @@ void CUIPdaWnd::SetActiveSubdialog(const shared_str& section) luabind::functor functor; if (GEnv.ScriptEngine->functor("pda.set_active_subdialog", functor)) { - CUIDialogWndEx* scriptWnd = functor(section.c_str()); - if (scriptWnd) + if (CUIDialogWndEx* scriptWnd = functor(section.c_str())) { scriptWnd->SetHolder(CurrentDialogHolder()); m_pActiveDialog = scriptWnd; @@ -254,16 +258,18 @@ void CUIPdaWnd::SetActiveSubdialog(const shared_str& section) InventoryUtilities::SendInfoToActor("ui_pda_actor_info"); } - R_ASSERT(m_pActiveDialog); - UIMainPdaFrame->AttachChild(m_pActiveDialog); - m_pActiveDialog->Show(true); - - if (UITabControl->GetActiveId() != section) + if (m_pActiveDialog) { - UITabControl->SetActiveTab(section); + if (!UIMainPdaFrame->IsChild(m_pActiveDialog)) + UIMainPdaFrame->AttachChild(m_pActiveDialog); + m_pActiveDialog->Show(true); + m_sActiveSection = section; + SetActiveCaption(); + } + else + { + m_sActiveSection = ""; } - m_sActiveSection = section; - SetActiveCaption(); } void CUIPdaWnd::SetActiveCaption() @@ -319,25 +325,13 @@ void CUIPdaWnd::Draw() void CUIPdaWnd::DrawHint() { - if (m_pActiveDialog == pUITaskWnd && pUITaskWnd) - { + if (m_sActiveSection == "eptTasks" && pUITaskWnd) pUITaskWnd->DrawHint(); - } - if (m_pActiveDialog == pUIMapWnd && pUIMapWnd) - { + else if (m_sActiveSection == "eptMap" && pUIMapWnd) pUIMapWnd->DrawHint(); - } - else if (m_pActiveDialog == pUIFactionWarWnd && pUIFactionWarWnd) - { - //m_hint_wnd->Draw(); - } - else if (m_pActiveDialog == pUIRankingWnd && pUIRankingWnd) - { + else if (m_sActiveSection == "eptRanking" && pUIRankingWnd) pUIRankingWnd->DrawHint(); - } - else if (m_pActiveDialog == pUILogsWnd && pUILogsWnd) - { - } + m_hint_wnd->Draw(); } @@ -346,7 +340,7 @@ void CUIPdaWnd::UpdatePda() if (pUILogsWnd) pUILogsWnd->UpdateNews(); - if (m_pActiveDialog == pUITaskWnd && pUITaskWnd) + if (m_sActiveSection == "eptTasks" && pUITaskWnd) { pUITaskWnd->ReloadTaskInfo(); } diff --git a/src/xrGame/ui/UIPdaWnd.h b/src/xrGame/ui/UIPdaWnd.h index a6d71836231..367fc56862d 100644 --- a/src/xrGame/ui/UIPdaWnd.h +++ b/src/xrGame/ui/UIPdaWnd.h @@ -77,11 +77,13 @@ class CUIPdaWnd final : public CUIDialogWnd void SetCaption(pcstr text); void Show_SecondTaskWnd(bool status); void Show_MapLegendWnd(bool status); - pcstr GetActiveSection() { return m_sActiveSection.c_str(); }; - CUITabControl* GetTabControl() const { return UITabControl; }; + void SetActiveDialog(CUIWindow* wnd) { m_pActiveDialog = wnd; } + CUIWindow* GetActiveDialog() const { return m_pActiveDialog; } + pcstr GetActiveSection() const { return m_sActiveSection.c_str(); } void SetActiveSubdialog(const shared_str& section); - void SetActiveSubdialog_script(pcstr section) { SetActiveSubdialog(section); }; + CUITabControl* GetTabControl() const { return UITabControl; } + virtual bool StopAnyMove() { return false; } void UpdatePda(); void UpdateRankingWnd(); diff --git a/src/xrGame/ui/UIRankingWnd.cpp b/src/xrGame/ui/UIRankingWnd.cpp index 969e504e174..bd4d8212549 100644 --- a/src/xrGame/ui/UIRankingWnd.cpp +++ b/src/xrGame/ui/UIRankingWnd.cpp @@ -21,33 +21,46 @@ #include "character_reputation.h" #include "relation_registry.h" #include "UICharacterInfo.h" +#include "UIRankFaction.h" +#include "UIAchievements.h" +#include "UIRankingsCoC.h" #include "xrUICore/ui_base.h" #define PDA_RANKING_XML "pda_ranking.xml" CUIRankingWnd::CUIRankingWnd() - : CUIWindow("CUIRankingWnd"), - m_delay(3000), m_previous_time(Device.dwTimeGlobal), m_stat_count(0), + : CUIWindow("CUIRankingWnd"), m_delay(3000), m_previous_time(Device.dwTimeGlobal), m_last_monster_icon_back(""), m_last_monster_icon(""), m_last_weapon_icon("") {} CUIRankingWnd::~CUIRankingWnd() { - auto b = m_achieves_vec.begin(), e = m_achieves_vec.end(); - for (; b != e; ++b) - xr_delete(*b); + for (auto& achievement : m_achieves_vec) + xr_delete(achievement); m_achieves_vec.clear(); + + //Alundaio: CoC Rankings + for (auto& ranking : m_coc_ranking_vec) + xr_delete(ranking); + m_coc_ranking_vec.clear(); + + xr_delete(m_coc_ranking_actor); + //-Alundaio } void CUIRankingWnd::Show(bool status) { if (status) { - m_actor_ch_info->InitCharacter(Actor()->object_id()); + if (m_actor_ch_info) + m_actor_ch_info->InitCharacter(Actor()->object_id()); - string64 buf; - xr_sprintf(buf, sizeof(buf), "%d %s", Actor()->get_money(), "RU"); - m_money_value->SetText(buf); - m_money_value->AdjustWidthToText(); + if (m_money_value) + { + string64 buf; + xr_sprintf(buf, sizeof(buf), "%d %s", Actor()->get_money(), "RU"); + m_money_value->SetText(buf); + m_money_value->AdjustWidthToText(); + } update_info(); inherited::Update(); } @@ -80,70 +93,72 @@ bool CUIRankingWnd::Init() std::ignore = UIHelper::CreateStatic(xml, "center_background", this, false); std::ignore = UIHelper::CreateFrameWindow(xml, "down_background", this, false); - m_actor_ch_info = xr_new(); - m_actor_ch_info->SetAutoDelete(true); - AttachChild(m_actor_ch_info); - m_actor_ch_info->InitCharacterInfo(&xml, "actor_ch_info"); + if (xml.NavigateToNode("actor_ch_info")) + { + m_actor_ch_info = xr_new(); + m_actor_ch_info->SetAutoDelete(true); + AttachChild(m_actor_ch_info); + m_actor_ch_info->InitCharacterInfo(&xml, "actor_ch_info"); - auto* community = m_actor_ch_info->GetIcon(CUICharacterInfo::eCommunity); - auto* communityCaption = m_actor_ch_info->GetIcon(CUICharacterInfo::eCommunityCaption); + auto* community = m_actor_ch_info->GetIcon(CUICharacterInfo::eCommunity); + auto* communityCaption = m_actor_ch_info->GetIcon(CUICharacterInfo::eCommunityCaption); - if (community && communityCaption) - { - communityCaption->AdjustWidthToText(); - pos = community->GetWndPos(); - pos.x = communityCaption->GetWndPos().x + communityCaption->GetWndSize().x + 10.0f; - community->SetWndPos(pos); + if (community && communityCaption) + { + communityCaption->AdjustWidthToText(); + pos = community->GetWndPos(); + pos.x = communityCaption->GetWndPos().x + communityCaption->GetWndSize().x + 10.0f; + community->SetWndPos(pos); + } } std::ignore = UIHelper::CreateFrameWindow(xml, "actor_icon_over", this, false); - auto* money_caption = UIHelper::CreateStatic(xml, "money_caption", this); - m_money_value = UIHelper::CreateStatic(xml, "money_value", this); - money_caption->AdjustWidthToText(); - pos = money_caption->GetWndPos(); - pos.x += money_caption->GetWndSize().x + 10.0f; - m_money_value->SetWndPos(pos); + auto* money_caption = UIHelper::CreateStatic(xml, "money_caption", this, false); + m_money_value = UIHelper::CreateStatic(xml, "money_value", this, false); + if (money_caption && m_money_value) + { + money_caption->AdjustWidthToText(); + pos = money_caption->GetWndPos(); + pos.x += money_caption->GetWndSize().x + 10.0f; + m_money_value->SetWndPos(pos); + } - auto* center_caption = UIHelper::CreateStatic(xml, "center_caption", this); + if (auto* center_caption = UIHelper::CreateStatic(xml, "center_caption", this, false)) + { + string256 buf; + xr_strcpy(buf, center_caption->GetText()); + xr_strcat(buf, StringTable().translate("ui_ranking_center_caption").c_str()); + center_caption->SetText(buf); + } std::ignore = UIHelper::CreateStatic (xml, "fraction_static", this, false); std::ignore = UIHelper::CreateFrameLine(xml, "fraction_line1", this, false); std::ignore = UIHelper::CreateFrameLine(xml, "fraction_line2", this, false); + // Dynamic stats XML_NODE stored_root = xml.GetLocalRoot(); XML_NODE node = xml.NavigateToNode("stat_info", 0); xml.SetLocalRoot(node); - m_stat_count = (u32)xml.GetNodesNum(node, "stat"); + auto stat_count = xml.GetNodesNum(node, "stat"); const u32 value_color = CUIXmlInit::GetColor(xml, "value", 0, 0xFFffffff); - for (u8 i = 0; i < m_stat_count; ++i) + for (size_t i = 0; i < stat_count; ++i) { - m_stat_caption[i] = xr_new("Caption"); - AttachChild(m_stat_caption[i]); - m_stat_caption[i]->SetAutoDelete(true); - CUIXmlInit::InitStatic(xml, "stat", i, m_stat_caption[i]); - m_stat_caption[i]->AdjustWidthToText(); - - m_stat_info[i] = xr_new("Info"); - AttachChild(m_stat_info[i]); - m_stat_info[i]->SetAutoDelete(true); - CUIXmlInit::InitStatic(xml, "stat", i, m_stat_info[i]); - - m_stat_info[i]->SetTextColor(value_color); - - pos.y = m_stat_caption[i]->GetWndPos().y; - pos.x = m_stat_caption[i]->GetWndPos().x + m_stat_caption[i]->GetWndSize().x + 5.0f; - m_stat_info[i]->SetWndPos(pos); + auto* stat_caption = UIHelper::CreateStatic(xml, "stat", i, this); + stat_caption->AdjustWidthToText(); + + auto* stat_info = m_stat_info.emplace_back(UIHelper::CreateStatic(xml, "stat", i, this)); + + stat_info->SetTextColor(value_color); + + pos.y = stat_caption->GetWndPos().y; + pos.x = stat_caption->GetWndPos().x + stat_caption->GetWndSize().x + 5.0f; + stat_info->SetWndPos(pos); } xml.SetLocalRoot(stored_root); - string256 buf; - xr_strcpy(buf, center_caption->GetText()); - xr_strcat(buf, StringTable().translate("ui_ranking_center_caption").c_str()); - center_caption->SetText(buf); - m_factions_list = UIHelper::CreateScrollView(xml, "fraction_list", this, false); if (m_factions_list) { @@ -166,6 +181,7 @@ bool CUIRankingWnd::Init() } } + // Monsters & weapons m_monster_icon_back = UIHelper::CreateStatic(xml, "monster_icon_back", this, false); m_monster_icon = UIHelper::CreateStatic(xml, "monster_icon", this, false); std::ignore = UIHelper::CreateFrameWindow(xml, "monster_background", this, false); @@ -176,6 +192,7 @@ bool CUIRankingWnd::Init() std::ignore = UIHelper::CreateFrameWindow(xml, "favorite_weapon_ramka", this, false); std::ignore = UIHelper::CreateFrameWindow(xml, "favorite_weapon_over", this, false); + // Achievements std::ignore = UIHelper::CreateFrameWindow(xml, "achievements_background", this, false); m_achievements = UIHelper::CreateScrollView(xml, "achievements_wnd", this, false); if (m_achievements) @@ -191,6 +208,37 @@ bool CUIRankingWnd::Init() add_achievement(xml, item.first); } } + + //Alundaio: CoC Rankings + u8 topRankCount = 50; + luabind::functor getRankingArraySize; + + if (GEnv.ScriptEngine->functor("pda.get_rankings_array_size", getRankingArraySize)) + { + topRankCount = getRankingArraySize(); + } + + std::ignore = UIHelper::CreateFrameWindow(xml, "coc_ranking_background", this, false); + if (auto* coc_ranking = UIHelper::CreateScrollView(xml, "coc_ranking_wnd", this, false)) + { + coc_ranking->SetWindowName("coc_ranking_list"); + + for (u8 i = 1; i <= topRankCount; i++) + { + auto character_rank_item = m_coc_ranking_vec.emplace_back(xr_new(coc_ranking)); + character_rank_item->init_from_xml(xml, i, false); + } + } + + if (auto* coc_ranking_actor_view = UIHelper::CreateScrollView(xml, "coc_ranking_wnd_actor", this, false)) + { + coc_ranking_actor_view->SetWindowName("coc_ranking_list_actor"); + + m_coc_ranking_actor = xr_new(coc_ranking_actor_view); + m_coc_ranking_actor->init_from_xml(xml, topRankCount + 1, true); + } + //-Alundaio + xml.SetLocalRoot(stored_root); return true; @@ -235,68 +283,88 @@ void CUIRankingWnd::update_info() for (const auto& achievement : m_achieves_vec) achievement->Update(); + for (const auto& ranking : m_coc_ranking_vec) + ranking->Update(); + get_statistic(); get_best_monster(); get_favorite_weapon(); - if (!m_factions_list) - return; - - bool force_rating = false; - for (u8 i = 0; i < m_factions_list->GetSize(); ++i) + if (m_factions_list) { - if (const auto* ui_faction = smart_cast(m_factions_list->GetItem(i))) + bool force_rating = false; + for (u8 i = 0; i < m_factions_list->GetSize(); ++i) { - if (ui_faction->get_cur_sn() != i + 1) + if (const auto* ui_faction = smart_cast(m_factions_list->GetItem(i))) { - force_rating = true; - break; + if (ui_faction->get_cur_sn() != i + 1) + { + force_rating = true; + break; + } } } - } - for (u8 i = 0; i < m_factions_list->GetSize(); ++i) - { - if (auto* ui_faction = smart_cast(m_factions_list->GetItem(i))) + for (u8 i = 0; i < m_factions_list->GetSize(); ++i) { - ui_faction->update_info(i + 1); - ui_faction->rating(i + 1, force_rating); + if (auto* ui_faction = smart_cast(m_factions_list->GetItem(i))) + { + ui_faction->update_info(i + 1); + ui_faction->rating(i + 1, force_rating); + } } - } - m_factions_list->ForceUpdate(); - get_value_from_script(); + m_factions_list->ForceUpdate(); + } } void CUIRankingWnd::DrawHint() { - auto b = m_achieves_vec.begin(), e = m_achieves_vec.end(); - for (; b != e; ++b) + for (const auto& achievement : m_achieves_vec) + { + if (achievement->IsShown()) + achievement->DrawHint(); + } + + //Alundaio: CoC Ranking + for (const auto& ranking : m_coc_ranking_vec) { - if ((*b)->IsShown()) - (*b)->DrawHint(); + if (ranking->IsShown()) + ranking->DrawHint(); } + + if (m_coc_ranking_actor && m_coc_ranking_actor->IsShown()) + m_coc_ranking_actor->DrawHint(); + //-Alundaio } -void CUIRankingWnd::get_statistic() +void CUIRankingWnd::get_statistic() const { - string128 buf; - InventoryUtilities::GetTimePeriodAsString(buf, sizeof(buf), Level().GetStartGameTime(), Level().GetGameTime()); - m_stat_info[0]->SetTextColor(color_rgba(170, 170, 170, 255)); - m_stat_info[0]->SetText(buf); + u8 idx = 0; + const auto size = m_stat_info.size(); + if (size && m_actor_ch_info && m_money_value) // hacky condition to determine CoC, which don't reserve first stat_info + { + string128 buf; + InventoryUtilities::GetTimePeriodAsString(buf, sizeof(buf), Level().GetStartGameTime(), Level().GetGameTime()); + m_stat_info[0]->SetTextColor(color_rgba(170, 170, 170, 255)); + m_stat_info[0]->SetText(buf); + idx = 1; + } luabind::functor funct; if (!GEnv.ScriptEngine->functor("pda.get_stat", funct)) return; - for (u8 i = 1; i < m_stat_count; ++i) + for (u8 i = idx; i < size; ++i) { cpcstr str = funct(i); m_stat_info[i]->SetTextColor(color_rgba(170, 170, 170, 255)); + m_stat_info[i]->TextItemControl()->SetColoringMode(true); m_stat_info[i]->SetTextST(str); } } + void CUIRankingWnd::get_best_monster() { pcstr str; @@ -336,6 +404,7 @@ void CUIRankingWnd::get_best_monster() } } } + void CUIRankingWnd::get_favorite_weapon() { luabind::functor functor; @@ -379,24 +448,6 @@ bool CUIRankingWnd::SortingLessFunction(CUIWindow* left, CUIWindow* right) return (lpi->get_faction_power() > rpi->get_faction_power()); } -void CUIRankingWnd::get_value_from_script() -{ - string128 buf; - InventoryUtilities::GetTimePeriodAsString(buf, sizeof(buf), Level().GetStartGameTime(), Level().GetGameTime()); - m_stat_info[0]->SetText(buf); - - for (u8 i = 1; i < m_stat_count; ++i) - { - luabind::functor functor; - if (GEnv.ScriptEngine->functor("pda.get_stat", functor)) - { - pcstr str = functor(i); - m_stat_info[i]->SetTextST(str); - } - } -} - - void CUIRankingWnd::ResetAll() { m_last_monster_icon_back = ""; @@ -408,9 +459,17 @@ void CUIRankingWnd::ResetAll() m_monster_icon->TextureOff(); if (m_favorite_weapon_icon) m_favorite_weapon_icon->TextureOff(); - auto b = m_achieves_vec.begin(), e = m_achieves_vec.end(); - for (; b != e; ++b) - (*b)->Reset(); + + for (const auto& achievement : m_achieves_vec) + achievement->Reset(); + + //Alundaio: CoC Rankings + for (const auto& ranking : m_coc_ranking_vec) + ranking->Reset(); + + if (m_coc_ranking_actor) + m_coc_ranking_actor->Reset(); + //-Alundaio inherited::ResetAll(); } diff --git a/src/xrGame/ui/UIRankingWnd.h b/src/xrGame/ui/UIRankingWnd.h index 51bade49ae3..f1184541284 100644 --- a/src/xrGame/ui/UIRankingWnd.h +++ b/src/xrGame/ui/UIRankingWnd.h @@ -2,14 +2,13 @@ // Module : UIRankingWnd.h // Created : 17.01.2008 // Author : Evgeniy Sokolov +// Modified By : Alundaio (8/22/2016) // Description : UI Ranking window class //////////////////////////////////////////////////////////////////////////// #pragma once #include "xrUICore/Windows/UIWindow.h" #include "xrUICore/Callbacks/UIWndCallback.h" -#include "UIRankFaction.h" -#include "UIAchievements.h" class CUIStatic; class CUIXml; @@ -18,6 +17,8 @@ class CUIFrameLineWnd; class CUIFrameWindow; class CUICharacterInfo; class CUIScrollView; +class CUIAchievements; +class CUIRankingsCoC; class CUIRankingWnd final : public CUIWindow, public CUIWndCallback { @@ -34,19 +35,17 @@ class CUIRankingWnd final : public CUIWindow, public CUIWndCallback CUIStatic* m_monster_icon{}; CUIStatic* m_favorite_weapon_icon{}; - using ACHIEVES_VEC = xr_vector; - ACHIEVES_VEC m_achieves_vec; + xr_vector m_achieves_vec; - enum - { - max_stat_info = 15 - }; - CUIStatic* m_stat_caption[max_stat_info]{}; - CUIStatic* m_stat_info[max_stat_info]{}; + //Alundaio: CoC Rankings + xr_vector m_coc_ranking_vec; + CUIRankingsCoC* m_coc_ranking_actor; + //-Alundaio + + xr_vector m_stat_info; u32 m_delay; u32 m_previous_time; - u32 m_stat_count; LPCSTR m_last_monster_icon_back; LPCSTR m_last_monster_icon; LPCSTR m_last_weapon_icon; @@ -69,11 +68,9 @@ class CUIRankingWnd final : public CUIWindow, public CUIWndCallback void add_faction(CUIXml& xml, shared_str const& faction_id); void clear_all_factions(); bool SortingLessFunction(CUIWindow* left, CUIWindow* right); - void get_value_from_script(); void add_achievement(CUIXml& xml, shared_str const& achiev_id); - void get_statistic(); + void get_statistic() const; void get_best_monster(); void get_favorite_weapon(); - }; // class CUIRankingWnd diff --git a/src/xrGame/ui/UIRankingsCoC.cpp b/src/xrGame/ui/UIRankingsCoC.cpp new file mode 100644 index 00000000000..2de9442d27b --- /dev/null +++ b/src/xrGame/ui/UIRankingsCoC.cpp @@ -0,0 +1,155 @@ +#include "StdAfx.h" + +#include "UIRankingsCoC.h" +#include "UIXmlInit.h" +#include "UIHelper.h" +#include "../ai_space.h" + +CUIRankingsCoC::CUIRankingsCoC(CUIScrollView* parent) + : CUIWindow("CUIRankingsCoC"), m_parent(parent) {} + +CUIRankingsCoC::~CUIRankingsCoC() +{ + xr_delete(m_hint); +} + +void CUIRankingsCoC::init_from_xml(CUIXml& xml, u8 index, bool bUnique) +{ + string128 tmp; + xr_sprintf(tmp, sizeof(tmp), "%s", bUnique ? "coc_ranking_itm_actor" : "coc_ranking_itm"); + + CUIXmlInit::InitWindow(xml, tmp, 0, this); + + XML_NODE stored_root = xml.GetLocalRoot(); + XML_NODE node = xml.NavigateToNode(tmp, 0); + + xml.SetLocalRoot(node); + + m_index = index; + m_name = UIHelper::CreateStatic(xml, "name", this); + m_descr = UIHelper::CreateStatic(xml, "descr", this); + m_icon = UIHelper::CreateStatic(xml, "icon", this); + m_hint = UIHelper::CreateHint(xml, "hint_wnd"); + //m_border = UIHelper::CreateStatic(xml, "border", this); + + xml.SetLocalRoot(stored_root); + Show(false); +} +void CUIRankingsCoC::Update() +{ + //if (ParentHasMe()) + // return; + + luabind::functor functorCanShow; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_can_show", functorCanShow)) + { + if (functorCanShow(m_index)) + { + if (!ParentHasMe()) + { + luabind::functor functorSetName; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_set_name", functorSetName)) + SetName(functorSetName(m_index)); + + luabind::functor functorSetDescription; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_set_description", functorSetDescription)) + SetDescription(functorSetDescription(m_index)); + luabind::functor functorSetHint; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_set_hint", functorSetHint)) + SetHint(functorSetHint(m_index)); + + luabind::functor functorSetIcon; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_set_icon", functorSetIcon)) + SetIcon(functorSetIcon(m_index)); + + /* + luabind::functor functorShowBorder; + if (GEnv.ScriptEngine->functor("pda.coc_rankings_show_border", functorShowBorder)) + { + if (functorShowBorder(m_index)) + { + if (!m_border->IsShown()) + m_border->Show(true); + } + else + { + if (m_border->IsShown()) + m_border->Show(false); + } + } + */ + + m_parent->AddWindow(this, false); + if (!IsShown()) + Show(true); + } + } + else + { + if (ParentHasMe()) + { + m_parent->RemoveWindow(this); + if (IsShown()) + Show(false); + } + } + } +} +bool CUIRankingsCoC::ParentHasMe() const +{ + const auto& items = m_parent->Items(); + + const auto it = std::find(items.begin(), items.end(), this); + return it != items.end(); +} + +void CUIRankingsCoC::SetName(pcstr name) const +{ + m_name->TextItemControl()->SetColoringMode(true); + m_name->TextItemControl()->SetUseNewLineMode(true); + m_name->SetText(name); +} + +void CUIRankingsCoC::SetDescription(pcstr desc) +{ + m_descr->TextItemControl()->SetColoringMode(true); + m_descr->TextItemControl()->SetUseNewLineMode(true); + m_descr->SetText(desc); + m_descr->AdjustHeightToText(); + Fvector2 descr_size = m_descr->GetWndSize(); + descr_size.y += 30.0f; + if(descr_size.y>GetWndSize().y) + SetWndSize(Fvector2().set(GetWndSize().x, descr_size.y)); +} + +void CUIRankingsCoC::SetHint(pcstr hint) const +{ + m_hint->set_text(CStringTable().translate(hint).c_str()); +} + +void CUIRankingsCoC::SetIcon(pcstr icon) const +{ + if (!xr_strcmp(icon, "")) + return; + + m_icon->InitTexture(icon); +} + +void CUIRankingsCoC::DrawHint() +{ + Frect r; + GetAbsoluteRect(r); + Fvector2 pos = UI().GetUICursor().GetCursorPosition(); + if (r.in(pos)) + m_hint->Draw(); +} + +void CUIRankingsCoC::Reset() +{ + if (ParentHasMe()) + { + m_parent->RemoveWindow(this); + Show(false); + } + inherited::Reset(); +} diff --git a/src/xrGame/ui/UIRankingsCoC.h b/src/xrGame/ui/UIRankingsCoC.h new file mode 100644 index 00000000000..5186bea830c --- /dev/null +++ b/src/xrGame/ui/UIRankingsCoC.h @@ -0,0 +1,40 @@ +#pragma once + +#include "xrUICore/Windows/UIWindow.h" + +class CUIXml; +class CUIStatic; +class UIHint; +class CUIScrollView; + +class CUIRankingsCoC : public CUIWindow +{ + typedef CUIWindow inherited; + +private: + CUIScrollView* m_parent; + CUIStatic* m_name{}; + CUIStatic* m_descr{}; + CUIStatic* m_icon{}; + //CUIStatic* m_border; + UIHint* m_hint{}; + u8 m_index{}; + +public: + CUIRankingsCoC(CUIScrollView* parent); + ~CUIRankingsCoC() override; + + void init_from_xml(CUIXml& xml, u8 index, bool bUnique); + void Update() override; + + void SetName(pcstr name) const; + void SetDescription(pcstr desc); + void SetHint(pcstr hint) const; + void SetIcon(pcstr icon) const; + + virtual void DrawHint(); + void Reset() override; + +protected: + bool ParentHasMe() const; +}; diff --git a/src/xrGame/ui/UIWpnParams.cpp b/src/xrGame/ui/UIWpnParams.cpp index 82ea67046f5..bc001ebc5a1 100644 --- a/src/xrGame/ui/UIWpnParams.cpp +++ b/src/xrGame/ui/UIWpnParams.cpp @@ -232,6 +232,13 @@ bool CUIWpnParams::Check(const shared_str& wpn_section) { if (pSettings->line_exist(wpn_section, "fire_dispersion_base")) { + //Alundaio: Most likely a fake weapon or melee weapon + if (pSettings->line_exist(wpn_section, "ammo_mag_size")) + if (pSettings->r_u32(wpn_section, "ammo_mag_size") == 0) + return false; + + if (0 == xr_strcmp(pSettings->r_string(wpn_section,"class"), "WP_KNIFE")) + return false; if (0 == xr_strcmp(wpn_section, "wpn_addon_silencer")) return false; if (0 == xr_strcmp(wpn_section, "wpn_binoc")) diff --git a/src/xrGame/ui/ui_af_params.cpp b/src/xrGame/ui/ui_af_params.cpp index 57593b770aa..24ccbccad70 100644 --- a/src/xrGame/ui/ui_af_params.cpp +++ b/src/xrGame/ui/ui_af_params.cpp @@ -3,6 +3,7 @@ #include "xrUICore/Static/UIStatic.h" #include "Actor.h" #include "ActorCondition.h" +#include "inventory_item.h" #include "Common/object_broker.h" #include "UIXmlInit.h" #include "UIHelper.h" @@ -18,7 +19,7 @@ CUIArtefactParams::~CUIArtefactParams() xr_delete(m_Prop_line); } -constexpr std::tuple af_immunity[] = +constexpr std::tuple af_immunity[] = { //{ ALife::infl_, "section", "caption", magnitude, sign_inverse, "unit" } { ALife::infl_rad, "radiation_immunity", "ui_inv_outfit_radiation_protection", 1.0f, false, "%" }, @@ -26,13 +27,11 @@ constexpr std::tuple { ALife::infl_acid, "chemical_burn_immunity", "ui_inv_outfit_chemical_burn_protection", 1.0f, false, "%" }, { ALife::infl_psi, "telepatic_immunity", "ui_inv_outfit_telepatic_protection", 1.0f, false, "%" }, { ALife::infl_electra, "shock_immunity", "ui_inv_outfit_shock_protection", 1.0f, false, "%" }, - //{ ALife::infl_strike, "strike_immunity", "ui_inv_outfit_strike_protection", 1.0f, false, "%" } - //{ ALife::infl_wound, "wound_immunity", "ui_inv_outfit_wound_protection", 1.0f, false, "%" } - //{ ALife::infl_explosion, "explosion_immunity", "ui_inv_outfit_explosion_protection", 1.0f, false, "%" } - //{ ALife::infl_fire_wound, "fire_wound_immunity", "ui_inv_outfit_fire_wound_protection", 1.0f, false, "%" } + { 5, "strike_immunity", "ui_inv_outfit_strike_protection", 1.0f, false, "%" }, + { 6, "wound_immunity", "ui_inv_outfit_wound_protection", 1.0f, false, "%" }, + { 7, "explosion_immunity", "ui_inv_outfit_explosion_protection", 1.0f, false, "%" }, + { 8, "fire_wound_immunity", "ui_inv_outfit_fire_wound_protection", 1.0f, false, "%" }, }; -static_assert(std::size(af_immunity) == ALife::infl_max_count, - "All influences should be listed in the tuple above."); constexpr std::tuple af_restore[] = { @@ -73,6 +72,10 @@ bool CUIArtefactParams::InitFromXml(CUIXml& xml) if ((m_Prop_line = UIHelper::CreateStatic(xml, "prop_line", this, false))) m_Prop_line->SetAutoDelete(false); + //Alundaio: Show AF Condition + m_disp_condition = CreateItem(xml, "condition", "ui_inv_af_condition"); + //-Alundaio + for (auto [id, section, caption, magnitude, sign_inverse, unit] : af_immunity) { m_immunity_item[id] = CreateItem(xml, section, magnitude, sign_inverse, unit, caption); @@ -93,8 +96,7 @@ UIArtefactParamItem* CUIArtefactParams::CreateItem(CUIXml& uiXml, pcstr section, { UIArtefactParamItem* item = xr_new(); - const UIArtefactParamItem::InitResult result = item->Init(uiXml, section); - switch (result) + switch (item->Init(uiXml, section)) { case UIArtefactParamItem::InitResult::Failed: xr_delete(item); @@ -129,23 +131,23 @@ bool CUIArtefactParams::Check(const shared_str& af_section) return !!pSettings->line_exist(af_section, "af_actor_properties"); } -void CUIArtefactParams::SetInfo(shared_str const& af_section) +void CUIArtefactParams::SetInfo(const CInventoryItem& pInvItem) { DetachAll(); if (m_Prop_line) AttachChild(m_Prop_line); - CActor* actor = smart_cast(Level().CurrentViewEntity()); + const CActor* actor = smart_cast(Level().CurrentViewEntity()); if (!actor) - { return; - } - float val = 0.0f, max_val = 1.0f, h = 0.0f; + const shared_str& af_section = pInvItem.object().cNameSect(); + + float h = 0.0f; if (m_Prop_line) h = m_Prop_line->GetWndPos().y + m_Prop_line->GetWndSize().y; - const auto setValue = [&](UIArtefactParamItem* item) + const auto setValue = [&](UIArtefactParamItem* item, const float val) { item->SetValue(val); @@ -157,27 +159,34 @@ void CUIArtefactParams::SetInfo(shared_str const& af_section) AttachChild(item); }; + //Alundaio: Show AF Condition + if (m_disp_condition) + setValue(m_disp_condition, pInvItem.GetCondition()); + //-Alundaio + for (auto [id, immunity_section, immunity_caption, magnitude, sign_inverse, unit] : af_immunity) { if (!m_immunity_item[id]) continue; shared_str const& hit_absorbation_sect = pSettings->r_string(af_section, "hit_absorbation_sect"); - val = pSettings->r_float(hit_absorbation_sect, immunity_section); + float val = pSettings->r_float(hit_absorbation_sect, immunity_section); if (fis_zero(val)) continue; - max_val = actor->conditions().GetZoneMaxPower(id); + val *= pInvItem.GetCondition(); + const float max_val = actor->conditions().GetZoneMaxPower(static_cast(id)); val /= max_val; - setValue(m_immunity_item[id]); + setValue(m_immunity_item[id], val); } if (m_additional_weight) { - val = pSettings->r_float(af_section, "additional_inventory_weight"); + float val = pSettings->r_float(af_section, "additional_inventory_weight"); if (!fis_zero(val)) { - setValue(m_additional_weight); + val *= pInvItem.GetCondition(); + setValue(m_additional_weight, val); } } @@ -186,11 +195,12 @@ void CUIArtefactParams::SetInfo(shared_str const& af_section) if (!m_restore_item[id]) continue; - val = pSettings->r_float(af_section, restore_section); + float val = pSettings->r_float(af_section, restore_section); if (fis_zero(val)) continue; - setValue(m_restore_item[id]); + val *= pInvItem.GetCondition(); + setValue(m_restore_item[id], val); } SetHeight(h); diff --git a/src/xrGame/ui/ui_af_params.h b/src/xrGame/ui/ui_af_params.h index 9b7c9fe1c38..3c89b2f8899 100644 --- a/src/xrGame/ui/ui_af_params.h +++ b/src/xrGame/ui/ui_af_params.h @@ -2,6 +2,7 @@ #include "xrUICore/Windows/UIWindow.h" #include "xrServerEntities/alife_space.h" +class CInventoryItem; class CUIXml; class CUIStatic; class UIArtefactParamItem; @@ -13,7 +14,7 @@ class CUIArtefactParams final : public CUIWindow ~CUIArtefactParams() override; bool InitFromXml(CUIXml& xml); bool Check(const shared_str& af_section); - void SetInfo(const shared_str& af_section); + void SetInfo(const CInventoryItem& pInvItem); pcstr GetDebugType() override { return "CUIArtefactParams"; } protected: @@ -25,7 +26,8 @@ class CUIArtefactParams final : public CUIWindow const shared_str& translationId, const shared_str& translationId2 = nullptr); protected: - UIArtefactParamItem* m_immunity_item[ALife::infl_max_count]{}; + UIArtefactParamItem* m_disp_condition; //Alundaio: Show AF Condition + UIArtefactParamItem* m_immunity_item[9]{}; UIArtefactParamItem* m_restore_item[ALife::eRestoreTypeMax]{}; UIArtefactParamItem* m_additional_weight{}; diff --git a/src/xrGame/visual_memory_manager.cpp b/src/xrGame/visual_memory_manager.cpp index cc2cec36e83..6f7d5dc9409 100644 --- a/src/xrGame/visual_memory_manager.cpp +++ b/src/xrGame/visual_memory_manager.cpp @@ -293,7 +293,7 @@ float CVisualMemoryManager::object_visible_distance(const CGameObject* game_obje float CVisualMemoryManager::object_luminocity(const CGameObject* game_object) const { - if (!smart_cast(game_object)) + if (!smart_cast(game_object)) //Alundaio return (1.f); float luminocity = const_cast(game_object)->ROS()->get_luminocity(); float power = log(luminocity > .001f ? luminocity : .001f) * current_state().m_luminocity_factor; @@ -303,6 +303,11 @@ float CVisualMemoryManager::object_luminocity(const CGameObject* game_object) co float CVisualMemoryManager::get_object_velocity( const CGameObject* game_object, const CNotYetVisibleObject& not_yet_visible_object) const { + //Alundaio: no need to check velocity on anything but stalkers, mutants and actor + if (!smart_cast(game_object)) + return (0.f); + //-Alundaio + if ((game_object->ps_Size() < 2) || (not_yet_visible_object.m_prev_time == game_object->ps_Element(game_object->ps_Size() - 2).dwTime)) return (0.f); @@ -313,7 +318,7 @@ float CVisualMemoryManager::get_object_velocity( return (pos1.vPosition.distance_to(pos0.vPosition) / (float(pos1.dwTime) / 1000.f - float(pos0.dwTime) / 1000.f)); } -float CVisualMemoryManager::get_visible_value( +float CVisualMemoryManager::get_visible_value(const CGameObject* game_object, float distance, float object_distance, float time_delta, float object_velocity, float luminocity) const { float always_visible_distance = current_state().m_always_visible_distance; @@ -321,6 +326,12 @@ float CVisualMemoryManager::get_visible_value( if (distance <= always_visible_distance + EPS_L) return (current_state().m_visibility_threshold); + //Alundaio: hijack not_yet_visible_object to lua + luabind::functor funct; + if (GEnv.ScriptEngine->functor("visual_memory_manager.get_visible_value", funct)) + return (funct(m_object ? m_object->lua_game_object() : nullptr, game_object ? game_object->lua_game_object() : nullptr, time_delta, current_state().m_time_quant, luminocity, current_state().m_velocity_factor, object_velocity, distance, object_distance, always_visible_distance)); + //-Alundaio + return (time_delta / current_state().m_time_quant * luminocity * (1.f + current_state().m_velocity_factor * object_velocity) * (distance - object_distance) / (distance - always_visible_distance)); @@ -391,7 +402,7 @@ bool CVisualMemoryManager::visible(const CGameObject* game_object, float time_de CNotYetVisibleObject new_object; new_object.m_object = game_object; new_object.m_prev_time = 0; - new_object.m_value = get_visible_value(distance, object_distance, time_delta, + new_object.m_value = get_visible_value(game_object, distance, object_distance, time_delta, get_object_velocity(game_object, new_object), object_luminocity(game_object)); clamp(new_object.m_value, 0.f, current_state().m_visibility_threshold + EPS_L); new_object.m_update_time = Device.dwTimeGlobal; @@ -401,7 +412,7 @@ bool CVisualMemoryManager::visible(const CGameObject* game_object, float time_de } object->m_update_time = Device.dwTimeGlobal; - object->m_value += get_visible_value(distance, object_distance, time_delta, + object->m_value += get_visible_value(game_object, distance, object_distance, time_delta, get_object_velocity(game_object, *object), object_luminocity(game_object)); clamp(object->m_value, 0.f, current_state().m_visibility_threshold + EPS_L); object->m_prev_time = get_prev_time(game_object); diff --git a/src/xrGame/visual_memory_manager.h b/src/xrGame/visual_memory_manager.h index b19fe5a48cb..2652ff051a7 100644 --- a/src/xrGame/visual_memory_manager.h +++ b/src/xrGame/visual_memory_manager.h @@ -74,7 +74,7 @@ class CVisualMemoryManager void add_visible_object(const CVisibleObject visible_object); float object_visible_distance(const CGameObject* game_object, float& object_distance) const; float object_luminocity(const CGameObject* game_object) const; - float get_visible_value( + float get_visible_value(const CGameObject* game_object, float distance, float object_distance, float time_delta, float object_velocity, float luminocity) const; float get_object_velocity(const CGameObject* game_object, const CNotYetVisibleObject& not_yet_visible_object) const; u32 get_prev_time(const CGameObject* game_object) const; diff --git a/src/xrGame/xrGame.vcxproj b/src/xrGame/xrGame.vcxproj index 1fc2352e6c6..4c1cfbb81ec 100644 --- a/src/xrGame/xrGame.vcxproj +++ b/src/xrGame/xrGame.vcxproj @@ -784,6 +784,7 @@ + @@ -1371,6 +1372,7 @@ + @@ -1411,7 +1413,6 @@ - @@ -2358,6 +2359,7 @@ pch_script.h $(IntDir)$(ProjectName)_script.pch + pch_script.h @@ -3334,6 +3336,7 @@ + pch_script.h $(IntDir)$(ProjectName)_script.pch @@ -3396,7 +3399,6 @@ - diff --git a/src/xrGame/xrGame.vcxproj.filters b/src/xrGame/xrGame.vcxproj.filters index 6ec15dde90f..20cf6203a66 100644 --- a/src/xrGame/xrGame.vcxproj.filters +++ b/src/xrGame/xrGame.vcxproj.filters @@ -6400,9 +6400,6 @@ Core\Client\Objects\items & weapons\Weapons\Custom Weapon\Pistol - - Core\Client\Objects\items & weapons\Weapons\Custom Weapon\Pistol - Core\Common @@ -6488,6 +6485,12 @@ Core\Client\Objects\items & weapons\HudItem + + Core\Client\Objects\base\GameObject\Holder + + + UI\Common\PDA\Statistics & Rankings + @@ -9755,9 +9758,6 @@ Core\Client\Objects\items & weapons\Weapons\Custom Weapon\Pistol - - Core\Client\Objects\items & weapons\Weapons\Custom Weapon\Pistol - Core\Common @@ -9843,6 +9843,12 @@ UI\Common\PDA\Tasks + + Core\Client\Objects\base\GameObject\Holder + + + UI\Common\PDA\Statistics & Rankings + diff --git a/src/xrServerEntities/clsid_game.h b/src/xrServerEntities/clsid_game.h index 62ff32a3a49..e1a591b4ade 100644 --- a/src/xrServerEntities/clsid_game.h +++ b/src/xrServerEntities/clsid_game.h @@ -130,6 +130,7 @@ constexpr CLASS_ID CLSID_TARGET_CS_CASK = MK_CLSID('T', '_', 'C', 'S constexpr CLASS_ID CLSID_OBJECT_ITEM_STD = MK_CLSID('O', '_', 'I', 'T', 'E', 'M', ' ', ' '); constexpr CLASS_ID CLSID_OBJECT_BREAKABLE = MK_CLSID('O', '_', 'B', 'R', 'K', 'B', 'L', ' '); constexpr CLASS_ID CLSID_OBJECT_CLIMABLE = MK_CLSID('O', '_', 'C', 'L', 'M', 'B', 'L', ' '); +constexpr CLASS_ID CLSID_OBJECT_HOLDER_ENT = MK_CLSID('O', '_', 'H', 'L', 'D', 'R', '_', 'E'); // constexpr CLASS_ID CLSID_PH_SKELETON_OBJECT = MK_CLSID('P', '_', 'S', 'K', 'E', 'L', 'E', 'T'); diff --git a/src/xrServerEntities/object_factory_register.cpp b/src/xrServerEntities/object_factory_register.cpp index c78cbeff712..385d772e180 100644 --- a/src/xrServerEntities/object_factory_register.cpp +++ b/src/xrServerEntities/object_factory_register.cpp @@ -151,6 +151,7 @@ #include "BreakableObject.h" #include "PhysicsSkeletonObject.h" #include "DestroyablePhysicsObject.h" +#include "HolderEntityObject.h" #include "game_sv_single.h" #include "game_sv_deathmatch.h" @@ -395,6 +396,7 @@ void CObjectFactory::register_classes() ADD(CClimableObject, CSE_ALifeObjectClimable, CLSID_OBJECT_CLIMABLE, "obj_climable"); ADD(CPhysicsSkeletonObject, CSE_ALifePHSkeletonObject, CLSID_PH_SKELETON_OBJECT, "obj_phskeleton"); ADD(CDestroyablePhysicsObject, CSE_ALifeObjectPhysic, CLSID_PHYSICS_DESTROYABLE, "obj_phys_destroyable"); + ADD(CHolderEntityObject, CSE_ALifeDynamicObjectVisual, CLSID_OBJECT_HOLDER_ENT, "obj_holder_ent"); ADD(CInventoryBox, CSE_ALifeInventoryBox, CLSID_INVENTORY_BOX, "inventory_box"); ADD(smart_cover::object, CSE_SmartCover, TEXT2CLSID("SMRTCOVR"), "smart_cover"); diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp index 53e19117ae3..23d94864015 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp @@ -600,6 +600,7 @@ u8 CSE_ALifeItemWeapon::get_slot() { return ((u8)pSettings->r_u8(s_name, "slot") u16 CSE_ALifeItemWeapon::get_ammo_limit() { return (u16)pSettings->r_u16(s_name, "ammo_limit"); } u16 CSE_ALifeItemWeapon::get_ammo_total() { return ((u16)a_current); } u16 CSE_ALifeItemWeapon::get_ammo_elapsed() { return ((u16)a_elapsed); } +void CSE_ALifeItemWeapon::set_ammo_elapsed(u16 count) { a_elapsed = count; } u16 CSE_ALifeItemWeapon::get_ammo_magsize() { if (pSettings->line_exist(s_name, "ammo_mag_size")) diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items.h b/src/xrServerEntities/xrServer_Objects_ALife_Items.h index 63f3bdbe683..12f68afffb0 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items.h +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items.h @@ -226,6 +226,7 @@ class CSE_ALifeItemWeapon : public CSE_ALifeItem u16 get_ammo_limit(); u16 get_ammo_total(); u16 get_ammo_elapsed(); + void set_ammo_elapsed(u16 count); u16 get_ammo_magsize(); void clone_addons(CSE_ALifeItemWeapon* parent); diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp index 9c82a0942bc..373dce26d27 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp @@ -19,6 +19,14 @@ SCRIPT_EXPORT(CSE_ALifeInventoryItem, (), [ class_("cse_alife_inventory_item") //.def(constructor()) + .def("has_upgrade", +[](CSE_ALifeInventoryItem* ta, pcstr str) + { + ta->add_upgrade(str); + }) + .def("add_upgrade", +[](CSE_ALifeInventoryItem* ta, pcstr str) + { + return ta->has_upgrade(str); + }) ]; }); @@ -70,6 +78,9 @@ SCRIPT_EXPORT(CSE_ALifeItemWeapon, (CSE_ALifeItem), value("eAddonPermanent", int(CSE_ALifeItemWeapon::EWeaponAddonStatus::eAddonPermanent)) ] .def("clone_addons", &CSE_ALifeItemWeapon::clone_addons) + .def("set_ammo_elapsed", &CSE_ALifeItemWeapon::set_ammo_elapsed) + .def("get_ammo_elapsed", &CSE_ALifeItemWeapon::get_ammo_elapsed) + .def("get_ammo_magsize", &CSE_ALifeItemWeapon::get_ammo_magsize) ]; }); diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp index 2c2b2ee52ac..f1005fbd7c9 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp @@ -878,7 +878,7 @@ u32 CSE_ALifeCreatureAbstract::ef_detector_type() const #ifdef XRGAME_EXPORTS void CSE_ALifeCreatureAbstract::on_death(CSE_Abstract* killer) { - VERIFY(!m_game_death_time); + //VERIFY(!m_game_death_time); m_game_death_time = ai().get_alife() ? alife().time_manager().game_time() : Level().GetGameTime(); fHealth = -1.f; } diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Monsters_script.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Monsters_script.cpp index 97f9a76cb01..77b41630446 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Monsters_script.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Monsters_script.cpp @@ -7,8 +7,12 @@ //////////////////////////////////////////////////////////////////////////// #include "pch_script.h" + +#include "specific_character.h" + #include "xrServer_Objects_ALife_Monsters.h" #include "xrServer_script_macroses.h" + #include "xrScriptEngine/ScriptExporter.hpp" #ifdef XRGAME_EXPORTS diff --git a/src/xrUICore/ComboBox/UIComboBox.cpp b/src/xrUICore/ComboBox/UIComboBox.cpp index c081a788a7a..72e7a2bf6e0 100644 --- a/src/xrUICore/ComboBox/UIComboBox.cpp +++ b/src/xrUICore/ComboBox/UIComboBox.cpp @@ -270,27 +270,20 @@ bool CUIComboBox::OnMouseAction(float x, float y, EUIMessages mouse_action) { if (CUIWindow::OnMouseAction(x, y, mouse_action)) return true; - - bool bCursorOverScb = false; - bCursorOverScb = m_list_box.ScrollBar()->CursorOverWindow(); - switch (m_eState) + if (mouse_action == WINDOW_LBUTTON_DOWN) { - case LIST_EXPANDED: - - if ((!bCursorOverScb) && mouse_action == WINDOW_LBUTTON_DOWN) - { - ShowList(false); - return true; - } - break; - case LIST_FONDED: - if (mouse_action == WINDOW_LBUTTON_DOWN) + switch (m_eState) { + case LIST_EXPANDED: + if (!m_list_box.ScrollBar()->CursorOverWindow()) + { + ShowList(false); + return true; + } + case LIST_FONDED: OnBtnClicked(); return true; } - break; - default: break; } return false; @@ -331,3 +324,13 @@ void CUIComboBox::ClearList() ShowList(false); m_disabled.clear(); } + +void CUIComboBox::SetSelectedIDX(u32 idx) +{ + m_list_box.SetSelectedIDX(idx); +} + +u32 CUIComboBox::GetSelectedIDX() +{ + return m_list_box.GetSelectedIDX(); +} diff --git a/src/xrUICore/ComboBox/UIComboBox.h b/src/xrUICore/ComboBox/UIComboBox.h index e48154dc70c..db1f4847b6c 100644 --- a/src/xrUICore/ComboBox/UIComboBox.h +++ b/src/xrUICore/ComboBox/UIComboBox.h @@ -36,6 +36,8 @@ class XRUICORE_API CUIComboBox final : public CUIWindow, public CUIOptionsItem, void InitComboBox(Fvector2 pos, float width); void SetItemIDX(int idx); void SetItemToken(int tok); + u32 GetSelectedIDX(); + void SetSelectedIDX(u32 idx); virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = 0); virtual void OnFocusLost(); diff --git a/src/xrUICore/ComboBox/UIComboBox_script.cpp b/src/xrUICore/ComboBox/UIComboBox_script.cpp index c937af4380a..beecad65483 100644 --- a/src/xrUICore/ComboBox/UIComboBox_script.cpp +++ b/src/xrUICore/ComboBox/UIComboBox_script.cpp @@ -43,5 +43,7 @@ SCRIPT_EXPORT(CUIComboBox, (CUIWindow), .def("ClearList", &CUIComboBox::ClearList) .def("SetCurrentValue", &CUIComboBox::SetCurrentOptValue) .def("SetCurrentOptValue", &CUIComboBox::SetCurrentOptValue) + .def("SetCurrentIdx", &CUIComboBox::SetSelectedIDX) + .def("GetCurrentIdx", &CUIComboBox::GetSelectedIDX) ]; }); diff --git a/src/xrUICore/ListBox/UIListBoxItem.cpp b/src/xrUICore/ListBox/UIListBoxItem.cpp index 5975bb69229..833e91e4b59 100644 --- a/src/xrUICore/ListBox/UIListBoxItem.cpp +++ b/src/xrUICore/ListBox/UIListBoxItem.cpp @@ -8,7 +8,7 @@ CUIListBoxItem::CUIListBoxItem(float height) : CUIFrameLineWnd(CUIListBoxItem::GetDebugType()), m_text(nullptr), tag(u32(-1)) { SetHeight(height); - m_text = AddTextField("---", 10.0f); + m_text = AddTextField("", 10.0f); } void CUIListBoxItem::SetTAG(u32 value) { tag = value; } @@ -39,8 +39,12 @@ bool CUIListBoxItem::OnMouseDown(int mouse_btn) GetMessageTarget()->SendMessage(this, LIST_ITEM_CLICKED, &tag); return true; } - else - return false; + if (mouse_btn == MOUSE_2) + { + GetMessageTarget()->SendMessage(this, WINDOW_RBUTTON_DOWN, &tag); + return true; + } + return false; } void CUIListBoxItem::SetTextColor(u32 color) { m_text->SetTextColor(color); } diff --git a/src/xrUICore/ListWnd/UIListItemEx.cpp b/src/xrUICore/ListWnd/UIListItemEx.cpp index 3b7b12710c6..a9b1e35f662 100644 --- a/src/xrUICore/ListWnd/UIListItemEx.cpp +++ b/src/xrUICore/ListWnd/UIListItemEx.cpp @@ -15,7 +15,7 @@ CUIListItemEx::CUIListItemEx() : m_dwSelectionColor(color_argb(200, 95, 82, 74)) { //. InitTexture("ui\\hud_map_point"); //. SetStretchTexture(true); - inherited::SetColor(color_argb(0, 0, 0, 0)); + inherited::SetTextureColor(color_argb(0, 0, 0, 0)); } CUIListItemEx::~CUIListItemEx() @@ -29,11 +29,11 @@ void CUIListItemEx::SendMessage(CUIWindow* /*pWnd*/, s16 msg, void* /*pData*/) switch (msg) { case LIST_ITEM_SELECT: - this->SetColor(m_dwSelectionColor); + this->SetTextureColor(m_dwSelectionColor); //this->Draw(); break; case LIST_ITEM_UNSELECT: - this->SetColor(color_argb(0, 0, 0, 0)); + this->SetTextureColor(color_argb(0, 0, 0, 0)); //this->Draw(); break; } diff --git a/src/xrUICore/ProgressBar/UIProgressBar.cpp b/src/xrUICore/ProgressBar/UIProgressBar.cpp index 3db384df4ba..2f2b603fb97 100644 --- a/src/xrUICore/ProgressBar/UIProgressBar.cpp +++ b/src/xrUICore/ProgressBar/UIProgressBar.cpp @@ -59,7 +59,7 @@ void CUIProgressBar::UpdateProgressBar() if (m_bUseColor) { - if ( m_bUseGradient ) + if (m_bUseGradient) { Fcolor curr; if (m_bUseMiddleColor) diff --git a/src/xrUICore/PropertiesBox/UIPropertiesBox_script.cpp b/src/xrUICore/PropertiesBox/UIPropertiesBox_script.cpp index 16ede4004dc..1e3b7484100 100644 --- a/src/xrUICore/PropertiesBox/UIPropertiesBox_script.cpp +++ b/src/xrUICore/PropertiesBox/UIPropertiesBox_script.cpp @@ -1,5 +1,6 @@ #include "pch.hpp" #include "UIPropertiesBox.h" +#include "ListBox/UIListBoxItem.h" #include "xrScriptEngine/ScriptExporter.hpp" SCRIPT_EXPORT(CUIPropertiesBox, (CUIFrameWindow), @@ -14,8 +15,9 @@ SCRIPT_EXPORT(CUIPropertiesBox, (CUIFrameWindow), .def("RemoveAll", &CUIPropertiesBox::RemoveAll) .def("Show", (void (CUIPropertiesBox::*)(int, int)) &CUIPropertiesBox::Show) .def("Hide", &CUIPropertiesBox::Hide) - // .def("GetClickedIndex", &CUIPropertiesBox::GetClickedIndex) + .def("GetSelectedItem", &CUIPropertiesBox::GetClickedItem) .def("AutoUpdateSize", &CUIPropertiesBox::AutoUpdateSize) .def("AddItem", &CUIPropertiesBox::AddItem_script) + .def("InitPropertiesBox", &CUIPropertiesBox::InitPropertiesBox) ]; }); diff --git a/src/xrUICore/Static/UIStatic.h b/src/xrUICore/Static/UIStatic.h index b5e9817059e..95338579d6a 100644 --- a/src/xrUICore/Static/UIStatic.h +++ b/src/xrUICore/Static/UIStatic.h @@ -60,9 +60,6 @@ class XRUICORE_API CUIStatic : public CUIWindow, public ITextureOwner, public CU TextItemControl()->m_TextOffset.y = y; } - virtual void SetColor(u32 color) { m_UIStaticItem.SetColor(color); } - virtual u32 GetColor() const { return m_UIStaticItem.GetColor(); } - virtual void CreateShader(LPCSTR tex, LPCSTR sh = "hud" DELIMITER "default"); ui_shader& GetShader() { return m_UIStaticItem.GetShader(); }; virtual void SetTextureColor(u32 color) { m_UIStaticItem.SetTextureColor(color); } diff --git a/src/xrUICore/Static/UIStaticItem.h b/src/xrUICore/Static/UIStaticItem.h index c9bb8a1cd48..0688717fd29 100644 --- a/src/xrUICore/Static/UIStaticItem.h +++ b/src/xrUICore/Static/UIStaticItem.h @@ -51,11 +51,8 @@ class XRUICORE_API CUIStaticItem IC float GetPosY() { return vPos.y; } IC void SetTextureColor(u32 clr) { dwColor = clr; } IC u32 GetTextureColor() const { return dwColor; } - void SetColor(u32 clr) { dwColor = clr; } - void SetColor(Fcolor clr) { dwColor = clr.get(); } - u32 GetColor() const { return dwColor; } - u32& GetColorRef() { return dwColor; } ui_shader& GetShader() { return hShader; } + public: CUIStaticItem(); IC void SetSize(const Fvector2& sz) diff --git a/src/xrUICore/Static/UIStatic_script.cpp b/src/xrUICore/Static/UIStatic_script.cpp index a508b3de923..b266c2c8f69 100644 --- a/src/xrUICore/Static/UIStatic_script.cpp +++ b/src/xrUICore/Static/UIStatic_script.cpp @@ -50,8 +50,8 @@ SCRIPT_EXPORT(CUIStatic, (CUIWindow), .def("GetTextX", +[](CUIStatic* self) { return self->TextItemControl()->m_TextOffset.x; }) .def("GetTextY", +[](CUIStatic* self) { return self->TextItemControl()->m_TextOffset.y; }) - .def("SetColor", &CUIStatic::SetColor) - .def("GetColor", &CUIStatic::GetColor) + .def("SetColor", &CUIStatic::SetTextureColor) + .def("GetColor", &CUIStatic::GetTextureColor) .def("SetFont", &CUIStatic::SetFont) .def("GetFont", &CUIStatic::GetFont)