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

Рекомендуемые сообщения

@FonSwong

Оператор # может применяться к любой таблице. Если в таблице есть индексированная часть, то оператор определит её размер.

В твоём случае ключами таблицы являются ID, которые не создают индексированного массива. Т.е. ключи таблицы не соответствуют порядку ключей массива 1,2,3,4,5,6, ... и т.д. по порядку. А что-то вроде 1523, 907, 23120 и т.п.
Поэтому когда ты определяешь длину массива оператором #, то длина будет равна нулю (если конечно не будет ID с номером 1).
А 
math.random не понимает единственного аргумента 0. Если первым аргументом задан 0 (являющийся началом интервала случайных чисел), то должен быть задан и второй аргумент, обозначающий конец этого интервала. Отсюда и ошибка - bad argument #1 to 'random' (interval is empty)

 

  • Нравится 1
Ссылка на комментарий

FonSwong, Charsi дал простой и верный намёк на решение проблемы. Надо всего лишь изменить структуру массива tbl_sos. Сделать его не ассоциативным, а индексированным, т.е. вида

tbl_sos = {{npc_id = id1, sos = 'SOS'},{ npc_id = id2, sos = ' '}, . . .}
ну и далее получаем по случайному индексу соответствующее ему значение, т.е. ассоциативный массив, а из него чего уж там требуется или tbl_sos[index].npc_id или строку tbl_sos[index].sos
Ссылка на комментарий

Кстати, давно интересовал момент - как правильно будет получить количество элементов в ассоциативном массиве? Я помню делал полный перебор массива чтобы получить его размер, но может есть более приятный вариант?

Freedom

Ссылка на комментарий

Как правильно достать профиль?

 

Сохраняю npc:id() непися, затем загружаю и мне нужно получить его профиль, но не через npc = level.object_by_id(id), ибо в оффлайне если нпс, то крашится игра

затем передать npc другой фунции, а там уже она снова возьмёт npc:id()

Пробовал после загрузки профиль вытаскивать через npc = alife():object(a), но он вроде как даёт сид, а дальше нужно передать "npc" с "id()"

Изменено пользователем FonSwong
Ссылка на комментарий

Кстати, давно интересовал момент - как правильно будет получить количество элементов в ассоциативном массиве? Я помню делал полный перебор массива чтобы получить его размер, но может есть более приятный вариант?

Быстрее будет наверное только использование метаданных (setmetatable), в которых в процедурах добавления/удаления управлять списком ключей/количеством элементов. из плюсов - в дальнейшем не надо пробегаться каждый раз по всему массиву для подсчета , а обратится сразу к переменной метаданных, из минусов - накладные вычислительные расходы на эти процедуры. Если массив очень большой - то само собой обращение к метаданным будет быстрее. если часто меняется - то считать количество можно достаточно редко. Вам выбирать :)

Ссылка на комментарий
может есть более приятный вариант?

:) Ну это кому и как приятнее будет.

 

Winsor, в принципе уже основное определил.

 

Нужно сделать прокси таблицу в которой хранить ссылку на реальную таблицу.

В этой прокси таблице завести уникальные поля, случайный доступ к которым

будет максимально исключен. В таких полях можно хранить всякие

служебные данные, как например длина таблицы.

Также нужно определить для прокси и метатаблицу с полями (как минимум)

__index и __newindex. В __newindex сделать слежение за размером таблицы

при добавлении\удалении полей.

 

Объявлять таблицу нужно с использованием специальной обёртки.

эта обертка, при объявлении таблицы, присвоит переменной значение не реальной,

а прокси-таблицы.

 

Теперь при обращении к созданной таблице (а реально к прокси) каждый раз будет

вызываться метаметод, так как таких полей в проски, к которым вы обращаетесь нет

(на уникальные ключи попасть будет крайне сложно).

 

Но тут минусы не ограничиваются

"из минусов - накладные вычислительные расходы на эти процедуры."

Для работы с такими таблицами нужно "научить понимать их" соответствующие функции.

А именно :

все из библиотеки "table"

pairs

ipairs

next

rawget

rawset

unpack

getmetatable

setmetatable

 

В принципе там изменить быстрее чем говорить об этом :)

 

Ну и последнее. Я это уже давно написал и пользуюсь. Так что если нужно, то поделюсь

примером.
Изменено пользователем Nazgool
  • Нравится 1
Ссылка на комментарий

@Nazgool, зачем ждать запроса? Кому-то может пригодиться позже, а своевременно выложить пример возможности не будет.

Лучше сейчас, это полезно. :)

Ссылка на комментарий

Ок. Подготовлю выложу.Ведь я так понимаю, что нужно и расписать всё "по понятиям" :)

 

Вроде готово. Как-то так

 

local _pairs  = pairs
local _ipairs = ipairs
local _next   = next
local _rawget = rawget
local _rawset = rawset
local _unpack = unpack
local _getmt  = getmetatable
local _setmt  = setmetatable

local _concat = table.concat
local _insert = table.insert
local _maxn   = table.maxn
local _remove = table.remove
local _sort   = table.sort

function table.concat(t, ...) return _concat(t.__PROXY_KEY or t, ...) end
function table.maxn  (t)      return _maxn  (t.__PROXY_KEY or t)      end
function table.remove(t, pos) return _remove(t.__PROXY_KEY or t, pos) end
function table.insert(t, ...) _insert(t.__PROXY_KEY or t, ...) end
function table.sort  (t, fun) _sort  (t.__PROXY_KEY or t, fun) end

function pairs (t)          return _pairs (t.__PROXY_KEY or t)      end
function ipairs(t)          return _ipairs(t.__PROXY_KEY or t)      end
function next  (t)          return _next  (t.__PROXY_KEY or t)      end
function rawget(t,k)        return _rawget(t.__PROXY_KEY or t,k)    end
function rawset(t,k,v)      return _rawset(t.__PROXY_KEY or t,k,v)  end
function unpack(t,...)      return _unpack(t.__PROXY_KEY or t,...)  end
function getmetatable(t)    return _getmt (t.__PROXY_KEY or t)      end
function setmetatable(t,mt) _setmt(t.__PROXY_KEY or t, mt) return t end


-- Получение длины таблицы.
-- Если таблица создавалась при помощи функции 'proxy', то просто возвращается значение поля.
-- Если таблица создавалась обычным образом, то происходит перебор всей таблицы и подсчет полей.
function table.len(t)
    if t.__PROXY_LEN then
        return t.__PROXY_LEN
    else
        local n = 0
        for _ in pairs(t) do
            n = n + 1
        end
        return n
    end
end

-- Метатаблица для прокси-таблицы, определяющая все её возможности.
local mt_proxy = {}

-- Операция получения по индексу  -- '.' or '[]'
-- Возвращается значение поля из реальной таблицы.
function mt_proxy.__index (t,k)
    return t.__PROXY_KEY[k]
end

-- Операция присваивания -- '='
-- Запись, изменение или удаление поля происходит в реальной таблице
-- Для примера добавлен учет длины таблицы
function mt_proxy.__newindex (t,k,v)
    local real = t.__PROXY_KEY
    -- если нужно изменяем счетчик длины таблицы
    if real[k] == nil then
        if v ~= nil then
            t.__PROXY_LEN = t.__PROXY_LEN + 1
        end
    elseif v == nil then
        t.__PROXY_LEN = t.__PROXY_LEN - 1
    end
    
    real[k] = v 
end

-- При необходимости можно добавить и другие метаметоды

-- Обертка для создания прокси-таблиц
-- Может передаваться и заранее созданная таблица.
-- Уникальные ключи с именами __PROXY_KEY и __PROXY_LEN выбраны для простоты.
-- Ничто не мешает создать ключ типа 'z7vRmv45fUsd78idfJHubnhuHJkj6Gghsd3m5', чтобы наверняка.
function proxy(t)
    local src = t or {}
    local new = {}
    new.__PROXY_KEY = src
    new.__PROXY_LEN = table.len(src)
    -- Т.е. в таблице 'new' только служебные, уникальные поля, а любые обращения идут именно к ней.
    -- Поэтому в любом случае вызывается соответствующий метаметод.
    return _setmt(new, mt_proxy)
end

-- Создавать таблицу с поддержкой прокси можно несколькими способами.
-- 1. Простой вызов функции без аргументов. Возвратиться новая прокси-таблица
t = proxy()
-- 2. Вызов функции с передачей уже существующей таблицы.
local x = {a=5, [3]='s'}
t = proxy(x)
-- 3. Похож на 1-й, но благодаря возможностям синтаксиса lua более информативный.
--    т.е. видно что 't' это таблица, а непонтно что возвращаемое функцией 'proxy'
t = proxy {}

-- Получить длину таблицы можно либо вызвав table.len(t), либо напрямую обратившись
-- к уникальномк ключу : local len = t.__PROXY_LEN

-- Всё. Работать с 't' как обычно.
-- P.S. Выдирал по кускам из более сложной разработки плюс некоторое редактирование,
-- поэтому не исключены и очепятки.

 

 

Изменено пользователем Nazgool
  • Полезно 4
Ссылка на комментарий

Нужна помощь. ЗП

Имеется выброс. Он случается раз в 2 - 4 дня.

Из игры я могу получить дату и время, когда был последний выброс, например, 20 апреля в 13 часов 20 минут.

Могу получить промежуток между выбросами, в секундах.

Могу получить текущие дату и время, например 21 апреля 11 часов 48 минут.

Нужно рассчитать оставшееся до следующего выброса время, в часах и минутах (т.е. до выброса осталось Н часов и м минут)

Имеется у меня функция, но она бред выдаёт. Конкретно, отрицательные значения часов и минут.

К тому же, не учитывается, что выброс мог произойти в прошлом месяце (т.е. например, выброс был 28 апреля, а сейчас 1 мая)

	local delta_all = surge_manager.get_delta()
	local d,h,m = surge_manager.get_last_surge_time()
	--текущее время
	local d_t = vergas_lib.return_time(3)
	local h_t = vergas_lib.return_time(4)
	local m_t = vergas_lib.return_time(5)
	
	--считаю время (сек) прошедшее с последнего выброса
	local delta_d = 0
	local delta_h = 0
	if d == d_t then
		--выброс был в этот же день
		--считаю прошедшие часы
		delta_h = h_t - h
	else
		--выброс был накануне
		delta_h = 24 - h + h_t
	end	
	--считаю прошедшие минуты
	local delta_m = math.abs(m - m_t)
	--перевожу все в игровые секунды
	local delta = delta_all - delta_h*3600 - delta_m*60
	
	local delta_ost = math.fmod(delta,3600)
	local delta_h = (delta - delta_ost)/3600
	delta = math.fmod(delta_ost,60)
	local delta_m = (delta_ost - delta)/60
	
	return delta_h, delta_m

 

	local delta_all = surge_manager.get_delta()
	local d,h,m = surge_manager.get_last_surge_time()
	--текущее время
	local d_t = VS_surge_news.return_time(3)
	local h_t = VS_surge_news.return_time(4)
	local m_t = VS_surge_news.return_time(5)
	local delta_d = 0
	local delta_h = 0
	local delta_m = 0

	--считаю время (сек) прошедшее с последнего выброса

	delta_d = d_t - d
	--считаю прошедшие часы
	if d == d_t then
		--выброс был в этот же день
		delta_h = h_t - h
	else
		--выброс был накануне
		delta_h = 24 - h + h_t
	end
	--считаю прошедшие минуты
	delta_m = math.abs(m - m_t)

	--перевожу все в игровые секунды
	local delta = delta_all - delta_d*86400 - delta_h*3600 - delta_m*60

	local delta_ost = math.fmod(delta,3600)
	local delta_h = math.abs((delta - delta_ost)/3600)
	delta = math.fmod(delta_ost,60)
	local delta_m = math.abs((delta_ost - delta)/60)
	
	return delta_h, delta_m

 

Но всё равно не взлетает...

Шаман - СисАдмин

Всяко-разно: для ЧН

Ссылка на комментарий

@Romz, у тебя есть все необходимые инструменты, ты же сам недавно подключал модули Артоса.

В lua_helper есть метод (импортированный в публичное пространство) Get_PastSeconds. Получаешь им кол-во секунд, прошедшее со времени последнего выброса:

local past_seconds = Get_PastSeconds(surge_manager.get_last_surge_time())

Затем из дельты между выбросами (которая тоже в секундах) вычитаешь полученное значение и превращаешь в часы и минуты простой арифметикой.

 

Upd: единственное - твоя добавленная функция surge_manager.get_last_surge_time() должна возвращать объект типа CTime, то есть то, что в оригинальном surge_manager хранится в свойстве self.last_surge_time.

 

Upd2: если интересно, как то же самое можно сделать без lua_helper, то вот:

local past_seconds = game.get_game_time():diffSec(surge_manager.get_last_surge_time())
Изменено пользователем Kirgudu
  • Спасибо 1
Ссылка на комментарий

 

 

единственное - твоя добавленная функция surge_manager.get_last_surge_time() должна возвращать объект типа CTime,
Ну это не моя функция, а @Vergas :)
function get_last_surge_time()
	local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0
	local g_s_m = get_surge_manager()
	Y, M, D, h, m, s, ms = g_s_m.last_surge_time:get(Y, M, D, h, m, s, ms)
	return D, h, m
end

 

То есть, можно было гораздо проще всё сделать...


Просто, для информации и личного развития
А что, в ЛУА регистр названия переменной играет роль?
То есть "M" и "m" будут разные переменные?

 

Шаман - СисАдмин

Всяко-разно: для ЧН

Ссылка на комментарий

@Romz, да, Lua регистр различает.

То есть, можно было гораздо проще всё сделать...

Смотря для чего сам Vergas её писал. А тебе да, можно сделать всё намного проще, по крайней мере в рамках заданного вопроса. Думаю, окончательное решение должно быть уже понятно.

Изменено пользователем Kirgudu
  • Согласен 1
Ссылка на комментарий

Да я, собственно, переделываю скрипт Vergas-a, который должен будить ГГ перед выбросом. У него это реализовано таким образом, что при вызове функции сна проверяется, сколько времени осталось до следующего выброса, и если меньше, чем ГГ собрался поспать, то устанавливается время сна равное оставшемуся до выброса времени, в часах.

Но у него это сделано под оригинальный выброс, а у меня в сборке Атмосфир прикручен, и период выброса стоит раз в 2-4 дня. Причём, у меня такое ощущение, что промежуток между выбросами тоже может динамически меняться в некоторых пределах. Потому что если проматывать время, часто спать, то можно ловить выбросы на каждом сне, чего быть не должно.

Шаман - СисАдмин

Всяко-разно: для ЧН

Ссылка на комментарий

Всем привет. Пытался переадаптировать схему боя НПС с ножом из ЗП в ТЧ. В итоге НПС достает нож, смотрит на ГГ и больше ничего не делает. Возникли вопросы:
1. Кто-нибудь разбирал этот скрипт?
2. Возможно подправить это баг?
Вот еще файл скрипта

---- Rulix aka Bak --- 8.3.2010

function printf(s, ...)
-- rx_ai.printf("kn:"..s,...)
-- get_console():execute("flush")
end

local kn_ini = ini_file("misc\\rx_knife.ltx")
local knife_sets = {forbiddens = {weapons = {},factions = {},npcs = {}},
communities = {},
ranks = {},
check_prd = rx_utils.read_from_ini(kn_ini,"main","check_period",1001),
fire_dist = rx_utils.read_from_ini(kn_ini,"main","fire_dist",1.5),
enabled = rx_utils.read_from_ini(kn_ini,"main","enabled",false,0)}

function init()
if not knife_sets.enabled then
kn_ini = nil
return
end
local ranks = {"novice","experienced","veteran","master"}
for k,v in ipairs(ranks) do
if kn_ini:section_exist(v) then
knife_sets.ranks[v] = {rate = rx_utils.read_from_ini(kn_ini,v,"rate",1)}
end
end
local communities = { "stalker", "dolg", "freedom", "bandit", "military", "ecolog", "killer", "monolith" }
for k,v in ipairs(communities) do
knife_sets.communities[v] = {rate_add = rx_utils.read_from_ini(kn_ini,v,"rate_add",0),
courage = rx_utils.read_from_ini(kn_ini,v,"courage",1),
attack_wounded = rx_utils.read_from_ini(kn_ini,v,"attack_wounded",0),
mutant_hunt = rx_utils.read_from_ini(kn_ini,v,"mutant_hunt",true,0) or nil}
end
knife_sets.forbiddens.weapons = rx_utils.parse_list(kn_ini,"main","forbidden_weapons",true)
knife_sets.forbiddens.factions = rx_utils.parse_list(kn_ini,"main","forbidden_factions",true)
knife_sets.forbiddens.npcs = rx_utils.parse_list(kn_ini,"main","forbidden_npcs",true)
kn_ini = nil
knife_sets.inited = true
end

local kill_wounded = 0
local sneak_attack = 1
local close_attack = 2
local mutant_hunt = 3
local mutant_defend = 4

local mutant_hunt_clsids = {
[clsid.bloodsucker_s] = true,
[clsid.boar_s] = true,
-- [clsid.dog_s] = true,
[clsid.flesh_s] = true,
-- [clsid.pseudodog_s] = true,
-- [clsid.burer_s] = true,
-- [clsid.cat_s] = true,
-- [clsid.chimera_s] = true,
[clsid.controller_s] = true,
-- [clsid.fracture_s] = true,
-- [clsid.poltergeist_s] = true,
-- [clsid.gigant_s] = true,
-- [clsid.zombie_s] = true,
-- [clsid.snork_s] = true,
-- [clsid.tushkano_s] = true,
[clsid.psy_dog_s] = true,
-- [clsid.psy_dog_phantom_s] = true}
}
local mutant_defend_clsids = {
-- [clsid.bloodsucker_s] = true,
[clsid.boar_s] = true,
-- [clsid.dog_s] = true,
[clsid.flesh_s] = true,
[clsid.pseudodog_s] = true,
-- [clsid.burer_s] = true,
[clsid.cat_s] = true,
-- [clsid.chimera_s] = true,
-- [clsid.controller_s] = true,
[clsid.fracture_s] = true,
-- [clsid.poltergeist_s] = true,
-- [clsid.gigant_s] = true,
-- [clsid.zombie_s] = true,
-- [clsid.snork_s] = true,
[clsid.tushkano_s] = true,
[clsid.psy_dog_s] = true,
-- [clsid.psy_dog_phantom_s] = true}
}

targets = {}

local function remove_target(npc_id,st)
if st.target and targets[st.target] == npc_id then
targets[st.target] = nil
end
st.target = nil
end

class "evaluator_knife_attack" (property_evaluator)
function evaluator_knife_attack:__init(npc,name,storage) super (nil,name)
self.st = storage
self.st.delay = 0
self.st.timer = 0
self.check_timer = 0
local comm = npc:character_community()
if self.attack_wounded == nil then
self.attack_wounded = math.random() < knife_sets.communities[comm].attack_wounded
end
if not self.courage then
self.courage = math.random(25,npc:character_rank()/4+51)
end
self.courage = self.courage*knife_sets.communities[comm].courage
self.cmhunt = knife_sets.communities[comm].mutant_hunt
-- rx_ai.printf("knife_init[%s]:kn_aw %s, courage %s, rank %s",npc:character_name(),tostring(self.attack_wounded),self.courage,npc:character_rank())
rx_ai.subscribe_for_events(npc,self)
end

function evaluator_knife_attack:evaluate()
local npc = self.object
if rx_utils.IsTrader(npc) then
return false
end
local wm = rx_wmgr and rx_wmgr.get_wm(npc)
local knife = npc:object("wpn_knife")
if not knife or npc:animation_count() ~= 0 then
-- printf("evaluator_knife_attack[%s]:not knife or anims",npc:character_name())
remove_target(npc_id,self.st)
return false
end
local npc_id,tg = npc:id(),time_global()
if self.st.delay > tg then
remove_target(npc_id,self.st)
-- printf("evaluator_knife_attack[%s]:delay",npc:character_name())
return false
end
local be = npc:best_enemy()
if not be then
remove_target(npc_id,self.st)
return false
end
local be_id = be:id()
local target = self.st.target and level.object_by_id(self.st.target)
if not (target and target:alive()) then
-- printf("evaluator_knife_attack[%s]:not target",npc:character_name())
remove_target(npc_id,self.st)
end
local npc_pos = npc:position()
if target then
-- printf("evaluator_knife_attack[%s]:target",npc:character_name())
local target_pos = be:position()
local dist = target_pos:distance_to(npc_pos)
if targets[self.st.target] then
if targets[self.st.target] ~= npc_id then
printf("evaluator_knife_attack[%s]:target gette",npc:character_name())
remove_target(npc_id,self.st)
elseif self.st.target ~= be_id and dist > 3 or not npc:accessible(target_pos) then
printf("evaluator_knife_attack[%s]:target not access",npc:character_name())
remove_target(npc_id,self.st)
else
if self.st.type == kill_wounded and dist > 5 then
remove_target(npc_id,self.st)
self.st.delay = tg+15000
return false
elseif self.st.type == sneak_attack and target:see(npc) and dist > self.courage/20 then
self.st.type = close_attack
return true
elseif self.st.type == close_attack and dist > self.courage/10 then
remove_target(npc_id,self.st)
self.st.delay = tg+15000
return false
elseif self.st.type == mutant_hunt and dist > 15 then
remove_target(npc_id,self.st)
self.st.delay = tg+12000
return false
elseif self.st.type == mutant_defend and dist > 12 or npc.health < 0.2 then -- or not (target:get_enemy() and target:get_enemy():id() == npc_id)
remove_target(npc_id,self.st)
self.st.delay = tg+12000
return false
end
return true
end
else
if dist > 12 then
printf("evaluator_knife_attack[%s]:target dist > 12",npc:character_name())
self.st.target = nil
end
end
end
if self.check_timer > tg then
return target ~= nil
end
self.check_timer = tg+knife_sets.check_prd
local be_pos = be:position()
local dist = npc_pos:distance_to(be_pos)
if targets[be_id] or (xr_wounded.is_wounded(be) and not self.attack_wounded) or dist > 10 or not npc:accessible(be_pos) then
-- printf("evaluator_knife_attack[%s]:not access %s %s %s %s",npc:character_name(),tostring(targets[be_id]),tostring((xr_wounded.is_wounded(be) and not self.attack_wounded)),tostring(dist > 15),tostring(not npc:accessible(be_pos)))
return false
end
local be_see_me,me_see_be = be:see(npc),npc:see(be)
if IsStalker(be) then
if xr_wounded.is_wounded(be) then
if self.attack_wounded and me_see_be and dist < 3.5 then
self.st.target = be_id
self.st.type = kill_wounded
return true
end
return false
end
if me_see_be and not be_see_me and self.courage > 40 and npc:body_state() == move.crouch and dist < 5 and npc.health > 0.5 then
-- printf("sneak_attack[%s]:return true",npc:character_name())
self.st.target = be_id
self.st.type = sneak_attack
return true
end
if self.courage > 33+5*dist and me_see_be then
local npc_wpn,be_wpn = npc:active_item(),be:active_item()
if not (be_wpn and rx_utils.item_is_fa(be_wpn) and npc_wpn and npc_wpn:section() ~= "wpn_knife" and npc_wpn:get_ammo_in_magazine() ~= 0 and be_wpn:get_ammo_in_magazine() ~= 0) then
-- printf("close_attack[%s]:return true",npc:character_name())
self.st.target = be_id
self.st.type = close_attack
self.st.timer = self.st.timer+6000
return true
end
end
else
local bee = be:get_enemy()
-- printf("monster[%s]: %s %s",npc:character_name(),tostring(not (be_see_me and be:get_enemy() and be:get_enemy():id() == npc_id)),tostring(npc.health > 0.8))
if self.cmhunt and mutant_hunt_clsids[be:clsid()] and self.courage > 35+5*dist and not (be_see_me and bee and bee:id() == npc_id) and npc.health > 0.8 then
-- printf("mutant_hunt[%s]:return true",npc:character_name())
self.st.target = be_id
self.st.type = mutant_hunt
self.st.timer = self.st.timer+6000
return true
elseif mutant_defend_clsids[be:clsid()] and dist < 6 and self.courage > 40+dist and (be_see_me and bee and bee:id() == npc_id) and npc.health > 0.2 then
-- printf("mutant_defend[%s]:return true",npc:character_name())
self.st.target = be_id
self.st.type = mutant_defend
self.st.timer = self.st.timer+4000
return true
end
end
return false
end
function evaluator_knife_attack:death_callback(who)
if self.object then
remove_target(self.object:id(),self.st)
end
end


class "evaluator_knife_defend" (property_evaluator)
function evaluator_knife_defend:__init(npc,name,storage) super (nil,name)
self.st = storage
end

function evaluator_knife_defend:evaluate()
return false
end


class "action_knife_attack" (action_base)
function action_knife_attack:__init(npc,action_name,storage) super (nil,action_name)
self.st = storage
self.rank = ranks.get_obj_rank_name(npc)
self.comm = npc:character_community()
self.rate = 1000/(knife_sets.ranks[self.rank].rate+knife_sets.communities[self.comm].rate_add)
end
function action_knife_attack:initialize()
action_base.initialize(self)
local npc = self.object
printf("knife_attack[%s]:init",npc:character_name())
self.st.timer = time_global()+30000
self.start_time = time_global()
self.fire_time = 0
self.mental_time = 0
if rx_wmgr then
local wm = rx_wmgr.get_wm(npc)
-- local knife = wm:get_best_weapon(1)
-- wm:return_items(knife and knife:id() or 0)
wm:disable(self.st.timer)
end
npc:set_desired_position()
npc:set_desired_direction()
npc:set_mental_state(anim.danger)
npc:set_movement_type(move.run)
-- state_mgr.set_state(npc,"assault")
state_mgr.set_state(npc,"idle")
targets[self.st.target] = npc:id()
if self.st.type == kill_wounded then
--xr_sound.set_sound_play(targets[self.st.target],"kill_wounded")
end
self.ddr = math.random() > 0.5
end

function action_knife_attack:execute()
action_base.execute(self)
local npc,tg = self.object,time_global()
local npc_id = npc:id()
if self.st.timer < tg then
remove_target(npc_id,self.st)
self.st.delay = tg+10000
printf("knife_attack[%s]:timer < tg",npc:character_name())
return
end
local target = level.object_by_id(self.st.target)
local dist = npc:position():distance_to(target:position())
local knife = npc:object("wpn_knife")
local dir = target:position()
dir:sub(npc:position())
npc:set_sight(look.direction,dir)
local acti = npc:active_item()
acti = acti and acti:section() == "wpn_knife"
if acti and (dist < knife_sets.fire_dist or self.st.type == mutant_defend and dist < knife_sets.fire_dist*1.5) then
-- printf("attack[%s]:set fire",npc:character_name())
npc:set_sight(look.fire_point,target:bone_position("bip01_neck"))
if self.fire_time < tg then
npc:set_item(object.fire1,knife,1,self.rate)
self.fire_time = tg+self.rate
end
if self.st.type == kill_wounded then
-- npc:set_dest_level_vertex_id(npc:level_vertex_id())
npc:set_movement_type(move.stand)
npc:set_body_state(move.crouch)
end
else
if not (self.st.type == kill_wounded or self.st.type == sneak_attack or IsMonster(target)) then
--xr_sound.set_sound_play(npc_id,"knife_attack")
end
if self.st.type ~= mutant_defend then
npc:set_movement_type(move.run)
end
npc:set_item(object.aim1,knife)
end
if not acti then
if self.start_time+4000 < tg then
remove_target(npc_id,self.st)
self.st.delay = tg+15000
printf("knife_attack[%s]:timer < tg",npc:character_name())
return
end
npc:set_mental_state(anim.danger)
elseif self.st.type == sneak_attack then
npc:set_body_state(move.crouch)
npc:set_mental_state(anim.danger)
if dist > 6 and target:see(npc) then
printf("sneak_attack[%s]:abort",npc:character_name())
remove_target(npc_id,self.st)
return
end
elseif self.st.type == mutant_hunt then
npc:set_body_state(move.standing)
if self.mental_time < tg then
if dist < 3 and self.mental ~= anim.danger then
self.mental_time = tg+900
self.mental = anim.danger
elseif self.mental ~= anim.panic then
self.mental_time = tg+1500
self.mental = anim.panic
end
npc:set_mental_state(self.mental)
end
-- printf("mutant_hunt[%s]:send",npc:character_name())
elseif self.st.type == close_attack then
npc:set_body_state(move.standing)
npc:set_mental_state(anim.danger)
-- printf("close_attack[%s]:send",npc:character_name())
elseif self.st.type == mutant_defend then
npc:set_body_state(move.standing)
npc:set_mental_state(anim.danger)
if dist < 3.5 then
npc:set_movement_type(move.run)
else
npc:set_movement_type(move.walk)
end
-- printf("mutant_defend[%s]:send",npc:character_name())
end
local vertex = self.st.type == mutant_defend and get_dodge_vertex(npc,target,self.ddr) or target:level_vertex_id()
utils.send_to_nearest_accessible_vertex(npc,vertex)
end

function action_knife_attack:finalize()
local npc = self.object
printf("knife_attack[%s]:fin",npc:character_name())
if rx_wmgr then
rx_wmgr.get_wm(npc):enable()
end
if not npc:best_enemy() then
npc:set_item(object.idle,npc:object("wpn_knife"))
state_mgr.set_state(npc,"guard")
end
npc:set_sight(look.direction,npc:direction())
remove_target(npc:id(),self.st)
self.mental = nil
self.ddr = nil
action_base.finalize(self)
end

class "action_knife_defend" (action_base)
function action_knife_defend:__init (npc,action_name,storage) super (nil,action_name)
self.st = storage
end
function action_knife_defend:initialize()
action_base.initialize(self)
self.wm = db.storage[npc:id()].wm
self.wm:set_weapon(npc:object("wpn_knife"))
self.wm.disabled_temp = true
end
function action_knife_defend:execute()
action_base.execute(self)
end
function action_knife_defend:finalize()
action_base.finalize(self)
end

function get_dodge_vertex(s,o,d)
local dir = o:position():sub(s:position())
dir = vector_rotate_y(dir,d and 50 or 310)
return s:vertex_in_direction(s:level_vertex_id(),dir,3)
end

function npc_update(npc)
if knife_sets.enabled then
local knife = npc:object("wpn_knife")
if not knife then
alife():create("wpn_knife",npc:position(),npc:level_vertex_id(),npc:game_vertex_id(),npc:id())
end
end
end

evid_knife_attack=rx_ai.base_id+35
--evid_knife_defend=evid_knife_attack+1
actid_knife_attack=evid_knife_attack
--actid_knife_defend=actid_knife_attack+1

function add_to_binder(npc,ini,scheme,section,storage)
if not knife_sets.inited then
init()
end
local manager = npc:motivation_action_manager()
if not (knife_sets.enabled and not knife_sets.forbiddens.factions[npc:character_community()] and knife_sets.ranks[ranks.get_obj_rank_name(npc)] and not knife_sets.forbiddens.npcs[npc:name()]) then
manager:add_evaluator(evid_knife_attack,property_evaluator_const(false))
return
end
manager:add_evaluator(evid_knife_attack,evaluator_knife_attack(npc,"evaluator_knife_attack",storage))
local action = action_knife_attack(npc,"knife_attack",storage)
action:add_precondition(world_property(stalker_ids.property_alive,true))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false))
-- action:add_precondition(world_property(xr_evaluators_id.state_mgr+1,true))
if rx_gl then
action:add_precondition(world_property(rx_gl.evid_gl_fire,false))
end
if rx_bandage then
action:add_precondition(world_property(rx_bandage.evid_bandage,false))
end
action:add_precondition(world_property(evid_knife_attack,true))
action:add_effect(world_property(evid_knife_attack,false))
manager:add_action(actid_knife_attack,action)
for i,id in ipairs({stalker_ids.action_combat_planner,stalker_ids.action_danger_planner,xr_actions_id.stohe_meet_base+1}) do
action = manager:action(id)
action:add_precondition(world_property(evid_knife_attack,false))
end
end

function set_scheme(npc,ini,scheme,section)
local st = xr_logic.assign_storage_and_bind(npc,ini,scheme,section)
end

function disable_scheme(npc,scheme)
local st = db.storage[npc:id()][scheme]
if st then
st.enabled = false
end
end

ltx-фаил

;--------------------------------------

; Модуль knife
; Rulix aka Bak
;--------------------------------------

[main]
enabled = true
check_period = 1001 ;мс ; время между проверками
forbidden_weapons = none ; запрещенное к использованию оружие
forbidden_factions = zombied
forbidden_npcs = none
fire_dist = 1.5

[novice]
rate = 0.6 ; ударов в секунду

[experienced]
rate = 1.1

[veteran]
rate = 1.3

[master]
rate = 2

;---------------------------------------
[stalker]
rate_add = 0
courage = 0.9
attack_wounded = 0.1
mutant_hunt = true

[bandit]
rate_add = 0.1
courage = 0.7
attack_wounded = 0.2
mutant_hunt = false

[freedom]
rate_add = 0.3
courage = 1.4
attack_wounded = 0.2
mutant_hunt = true

[dolg]
rate_add = 0
courage = 1
attack_wounded = 0
mutant_hunt = true

[killer]
rate_add = 0.2
courage = 0.8
attack_wounded = 0
mutant_hunt = true

[military]
rate_add = 0
courage = 0.6
attack_wounded = 0
mutant_hunt = false

[ecolog]
rate_add = 0
courage = 0.1
attack_wounded = 0
mutant_hunt = false

[monolith]
rate_add = 0
courage = 1.5
attack_wounded = 0.05
mutant_hunt = false

Скрин

post-23395-0-56300200-1445767417_thumb.jpg

Изменено пользователем Gaz24
Ссылка на комментарий

Добрый день.

 

Для Зова Припяти нужна функция в xr_conditions.  Функция вызывается их логики объекта inventiory_box.  Функция должна выдать true, если ближе 10 метров к этому inventory_box окажется любой сталкер или монстр.  Какой функцией можно воспользоваться? Или как её правильно составить?

Ссылка на комментарий

 

 

Функция должна выдать true, если ближе 10 метров к этому inventory_box окажется любой сталкер или монстр

Как вариант: если похотелка одноразовая(т.е. для единичного инвентарного ящика), то накрыть его(ящик) спейс-рестриктором, в котором все делается элементарно и без заморочек...

Ссылка на комментарий

И снова здравстуйте.

Опять за помощью. ЗП.

Имеется инфопоршень. Взводится на пропадание индикаторов ХУДа, сбрасывается при их отображении. Ну, должен, по крайней мере.

Взвод и сброс инфопоршня прописал, соответственно, в xr_effects, в disable_ui, disable_ui_only и enable_ui.

Если находиться на одной локе, то всё работает, как задумано, а вот если перейти на другую с проводником, то инфопоршень "зависает" во взведённом положении.

Где ещё производится проверка на включение\отключение ХУДа?


Нашёл ещё в _g show_all_ui, добавил туда взведение и сброс инфопоршня. Всё равно, не срабатывает до тех пор, пока не будет использована функция, в которой явно отключается\включается UI. Например, поспать.

Шаман - СисАдмин

Всяко-разно: для ЧН

Ссылка на комментарий

@Romz, ты можешь его сбрасывать при первом апдейте, ведь сразу после загрузки никакой диалог (в том числе проводника) ещё не открыт.

Ссылка на комментарий

 

 

сразу после загрузки никакой диалог (в том числе проводника) ещё не открыт.
Не всегда это возможно. Например, первый переход на Янов. Там разговоры вначале. Хотя ГГ уже заспавнился, но UI пока отключен.

Прикол, вернулся на предыдущую локу - инфопоршень сбросился! Инфопоршни, что ли, сохраняются для каждой локи отдельно?

Переведу-ка я проверку с инфопоршней на se_stor

Добавлено Kirgudu,

Рекомендую, кстати, глянуть доработанный se_stor, который я выложил вчера в «сборочном цехе». Теперь там полное сохранение всех возможных данных внешних модулей в универсальном хранилище, в том числе и с кастомными методами сохранения/загрузки.

Шаман - СисАдмин

Всяко-разно: для ЧН

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...