Chypakabra - AMK Team
Перейти к контенту

Chypakabra

Жители
  • Число публикаций

    1 172
  • Регистрация

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

  • Дней в топе

    23
  • AMKoin

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

Chypakabra последний раз побеждал 11 Декабря

Chypakabra - автор самых популярных публикаций!

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

838

5 подписчиков

О Chypakabra

Звание

  • Звание
    Уравнобешеный!

Информация

  • Реальное имя
    Денис

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

12 635 просмотров профиля

Закладки

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

    окошко закрывалось само

    Пример без всяких таймеров (bind_stalker.script):

    function actor_binder:take_item_from_box(box, item)
    	-- здесь переделываем исходную функцию так, чтобы не выходить из неё, если нет story_id (иначе на "обычных" ящиках не сработает)
    	local story_id = box:story_id()
    	if story_id ~= nil then
    		treasure_manager.take_item_from_box(box, story_id)
    	end
    
    	-- проверяем, что контейнер, из которого брали предметы, стал пустым
    	if box:is_inv_box_empty() then
    		-- получаем активное окно и закрываем его
    		local inv = level.main_input_receiver()
    		if inv ~= nil then
    			level.start_stop_menu(inv)
    		end
    	end
    end

    Нюанс в том, что контейнер закроется не только по кнопке "взять всё", но и если мы вручную переместили из него последний предмет.

    Доработать под кнопку и/или другие нужды не сложно.


  2. Правки игры и билды модификаций
    Правки игры и билды модификаций

    Зов Припяти 2 - Билд + SDK 0.7

    «Зов Припяти 2» -  с таким названием представлена глобальная модификация с новым сюжетом, разработанная на платформе игры Сталкер Зов Припяти. Модификация Зов Припяти 2 по сути является сюжетным продолжением игры, которая была представлена игрокам в оригинальной версии. Главным героем мода является по прежнему майор Дегтярёв от лица которого Вам предстоит пройти новый сюжет, побывать на совершенно новых локациях, на которых присутствуют новые группировки и квестовые персонажи.

    Атмосфера игры кардинально изменена благодаря использованию скрытых возможностей движка игры, введением в игру новых аномальных явлений, погодных условий и обновленной графики, мир зоны отчуждения стал еще более таинственным и загадочным. Идея о создании проекта возникла сразу после внезапного сообщения о распаде компании компания-разработчик (признана нежелательной).

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

    О сюжете:

    Сюжет игры Вам предстоит проходить от лица Дегтярёва, который по прежнему является главным героем игры. По завершении спец. операции Фарватер полученные данные были тщательным образом проанализированы и отправлены для дальнейшего анализа в лабораторию по изучению Зоны, главным консультантом в которой был назначен Стрелок. В своем последнем походе к центру Зоны, Стрелку удается разыскать информацию о секретной лаборатории. На базе Диггеров, Стрелку удается раздобыть один из уникальных образцов аномального происхождения под названием Тектонит. Из разговора Диггеров становиться очевидно, что данный образец должен отправиться в одну из секретных лабораторий Монолита, в которой проходят разработки нового оружия. Поиски лаборатории заводят его в тупик и он вынужден обратиться за помощью к военным.

    Становиться очевидным что последние изменения в Зоне Отчуждения напрямую связаны с секретной лабораторией и найденной новой аномальной породой. Стрелок уверен что ему все-таки не удалось уничтожить полностью О-Сознание и в поиске разгадки придется все-таки попасть в эту лаборатория. Из разведданных СБУ становиться известно, что некая группа наемников начала поиски этой лабаратории. Цепочка динамично разворачивающихся событий все-таки приведет главного героя в лабораторию управления Ноосферой, поставив его перед выбором - уничтожить Пророка (Он же младший профессор Кайманов) или во фриплее помочь Монолиту установить всеобщий контроль над Зоной.

     

    Локации:

    В модификации добавлены новые локации, некоторые модели из которых были взяты из билдов.

    Добавленные локации:

    Лаборатория X-Z 01

    Капёр

    Лабиринт База Диггеров

    Рабочий Посёлок

    Колхоз Путь Ильича

    Дикий Лес

    Мёртвая Река

     

    Команда разработчиков:

    Alex Moroz (США) - продюсер, веб-пиар, главный художник, 3D видеомонтаж.

    Олег Якубовский (Crazy_Stalker) - автор сюжета, конфиги, веб-пиар.

    Андрей Непряхин (Genior) - автор сюжета, главный художник, автор новых решений.
    Михаил Калуга (Михась) - автор сюжета, консультант по оружию.
    Иван Рудских (Shredder) - логика, скрипты.
    Иван Евгеньевич (optivankiev) - текстуры.
    Бложко Олег (Дезертир) (Brom) - моделлер.
    Снеговский Анатолий (Carrion-Crow) - левел-дизайн, текстурщик и моделлер.

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

    Загрузить «Зов Припяти 2 - Тестовый билд» с ФО: торрент [6.58 ГБ]

    Тестовый билд для ознакомления. Переходы на все локации в одном месте для удобства. Выйти из лаборатории Стрелка и повернуть налево.

    Загрузить «Зов Припяти 2 - SDK 0.7» с ФО: торрент [26.3 ГБ]

     

    Важно! СДК 0.7, полная версия! Для свободного использования в своих разработках! Не забывайте упоминать компанию компания-разработчик (признана нежелательной) как правообладателя данного контента.

    Stalker Call of Pripyat Lab XZ-01 custom made location

     

    За оформление, благодарности @Hardmuth.


  3. Правки игры и билды модификаций
    Правки игры и билды модификаций

    ФИКС ТЯНУЩИХСЯ ТЕНЕЙ ПО БОКАМ (автор оригинальной статьи товарищ ZHUKMAR)

     

    Когда вы двигаетесь вы наверняка сталкивались с проблемой тянущихся по бокам теней. Такая проблема на широкоформатных мониторах 16:9, но на мониторах 5:4 такой проблемы нет. В общем, чтобы исправить данную проблему и на широкоформатных мониторах нужно изменить параметр r2_sun_near_border на значение 1, так как по дефолту стоит 0.75. 

    Вот этот параметр

     


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

    Всё. Вопрос таки решил. Месяц бился... Надо было менять в init, в update и в use_callback. В init добавил условие которое предложил @RayTwitty а именно:

    ... or item:clsid() == clsid.inventory_box then ...
    --' кстати, работает также и :
    .. or item:section() == "inventory_box" then ...
    --' вопрос только в том, что быстрее отрабатывает?...

    дальше, путём метода народного втыка и постоянного вывода в лог чтобы понять что и куда и когда, выяснил, что в update надо добавить условие для ящиков без логики и в этом условии ещё раз вызывать use_callback, а именно добавил:

    --' для всех inventory_box у которых нет логики вызываем callback отдельно
    ...  
    
    else
        if item:clsid() == clsid.inventory_box then
          item:set_callback( callback.use_object, generic_physics_binder.use_callback, self )
        end
    
    ...

    и, наконец, в use_callback заработало то, что мне было надо, а именно, если ГГ открыл ящик, то получаем object ящика:

    --' проверка нужна, т.к. use_callback возвращает и двери...
    if item:clsid() == clsid.inventory_box then
      my_global_var.GVObj(item)
      log("* [bind_physic_object](use_callback) obj: "..item:id()..", "..item:section()..", "..item:name() )
    else
      log("! (1)[bind_physic_object](use_callback) obj: "..item:id()..", "..item:section()..", "..item:name() )
      log("! (2)[bind_physic_object](use_callback) obj: " .. item:id() .. " - это не ящик")
    end

    Для чего было надо? Сделал кнопки при открытии ящика: Выложить еду, арты, части мутантов, патроны. Для меня очень удобно, вместо того чтобы клацать мышкой 50 раз, просто один раз на кнопочке - выложить в ящик, и все патроны, например, перекладываются. Также сделал кнопку в инвентаре, сбросить всё в рюкзак, если есть рюкзак, кроме того что в слотах.
    Всех кто участвовал - благодарю.


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

    @dsh, у меня тоже поначалу перестало работать, но потом заметил, что не работает только "use_object".

    В результате "раскопок" выяснил, что этот callback снимается в "xr_logic.reset_generic_schemes_on_scheme_switch()" при переключении схемы. Для чего это было сделано, не понятно, ведь ни одна схема callback'и не устанавливает.
    Решил, что это все-таки ошибка и убрал, после чего все callback'и в "bind_physic_object" нормально заработали. Пока что полет нормальный.
    В итоге получил следующий код:

    Скрытый текст
    function generic_physics_binder:net_spawn(data)
    
    	...
    
    	local c = self.object:clsid()
    	if not ((c ~= clsid.inventory_box) and (c ~= clsid.inventory_box_s)) then
    		self.object:set_callback(callback.hit, generic_physics_binder.hit_callback, self)
    		self.object:set_callback(callback.death, generic_physics_binder.death_callback, self)
    	end
    	self.object:set_callback(callback.use_object, generic_physics_binder.use_callback, self)
    
    	db.add_obj(self.object)
    	return true
    end
    
    
    function generic_physics_binder:update(delta)
    
    	...
    
    	if self.st.active_scheme ~= nil then
    		xr_logic.issue_event(self.object, self.st[self.st.active_scheme], "update", delta)
    	end
    
    	xr_sound.update(self.object:id())
    end

     

     


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

     


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

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

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

     

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

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


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

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


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

    @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

     

     

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


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

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


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

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

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

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

     

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

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


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

     


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

     

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


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

     

     


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

     


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


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

     

     

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

     

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


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

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

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

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

     

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

    [smart_terrains] 

    esc_lager = true

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

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

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

     

     


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