-
Число публикаций
297 -
Регистрация
-
Последнее посещение
-
AMKoin
7,433 [Подарить AMKoin]
Закладки
-
Правки и моды к S.T.A.L.K.E.R. 2
Правки и моды к S.T.A.L.K.E.R. 2Есть рецепт увеличения производительности с DTF.
Можно значительно улучшить производительность, если отключить Lumen и всю остальную трассировку лучей. Освещение станет более плоским и примитивным, но игра в целом всё равно будет выглядеть неплохо. И самое главное — значительно вырастет FPS.
Найдите файл GameUserSettings.ini по адресу C:\Users («Пользователи»)\ИмяПользователя\AppData\Stalker2\Saved\Config\Windows
Добавьте в конец файла следующие строки:
[SystemSettings] r.RayTracing=False r.RayTracing.Shadows=False r.RayTracing.Reflections=False r.RayTracing.AmbientOcclusion=False r.RayTracing.GlobalIllumination=False r.RayTracing.Lighting=False r.RayTracing.Translucency=False r.RayTracing.SkyLight=False r.Lumen.Reflections=False r.Lumen.Reflections.HardwareRayTracing=False r.Lumen.Reflections.ScreenTraces=False r.Lumen.GlobalIllumination=False r.Lumen.ScreenProbeGather=False
После этого сохраните файл.
Добавлю от себя - бэкап файлика не забудьте сделать на всякий.
-
"косые сталкеры"
[SoC] Ковыряемся в файлах08.10.2024 в 20:02, Капрал Хикс сказал:[error]File : E:\stalker\sources\trunk\xrCore\xrDebugNew.cpp
[error]Line : 804 - тут скорее всего 815 должно быть, у меня движок правленый X-ray extensions.После включения префетча звуков такой вылет был, пока не заменил скобки [[ на ", в sound_theme.script (во всех ph_snd_themes).
08.10.2024 в 16:25, Balavnik сказал:Можно ли выносить секцию [spawn] в ltx-файл?
Можно выносить кастомдату любых объектов. Работает во частях трилогии.
10 часов назад, DarkSnowder сказал:где прописаны показатели повышения ранга НПС в момент их привязки к смарту?
smart_terrain.script, se_smart_terrain:update_obj_rank и game_relations.ltx, [smart_terrain_rank_change]
10.10.2024 в 17:57, Sikorskyi сказал:В чистом ТЧ 1.0006 есть такой баг, как "косые сталкеры", когда нпс целятся в бок, угрожая гг.
В state_mgr.script, function state_manager:set_state
Находишь ориг. блок кода: if state_lib.states[self.target_state].movement ~= move.stand and state_lib.states[state_name].movement == move.stand then self.npc:movement_enabled(false) end и меняешь его на: if state_lib.states[self.target_state].movement ~= move.stand and state_lib.states[self.target_state].animation ~= nil and --'исправление анимации нпс при наведении оружия на игрока state_lib.states[state_name].movement == move.stand then self.npc:movement_enabled(false) end
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлах22 часа назад, Капрал Хикс сказал:микрозависания при подходе к Бару
Где-то встречал, что нужно заранее грузить все звуки для нпс (characters_voice). Для движка правок не встречал, но оригинале есть функции для итерации звуков и их префетча, реализация в sound_prefetch.script. Работает не пойми как, вроде чуть лучше стало.
https://drive.google.com/file/d/1jC_4xSqnypxmG_qoEPPIhM6O0gD75MVf/view?usp=sharing
Для чистой игры, чтобы сразу в баре + правленые скрипты, т.к. изначально sound_prefetch отключен.
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлахВ который раз подниму тему про микрозависания при подходе к Бару... Вроде говорилось по то, что там сразу четыре гулага в онлайн выходят... Оттого и фриз. Как это вообще разрулить по уму? Фиксил кто конкретно этот момент у себя? P. S. Движок OGSR не предлагать:).
-
Скриптование
Скриптование@Balavnik, перебор всех предметов в инвентаре и подсчёт количества каждого типа предмета с возвратом таблицы вида { секция1 = кол-во1, секция2 = кол-во2...}:
Скрытый текстfunction enumerate_items() local counts = {} db.actor:iterate_inventory(function(dummy, item) local sect = item:section() if counts[sect] then counts[sect] = counts[sect] + 1 else counts[sect] = 1 end end, nil) return counts end -- использование local item_counts = enumerate_items() -- получаем таблицу секций предметов в инвентаре и их количества for section, count in pairs(item_counts) do -- здесь что-то делаем с каждой секцией и количеством end
Имхо, это всё вопросы для Скриптования, а не Ковырялки.
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлах2 часа назад, UriZzz сказал:функции позволяющие их скриптово закрыть?
function close_current_inv_window() local engine_inv = level.main_input_receiver() if engine_inv ~= nil then engine_inv:GetHolder():start_stop_menu(engine_inv,true) engine_inv = nil end end
В "СЗ" оно долгие годы было частью скриптового инвентаря.
-
[CoP] Ковыряемся в файлах
[CoP] Ковыряемся в файлах1 час назад, SWEAW сказал:В общем, сделал по совету, это
Не правильно. Нужно было ИЛИ раскоментировать стандартный код ИЛИ изменить его, как посоветовал @Kirgudu.
Посмотри внимательно, как написано в его посте.
В функции "trade_manager.update" в условиях для переменных "tt.update_time" и "tt.resuply_time" нужно поменять знак сравнения на "больше" - ">".
При использовании "game.time()" значения времени 60000 и 120000 чрезвычайно малы.
-
[CoP] Ковыряемся в файлах
[CoP] Ковыряемся в файлах2 часа назад, WinCap сказал:И, может быть, его активация вызовет ещё какие-нибудь ошибки.
Чтобы обезопасить себя от теоретически возможных ошибок, но при этом сохранить значения таймаутов хотя бы для находящихся в онлайне торговцев, можно записать переинициализацию таблицы примерно так:
--' if trade_manager[npc:id()] == nil then -- trade_manager[npc:id()] = {} -- вместо этой строки пишем нижеследующую trade_manager[npc:id()] = trade_manager[npc:id()] and { update_time = trade_manager[npc:id()].update_time, resuply_time = trade_manager[npc:id()].resuply_time } or {} --' end
-
[CoP] Ковыряемся в файлах
[CoP] Ковыряемся в файлах30.05.2024 в 12:02, SWEAW сказал:Подскажите, пожалуйста, как изменить trade_manager.script, чтобы торговцы обновляли ассортимент не раз в реальные сутки, а раз в несколько игровых, и, не менее важно, чтобы обновление ассортимента не вызывалось сейв-лоадом (потому что это по сути своей абуз).
Как уже и ответили выше, обновление ассортимента торговцев происходит при вызове функции "npc:buy_supplies(tt.config, str)".
Именно в этот момент в движке происходит наполнение ассортимента в соответствии с конфигами и вызывается она именно из "trade_manager.script".
В этом скрипте присутствуют две переменных для отсчёта времени "tt.update_time" и "tt.resuply_time" и они даже сохраняются и загружаются, но есть один "косяк". Эти переменные загружаются в таблицу в функции "trade_manager.load", а в функции "trade_manager.trade_init" эта таблица "затирается" новой и переменные становятся "nil":
--' if trade_manager[npc:id()] == nil then trade_manager[npc:id()] = {} --' end
И, как следствие, на первом же апдейте, происходит обновление ассортимента торговцев.
Можно раскомментировать условие и тогда обновления ассортимента после save/load’а не будет, но только для тех торговцев кто online. Если отойти подальше и сделать save/load, то он обновится. Поскольку "xr_motivator.script", откуда вызывается сохранение и загрузка trade_manager’а, работает только для тех, кто online.
З.Ы. Дополнительно отмечу, что причина, по которой ПЫСы закомментировали этот код, неизвестна. И, может быть, его активация вызовет ещё какие-нибудь ошибки.
-
[CS] Ковыряемся в файлах
[CS] Ковыряемся в файлахОстановка выдачи заданий категории recover_item (поиск уникальных предметов) после перехода на новую локацию – проблема древняя, однако найти исправление отдельно от глобальных модов и с описанием не удалось. Выкладываю здесь, может кому пригодится…
Проблема кроется в механизме обработки заданий: сначала они все сохраняются в список [task_manager.script] self.inited_tasks в статусе normal (готово к выдаче), потом переводятся в статус selected / completed (начато / выполнено) и удаляются по мере выполнения, при этом задание, которое было только просмотрено (даже в виде заголовка), но не начато, остается в списке навечно.
Ввиду того, что все задания recover_item используют общий заголовок, задание со старой локации занимает собой единственное место в очереди, но не выдается, так как не может пройти проверку actor_on_level(…).
Дополнительная сложность: перед выдачей в диалог все задания также сохраняются в память отряда под номером категории (для recover_item это номер [3], который почему-то не совпадает с номером [7] в менеджере заданий), а все дефолтные проверки сделаны без учета варианта "есть порядковый номер задания entity_id в памяти отряда squad.random_tasks[?], но нет самого задания в inited_tasks".
Правка сводится к удалению "висящих" заданий из памяти и изменению проверок, связанных с перебором squad.random_tasks целиком или только категории recover_item. Ну и, раз уж есть очистка памяти, можно сделать случайный выбор задания при входе в диалог, чтобы не все отряды NPC на локации искали один и тот же предмет.
Начинать новую игру не требуется.
Spoiler-- очистка памяти (возможно, задание с другой локации) и апдейт отряда [sim_squad_generic.script] function sim_squad_generic:init_squad_task() … local task = tm:select_task("recover_item", self.squad_id, player.player_name) (+) выше if tm.inited_tasks.recover_item ~= nil then if tm.inited_tasks.recover_item.status == "normal" then tm.inited_tasks.recover_item = nil end end … function sim_stay_point:update() … local task_entity_id = squad.random_tasks[3] … if task.status == "selected" then (/) if task and task.status == "selected" then -- проверки в диалогах [task_dialogs.script] function squad_has_tasks(npc, actor, p1, p2) function squad_hasnt_tasks(npc, actor, p1, p2) (–) if(task_manager.get_task_manager():get_task_by_entity_id(v).status~="selected") then (+) local rt = task_manager.get_task_manager():get_task_by_entity_id(v) if rt and rt.status ~= "selected" then … function show_tasks(npc, actor, dialog, phrase) function show_description(npc, dialog_name, phrase_id) … if(tsk.status~="selected") then (/) if tsk and tsk.status ~= "selected" then … function give_squad_capture_task(npc, actor, p1, p2) function squad_hasnt_capture_tasks(actor, npc, p1, p2, p3) … if task.status ~= "selected" then (/) if task and task.status ~= "selected" then … function is_recover_item_task(actor, npc) … if task.target == npc_id then (/) if task and task.target == npc_id then -- случайный выбор [task_manager.script] function CRandomTask:select_task(type, obj, faction) … (–) for k,v in pairs(task_table) do if v:check_target(obj, faction) then if v.prior > max_prior then max_prior = v.prior selected_task = v end end end (+) local rec = {} for k,v in pairs(task_table) do if v:check_target(obj, faction) then if type ~= "recover_item" then if v.prior > max_prior then max_prior = v.prior selected_task = v end else rec[#rec +1] = v end end end if next(rec) then selected_task = rec[ math.random(#rec) ] end
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлах03.02.2024 в 16:39, Balavnik сказал:Например npc:id() прокатит? Или это метод клиента и не прокатит?
Прокатит-непрокатит, покатит-непокатит... вам не надоело в асфальтовый каток играться?
Можно же изначально писать функции устойчивые к нештатным ситуациям/готовые распознать что угодно в рамках разумно-ожидаемого.
function get_id(obj) if obj ~= nil then if type(obj.id) == 'function' then return obj:id() end -- Если получен клиентский объект, возвращаем его ID if type(obj.id) == 'number' then return obj.id end -- Если получен серверный объект, возвращаем его ID end return nil -- Если объект не получен, или не имеет поля id в ожидаемом формате. Значит это не клиентский и не серверный объект, и возвращать нечего. end
-
Prosectors Project
Prosectors ProjectДополню по подключению.
У нас в используется система событий, она позволяет легко и удобно подключать и отключать различные скриптовые модули без необходимости правки оригинальных файлов.
1. Файл скрипта должен начинаться на 'm_' (пр. m_sos.script), в этом случае он будет автоматически проинициализирован.2. создать функцию init()
function init() end
Она будет вызвана автоматически при инициализации скрипта. Это происходит на этапе создания сервера, ещё до загрузки уровня, поэтому игровые объекты, худ и многое другое тут ещё не доступны.3. Регистрация функций на вызов при определённом событии
function init() event("actor_update"):register(update) end
где "actor_update" - это название события, update - функцияВ данном случае update будет вызываться на каждом апдейте актора. Для того, чтобы функция вызывалась реже, пишем так
event("actor_update"):register(update, {__period = 500})
Вызов будет происходить по прошествии указанного времени (в мс) с прошлого, в данном случае 2 раза в секунду.4. Перейдём к самой функции
function update(args) if actor.health > 0.5 then actor.health = (0.5 - actor.health) / args.delta end end
Список аргументов в функцию передаётся в виде таблицы args. В данном случаеargs.time - текущее время (time_global)
args.delta - время, прошедшее с прошлого апдейта
args.binder - биндер актора
5. События и аргументы можно посмотреть в коде поиском по слову 'trigger'
actor_bind
actor_finalize
actor_spawn
actor_destroy
actor_stor
info_received
item_take
item_drop
item_ruck
item_slot
item_use
actor_enter
actor_exit
key_press
key_release
start_dialog
stop_dialog
actor_hit
item_group
item_take_from_box
trade_action
article_received
task_received
update_1st
actor_update
storage_save
storage_load
actor_save
actor_load
trade_perform
trade_terminate
=====
heli_spawn
heli_destroy
heli_death
=====
box_spawn
box_destroy
box_used
box_take
box_drop
box_open
box_close
obj_spawn
obj_used
obj_hit
obj_death
=====
mob_alive_use
mob_corpse_use
mob_living_update
mob_corpse_update
mob_update
mob_death
mob_hit
corpse_spawn
mob_spawn
mob_destroy
mob_save
mob_load
npc_spawn
npc_destroy
npc_hit
npc_death
npc_death_st
npc_living_used
npc_corpse_used
npc_used
npc_1st_update
npc_corpse_update
npc_living_update
npc_update
npc_save
npc_load
trader_used
trader_spawn
trader_destroy
trader_update
trader_save
trader_load
activate_by_section
6. Событие presets. Вызывается при спавне актора и используется для инициализации после загрузки уровня - например поиск графов, создание элементов худа и т.д.
function init() event("presets"):register(presets) end function presets() end
На этом пока всё, возможности системы раскрыл не полностью, но в основном. Примеров использования в скриптах предостаточно.Кроме того присутствуют другие замечательные системы - хранилище, таймеры, а также много другого функционала, полезного для разработчиков. Но об этом в другой раз.
При адаптации скриптов нужно иметь ввиду, что некоторые файлы/функции переименованы и вносить соответствующие корректировки (например ranks -> m_ranks; vector_rotate_y -> vector.rotate_y). И это касается конечно не только скриптов.
-
Prosectors Project
Prosectors ProjectЕдем дальше.
@ted.80, рассмотрел твои мини-моды, написал тутор по подключению. Автопауза и автосейв у нас по моему есть в дебаге, их, возможно, мы просто выведем во внутриигровое меню.
to ALL: Тутор по подключению опциональных модулей на примере actor_talk.script предложенный @ted.80.
Созданием файла:
1. В папке scripts создаем папку optional.
2. В папке optional создаем m_actor_talk.script.
Подключение модуля:
1. Берем текст из скрипта по ссылке и вставляем его в наш созданный файл (m_actor_talk.script), исходный вариант:
local radTbl = { [[characters_voice\human_01\dolg\states\radiation\radiation_1]], [[characters_voice\human_01\dolg\states\radiation\radiation_2]], [[characters_voice\human_01\dolg\states\radiation\radiation_3]], [[characters_voice\human_01\dolg\states\radiation\radiation_4]] } local hpTbl = { [[characters_voice\human_01\ecolog\states\health\health_1]], [[characters_voice\human_01\newbie\states\idle\idle_19]], [[characters_voice\human_01\stalker\states\idle\idle_26]], [[characters_voice\human_01\killer\states\idle\idle_19]] } local hlTbl = { [[characters_voice\human_01\killer\help\wounded_heavy\help_3]], [[characters_voice\human_01\killer\help\wounded_heavy\help_4]], [[characters_voice\human_01\killer\help\wounded_heavy\help_5]], [[characters_voice\human_01\killer\help\wounded_heavy\help_6]] } local victimSTbl = { [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_1]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_2]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_3]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_4]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_5]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_6]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_7]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_1]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_2]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_3]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_4]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_5]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_6]] } local victimMTbl ={ [[characters_voice\human_01\stalker\fight\fire\fire_1]], [[characters_voice\human_01\stalker\fight\fire\fire_2]], [[characters_voice\human_01\stalker\fight\fire\fire_3]], [[characters_voice\human_01\stalker\fight\fire\fire_4]], [[characters_voice\human_01\stalker\fight\fire\fire_5]], [[characters_voice\human_01\stalker\fight\fire\fire_6]], [[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_1]], [[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_2]], [[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_3]] } local Ptimer1, Ntimer1 = 0, 0 function start_talk() vol = 0.7 if db.actor.health < 0.33 then rand_music = hlTbl[math.random(#hlTbl)] this.playsnd(rand_music,vol) end if db.actor.health < 0.66 then rand_music = hpTbl[math.random(#hpTbl)] this.playsnd(rand_music,vol) end if db.actor.radiation > 0.1 and db.actor.health > 0.66 then rand_music = radTbl[math.random(#radTbl)] this.playsnd(rand_music,vol) end end function kill_mob(victim) vol = 0.5 local Ntimer2 = time_global() if Ntimer1 < Ntimer2 then Ntimer1 = Ntimer2 + 8000 if victim and IsStalker(victim) then rand_music = victimSTbl[math.random(#victimSTbl)] end if victim and IsMonster(victim) then rand_music = victimMTbl[math.random(#victimMTbl)] end this.playsnd(rand_music,vol) end end function playsnd(rand_music,vol) local Ptimer2 = time_global() if Ptimer1 < Ptimer2 then Ptimer1 = Ptimer2 + 10000 playsnd_obj = xr_sound.get_safe_sound_object(rand_music) playsnd_obj:play_no_feedback(db.actor, sound_object.s2d, 1, vector(), vol) end end
2. Во всем скрипте заменяем db.actor на actor
3. Заменяем xr_sound на m_sound (82 строка)
4. В конец(!) скрипта добавляем такую конструкцию:
function init() event("actor_update"):register(start_talk) event("mob_death"):register(kill_mob) event("npc_death"):register(kill_mob) end
5. Аргумент в функции kill_mob меняем на e, и следующей строкой пишем local victim = e.victim
6. В базе звуков меняем строчки:
[[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_1]], [[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_2]], [[characters_voice\human_01\dolg\reactions\dead_mutant\dead_mutant_3]]
на:
[[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_1]], [[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_2]], [[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_3]]
7. Конечный вариант скрипта должен получится таким:
local radTbl = { [[characters_voice\human_01\dolg\states\radiation\radiation_1]], [[characters_voice\human_01\dolg\states\radiation\radiation_2]], [[characters_voice\human_01\dolg\states\radiation\radiation_3]], [[characters_voice\human_01\dolg\states\radiation\radiation_4]] } local hpTbl = { [[characters_voice\human_01\ecolog\states\health\health_1]], [[characters_voice\human_01\newbie\states\idle\idle_19]], [[characters_voice\human_01\stalker\states\idle\idle_26]], [[characters_voice\human_01\killer\states\idle\idle_19]] } local hlTbl = { [[characters_voice\human_01\killer\help\wounded_heavy\help_3]], [[characters_voice\human_01\killer\help\wounded_heavy\help_4]], [[characters_voice\human_01\killer\help\wounded_heavy\help_5]], [[characters_voice\human_01\killer\help\wounded_heavy\help_6]] } local victimSTbl = { [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_1]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_2]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_3]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_4]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_5]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_6]], [[characters_voice\human_01\stalker\fight\enemy_down\enemy_down_7]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_1]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_2]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_3]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_4]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_5]], [[characters_voice\human_01\stalker\fight\enemy_hit\enemy_hit_6]] } local victimMTbl ={ [[characters_voice\human_01\stalker\fight\fire\fire_1]], [[characters_voice\human_01\stalker\fight\fire\fire_2]], [[characters_voice\human_01\stalker\fight\fire\fire_3]], [[characters_voice\human_01\stalker\fight\fire\fire_4]], [[characters_voice\human_01\stalker\fight\fire\fire_5]], [[characters_voice\human_01\stalker\fight\fire\fire_6]], [[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_1]], [[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_2]], [[characters_voice\_deleted\reactions\dead_mutant\dead_mutant_3]] } local Ptimer1, Ntimer1 = 0, 0 function start_talk() vol = 0.7 if actor.health < 0.33 then rand_music = hlTbl[math.random(#hlTbl)] this.playsnd(rand_music,vol) end if actor.health < 0.66 then rand_music = hpTbl[math.random(#hpTbl)] this.playsnd(rand_music,vol) end if actor.radiation > 0.1 and actor.health > 0.66 then rand_music = radTbl[math.random(#radTbl)] this.playsnd(rand_music,vol) end end function kill_mob(e) local victim = e.victim vol = 0.5 local Ntimer2 = time_global() if Ntimer1 < Ntimer2 then Ntimer1 = Ntimer2 + 8000 if victim and IsStalker(victim) then rand_music = victimSTbl[math.random(#victimSTbl)] end if victim and IsMonster(victim) then rand_music = victimMTbl[math.random(#victimMTbl)] end this.playsnd(rand_music,vol) end end function playsnd(rand_music,vol) local Ptimer2 = time_global() if Ptimer1 < Ptimer2 then Ptimer1 = Ptimer2 + 10000 playsnd_obj = m_sound.get_safe_sound_object(rand_music) playsnd_obj:play_no_feedback(actor, sound_object.s2d, 1, vector(), vol) end end function init() event("actor_update"):register(start_talk) event("mob_death"):register(kill_mob) event("npc_death"):register(kill_mob) end
Подключение окончено! Теперь этот файл можно удалять и добавлять к скриптам проекта в любое время без всяких дополнительных телодвижений, он стал абсолютно автономным и опциональным.
На вопросы остальных отвечу немного позже, в крайнем случае завтра.
-
Скриптование
Скриптование17 часов назад, phalcor сказал:давно нет респавна убитым монстрам/сталкерам
Нашёл-таки причину. Кому интересно:
Скрытый текстДело всё в том, что при поиске подходящего гулага в obj:brain():update() учитываются allspawnоские трупы, так как у них в ini есть секции
[smart_terrains]
esc_lager = true
Из-за этого такие трупы занимают свободные места в smart_terrainах, уменьшая значения self.gulag.capacity_non_exclusive.
Т.е. в методах fill_exclusives для сталков/монстров не проверяется их живость... Где-то это хорошо, а мне вот оказалось плохо - кучу времени потратил.
Решение: ждать пропажи трупов или добавить таки проверку в fill_exclusives на alive.
-
Скриптование
Скриптование30.05.2023 в 16:25, phalcor сказал:function generic_physics_binder:death_callback(victim, who)
Хочу идентифицировать, КТО "убил" ящик, но who:id(), who.id, who:section(), who:section_name() и т.д. вызывают вылет - нет такого метода.
Подскажите, кто знает, как же можно идентифицировать who?
Так вы бы и разбирались для начала, передан ли вообще who, и что он из себя представляет.
Вылет происходит когда вы дергаете методы не удостоверившись в их наличии, а также наличии самого объекта.
if who and type(who) == 'userdata' then if type(who.id) == 'number' then log("who - серверный объект") -- НЕ КЛИЕНТСКИЙ! -- Здесь можно смело использовать who.id, who:section_name(), и другие методы и свойства СЕРВЕРНОГО объекта. elseif type(who.id) == 'function' then log("who - клиентский объект") -- НЕ СЕРВЕРНЫЙ! -- Здесь можно смело использовать who:id(), who:section(), и другие методы и свойства КЛИЕНТСКОГО объекта else log("who - объект, но не серверный и не клиентский. Вообще непонятно что.") -- Такого скорее всего не произойдет никогда. Ну, или почти. end else log("who not found") -- Объект не был передан. end -- Главное не путайте серверные и клиентские объекты между собой.
-
Прозекторская
ПрозекторскаяУ себя уже давно использую оригинальный пысовский метод level.add_call() - как раз для таких "быстрых" таймеров. Каждый новый вызов этого метода, по сути и является созданием экземпляра класса и всё действо помещается в одну строку луашного кода. Но при такой компактности, конечно, и наворотов меньше чем у malandrinus'a - например из входных параметров только: имя таймера, время (таймаут), функция, которая будет вызвана по окончанию таймера и аргументы, переданные в эту функцию. То есть это именно таймер, с одним лишь условием - временем. Сохранение между сейвами так же не предусмотрено, но лично для моих нужд, пока этого хватает.
-
Работа с текстурами
Работа с текстурамиСкрытый текст;--------------------------------------------------------------------
act_lenin = prop_lenin (soc has duplicate tex in act / prop)
act_lenin02 = prop_lenin_02 (soc has duplicate tex in act / prop)
;--------------------------------------------------------------------
crete_beton_2 = crete_beton_1
crete_beton_3 = crete_beton_2
crete_border1 = crete_border_05
crete_dirty_gr = floor_dirty_gr
crete_dirty1_gr = floor_dirty1_gr
crete_fl_gr02 ~ wall_stucco_04
crete_floor3 ~ wall_ceiling_01
crete_floor4a = floor_tile_02
crete_floor4a_1 = floor_tile_02
crete_floor_linol = floor_linoleum_02
crete_plitka_iov_01 ~ tile_white_blasted_01
crete_plitka_qllab = tile_plitka_01
crete_podval = wall_walls_paint_02
crete_pol_t = floor_tile_01b
crete_pol_t_01 = floor_tile_01b
crete_provoda_ql = prop_cable_bobbin
crete_provoda_ql_02 = prop_provod_05
crete_railborder1 ~ crete_border_01 / wall_border_01
crete_railborder2 ~ crete_border_01 / wall_border_01
crete_roof_gr01 = roof_smola
crete_roof1_border = roof_smola_border
crete_roof1 = roof_smola
crete_roof2 = roof_smola_02
crete_roof3 = roof_crete_01
crete_schiffer2 = roof_schiffer_01
crete_schiffer2a = roof_schiffer_02
crete_schiffer3 = roof_schiffer_01
crete_stena_kraska_02 ~ wall_stucco_05
crete_stena_kraska_02a ~ wall_stucco_05
crete_stena_kraska_03a = wall_walls_paint_01
crete_stena_kraska_03b = wall_walls_paint_01b
crete_st_gr02 = crete_walls_old_02
crete_stuccowall3_iov = wall_stucco_01
crete_truba_ql ~ mtl_barrel_big_rust
crete_walls3 ~ crete_beton_7
crete_walls6 ~ crete_beton_7 / crete_beton_6 / crete_walls_02
crete_walls7 = wall_stena_01
crete_walls8 = wall_ceiling_01
crete_walls8a = wall_ceiling_01
crete_walls8d = wall_ceiling_01
crete_walls9 = wall_walls_paint_03
crete_walls9a = wall_walls_paint_03
crete_walls9b = wall_walls_paint_03
crete_walls9_a = wall_ceiling_01
crete_walls11_1 = floor_tile_01
crete_walls12 = crete_walls_01
crete_walls17 = wall_wallpaper_02b
crete_walls17a = wall_wallpaper_02b
crete_walls18 = wall_wallpaper_02c
crete_walls_cy01 = wall_stucco_15
crete_walls_j12 = crete_walls_01
crete_walls_j12a = crete_walls_01
crete_walls_j12b = crete_walls_01
crete_walls_blue_iov = wall_walls_paint_03b
crete_walls_pryp_01 = wall_house_red_01
crete_walls_pryp_02 = wall_house_white_01
crete_walls_rg01 = tile_walls_rg01
crete_walls_rg03 = tile_white_02
crete_walls_rg04 = tile_walls_rg04
crete_walls_rg06 = tile_white_02
crete_walls_rg07 = wall_walls_paint_05
crete_walls_tualgr = tile_plitka_tual
crete_walls_tualgr01 = tile_walls_tualgr01
crete_walls_tualgr03 = tile_plitka_tual_blue
crete_walls_tualgr04 = tile_plitka_tual_red
crete_walls_tual_b = floor_tile_02b
crete_wallsgr11 = floor_tile_03
;--------------------------------------------------------------------
door_gr_iov_01 = door_gr1
door_gr02 = door_wood_05
door_gr2_iov = door_gr2
door_iov2 = door_electricunit_01
door_iov3 = door_electricunit_02
door_j01 = door_white_02
door_j02 ~ door_metal_01
door_j03alfa = door_j03_alfa
door_korob_wh ~ wood_old
door_red_garaj_iov = door_wood_02
door_vorota_ch_train = door_gate_train_02
door_w01 = door_metal_04
;--------------------------------------------------------------------
fbr_linoleum1 = floor_linoleum_03
;--------------------------------------------------------------------
glas_gr02 = glass_blocks
glas_windows1 = wind_05
glas_windows1a = wind_05_alpha
glas_windows4 = wind_06
glas_windows4a = wind_06_alpha
;--------------------------------------------------------------------
grnd_concrete_1 = grnd_concrete_01
grnd_concrete_2 = grnd_shlak_03
grnd_dirt_dust_0 = grnd_dirt_dust_01
grnd_dry_j02 = grnd_shlak_02
grnd_dry_j02_pod = grnd_shlak_02
grnd_dry_iov ~ grnd_dry_gr_01
grnd_dry_gr = grnd_dry_gr_01
grnd_obriv_3 = grnd_precipice_01
grnd_zemlya_iov = grnd_zemlya
grnd_zemlya2_iov = grnd_land_01
;--------------------------------------------------------------------
mtl_bo4ka_big_iov = mtl_barrel_big / mtl_barrel_big_rust
mtl_budka_01 ~ mtl_walls11
mtl_daha_02 ~ mtl_rja_blue / mtl_rja_01
mtl_gar_pod_01 ~ mtl_rja_blue
mtl_gate_j01a = door_gate_metal_06
mtl_garage_gate_01a ~ mtl_rja_01
mtl_garage_gate_rjav = door_gate_metal_05
mtl_green_rja_iov = mtl_rja_green
mtl_floor_01tga = mtl_floor_plate_02
mtl_fence2 = mtl_floor_fence_01
mtl_fence2n = mtl_fence_01
mtl_fence2n_ql ~ mtl_fence_01
mtl_fence3 = mtl_fence_03
mtl_fence4 = mtl_fence_04
mtl_luk_ch ~ mtl_angar_a
mtl_metall_02_b = mtl_floor_plate_01
mtl_pod_02 = mtl_rja_blue
mtl_ql ~ mtl_pod_01
mtl_railroad_04 = mtl_railroad_01
mtl_railroad_04_bok = mtl_railroad_01_bok
mtl_rja_iov_01 = mtl_rja_01
mtl_rech_ch_01 = mtl_rech_ch_01
mtl_rech_ch_02 = mtl_stena_ch_04
mtl_refllist_ql ~ mtl_truba_any
mtl_resh_reil = mtl_girder_reil
mtl_resh_reil_a = mtl_girder_reil_a
mtl_resh_reil_b = mtl_girder_reil_b
mtl_resh_reil_c = mtl_girder_reil_c
mtl_roof_red_iov = roof_metal_01
mtl_rope2-1 = prop_provod_01
mtl_rope3-1 = prop_provod_02
mtl_rusty_0 = mtl_rja_02
mtl_rust_dark_iov = mtl_rust_dark
mtl_rza_ch_01 = mtl_rja_blue
mtl_stena_ch ~ mtl_pod_01
mtl_stena_ch_06 = mtl_walls8
mtl_stena_ch_08 = mtl_stena_08
mtl_stena_ch_10 ~
mtl_stena_old_iov = mtl_walls8_old
mtl_trub_gr ~ mtl_rust_dark_v
mtl_tubes2 ~ mtl_tubes1
mtl_tubes3a = mtl_tubes3b
mtl_tubes3c = mtl_tubes3b
mtl_tubes4 = mtl_tubes1
mtl_tubes6 ~ mtl_tubes1
mtl_ventel_ql = mtl_ventel
mtl_vorota_a = door_gate_metal_03
mtl_wall_gr ~ mtl_rja_01
mtl_wall_j02a = mtl_rja_01
mtl_walls1 = mtl_rja_01
mtl_walls1_b = mtl_rja_01
mtl_walls2 ~ mtl_railroad_items
mtl_walls2_1 = mtl_railroad_items
mtl_walls5 ~ mtl_rja_green
mtl_walls7 = mtl_walls10
mtl_walls11_tail = mtl_walls11
mtl_walls13 = mtl_walls11b
mtl_walls14 = mtl_walls11c
mtl_walls15 ~ mtl_rja_01
mtl_walls16 = door_gate_metal_04
mtl_walls18 = mtl_rja_blue
mtl_x-support1 = mtl_x_support_alpha
mtl_x-support2 = mtl_x_support
mtl_zakl_ch_01 = mtl_walls9b
mtl_z_trba = mtl_stena_ch_04
;--------------------------------------------------------------------
prop_batarea_p = mtl_batarea_p
prop_bathhole1 = prop_bathhole
prop_bathhole2 ~ prop_grate1
prop_bed2a ~ prop_blind01
prop_busdead1 = veh_busdead1
prop_ceil2 = wall_ceiling_01
prop_door1 = door_wood_03
prop_door2 = door_metal_02
prop_door3 = door_electricunit_03
prop_door4 = door_gate_metal_01
prop_door5 = door_metal_03
prop_door6 = door_white_03
prop_door7 = door_gate_metal_02
prop_door9 = door_white_04
prop_door_a = door_wood_03
prop_door_ql = door_wood_06
prop_door_tual = door_wood_04
prop_elec_door_01 = door_electricunit_04
prop_elec_door_01_wall ~ mtl_rja_blue
prop_elec_kran = prop_girder_01
prop_elec_kran_a = prop_girder_01
prop_elec_kran_02 = prop_elec_kran
prop_electricalunit3b = prop_electricalunit3c
prop_electroengine1 ~ prop_electroengine2
prop_garbage1 = prop_elec_kran
prop_gidravlika ~ mtl_balka_ch_01 / mtl_truba_factory
prop_grate2 = prop_grate_01
prop_grate5 = prop_grate_02
prop_house_door1 = door_white_05
prop_house_door2 = door_white_05
prop_lamppost2 = prop_lamppost2a
prop_lep1 = mtl_girder_reil_b
prop_lep1a = mtl_girder_reil_c
prop_lift_door = door_lift_01
prop_musor_01_1 = prop_musor_01
prop_mus_kont_01a = prop_musor_02
prop_osadok_iov ~ detail_grnd_yantar
prop_plitka_lab2 = tile_plitka_lab
prop_provod_05 = prop_provod_01
prop_roadborder_2iov = prop_roadborder_2
prop_roadborder_j2d ~ crete_border_02
prop_roadborder1 = prop_roadborder_1
prop_stupeni_a = crete_stupeni_a
prop_stupeni_b = crete_stupeni_b
prop_tabl_pod_01 = sign_nuke_zone
prop_trainwheel2 = prop_trainwheel1
prop_trainwheel2a = prop_trainwheel1a
prop_trash_1 = grnd_garbage
prop_vagon04 = veh_vagon1_03
prop_vagon_iov2 = prop_vagon_part
prop_waterpump1_step = mtl_steps1
;--------------------------------------------------------------------
sign_set_iov = sign_set
sign_set2_iov = sign_set2
sign_vorota_iov = sign_vorota
;--------------------------------------------------------------------
ston_asfalt_a = detail_grnd_asphalt
ston_asfalt_a_gray = detail_grnd_asphalt
ston_asfalt_iov_old_01 = detail_grnd_asphalt
ston_asfalt_sm_iov = grnd_asphalt_01
ston_beton04 = crete_walls_01
ston_beton_01d = crete_beton_01d
ston_beton_03 = crete_beton_03
ston_beton_ch_01 = crete_walls_01
ston_beton_ch_02 ~ crete_walls_01
ston_beton_ch_03 = crete_beton_ch_03
ston_beton_ch_06 = crete_beton_ch_06
ston_beton_ch_08 = crete_stena_ch_08
ston_beton_ch_09 = floor_tile_05
ston_beton_ch_10 = crete_beton_7 /
ston_beton_ch_13 ~ ston_beton_ch_12
ston_beton_ch_141 = crete_beton_slag
ston_beton_ch_15 = crete_beton_7
ston_beton_iov_01 = crete_beton_plita_3
ston_beton_iov_02 = crete_beton_plita
ston_beton_iov_05 = crete_beton_dirt_01
ston_beton_iov_06 ~ crete_beton_dirt_01
ston_beton_iov_dirt_01 = crete_beton_dirt_01
ston_beton_pod_01 = crete_debris_01
ston_beton_pod_03 = crete_beton_pod_03
ston_beton_potolok_contrast_iov =
ston_beton_potolok_iov ~ wall_ceiling_01
ston_beton_potolok2_iov = wall_ceiling_01
ston_beton_stena_iov = crete_beton_5
ston_beton_stena_iov_hi = crete_beton_5
ston_beton_stena_iov_n =
ston_big_iov = crete_beton_3
ston_bordur = prop_border
ston_bordur_j01 ~ ston_beton_ch_04
ston_bordur_j02b = wall_border_05
ston_brick_rostok_1 ~ briks_br4
ston_bricks_ql ~ briks_br4
ston_bricks1 ~ briks_dirt_01
ston_bricks3b ~ ston_bricks3
ston_bricks4 = briks_big_01
ston_bricks5 = briks_tube_02
ston_bricks8_bez_zeleni =
ston_bricks10 = briks_inside_02
ston_briks_ch ~ briks_br3
ston_briks_iov_dirt_01 = briks_dirt_01
ston_brickinside_iov = briks_inside_01
ston_br_hr_iov = briks_br1
ston_br2_iov = briks_br2
ston_kirpichi_a = briks_stucco
ston_marble_br_iov = tile_marble_1
ston_megabrick_iov = briks_br3
ston_megabrick_iov_1 = briks_br3
ston_mramor_iov = tile_marble_2
ston_musor_iov = grnd_dirt_dust_02
ston_oblicovka_dark03 = tile_border_dark_01
ston_old_beton_iov = crete_old_beton
ston_old_wall_iov = wall_stucco_11
ston_osnova ~ crete_beton_dirt_01
ston_plints1 = wall_stena_01b
ston_plitka_y_02 = tile_plitka_y_02
ston_plitka_iov_green = tile_green
ston_plitka_iov_wall_01 =
ston_plitka_pink_iov ~ tile_walls_pink_01
ston_pol_m_01 ~ floor_tile_09
ston_pol_m_iov_01 ~ floor_tile_10
ston_pol_m_iov_02 ~ floor_tile_10
ston_pol_smola_iov = floor_pitch_01
ston_rocks1 = grnd_rocks_01
ston_reka_ch = crete_border_01
ston_srarkon_iov = wall_stucco_04
ston_stanc = crete_stanc
ston_stanc_bl = crete_stanc_black
ston_stanc_g = crete_stanc_g
ston_stena_04a = crete_stena_04a
ston_stena_04d = crete_stena_04d
ston_stena_04e = crete_stena_04e
ston_stena_04f = crete_stena_04f
ston_stena_04g = crete_stena_04g
ston_stena_04h = crete_stena_04h
ston_stena_05b = wall_stena_05b
ston_stena_05b_i = wall_stena_05b
ston_stena_06a = briks_inside_03
ston_stena_07_a_j = crete_stena_07_a_j
ston_stena_07_d = prop_stena_07_d
ston_stena_ch = tile_stena_ch
ston_stena_ch_05 ~ crete_stanc
ston_stena_ch_07 ~ mtl_sarcofag_01
ston_stena_ch_11_1 = crete_house_wall_1
ston_stena_ch_11_2 = crete_stena_ch_11_2
ston_stena_ch_12 = crete_stena_ch_12
ston_stena_ch_13 = crete_stena_ch_13
ston_stena_ch_131 = crete_stena_ch_13
ston_stena_ch_14 = crete_stena_ch_14
ston_stena_ch_15 = crete_stena_ch_15
ston_stena_da_01 = wall_stucco_05
ston_stena_marbl_m_03 ~ crete_beton_3
ston_stena_pod_04 = wall_stucco_08
ston_stena_pod_08 = wall_border_02
ston_stena_pod_09 = wall_stucco_02
ston_stena_yz_iov = wall_stucco_13
ston_stolb_rail = crete_stolb_rail
ston_stuccowall_iov_01 ~ wall_stucco_01 (out) / wall_stucco_05 (in)
ston_stuccowall2_iov = wall_stucco_12
ston_stuccowall3_iov = wall_stucco_10
ston_stupeni_iov = crete_stupeni_c
ston_tr_iov = crete_dirt_2
ston_trotuar_sm_iov = floor_tile_08
ston_truba_ch = crete_truba_ch
ston_walls1 ~ crete_walls_old_01
ston_walls1_1 = crete_walls_old_01
ston_walls2 = crete_beton_dirt_01
ston_walls2_1 = crete_dirt_any
ston_walls3 ~ crete_walls10
ston_walls5 = crete_border_02
ston_zabor_iov = crete_zabor
ston_zabor_02 = crete_zabor_02
;--------------------------------------------------------------------
veh_diesel2c = veh_diesel1c
;--------------------------------------------------------------------
wind_01 = wind_gr04
wind_02_ch = wind_09
wind_03_ch = wind_03
wind_04_ch = wind_08
wind_04_ch_transp = wind_transp
wind_04_pryp_01 = wind_04
wind_05_ch = wind_07
wind_hr_gr1 = wall_hr_gr1
wind_hr_gr2 = wall_hr_gr2
wind_j04c ~ prop_grate1
;--------------------------------------------------------------------
wood_dosk_gr01 = wood_gr01
wood_doski_1 = wood_doski
wood_doski2 = wood_doski
wood_iov_bench = wood_old_iov
wood_parquet_iov = floor_parket_03
wood_parket_01 = floor_parket_02
wood_parket_gr01a = floor_parket_02
wood_plank4 = wood_old
wood_plank5 = wood_stolb
wood_plank6 = (h_ tex)
wood_plank6_bar = (h_ tex)
wood_plank9r ~ wood_plank6 (h_ tex)
wood_walls3 ~ wood_doski / wood_old_iov
wood_walls4a = wood_walls4
wood_walls7 ~ wood_old_iov
wood_walls7_dark ~ wood_old_iov
wood_walls10 ~ wood_walls1
wood_walls11 ~ wood_old
wood_walls11_zelen ~ wood_old
wood_zabor_iov = wood_fence_01
;--------------------------------------------------------------------
wm_board_a = decal_board_1b
wm_dirt_01 = decal_dirt_01
wm_graz1 = decal_graz1
wm_graz3 = decal_graz3
wm_pl_1 = decal_plakat_4
wm_pl_3 = decal_plakat_1
;--------------------------------------------------------------------
-
Скриптование
Скриптование19 часов назад, Labadal сказал:как мне скриптом заспавнить нужный мне предмет, чтоб он с чердака не провалился на сетку?
Например, сняв искомый флаг в нет-пакете объекта с помощью модуля m_netpk от Артоса:
local sobj = alife():create(section, position, lvid, gvid) if sobj then local pk = get_netpk(sobj) if pk:isOk() then local data = pk:get() data.object_flags = bit_and(data.object_flags, bit_not(object_flags.UsedAI_Locations)) -- сброс флага привязки к сетке (128) pk:set(data) end end
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлах@DarkSnowder , штатный параметр логики НПС: show_spot
Примеры использования в оригинале: сотоварищи Петрухи на Кордоне, десантоспецназ, высаживающийся на Агропроме после спасения группы Крота.
-
[SOC] Мелкие правки движка
[SOC] Мелкие правки движкаДелаю первые шаги в C++ Так что сильно не пинайте. Но, правочки такой, почему-то никто не выкладывал. Выложу тогда я.
Скрытый текстДобавление возможности автокоррекции размеров иконок и сеток, в окнах слотов и инвентаря.
Править потребовалось один единственный файл: xrGame/ui/UIXmlInit.cpp
Один метод в нем, изменил вот так:
bool CUIXmlInit::InitDragDropListEx(CUIXml& xml_doc, const char* path, int index, CUIDragDropListEx* pWnd) { R_ASSERT3(xml_doc.NavigateToNode(path,index), "XML node not found", path); float x = xml_doc.ReadAttribFlt(path, index, "x"); float y = xml_doc.ReadAttribFlt(path, index, "y"); float width = xml_doc.ReadAttribFlt(path, index, "width"); float height = xml_doc.ReadAttribFlt(path, index, "height"); InitAlignment (xml_doc, path, index, x, y, pWnd); pWnd->Init (x,y, width,height); Ivector2 w_cell_sz, w_cells, w_cell_sp; // Add by Zander Fvector2 device_scale; device_scale.x = 1024.0f / _max((float)Device.dwWidth, 1.0f); device_scale.y = 768.0f / _max((float)Device.dwHeight, 1.0f); int autclc = xml_doc.ReadAttribInt(path, index, "autocalc", 0); int cellmin = xml_doc.ReadAttribInt(path, index, "cell_minimals", 0); // end w_cell_sz.x = xml_doc.ReadAttribInt(path, index, "cell_width"); w_cell_sz.y = xml_doc.ReadAttribInt(path, index, "cell_height"); // Add by Zander if (autclc == 1) { w_cell_sz.x = (int)round(w_cell_sz.x * device_scale.x); w_cell_sz.y = (int)round(w_cell_sz.y * device_scale.y); } if (autclc == 2) { w_cell_sz.x = (int)round(50.0f * device_scale.x); w_cell_sz.y = (int)round(50.0f * device_scale.y); } // end w_cells.y = xml_doc.ReadAttribInt(path, index, "rows_num"); w_cells.x = xml_doc.ReadAttribInt(path, index, "cols_num"); // Add by Zander if (cellmin == 1) { // Приоритет - необходимое число ячеек в указанном объеме int w_cell_sz_x = (int)trunc(width / _max((float)w_cells.x, 1.0f)); int w_cell_sz_y = (int)trunc(height / _max((float)w_cells.y, 1.0f)); if (w_cell_sz_x < w_cell_sz.x) w_cell_sz.x = w_cell_sz_x; if (w_cell_sz_y < w_cell_sz.y) w_cell_sz.y = w_cell_sz_y; } else { // Приоритет - правильный размер иконок и сетки if (autclc == 1) { // Заполняем сетку максимально w_cells.x = (int)trunc(width / _max((float)w_cell_sz.x, 1.0f)); w_cells.y = (int)trunc(height / _max((float)w_cell_sz.y, 1.0f)); } } // end w_cell_sp.x = xml_doc.ReadAttribInt(path, index, "cell_sp_x", 0); w_cell_sp.y = xml_doc.ReadAttribInt(path, index, "cell_sp_y", 0); pWnd->SetCellSize (w_cell_sz); pWnd->SetCellsSpacing (w_cell_sp); pWnd->SetStartCellsCapacity (w_cells); int tmp = xml_doc.ReadAttribInt(path, index, "unlimited", 0); pWnd->SetAutoGrow (tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "group_similar", 0); pWnd->SetGrouping (tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "custom_placement", 1); pWnd->SetCustomPlacement(tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "vertical_placement", 0); pWnd->SetVerticalPlacement(tmp != 0); tmp = xml_doc.ReadAttribInt(path, index, "show_grid", 1); pWnd->SetDrawGrid (tmp != 0); tmp = xml_doc.ReadAttribInt(path, index, "condition_progress_bar", 0); pWnd->SetConditionProgBarVisibility(tmp!=0); if (xr_strlen(path)) pWnd->SetWindowName (path, TRUE); return true; }
В результате этой правки, движок начинает понимать в конфигах xml инвентаря, два новых атрибута в окнах с инвентарными сетками:
autocalc (возможные значения - 0,1,2) - необходимость пересчитывать размер ячеек сетки и иконок.
cell_minimals (возможные значения - 0,1) - необходимость во что бы то ни стало вместить указанное количество ячеек в заданные размеры окна.
Если эти атрибуты в конфигах отсутствуют, или указано значение 0 - то поведение в точности такое же, как и раньше. Сетка/иконки выводятся в координатах 1024х768, в тех размерах и координатах, что указаны в xml.
autocalc="1" - ячейки иконок примут размер в пикселах, указанный в xml, на мониторе конечного пользователя с учетом его разрешения. Т.е. если например у нас написано
<dragdrop_bag cell_width="42" cell_height="42" autocalc="1"/>
То 1 клетка сетки/иконок примет размер 42х42 пиксела на мониторе юзера. И не важно, какое у него разрешение, и насколько оно (не)похоже на то, что имели в виду составители xml конфига.
Ненужные в данном вопросе атрибуты xml в этой строке опущены, но удалять их конечно не надо.
autocalc="2" - для ленивых) Поведение то же, что и в предыдущем варианте, но подгонять сетку будет к размеру 50х50, игнорируя указания cell_width, cell_height.
cell_minimals="1" - Это для слотов. Если указано 1, окно слота маленькое, и указанное число ячеек в нем не помещается, то размер ячейки дополнительно ужимается до того чтобы поместилось. Это все опять же на экране пользователя с учетом его разрешения.
Ну и бонусом, если для окна инвентаря указать autocalc 1 или 2, и cell_minimals 0, то размер ячейки будет изменен с учетом разрешения монитора пользователя, а сетка инвентаря переформирована под то число ячеек, которое в нее поместится с учетом этого изменения. Игнорируя указанные в xml значения rows_num и cols_num.
У себя проверил - работает... может быть, пригодится кому-то)
-
Скриптование
Скриптование1. При построчном чтении конфига выводятся три переменных: пустышка, имя параметра, значение.
2. Конфиг [keep_items] достаточно вычитать один раз – см. последний пример.
Spoilerfunction drop_all_items() local function fx(item) db.actor:drop_item(item) end db.actor:inventory_for_each(fx) -- кроме квестовых и специальных предметов end
Spoilerlocal t = {} function drop_all_items() local function fx(dummy, item) t[#t +1] = item -- можно заносить в таблицу сами предметы – drop_item позволяет обходить пустышки end db.actor:iterate_inventory(fx, nil) for i = 1, 5 do -- несколько случайных предметов local k = math.random(#t) -- случайный ключ db.actor:drop_item( t[k] ) table.remove(t, k) -- построчная очистка end end
Spoilerlocal keep = {} -- полный список; заполняется один раз keep.bolt = true keep.device_torch = true keep.device_pda = true local death_ini = ini_file("misc\\death_generic.ltx") local n = death_ini:line_count("keep_items") for i = 0, n -1 do local dummy, sect, bool = death_ini:r_line("keep_items", i, "" , "") -- три переменных: пустышка, параметр, значение (в данном случае true для всех) keep[sect] = bool end local items = {} function drop_all_items() local function list(dummy, item) if not keep[ item:section() ] then -- сверка по ключу (вместо перебора) items[#items +1] = item -- можно заносить в таблицу сами предметы – drop_item позволяет обходить пустышки без вылета -- items[#items +1] = item:id() -- вариант с id end end db.actor:iterate_inventory(list, nil) for i = 1, #items do db.actor:drop_item( items[i] ) -- db.actor:drop_item( level.object_by_id( items[i] ) ) -- вариант с id end items = {} -- полная очистка end
-
[SoC] Ковыряемся в файлах
[SoC] Ковыряемся в файлахСкрытый текстfunction get_cost() local t_cost = 0 local objects = {} db.actor:iterate_inventory(function(d, o) local sect = o:section() if sect ~= "bolt" and sect ~= "device_pda" then t_cost = t_cost + o:cost() table.insert(objects, o) end end) for _, obj in pairs(objects) do local sobj = alife():object(obj:id()) if sobj then alife():release(sobj, true) end end dialogs.relocate_money(db.actor, t_cost, "in") end
-
Ваши правки для Сталкер ЧН
Ваши правки для Сталкер ЧНАвто сохранения после взятии квеста для сталкер Чистое небо (примерно как в ЗП)
Скрытый текстАвтор: SaViMoN
Скрытый текстПросьба, при добавлении в сборку или мод обязательно указать автора