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

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

@dukekan, для ограниченного объёма данных можно использовать трюк с хранением данных в имени файла с использованием класса FS. Этот класс не позволяет записывать данные в файл, но позволяет копировать файлы, менять их имена, читать содержимое каталога. Нужно завести таким образом специальные пустые файлы, придумать формат для имён и хранить данные в именах. Это вполне работает, хотя конечно и пахнет трюкачеством за милю.

С другой стороны можно рассмотреть использование расширений Lua. Есть проект от RvP, где добавлялись недостающие библиотеки работы с файлами.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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

Есть ещё вариант, тут его читал как раз. Через функцию get_console():execute("команда значение")

присвоить какой либо не используемой\незначительной консольной команде (список команд через help получить можно) своё значение (отличное от значения по умолчанию), а потом при следующем запуске из этой же консоли его и считать (class CConsole в scripts\lua_help.script глянь) 

 

Из плюсов - значение вроде как хранится в user.ltx а потому у каждого игрока он свой, из минусов - user.ltx могут удалить игроки)

Вариант с переименовыванием в этом плане понадёжней. 

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

Действительно, вариант Charsi работает, спасибо.

Кому понадобится, немного растолкую суть этого метода.

-- Сохранение данных в S.T.A.L.K.E.R. Тень Чернобыля
local value = 0 -- переменная, которую нужно сохранить-считать
local concomm ="sv_vote_enabled" -- строка в конфиге my_config.ltx, после которой будет значение нашей переменной
local con = get_console()

function var_load()
con:execute("cfg_load my_config") -- загружаем наш конфиг
value = con:get_string(concomm) -- получаем значение, котрое идёт после sv_vote_enabled
con:execute("cfg_load user")--загружаем стандартный конфиг user.ltx
end

function var_save()
con:execute("cfg_load my_config")-- загружаем наш конфиг
con:execute(concomm.." "..value) --сохраняем значение переменной
con:execute("cfg_save my_config") -- сохраняем конфиг
con:execute("cfg_load user") -- загружаем стандартный
end 

 

my_config будет лежать там же, где и user.ltx

Значение переменной vaue после загрузки будет не числовым, а строковым, и, к примеру, проверка её значения будет выглядеть так:

if value == '3' then -- do something
end

 

 

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

Значение переменной vaue после загрузки будет не числовым, а строковым

Вместо get_string используй другую функцию, и будет грузить число. 

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

Всем привет, написал схему поведения "напарник", по работе red75, но вот незадача, после ее модифицирования, странным образом она перестала деактивироваться, сталкер после слов "спасибо, дальше я один" и тп, продолжает бегать за нами...
вот весь код...
S.T.A.L.K.E.R. ShoC v1.0004(с погодой амк)


 
property_faraway = 1000
act_stay_close = property_faraway+1
function i_am_friend(talker,target)
  return target:relation(talker)==game_object.friend
end

function weather_f()
local l=0
local w={"clear","pasmurno","rain","groza"}
local t=level.get_time_hours()
for i=1,#w do
if level.get_weather() == "amk_groza_"..w[i].."_"..t then
l=1 
end
end
return l==1
end
                   

function weather_g()
local l=0
local w = {"clear","pasmurno","rain","groza"}
local t=level.get_time_hours()
for i=1,#w do
if level.get_weather() ~= "amk_groza_"..w[i].."_"..t then
l=1 
end
end
return l==1
end

function night_n()
return  level.get_time_hours() < 22 or  level.get_time_hours() > 4 
end

function night_y()
return level.get_time_hours() > 22 or  level.get_time_hours() < 4 
end

-- За основу этой функции взята функция dialogs.actor_have_medkit
function npc_have_medkit(talker, target)
  return talker:object("medkit") ~= nil or
       talker:object("medkit_army") ~= nil or
       talker:object("medkit_scientic") ~= nil
end
function npc_havent_medkit(talker, target)
  return not npc_have_medkit(talker,target)
end


local scheme_status={}
function scheme_is_active(talker,target)
  return scheme_status[target:id()]==true 
end

function scheme_is_not_active(talker,target)
  return not scheme_is_active(talker,target)
end

function activate_scheme(talker,target)
  set_help(talker,talker:spawn_ini())
  scheme_status[talker:id()]=true
end

function deactivate_scheme(talker,target)
  disable_scheme(talker,"actor_need_help")
  scheme_status[talker:id()]=false
end

class "evaluator_faraway" (property_evaluator)

function evaluator_faraway:__init(name, storage) super (nil, name)
  self.st = storage
end


local min_faraway_dist=10
local max_faraway_dist=30
local min_dist = 5
local faraway_dist = 10

function evaluator_faraway:evaluate()
  local actor=db.actor
  if not actor then
  -- ГГ ещё не заспаунился
    return false
  end
  local dist=actor:position():distance_to(self.object:position())
  if dist > min_dist and dist < faraway_dist*20 then
  self.st.faraway=true
  elseif dist < min_dist or dist > faraway_dist*20then
  self.st.faraway=false
  end
  return self.st.faraway==true
end

 class "action_stay_close" (action_base)

function action_stay_close:__init(name, storage) super (nil, name)
  self.st=storage
end

function action_stay_close:initialize()
  local npc=self.object
  get_console():execute("Est' init")
  -- Не знаю зачем эти две функции, но они используются во всех операторах
  npc:set_desired_position()
  npc:set_desired_direction()
  -- Сбрасываем текущие анимации
  npc:clear_animations()
  -- Задаём параметры движения
  npc:set_detail_path_type(move.line)
  npc:set_body_state(move.standing)
  npc:set_movement_type(move.run)
  npc:set_path_type(game_object.level_path)
  -- Эксперименты показали, что эта функция устанавливает скорость движения (anim.danger - 
--минимальная скорость, anim.free - нормальная, anim.panic - максимальная)
  npc:set_mental_state(anim.panic)
  -- Повышаем зоркость NPC
  npc:set_sight(look.danger, nil, 0)
  -- Освободим сталкера от всех идиотских ограничений
  npc:remove_all_restrictions()
-- Зададим смещение точки назначения, чтобы помощники не сбивались в кучу
  self.offset=vector():set(math.random()*6-3,0,math.random()*6-3)
  self.offset:normalize()
  self.state_change_time=time_global()+3500
  self.last_v_id=npc:level_vertex_id()
  --get_console():execute("Finish")
end

function action_stay_close:execute()
  action_base.execute(self)
--  mylog("action exec")
  local npc=self.object
  local actor=db.actor
  if not actor then
  -- Хм, что-то не так. Может быть ГГ перешёл на другой уровень? Запрещаем схему поведения
    self.st.enabled=false
  end
  if self.delay and self.delay>time_global() then
    return
  end
  self.delay=time_global()+1000

  -- Получаем ближайшую доступную точку в 5 метрах от ГГ
  local vertex_id=level.vertex_in_direction(actor:level_vertex_id(),self.offset,5)

  if self.state_change_time<time_global() then
    self.state_change_time=time_global()+3500
    if self.last_v_id==npc:level_vertex_id() then
      state_mgr.set_state(npc,"sprint")
      npc:set_dest_level_vertex_id(self.last_v_id)
      self.last_v_id=0
      self.st.temp_disable=time_global()+3500
      return
    elseif self.st.dist then 
if self.st.dist<max_faraway_dist and self.st.dist>min_faraway_dist  then
      state_mgr.set_state(npc,"sprint",nil,nil,nil,{animation=true})
    elseif self.st.dist<max_faraway_dist and self.st.dist<min_faraway_dist then
      state_mgr.set_state(npc,"sprint",nil,nil,nil,{animation=true})
elseif self.st.dist>max_faraway_dist then
      state_mgr.set_state(npc,"fast_sprint",nil,nil,nil,{animation=true})
    end
    self.last_v_id=npc:level_vertex_id()
  end
  end

--  npc:set_detail_path_type(move.line)
  if vertex_id then
    npc:set_dest_level_vertex_id(vertex_id)
  end
end

 function add_to_binder(object, char_ini, scheme, section, st)
  local manager = object:motivation_action_manager()
  local property_wounded = xr_evaluators_id.sidor_wounded_base

  -- Удаляем эвалуатор, так как в xr_motivator мы установили его в property_evaluator_const
  manager:remove_evaluator(property_faraway)
  -- и заменяем его нашим
  manager:add_evaluator(property_faraway, evaluator_faraway("evaluator_faraway",st))
    -- Создаём оператор
  local action = action_stay_close("action_stay_close",st)
    -- и настраиваем предусловия. 1. Сталкер жив
  action:add_precondition(world_property(stalker_ids.property_alive, true))
  -- 2. Сталкер не ранен
  action:add_precondition(world_property(property_wounded, false))
  -- Я использую свой мод для обхода аномалий, иначе от помощников мало толку.
  if anomaly_evader then
  -- 3. Рядом нет аномалий
    action:add_precondition (world_property(1099,false))
  end
 -- 4. Сталкер слишком далеко от ГГ
   action:add_precondition(world_property(property_faraway, true))
  action:add_effect (world_property(property_faraway, false))
  -- Добавляем оператор в планировшик
  manager:add_action (act_stay_close, action)
  -- Теперь подкорректируем стандартные операторы, чтобы помощник не отвлекался на всякую ерунду.
  action=manager:action(stalker_ids.action_alife_planner)
  action:add_precondition(world_property(property_faraway, false))
  action=manager:action(stalker_ids.action_combat_planner)
  action:add_precondition(world_property(property_faraway, false))
  action=manager:action(stalker_ids.action_danger_planner)
  action:add_precondition(world_property(property_faraway, false))
end


 function set_help(npc, ini)
  local st = xr_logic.assign_storage_and_bind(npc, ini, "actor_need_help")
  st.enabled=true
end

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

 

 

--//функция - net_spawn()
local manager = self.object:motivation_action_manager()
manager:add_evaluator(actor_need_help.property_faraway, property_evaluator_const(false))
--//функция -addCommonPrecondition(action)
action:add_precondition (world_property(actor_need_help.property_faraway,false))

 



load_scheme("actor_need_help", "actor_need_help", stype_stalker)

 

 

<?xml version="1.0" encoding="windows-1251" standalone="yes" ?>
<game_dialogs>
    <dialog id="actor_will_need_help">
        <precondition>actor_need_help.i_am_friend</precondition>
        <precondition>actor_need_help.scheme_is_not_active</precondition>
        <phrase_list>
            <phrase id="0">
                <text>Выдвигаемся.</text>
                <next>11</next>
                <next>12</next>
				<next>13</next>
				<next>14</next>
            </phrase>
            <phrase id="11">
			    <precondition>actor_need_help.weather_g</precondition>
			    <precondition>actor_need_help.night_n</precondition>
                <text>Конечно.</text>
				<next>15</next>
               
            </phrase>
			
			<phrase id="15">
			    <text>За мной.</text>
				<next>16</next>          
			</phrase>
			<phrase id="16">
			    <text>Уже иду.</text>
				<action>actor_need_help.activate_scheme</action>
                          
			</phrase>
            <phrase id="12">
			    <precondition>actor_need_help.weather_g</precondition>
			    <precondition>actor_need_help.night_y</precondition>
				<text>Нее, я в такую темень не пойду.</text>
            </phrase>
			<phrase id="13">
			    <precondition>actor_need_help.night_n</precondition>
			    <precondition>actor_need_help.weather_f</precondition>
                <text>В грозу, куда то идти? Не, брат.</text>
            </phrase>
			<phrase id="14">
			    <precondition>actor_need_help.night_y</precondition>
			    <precondition>actor_need_help.weather_f</precondition>
                <text>Ты что? Темнота такая, да еще и льет как из ведра!</text>
            </phrase>
			
        </phrase_list>
    </dialog>
    <dialog id="actor_will_not_need_help">
        <precondition>actor_need_help.i_am_friend</precondition>
        <precondition>actor_need_help.scheme_is_active</precondition>
        <phrase_list>
            <phrase id="0">
                <text>Спасибо, друг, теперь я сам справлюсь.</text>
                <next>21</next>
            </phrase>
            <phrase id="21">
                <text>Да не за что, ты мне помог, я - тебе.</text>
                <action>actor_need_help.deactivate_scheme</action>
            </phrase>
        </phrase_list>
    </dialog>
</game_dialogs> 

 

 

 

Ну вроде бы все написал. Так, а вопрос состоит в следующем, почему схема перестала деактивироваться? Функция в диалоге присутствует, и ошибок в ней нет, до меня не доходит, это(

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

Что-то как-то не понял по object_binder (и про скрипт для серверного объекта тоже):

 

В части имеющихся изначально или в модах скриптов прописаны методы типа:

function generic_object_binder:reinit()
object_binder.reinit( self )
end
или, соответственно,
function se_artefact:can_switch_offline()
return cse_alife_item_artefact.can_switch_offline( self )
end

 

То есть, они ничего нового заведомо не делают, но тем не менее явно прописаны.

В других скриптах эти методы отсутствуют (то есть, очевидно, просто тупо наследуются, если есть от чего, и там все, что надо, очевидно, есть.

 

Вопрос: эта разница она зачем-то, или это остался мусор от чего-то,  или я чего-то не понимаю ?

 

То есть, если вот такое вот отовсюду поубирать - какие эффекты следует ожидать ?

 

 

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

Dennis_Chikin,
Разница есть, обусловлена разной природой биндера и серверного объекта. Скриптовый серверный объект является обёрткой для истинного движкового объекта, т.е. когда вызываем его метод в скриптах - тем самым явно вызываем соответствующий метод движка. Одно из следствий этого - когда переопределяем метод в скриптах - он полностью заменяет внутренний движковый метод. Если внутренний метод при этом использовал сервис базового класса в виде явного вызова метода базового класса, то это надо/можно повторить и в скриптах. Самый типичный пример - методы сохранения/чтения, где сам скриптовый метод сохраняет только "своё добро", а надо ещё и явно вызвать метод базового класса для сохранения/загрузки его состояния. Или метод проверки выхода в онлайн, где я могу определить свою логику для этого действия, но при этом могу использовать в качестве одной из веток алгоритма дефолтовое значение. А могу и не использовать. В последнем случае метод базового класса вызывать не надо. При этом всё-таки надо отчётливо понимать, что я сознательно выбрасываю определённый движковый функционал.

С другой стороны биндер работает совсем иначе. Есть онлайновый класс, у него есть базовый класс CScriptBinder, который входит в состав CGameObject (и значит в состав абсолютно всех классов). Класс CScriptBinder как раз и отвечает за функционал биндера. Там есть указатель на объект биндера, а биндер в свою очередь - это отдельный класс CScriptBinderObject, которому как раз и соответствует скриптовый биндер (является его обёрткой). Объект биндера может быть или не быть, мы сами создаём его в скриптах и цепляем к онлайновому объекту методом клиентского класса bind_object.
Если он есть, то это исключительно инициатива клиентского объекта-хозяина вызывать методы биндера и посылать сигналы колбеков. Отсюда идёт важный вывод. Нет никакой необходимости вызывать методы базового класса биндера, поскольку они ничего не делают. Т.е. всё движковое действие происходит в методе клиентского объекта, который сработает вне зависимости от того, вызвался метод биндера или нет, а биндер просто вызывается "до кучи". Я это проверял. Удалял вызовы базового класса биндера, и ничего ровным счётом не менялось.

  • Нравится 1
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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

Бр-р... Стало еще непонятнее.

Вот конкретные примеры были: из bind_monster и из se_artefacts.

Эти приведенные куски кода - они там зачем ? Если эти методы НЕ переопределяются - они ведь по дефолту как-то работают ?

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

Dennis_Chikin,


Эти приведенные куски кода - они там зачем ? Если эти методы НЕ переопределяются - они ведь по дефолту как-то работают ?

ок. Первый фрагмент - метод биндера.

function generic_object_binder:reinit()
    object_binder.reinit( self )
end

Вызов object_binder.reinit( self ) здесь не делает ничего, поскольку класс биндера не делает ничего, поскольку его единственное назначение - вызывать скриптовый код. Строку можно убрать, ничего не изменится.

Второй фрагмент. Переопределён метод класса se_artefact, заменен на скриптовый.

function se_artefact:can_switch_offline()
    return cse_alife_item_artefact.can_switch_offline( self )
end

Исходный метод cse_alife_item_artefact.can_switch_offline(self) что-то делал, пока мы его этим самым фрагментом не переопределили. Скорее всего возвращал значение серверного флага, хотя прямо сейчас не буду утверждать наверняка. Соответственно в показанном виде мы попросту воспроизвели то, что в движке было изначально. Теперь есть два выбора:
1. Заменить эту логику. Строку удаляем, тем самым игнорируя значение серверного флажка (предположительно). Вместо этого ставим что-то своё, к примеру return false, что будет означать, что объект означенного класса никогда не перейдёт из онлайна в оффлайн (разумеется до тех пор, пока на одном уровне с актором).
2. Дополнить эту логику. Можно поставить некий код, который при каких-то условиях будет переходить в оффлайн по нашему условию, а в других условиях по серверному флажку. Как-то так:

function se_artefact:can_switch_offline()
    if <какое-то скриптовое условия> then
        return false
    end
    return cse_alife_item_artefact.can_switch_offline( self )
end
  • Нравится 1
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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

Гм, еще уточняю:

А сама строка function generic_object_binder:reinit() end - вот именно в таком виде, вообще нужна, или это, все-таки, мусор ?

Ну и прочие save(), load(), update() ?

 

И, кстати, чудесное, аж из самого оригинала:

function generic_object_binder:reload(section) object_binder.reload(self, section) end
function generic_object_binder:reload(section) object_binder.reload(self, section) end

- ага, два раза в одном классе.

Это у нас переопределение, или 2 вызова ?

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

@Dennis_Chikin, т.е. как пустая функция? Это похоже на заглушку, наверняка результат копипасты. Заглушка наверное не нужна сама по себе. С другой стороны и вреда особенного нет.

 

Насчёт дубликата. Скорее всего баг, возможно результат всё той же копипасты. Срабатывать будет вторая функция. Вот смотри, такой код:



function generic_object_binder:reload(section) 
end

Является синтаксическим сахаром для вот такого:



generic_object_binder.reload = function(self, section) end

т.е. сделав это два раза мы просто переписываем поле reload. Естественно, там будет результат от второй записи.

Изменено пользователем ColR_iT
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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

Возникла небольшая проблема. Нужно, чтобы 2 НПС менялись работами каждые следующие сутки. Решил сделать проверку и вызвать её в логике, меняя им схемы.
Вот функция из xr_conditions.script, но НПСы остаются на своих работах(проверял 5 суток). В чём проблема? Можете намекнуть на правильный вариант, но не пишите прямо, только намёком, если здесь есть ошибка, либо есть другой вариант. Правда одна проблема будет из-за календарных дней, это та причина, по которой я сомневаюсь вызывать глобальную функцию get_time_days.

function is_next_day (actor, npc)
    if level.get_time_days() == 1 then -- проверка, что сейчас первый день
        return false
    elseif level.get_time_days() ~= 1 and (level.get_time_days() % 1) == 0 then -- проверка, что сейчас не первый день и остаток при делении дня на 1 равен 0, вызываем true
   return true
end
end
Изменено пользователем La'Rento
Ссылка на комментарий

La'Rento, функция get_time_days возвращает текущий день месяца, т.е. число и если в момент проверки у тебя в игре не первое число месяца, то первая проверка вернёт false.

А вторая проверка у тебя у тебя странноватая. Остаток от деления числа на единицу всегда будет равен нулю, поэтому твоё сравнение не имеет практического смысла. В конечном итоге, у тебя данная функция будет возвращать false, только в первое число, а в остальные будет возвращать true.

 

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

Ну правильно, поэтому каждый последующий день(кроме первого) будет выполнен переход на другие схемы, согласно возврату правды в данной функции. Но в следующий месяц в первое число функция не вернёт true и переход не будет выполнен.
Иначе, ты намекал на аккуратную проверку следующий суток, нужна здесь функция get_time_days или ты имел ввиду другую функцию?

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

La'Rento, самый простой способ - это запомнить число первых суток и сравнивать его с числом на следующих и так далее. Только в таком случае тебе нужно сохранять это число. Либо производить смену работ по чётным/нечётным дням, так сохранять ничего не нужно будет.

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

@ColR_iT,Собственно от второго варианта я и отталкивался и расписал функцию для состояний гулага, пока понял, что не знаю как использовать их при смене работ. Но тогда если день чётный, до вызываем true, нечётный - вызываем false, а смены работ должна быть независима от чётности дня. наверное, этот вариант остаётся удобен только для работ с состояниями. 
А про первый способ я не понял. Каким образом сравнить? Указывать, что не равно 1?

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

La'Rento, в первый работы сохраняешь число месяца и периодически сравниваешь его со значением get_time_days, на следующий день оно естественно изменится, тогда и поменяешь работу. При этом теперь сохранишь уже это число и так далее.

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

Народ, подскажите пожалуйста:

 делаю я переборку объектов:

	for i=1,65535 do
		local obj = alife():object(i)

и хочу затем сделать кое-что с этим объектом, а именно со сталкером:

   if obj then
    if obj:section() == "stalker" then

Однако получаю вылет из-за:

attempt to call method 'section' (a nil value)

То бишь у объекта нет такого метода, однако на stalkerin написано: ...Эти методы подходят к объектам любого класса...

string section() const

возвращает имя секции объекта. Аргументов не принимает.

 

Вообще я что хочу сделать: узнать какие из этих объектов сталкеры, желательно без нет-пакетов можно это осуществить?

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

Старлей, метод section - у клиентских объектов, у серверных - section_name.

Чтобы узнать, какие из этих объектов сталкеры, есть функция IsStalker (object, class_id).

 

 

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

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

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

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

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

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

Войти

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

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

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