Перейти к контенту

ted.80

Опытные
  • Число публикаций

    297
  • Регистрация

  • Последнее посещение

  • AMKoin

    7,433 [Подарить AMKoin]

Баланс оценок

251

4 подписчика

О ted.80

  • День рождения 30.05.1980

Контакты

  • Сайт
    https://yadi.sk/d/Snw1s-K43GjcX9
  • ICQ
    290428380

Информация

  • Реальное имя
    Денис
  • Город
    Павлодар.kz

Недавние посетители профиля

7 215 просмотров профиля

Закладки

  1. Правки и моды к 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
    

     

    После этого сохраните файл.

    Добавлю от себя - бэкап файлика не забудьте сделать на всякий.


  2. "косые сталкеры"
    [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-файл?

    inc-primer.jpg

    Можно выносить кастомдату любых объектов. Работает во частях трилогии.

     

    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 

     


  3. [SoC] Ковыряемся в файлах
    [SoC] Ковыряемся в файлах
    22 часа назад, Капрал Хикс сказал:

    микрозависания при подходе к Бару

    Где-то встречал, что нужно заранее грузить все звуки для нпс (characters_voice). Для движка правок не встречал, но оригинале есть функции для итерации звуков и их префетча, реализация в sound_prefetch.script. Работает не пойми как, вроде чуть лучше стало.

     

    https://drive.google.com/file/d/1jC_4xSqnypxmG_qoEPPIhM6O0gD75MVf/view?usp=sharing

    Для чистой игры, чтобы сразу в баре + правленые скрипты, т.к. изначально sound_prefetch отключен.


  4. [SoC] Ковыряемся в файлах
    [SoC] Ковыряемся в файлах

    В который раз подниму тему про микрозависания при подходе к Бару... Вроде говорилось по то, что там сразу четыре гулага в онлайн выходят... Оттого и фриз. Как это вообще разрулить по уму? Фиксил кто конкретно этот момент у себя? P. S. Движок OGSR не предлагать:).


  5. Скриптование
    Скриптование

    @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

     

     

    Имхо, это всё вопросы для Скриптования, а не Ковырялки.


  6. [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

    В "СЗ" оно долгие годы было частью скриптового инвентаря.


  7. [CoP] Ковыряемся в файлах
    [CoP] Ковыряемся в файлах
    1 час назад, SWEAW сказал:

    В общем, сделал по совету, это

    Не правильно. Нужно было ИЛИ раскоментировать стандартный код ИЛИ изменить его, как посоветовал @Kirgudu.

    Посмотри внимательно, как написано в его посте.

     

    В функции "trade_manager.update" в условиях для переменных "tt.update_time" и "tt.resuply_time" нужно поменять знак сравнения на "больше" - ">".

    При использовании "game.time()" значения времени 60000 и 120000 чрезвычайно малы.


  8. [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

     


  9. [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.

     

    З.Ы. Дополнительно отмечу, что причина, по которой ПЫСы закомментировали этот код, неизвестна. И, может быть, его активация вызовет ещё какие-нибудь ошибки.


  10. [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

     

     


  11. [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

     


  12. 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). И это касается конечно не только скриптов.


  13. 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
    

     

     

    Подключение окончено! Теперь этот файл можно удалять и добавлять к скриптам проекта в любое время без всяких дополнительных телодвижений, он стал абсолютно автономным и опциональным.

     

    На вопросы остальных отвечу немного позже, в крайнем случае завтра.


  14. Скриптование
    Скриптование
    17 часов назад, phalcor сказал:

    давно нет респавна убитым монстрам/сталкерам

    Нашёл-таки причину. Кому интересно:

    Скрытый текст

     

    Дело всё в том, что при поиске подходящего гулага в obj:brain():update() учитываются allspawnоские трупы, так как у них в ini есть секции 

    [smart_terrains] 

    esc_lager = true

    Из-за этого такие трупы занимают свободные места в smart_terrainах, уменьшая значения self.gulag.capacity_non_exclusive.  

    Т.е. в методах fill_exclusives для сталков/монстров не проверяется их живость... Где-то это хорошо, а мне вот оказалось плохо - кучу времени потратил.

    Решение: ждать пропажи трупов или добавить таки проверку в fill_exclusives на alive.

     

     


  15. Скриптование
    Скриптование
    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
    -- Главное не путайте серверные и клиентские объекты между собой.

     


  16. Прозекторская
    Прозекторская

    У себя уже давно использую оригинальный пысовский метод level.add_call() - как раз для таких "быстрых" таймеров. Каждый новый вызов этого метода, по сути и является созданием экземпляра класса и всё действо помещается в одну строку луашного кода. Но при такой компактности, конечно, и наворотов меньше чем у malandrinus'a - например из входных параметров только: имя таймера, время (таймаут), функция, которая будет вызвана по окончанию таймера и аргументы, переданные в эту функцию. То есть это именно таймер, с одним лишь условием - временем. Сохранение между сейвами так же не предусмотрено, но лично для моих нужд, пока этого хватает.


  17. Работа с текстурами
    Работа с текстурами

    @DDamian724

    Скрытый текст

    ;--------------------------------------------------------------------
    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
    ;--------------------------------------------------------------------


  18. Скриптование
    Скриптование
    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

     


  19. [SoC] Ковыряемся в файлах
    [SoC] Ковыряемся в файлах

    @DarkSnowder , штатный параметр логики НПС: show_spot
    Примеры использования в оригинале: сотоварищи Петрухи на Кордоне, десантоспецназ, высаживающийся на Агропроме после спасения группы Крота.


  20. [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.

    У себя проверил - работает... может быть, пригодится кому-то)

     

     


  21. Скриптование
    Скриптование

    @mole venomous

    1. При построчном чтении конфига выводятся три переменных: пустышка, имя параметра, значение.

    2. Конфиг [keep_items] достаточно вычитать один раз – см. последний пример.

    Spoiler
    function drop_all_items()
    	local function fx(item)
    		db.actor:drop_item(item)
    	end
    
    	db.actor:inventory_for_each(fx)		-- кроме квестовых и специальных предметов
    end

     

    Spoiler
    local 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

     

    Spoiler
    local 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

     

     


  22. [SoC] Ковыряемся в файлах
    [SoC] Ковыряемся в файлах

    @Houdini_one 

    Скрытый текст
    
    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

     

     


  23. Ваши правки для Сталкер ЗП
    Ваши правки для Сталкер ЗП

    в реале подсветка сетки включается/выключается:

     

    Ссылка: https://yadi.sk/d/kj3ZhEbGt3ZuC

     

     


  24. Ваши правки для Сталкер ЧН
    Ваши правки для Сталкер ЧН

    Авто сохранения после взятии квеста для сталкер Чистое небо (примерно как в ЗП)

    Скрытый текст

    Автор: SaViMoN

    Скрытый текст

    Просьба, при добавлении в сборку или мод обязательно указать автора


×
×
  • Создать...