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

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


Svoboда

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

Возможно ли в ТЧ без движковых правок отловить скриптом заклинивание оружия? Мож кто коллбек делал? Хочу прикрутить ругань ГГ из модов для CoC.

  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

Подскажите решение проблемы с большим количеством второстепенных квестов, когда сначала путаются их описания, а потом происходит вылет вида +165 bytes в конце - "XR_3DA.exe caused BREAKPOINT in module ""E:\GAMES\S.T.A.L.K.E.R\bin\xrCore.dll"" at 001B:00597D15, xrDebug::backend()+165 byte(s)"

Изменено пользователем Капрал Хикс

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

@naxac, вах! По методу последнему и хранилище от Артоса не понадобится, верно?

Изменено пользователем Капрал Хикс

Поделиться этим сообщением


Ссылка на сообщение

Дано: мод на активацию артефактов. Требуется: способ запретить артефакту перемещаться в слот для пистолета при двойном клике, без возни с движком.

Поделиться этим сообщением


Ссылка на сообщение

@UriZzz , default to ruck = true, по идее, должен предотвратить баг с немедленным взятием арта с земли в пистолетный слот, если тот пуст. А вообще была мысль назначить на активацию артов ножевой слот...

Поделиться этим сообщением


Ссылка на сообщение
(изменено)
3 часа назад, Space.Marine сказал:

это надо тогда заглушки делать - 300 штук...

Э, зачем так сложно, товарищ?

function CKampManager:checkNpcAbility(npc)
    local npc_id = npc:id()
    
    if npc:character_community() ~= "monolith" and
       npc:character_community() ~= "zombied" and - добавить and

       npc:character_community() ~= "military" - добавить вот эту строку, не помню, вояки вроде так правильно называются?
    then

В самом начале функции, где потом сторис.

Изменено пользователем Капрал Хикс
  • Нравится 1
  • Согласен 2

Поделиться этим сообщением


Ссылка на сообщение
9 минут назад, Space.Marine сказал:

Надо как-то по другому..

-- Если чувак знает истории, надо добавить их к лагерю 

   if self.population > 1 and db.story_by_id[npc:id()] ~= nil and npc:character_community() ~= "military" then

Ну тут совсем просто же.

  • Нравится 1
  • Полезно 1

Поделиться этим сообщением


Ссылка на сообщение
2 часа назад, mr.vispd сказал:

 

А не подскажите как? что нужно сделать, извините, но опыт у меня нулевой в этом, потому и спрашиваю, чтобы сделать одну или пару правок тяжело ли будет?

Если так, лучше даже не берись и забудь про идею. Реализуй что попроще без ковыряния движка.

  • Согласен 2

Поделиться этим сообщением


Ссылка на сообщение

Что-то не едут у меня лыжи... Есть у меня скрипт на проверку статика заклинивания оружия:

function jamupdate()
    local snd = sound_object([[actor\wpn_jammed\stalker_1]])
        if get_hud():GetCustomStatic("weapon_jammed_static") and not snd:playing() then
        snd:play_at_pos(db.actor, vector():set(0,0,0), 0, sound_object.s2d)
    end
end

Который должен воспроизводить звук ГГ при заклинивании ствола... Куда его вешать на апдейт, чтобы статик отлавливался, в биндер актора? P.S. функция в _g.script:

function on_actor_weapon_jammed()
  if has_alife_info("esc_trader_newbie") then
    game.start_tutorial("part_9_weapon")
  end
  if not has_alife_info("encyclopedy_tutorial_weapon") then
    db.actor:give_info_portion("encyclopedy_tutorial_weapon")
  end
end

Вообще рабочая в оригинале, там вроде туториал выводиться должен? Пробовал повесить туда функцию проигрывания звука - не работает.

  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

@Zander_driver, отлично всё работает, благодарствую, сейчас буду модифицировать под звуки в костюме с противогазом. А вот вопрос посложнее - как сию фишку с руганью реализовать для ЧН? OGSM CE 1.8, если что.

Поделиться этим сообщением


Ссылка на сообщение

В каком скрипте смотреть считывание рангов NPC для формирования 20-ки лучших сталкеров? Нашёл ranks.script, он что ли? Хочется тут с товарищами пофиксить багу одну, а именно:

Даже если сталкер мёртв, он все равно останется в рейтинге до тех пор, пока в игре есть его труп. Это связано с тем, что рейтинг не видит разницы между живым NPC и трупом.

Мёртвый сталкер автоматически пропадёт из рейтинга, как только труп исчезнет из игры. Стандартное время исчезновения трупа — 36 часов. При желании игрок может ускорить этот процесс, отнеся труп в ближайшую «воронку» или «карусель». При этом стоит учесть, что трупы ключевых персонажей (например, трупы Черепа и Лукаша) из игры не исчезнут.

 

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

Как-то всё в итоге к уборке трупов свелось, мда. Скрипты уборщика трупов-то уже на любой вкус есть, только под себя подогнать. Я вот вроде нашёл функцию в ranks.script:
 

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

-- возвращает название ранга заданного game_object (персонажа)

function get_obj_rank_name( obj )
    if not ranks_loaded then
        read_all_ranks()
    end

    local obj_rank

    -- HACK
    if obj.m_story_id ~= nil then
        obj_rank = obj:rank()
    else
        obj_rank = obj:character_rank()
    end

   --добавляем проверку в следующей строке на живость NPC:

    if IsStalker(obj) and obj:alive() then
        return get_rank_name( obj_rank, stalker_rank_intervals ) or stalker_max_rank_name
    else
        return get_rank_name( obj_rank, monster_rank_intervals ) or monster_max_rank_name
    end
end

 

Но честно говоря, не знаю, где ещё эта проверка ранга дёргается, может быть звания NPC при обыске трупов перестанут отображаться или ещё что...

Интересно, если монстрам добавить эту проверку можно ли будет забороть баг вида: при обыске трупа мутанта строка отношения копирует строку отношения последнего обысканного трупа, из-за чего может оказаться нейтральным или дружественным.

Изменено пользователем Капрал Хикс
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение
9 часов назад, _Sk8_AsTeR_ сказал(а):

Они ведь не обрабатываются скриптами вообще?

Можно добавить им в конфиг скриптовую обвязку вида: script_binding = bind_crow.init. Я так делал для выдачи инфопоршня при убийстве вороны.

  • Согласен 1

Поделиться этим сообщением


Ссылка на сообщение

Наткнулся на один очень странный и неприятный вылет. Платформа RMA mod v1.1.5 + Shadows Addon v0.8.5 + Патч lvg_brest v3.5... При быстром сохранении и загрузке с него вылет вида:

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

FATAL ERROR
 [error]Expression    : fatal error
[error]Function      : CScriptEngine::lua_error
[error]File          : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
[error]Line          : 73
[error]Description   : <no expression>
[error]Arguments     : LUA error: ... of chernobyl\gamedata\scripts\dialog_manager.script:880: attempt to compare number with nil
stack trace:

Собственно строка:

if ver >= 7 then

Идёт проверка патча, верно? В system.ltx указан шестой патч, т.е. current_server_entity_version = 7

 

А вот при попытке поставить затычку перед строкой if ver >= 7 then -> if not ver then ver = 8 end...

(вся функция ниже под спойлером)

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

function load(npc, reader, ver)
    if selected_phrase_by_id == nil then
        selected_phrase_by_id = {
            intro = {},
            cool_info = {},
            action_info = {}
        }
    end

    local flag = nil
        if not ver then ver = 8 end
    if ver >= 7 then
        flag = reader:r_stringZ()
    else
        flag = tostring(reader:r_s16())
    end

    if flag ~= "-1" then
        selected_phrase_by_id.intro[npc:id()] = {phrase = flag, count = 0}
    else
        selected_phrase_by_id.intro[npc:id()] = nil
    end

       
    if ver >= 7 then
        flag = reader:r_stringZ()
    else
        flag = tostring(reader:r_s16())
    end
    if flag ~= "-1" then
        selected_phrase_by_id.cool_info[npc:id()] = {phrase = flag, count = 0}
    else
        selected_phrase_by_id.cool_info[npc:id()] = nil
    end


    if ver >= 7 then
        flag = reader:r_stringZ()
    else
        flag = tostring(reader:r_s16())
    end
    if flag ~= "-1" then
        selected_phrase_by_id.action_info[npc:id()] = {phrase = flag, count = 0}
    else
        selected_phrase_by_id.action_info[npc:id()] = nil
    end
end

...начинаются вылеты вида:

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

Синхронизация...
* phase time: 4 ms
* phase cmem: 225135 K
* [win32]: free[2698856 K], reserved[466984 K], committed[1028400 K]
* [ D3D ]: textures[298939 K]
* [x-ray]: crt heap[225135 K], process heap[464336 K], game lua[27948 K], engine lua[217 K], render[4108 K]
* [x-ray]: economy: strings[6773 K], smem[8222 K]
stack trace:

0023:05185AF0 xrGame.dll
 [error][      87]    : Параметр задан неверно.

Но! С ручных сейвов всё грузится. Мало того. Стоит переименовать квиксейв в папке сейвов вручную, игра послушно грузится с него тоже.

Какая-то хаффовщина, честное слово.

То ли это проблема движка с правками x-ray extensions, то ли я не знаю.

Поделиться этим сообщением


Ссылка на сообщение
1 час назад, AndreySol сказал(а):

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

В том-то и дело, что эта переменная встречается только в этом скрипте и только в этой функции, с оригинала так. Где она инициализируется - непонятно.

Поделиться этим сообщением


Ссылка на сообщение
1 час назад, AndreySol сказал(а):

смотрите дальше, где вызывается эта ф-ция, и как передается соответствующий аргумент ф-ции.

Вот он, единственный вызов в xr_motivator:

    dialog_manager.load(self.object, reader)

Так в оригинале.

    dialog_manager.load(self.object, reader, self.npc_script_version)

Так в RMA.

Простите, для меня неочевидно, что 

self.npc_script_version = alife():object(self.object:id()).script_version

Это ver тот самый (если это и имелось в виду).

@I am Dead от души! Не думал, что аж так оно тянется.

Поделиться этим сообщением


Ссылка на сообщение

Дано: скрипт db.script, использующийся для правленой боевой схемы БТР (ph_car.script)... Выдержка отличающейся от оригинала части:

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

 

creature            = {}    -- true - человек, false - животное (исключая торговца)

FlagEsc = 0
Flag2 = 0
Dead2 = 0

creatures={}
monster_stock = {}
btr_target = {}


function add_obj( obj )
  creatures[obj:id()]=obj
end

function del_obj( obj )
  storage   [obj:id()] = nil
  creatures[obj:id()]=nil
end

 

function add_obj( obj )
    if IsStalker(obj) then
        creature[obj:id()] = true
    elseif IsMonster(obj) then
        creature[obj:id()] = false
    end

if IsMonster(obj) then
monster_stock[obj:id()] = obj
end

    if IsStalker(obj) and IsMonster(obj) then
        btr_target[obj:id()] = true
end


end

function del_obj( obj )
    storage   [obj:id()] = nil
    if IsStalker(obj) or IsMonster(obj) then
        creature[obj:id()] = nil
    end
if IsMonster(obj) then
monster_stock[obj:id()] = nil
end

    if IsStalker(obj) and IsMonster(obj) then
        btr_target[obj:id()] = nil
end
end

 


Почему-то повторяются функции function add_obj( obj ) и function del_obj( obj ) и мне это кажется странным. Такое вообще допустимо? Не лучше ли совместить функции как-то так:

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

 

function add_obj( obj )
  creatures[obj:id()] = obj

    if IsStalker(obj) then
        creature[obj:id()] = true
    elseif IsMonster(obj) then
        creature[obj:id()] = false
    end

if IsMonster(obj) then
monster_stock[obj:id()] = obj
end

    if IsStalker(obj) and IsMonster(obj) then
        btr_target[obj:id()] = true
end
end

 

function del_obj( obj )
   storage[obj:id()] = nil

   creatures[obj:id()] = nil
    if IsStalker(obj) or IsMonster(obj) then
        creature[obj:id()] = nil
    end
if IsMonster(obj) then
monster_stock[obj:id()] = nil
end

    if IsStalker(obj) and IsMonster(obj) then
        btr_target[obj:id()] = nil
end
end

 

 

Скрипт правленого ph_car вот:

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

 

----------------------------------------------------------------------------------------------------
-- Обновленная боевая схема БТР - Мишаня_Лютый aka CRAZY_STALKER666. Old Episodes - Epilogue
----------------------------------------------------------------------------------------------------
-- Исходный скрипт: Evgeniy Negrobov (Jon) jon@gsc-game.kiev.ua
-- Перевод на xr_logic: Andrey Fidrya (Zmey) af@svitonline.com
-- Доработка для БТР: Oleg Kreptul (Haron) haronk@ukr.net
-- ВНИМАНИЕ! Для монстров используется db.monster_stock. При желании можно перевести и на перебор цифрами, ничего не поменятся, но лагов будет больше
----------------------------------------------------------------------------------------------------
function printf() end

local pi_2 = math.pi / 3 -- 60 degree

local def_min_delta_per_sec = 0.2
local def_min_car_explode_time = 1000
local def_moving_speed = 10
--local def_arriving_factor = 0.4
local def_arriving_dist = 1.0
local def_not_rotating_angle = 0.4
local def_min_fire_time = 0
local def_update_time = 1.6
local def_fire_range = 50

local def_max_fc_upd_num = 1000 -- default maximum fastcall updates num
local def_arriving_koef = 3 --70

local delay_after_ignition = 500

local state_none = 0

local state_moving_fwd = 1
local state_moving_rot_left = 2
local state_moving_rot_right = 3
local state_moving_stop = 4
local state_moving_end = 5

local state_cannon_rotate = 1
local state_cannon_follow = 2
local state_cannon_delay = 3
local state_cannon_stop = 4

local state_shooting_on = 1

local state_firetarget_points = 1
local state_firetarget_enemy = 2

-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class "action_car"

function action_car:__init(obj, storage)
    --printf("car <state>: init.")
    self.object = obj
    self.car = self.object:get_car()
    self.st = storage
    self.friends = {}
end

function action_car:reset_scheme(loading)
    --printf("car <state>: START INITIALIZING ======================================================")
    --printf("car <state>: action_car:reset_scheme: self.object:name()='%s'", self.object:name())

    self.destroyed = false
    self.object:set_nonscript_usable(false)

    self.object:set_tip_text("")
    self.show_tips = self.st.show_tips
    self.tip_use = self.st.tip_use
    self.tip_locked = self.st.tip_locked

    if self.st.invulnerable then
        self.object.health = 1
        self.car:SetfHealth(1)
    end

    self.headlights = object.deactivate
    if self.st.headlights == "on" then
        self.headlights = object.activate
    end
    --printf("car <state>: headlights %s", self.st.headlights)
    xr_logic.mob_capture(self.object, true)
    action(self.object, object("left_light",  self.headlights), cond(cond.time_end, time_infinite))
    xr_logic.mob_capture(self.object, true)
    action(self.object, object("right_light", self.headlights), cond(cond.time_end, time_infinite))

    self.usable = self.st.usable
    
    --if self.usable ~= nil then
    --    self.car_holder = self.object.get_current_holder() --engaged()
    --else
    if self.usable == nil then
        self.car:SetExplodeTime(0) -- (-1)

        if self.car:HasWeapon() then
        --printf("car <fire>: car has weapon.")
        self.car:Action(CCar.eWpnActivate,1)
        self.hasWeapon = true
        else
            --printf("car <fire>: car hasn't weapon.")
            self.hasWeapon = false
        end

        if loading then
            self.speed = xr_logic.pstor_retrieve(self.object, "speed")
            self.loop = xr_logic.pstor_retrieve(self.object, "loop")
            self.min_delta_per_sec = xr_logic.pstor_retrieve(self.object, "min_delta_per_sec")
            self.min_car_explode_time = xr_logic.pstor_retrieve(self.object, "min_car_explode_time")
            self.state_moving = xr_logic.pstor_retrieve(self.object, "state_moving")
        else
            self.speed = def_moving_speed
            self.loop = false
            self.min_delta_per_sec = def_min_delta_per_sec
            self.min_car_explode_time = def_min_car_explode_time
            self.state_moving = state_none
        end

        --xr_logic.mob_capture(self.object, true)
        self.st.signals = {}

        self.fc_upd_num = 0 -- fastcall updates num
        self.fc_upd_avg = 10 -- average time of the fastcall updates (in millisecond)
        self.fc_last_upd_tm = -1 -- fastcall last update time

        self.last_pos = nil
        self.last_pos_time = 0
        
        self.state_delaying = false

        --self.state_moving = state_none

        self.target_walk_pt = -1
        -- path_walk
        if self.st.path_walk then
            self.path_walk = patrol(self.st.path_walk)
            if not self.path_walk then
                abort("object '%s': unable to find path_walk '%s' on the map", self.object:name(), self.st.path_walk)
            end

            self:start_car()
            self.path_walk_count = self.path_walk:count()

            --if not self.path_walk_info then
            self.path_walk_info = utils.path_parse_waypoints(self.st.path_walk)
            if not self.path_walk_info then
                abort("object '%s': path_walk ('%s'): unable to obtain path_walk_info from path",
                    self.object:name(), self.st.path_walk)
            end
            --end

            self.arrival_signalled = false
            self.target_dist = -1

            if loading then
                self.target_walk_pt = xr_logic.pstor_retrieve(self.object, "target_walk_pt")
                if self.target_walk_pt == -1 then
                    self.target_walk_pt = self:get_nearest_walkpoint()
                end
            else
                self.target_walk_pt = self:get_nearest_walkpoint()
            end
            --printf("car <move>: target_walk_pt.1(%d)", self.target_walk_pt)

            if self:at_target_walkpoint() then
                self:walk_arrival_callback(self.target_walk_pt)
            end
            
            self:go_to_walkpoint(self.target_walk_pt)
        else
            --printf("car <state>: target_walk_pt.2(-2)")
            self.target_walk_pt = -2
            self.state_moving = state_moving_stop
        end
        --printf("car <move>: start target_pt1 = %d", self.target_walk_pt)
        
        self.state_firetarget = state_none
        self.state_cannon = state_none
        self.state_shooting = state_none
        
        self.target_fire_pt = nil
        self.target_fire_pt_idx = 0
        self.target_obj = nil
        
        self.on_target_vis = nil
        self.on_target_nvis = nil

        if self.hasWeapon then
            --if loading then
            --    self.state_cannon = xr_logic.pstor_retrieve(self.object, "state_cannon")
            --    self.state_shooting = xr_logic.pstor_retrieve(self.object, "state_shooting")
            --end
            
            self:set_shooting(self.state_shooting)

            --printf("car <fire>: target = %s", self.st.fire_target)
            local n = 0
            if self.st.fire_target == "points" then
                self.state_firetarget = state_firetarget_points
            else
                if self.st.fire_target == "actor" and db.actor:alive() then
                    self.target_obj = db.actor
                    self.state_firetarget = state_firetarget_enemy
                else
                    n = tonumber(self.st.fire_target)
                    if n then
                        obj = level_object_by_sid(n)
                        if obj and obj:alive() then
                            self.target_obj = obj
                            self.state_firetarget = state_firetarget_enemy
                        end
                    end
                end
                --if self.target_obj then
                --    self.target_ph_shell = self.target_obj:get_physics_shell()
                --end
            end
            self.fire_track_target = self.st.fire_track_target

            if self.st.on_target_vis then
                vis = self.st.on_target_vis
                if vis.v1 == "actor" then
                    vis.v1 = db.actor
                    self.on_target_vis = vis
                    --printf("car <vis>: target actor")
                else
                    n = tonumber(vis.v1)
                    if n then
                        obj = level_object_by_sid(n)
                        if obj and obj:alive() then
                            vis.v1 = obj
                            self.on_target_vis = vis
                            --printf("car <vis>: target %d", n)
                        end
                    end
                end
            end
            if self.st.on_target_nvis then
                nvis = self.st.on_target_nvis
                if nvis.v1 == "actor" then
                    nvis.v1 = db.actor
                    self.on_target_nvis = nvis
                    --printf("car <nvis>: target actor")
                else
                    n = tonumber(nvis.v1)
                    if n then
                        obj = level_object_by_sid(n)
                        if obj and obj:alive() then
                            nvis.v1 = obj
                            self.on_target_nvis = nvis
                            --printf("car <nvis>: target %d", n)
                        end
                    end
                end
            end
            
            self.path_fire = nil
            self.path_fire_info = nil
            self.fire_pt_count = 0
            
            self.def_fire_time = self.st.fire_time
            if self.st.fire_rep then
                if self.st.fire_rep == "inf" then
                    self.def_fire_rep = -1
                else
                    local c = tonumber(self.st.fire_rep)
                    self.def_fire_rep = if_then_else(c > 0, c, 0)
                end
            else
                self.def_fire_rep = 0
            end
            self.fire_rep = self.def_fire_rep
            --printf("car <fire>: def_rep = %d (%s)", self.fire_rep, utils.to_str(self.st.fire_rep))
            
            self.fire_range_sqr = self.st.fire_range * self.st.fire_range

            -- path_fire
            if self.state_firetarget == state_firetarget_points and self.st.path_fire then
                --printf("car <state>: firetarget = points")
                self.path_fire = patrol(self.st.path_fire)
                if not self.path_fire then
                    abort("object '%s': unable to find path_fire '%s' on the map",
                        self.object:name(), self.st.path_fire)
                end

                if not self.path_fire_info then
                    self.path_fire_info = utils.path_parse_waypoints(self.st.path_fire)
                    if not self.path_fire_info then
                        abort("object '%s': path_fire ('%s'): unable to obtain path_fire_info from path",
                            self.object:name(), self.st.path_fire)
                    end
                end
                
                -- точки прострела для первой точки движения
                self:change_fire_pts()
                
                if self.st.auto_fire then
                    self.car:Action(CCar.eWpnAutoFire, 1)
                else
                    self.car:Action(CCar.eWpnAutoFire, 0)
                end
                
                self:fire_arrival_callback(self.target_fire_pt_idx)
                
                --self:rot_to_firepoint(self.target_fire_pt)
                --self:set_shooting(self.state_shooting)
            elseif self.state_firetarget == state_firetarget_enemy then
                --printf("car <state>: firetarget = enemy")
                self.state_shooting = state_none
                self.state_cannon = state_cannon_follow
                --self.target_fire_pt = db.actor:position()
                --self:rot_to_firepoint(self.target_fire_pt)
            else
                --printf("car <state>: firetarget = none")
                self.state_firetarget = state_none
                self.state_cannon = state_none
                self.state_shooting = state_none
            end
            --self:set_shooting(self.state_shooting)
        end
        
        --if self.st.path_walk then
        --    if self:at_target_walkpoint() and self.state_firetarget == state_none then
        --        self:walk_arrival_callback(self.target_walk_pt)
        --    end
        --    
        --    self:go_to_walkpoint(self.target_walk_pt)
        --end
        --printf("car <move>: start target_pt2 = %d", self.target_walk_pt)
    end

    self.object:set_fastcall(self.fastcall, self)
    --printf("car <state>: END INITIALIZING ========================================================\n")
end

function action_car:save()
    --printf("car <state>: saving")
    if self.usable == nil then
        xr_logic.pstor_store(self.object, "speed", self.speed)
        xr_logic.pstor_store(self.object, "loop", self.loop)
        xr_logic.pstor_store(self.object, "min_delta_per_sec", self.min_delta_per_sec)
        xr_logic.pstor_store(self.object, "min_car_explode_time", self.min_car_explode_time)
        xr_logic.pstor_store(self.object, "state_moving", self.state_moving)
        xr_logic.pstor_store(self.object, "target_walk_pt", self.target_walk_pt) -- or -2)
        --printf("car <save>: target_walk_pt(%d)", self.target_walk_pt)
    end
end

--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
--++++++++++++++++++++-- MOVE SECTION --++++++++++++++++++++--
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--

function action_car:get_nearest_walkpoint()
    return utils.get_nearest_waypoint(self.object, self.st.path_walk,
         self.path_walk, self.path_walk_count)
end

function action_car:get_next_walkpoint()
    if self.target_walk_pt >= 0 and self.target_walk_pt < self.path_walk_count - 1 then
        --printf("car <move>: action_car:get_next_walkpoint(%d)", self.target_walk_pt + 1)
        return self.target_walk_pt + 1
    elseif self.target_walk_pt == -1 or self.loop then
        --printf("car <move>: action_car:get_next_walkpoint(0)")
        return 0
    end
    --printf("car <move>: action_car:get_next_walkpoint(-2)")
    return -2
end

function action_car:at_target_walkpoint()
    --printf("car <move>: action_car:at_target_walkpoint(%s)", utils.to_str(self.target_walk_pt))
    if self.target_walk_pt == -2 then return true end

    local curVel = self.car:CurrentVel():magnitude()
    local dist = self.object:position():distance_to(self.path_walk:point(self.target_walk_pt))

    --local arrived = 2 * dist < def_update_time * (curVel.x + self.speed) --def_update_time > 2 * dist / (curVel.x + self.speed)
    --local arrived = dist < curVel.x * def_arriving_factor --8

    -- def_arriving_koef * self.fc_upd_avg / 1000 > 2 * dist / (curVel.x + self.speed)
    local arrived = false --2000 * dist < def_arriving_koef * self.fc_upd_avg * (curVel + self.speed)
    
    if self.fc_upd_avg < 100 then
        arrived = 2000 * dist < def_arriving_koef * self.fc_upd_avg * (curVel + self.speed)
        --printf("car <move>: check formula (%f < %f)", 2000 * dist, def_arriving_koef * self.fc_upd_avg * (curVel + self.speed))
        if arrived then
            --printf("car <move>: at target pt by formula.")
        end
    end
    
    if not arrived then
        local diff_angle = angle_xz(self.object, self.path_walk:point(self.target_walk_pt))
        --printf("car <move>: dist(%f), angle(%f).", dist, diff_angle)
        arrived = dist < 2 or diff_angle >= math.pi
        if arrived then
            --printf("car <move>: at target pt by dist(%f) and angle(%f).", dist, diff_angle)
            --printf("car <move>: at target pt by dist and angle.")
        end
    end
    
    local diff = dist - self.target_dist
    --printf("car <move>: dist = %f, target = %f, diff = %f, curVel = %f, speed = %f", dist, self.target_dist, diff, curVel, self.speed)
    if self.target_dist ~= -1 and not arrived then
        if diff > 0 then
            if diff > def_arriving_dist then
                arrived = true
                --printf("car <move>: at target pt by diff(%f).", diff)
            end
        else
            self.target_dist = dist
        end
    else
        self.target_dist = dist
    end
--[[
    --printf("car <move>: action_car:at_target_walkpoint(self.target_walk_pt=%d) = %d (arrived = %s)",        self.target_walk_pt, dist, utils.to_str(arrived))
    --if arrived then
        --printf("car <move>: arrived = %f > %f, dist(%f), diff(%f), curSpd(%f), spd(%f)",
               --def_arriving_koef * self.fc_upd_avg / 1000,
               --2 * dist / (curVel.x + self.speed),
               def_arriving_koef * self.fc_upd_avg * (curVel + self.speed),
               2000 * dist,
               dist, diff, curVel, self.speed)
        --printf("car <move>: arrived = %f < (%f,%f,%f) * %f, spd(%f)", dist, curVel.x, curVel.y, curVel.z, def_arriving_factor, self.speed)
    --end
--]]
    if arrived then
        self.target_dist = -1
    end
    return arrived
end

function action_car:go_to_walkpoint(pt)
    --action(self.object, object("left_light", object.activate), cond(cond.time_end, 1000))
    --action(self.object, object("right_light", object.activate), cond(cond.time_end, 1000))
    --printf("car <move>: action_car:go_to_walkpoint(%s)", utils.to_str(pt))
    if self.state_delaying then
        if time_global() - self.delay_time_start >= delay_after_ignition then
            --printf("car <state>: stop delaying after ignition")
            self.state_delaying = false
        else
            --printf("car <state>: delaying after ignition")
            self.state_moving = state_moving_stop
            return
        end
    end

    if pt == nil or pt < 0 then
        if self.state_cannon ~= state_cannon_stop then
            self:stop_car()
            self.state_moving = state_moving_end
        end
        --printf("car <state>: pt < 0 or pt == nil")
        return
    end

    local diff_angle = angle_xz(self.object, self.path_walk:point(pt))
    local accel = move.none
    local curVel = self.car:CurrentVel():magnitude()
    --printf("car <move>: curVel = %f, speed = %f", curVel, self.speed)
    if curVel < self.speed then
        accel = move.fwd
        --printf("car <move>: forward")
    elseif curVel > self.speed * 1.15 or diff_angle >= math.pi then
        accel = move.back
        --printf("car <move>: backward")
    end
    --printf("car <move>: diff_angle = %f, katet = %f", diff_angle, get_katet(self.object, self.path_walk:point(pt)))
    --if utils.no_need_to_rotate_xz(self.object, self.path_walk:point(pt)) then
    if diff_angle < def_not_rotating_angle then
        if self.state_moving ~= state_moving_fwd and accel ~= move.none then
            --printf("car <move>: no_need_to_rotate. speed = %f, time = %f", self.speed, self.fc_upd_avg)
               xr_logic.mob_capture(self.object, true)
            action(self.object,
                move(accel, self.speed), --move.on + 
                --object("right_light", self.headlights),
                --object("left_light", self.headlights),
                cond(cond.time_end, time_infinite)) --self.fc_upd_avg))
            self.state_moving = state_moving_fwd
        end
    else
        -- Поворачиваться нужно, но в какую сторону?
        local rotate_left = utils.angle_left_xz(self.object:direction(), 
                                                utils.vector_copy_by_val(self.path_walk:point(pt)
                                                                        ):sub(self.object:position()))
        --printf("car <move>: must rotate: left? %s. speed = %f, time = %f", utils.to_str(rotate_left), self.speed, self.fc_upd_avg)
        if rotate_left then
            if self.state_moving ~= state_moving_rot_left then 
                xr_logic.mob_capture(self.object, true)
                action(self.object,
                    move(accel + move.left, self.speed), --move.on + 
                    --object("right_light", self.headlights),
                    --object("left_light", self.headlights),
                    cond(cond.time_end, time_infinite)) --self.fc_upd_avg))
                self.state_moving = state_moving_rot_left
            end
        else
            if self.state_moving ~= state_moving_rot_right then
                xr_logic.mob_capture(self.object, true)
                action(self.object,
                    move(accel + move.right, self.speed), --move.on + 
                    --object("right_light", self.headlights),
                    --object("left_light", self.headlights),
                    cond(cond.time_end, time_infinite)) --self.fc_upd_avg))
                self.state_moving = state_moving_rot_right
            end
        end
    end
end

function action_car:start_car()
    --printf("car <move>: car started.")
    xr_logic.mob_capture(self.object, true)
    action(self.object, move(move.on + move.fwd, 100), cond(cond.time_end, 5000))
    --self.speed = 0
    self.state_delaying = true
    self.delay_time_start = time_global()
end

function action_car:stop_car()
    --printf("car <move>: car stopping.")
    self.state_delaying = false
    self.speed = 0
    xr_logic.mob_capture(self.object, true)
    action(self.object, move(move.off + move.handbrake, 0), cond(cond.time_end, 3000)) --cond(cond.move_end))
    --self.target_walk_pt = -1
end

function action_car:walk_arrival_callback(index)
    --printf("car <move>: action_car:walk_arrival_callback(%d)", index)
    if index == -2 then return end

    local suggested_explode = self.path_walk_info[index]["explode"]
    if suggested_explode == "true" then
                --printf("action_car:walk_arrival_callback(): EXPLODE")
        --self:car_explode()
        self.object.health = 0
        self.car:Action(CCar.eWpnActivate, 0)
    end

    local suggested_spd = self.path_walk_info[index]["spd"]
    if suggested_spd then
        self.speed = tonumber(suggested_spd)
    else
        self.speed = def_moving_speed
    end
    --printf("car <move>: new spd = %f", self.speed)

    local suggested_loop = self.path_walk_info[index]["loop"]
    if suggested_loop == "true" then
        self.loop = true
    else
        self.loop = false
    end

    local suggested_dps = self.path_walk_info[index]["dps"]
    if suggested_dps then
        self.min_delta_per_sec = tonumber(suggested_dps)
    else
        self.min_delta_per_sec = def_min_delta_per_sec
    end

    local suggested_exptm = self.path_walk_info[index]["exptm"]
    if suggested_exptm then
        self.min_car_explode_time = tonumber(suggested_exptm)
    else
        self.min_car_explode_time = def_min_car_explode_time
    end

    local sig = self.path_walk_info[index]["sig"]
    --printf("car <sig>: try")
    if sig then
        --self.st.signals[sig] = true
        self:set_signal(sig)
        --printf("car <sig>: %s", sig)
    end

    if self.hasWeapon and self.state_firetarget == state_firetarget_points then
        local next_idx = self:get_next_walkpoint()
        --local next_idx = self.target_walk_pt
        if next_idx >= 0 then
            local fw = self.path_walk_info[next_idx]["fw"]
            if fw then
                self.fire_wait = if_then_else(fw == "true", true, false)
            else
                self.fire_wait = false
            end

            local fr = self.path_walk_info[next_idx]["fr"]
            if fr then
                if fr == "inf" then
                    self.fire_rep = -1
                else
                    local c = tonumber(fr)
                    self.fire_rep = if_then_else(c > 0, c, 0)
                end
            else
                self.fire_rep = self.def_fire_rep
            end
        else
            self.fire_wait = false
            self.fire_rep = self.def_fire_rep
        end
        --printf("car <fire>: fire_wait = %s", if_then_else(self.fire_wait, "true", "false"))
        --printf("car <fire>: fire_rep = %d", self.fire_rep)
    end

    -- Выбрать следующую точку езды:
    self.target_walk_pt = self:get_next_walkpoint()
    --printf("car <move>: target_walk_pt = %s.", utils.to_str(self.target_walk_pt))
    --if not self.target_walk_pt then
    --printf("car <move>: stop moving.")
    --    self:stop_car()
        -- Остановить машину
        --if self.state_cannon == state_cannon_stop then
        --    xr_logic.mob_capture(self.object, true)
        --end
        --action(self.object, move(move.off, 0), cond(cond.time_end, 1000))
        --self.state_moving = state_moving_end
    --    return
    --end

    if self.target_walk_pt >= 0 then
        -- Если эта точка рядом и уже приехали - не ждать апдейта, чтобы вызвать callback
        if self:at_target_walkpoint() then
            self:walk_arrival_callback(self.target_walk_pt)
        else
            --self.target_dist = -1
            self:go_to_walkpoint(self.target_walk_pt)
        end
    else
        --printf("car <move>: stop moving.")
        self.target_walk_pt = -2
        if self.state_moving ~= state_moving_stop and self.state_moving ~= state_moving_end then
            self:stop_car()
            self.state_moving = state_moving_end
        end
    end
end

--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
--++++++++++++++++++++-- FIRE SECTION --++++++++++++++++++++--
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--

function action_car:change_fire_pts()
    --printf("car <fire>: action_car:change_fire_pts()")

    self.state_cannon = state_none
    self.state_shooting = state_none
    
    self.fire_pt_arr = {}
    self.fire_pt_count = 0
    self.target_fire_pt_idx = 0
    self.target_fire_pt = nil
    self.fire_rot_dir = 1
    self.fire_start_time = 0

    if not self.path_fire then return end
    
    local fire_idx
    if self.target_walk_pt >= 0 then
        -- Значение флагов огневых точек, котые будем искать:
        local fire_flags = self.path_walk_info[self.target_walk_pt].flags
        
        if fire_flags:get() == 0 then
            return
        end

        local this_val
        for fire_idx = 0, self.path_fire:count() - 1 do
            this_val = self.path_fire_info[fire_idx].flags
            if this_val:equal(fire_flags) then
                table.insert(self.fire_pt_arr, fire_idx)
                self.fire_pt_count = self.fire_pt_count + 1
            end
        end
    else
        for fire_idx = 0, self.path_fire:count() - 1 do
            table.insert(self.fire_pt_arr, fire_idx)
        end
        self.fire_pt_count = self.path_fire:count()
    end
    
    --printf("car <fire>: points")
    print_table(self.fire_pt_arr)

    if self.fire_pt_count == 0 then
        self.state_cannon = state_cannon_stop
        return
    end
    
    --if self.fire_pt_count > 0 then
    --    self.target_fire_pt_idx = 0
    --    self.target_fire_pt = self.path_fire:point(self.fire_pt_arr[0])
    --end
end

function action_car:get_next_firepoint()
    if self.fire_pt_count < 1 then return nil end

    --printf("car <fire>: action_car:get_next_firepoint(%d,%d,%d)", self.target_fire_pt_idx, self.fire_pt_count, self.fire_rep)
    local pt_idx
    if self.target_fire_pt_idx > 0 then -- not first time
        if self.fire_pt_count > 1 then -- we have at least 2 point to switch
            pt_idx = self.target_fire_pt_idx + self.fire_rot_dir
            if (pt_idx < 1 or pt_idx > self.fire_pt_count) then
                self.fire_rot_dir = -self.fire_rot_dir -- change rotate direction [-1,1]
                --printf("car <fire>: changing direction")
                if self.fire_rep == -1 then
                    pt_idx = self.target_fire_pt_idx + self.fire_rot_dir
                elseif self.fire_rep > 0 then
                    pt_idx = self.target_fire_pt_idx + self.fire_rot_dir
                    self.fire_rep = self.fire_rep - 1
                else
                    pt_idx = 0
                end
            end
        elseif self.fire_rep == -1 then -- left same point in the infinity loop
            pt_idx = 1
        elseif self.fire_rep > 0 then -- left same point if loop defined
            pt_idx = 1
            self.fire_rep = self.fire_rep - 1
        end
    else
        pt_idx = 1
    end
    --self.target_fire_pt_idx = pt_idx
    
    --printf("car <fire>: pt_idx = %d", pt_idx)

    if pt_idx > 0 then
        return pt_idx, self.path_fire:point(self.fire_pt_arr[pt_idx])
    end

    self.state_firetarget = state_none
    return pt_idx, nil
end

function action_car:rot_to_firepoint(pt)
--[[
    if pt then
        self.car:SetParam(CCar.eWpnDesiredPos, pt)
    end
    --printf("car <fire>: action_car:rot_to_firepoint(%d)", shooting)
    self.car:Action(CCar.eWpnFire, shooting)
--]]
    if self.target_fire_pt then
    --    self.state_cannon = state_cannon_rotate
        self.car:SetParam(CCar.eWpnDesiredPos, self.target_fire_pt)
        --printf("car <fire>: action_car:rot_to_firepoint(%d)", self.target_fire_pt_idx)
    --else
    --    self.state_cannon = state_cannon_stop
    end
end

function action_car:set_shooting(shooting)
    self.car:Action(CCar.eWpnFire, shooting)
    --printf("car <fire>: action_car:set_shooting(%d)", shooting)
end

function action_car:fire_arrival_callback(cur_index)
    if self.fire_pt_count < 1 or self.state_cannon == state_cannon_stop then return end
    
    --printf("car <fire>: action_car:fire_arrival_callback(%s)", utils.to_str(cur_index))
    if self.state_cannon == state_cannon_delay then
        --printf("car <fire>: 1.delay mode off.")
        -- Выбрать следующую точку езды:
        self.target_fire_pt_idx, self.target_fire_pt = self:get_next_firepoint()

        if self.target_fire_pt then
            --printf("car <fire>: 1.rotate mode on.")
            self.state_cannon = state_cannon_rotate
            if self.fire_rot_dir == 1  and self.fire_forward or
               self.fire_rot_dir == -1 and self.fire_backward then
                --printf("car <fire>: 1.shooting on.")
                self.state_shooting = state_shooting_on
            else
                --printf("car <fire>: 1.shooting off.")
                self.state_shooting = state_none
            end
            self:rot_to_firepoint(self.target_fire_pt)
            self:set_shooting(self.state_shooting)
        else
            --printf("car <fire>: 1.cannon stopped.")
            self.state_cannon = state_cannon_stop
            if self.state_shooting ~= state_none then
                self.state_shooting = state_none
                self:set_shooting(self.state_shooting)
                self:set_signal("fire_end")
            end
        end
        return
    end

    --printf("car <fire>: action_car: fire_arrival_callback(%s)", utils.to_str(cur_index))
    if cur_index > 0 then
        local idx = self.fire_pt_arr[cur_index]

        local ff = self.path_fire_info[idx]["ff"]
        if ff then
            self.fire_forward = if_then_else(ff == "true", true, false)
        else
            self.fire_forward = false
        end

        local fb = self.path_fire_info[idx]["fb"]
        if fb then
            self.fire_backward = if_then_else(fb == "true", true, false)
        else
            self.fire_backward = false
        end

        local f = self.path_fire_info[idx]["f"]
        if f then
            self.state_shooting = if_then_else(f == "true", state_shooting_on, state_none)
        else
            self.state_shooting = if_then_else(self.st.auto_fire, state_shooting_on, state_none)
        end

        local ft = self.path_fire_info[idx]["ft"]
        if ft then
            self.fire_time = tonumber(ft)
        else
            self.fire_time = self.def_fire_time
        end
    else
            self.fire_forward = false
            self.fire_backward = false
            self.state_shooting = if_then_else(self.st.auto_fire, state_shooting_on, state_none)
            self.fire_time = def_min_fire_time
    end
    --printf("car <fire>: state_shooting = %s", if_then_else(self.state_shooting ~= 0, "true", "false"))
    --printf("car <fire>: auto_fire = %s", if_then_else(self.st.auto_fire, "true", "false"))
    --printf("car <fire>: fire_time = %f", self.fire_time)

    if self.fire_time > 0 then
        --printf("car <fire>: 2.delay mode on.")
        self.state_cannon = state_cannon_delay
        self.fire_start_time = time_global()
        --printf("car <fire>: state_shooting = %s", if_then_else(self.state_shooting ~= 0, "true", "false"))
        --self:rot_to_firepoint(nil)
        self:set_shooting(self.state_shooting)
    else
        -- Выбрать следующую точку стрельбы:
        self.target_fire_pt_idx, self.target_fire_pt = self:get_next_firepoint()

        -- Если мы уже целимся в эту точку - не ждать апдейта, чтобы вызвать callback
        if self.target_fire_pt then
            --printf("car <fire>: 2.rotate mode on.")
            self.state_cannon = state_cannon_rotate
            if self.fire_rot_dir == 1  and self.fire_forward or
               self.fire_rot_dir == -1 and self.fire_backward then
                self.state_shooting = state_shooting_on
                --printf("car <fire>: 2.shooting on.")
            else
                self.state_shooting = state_none
                --printf("car <fire>: 2.shooting off.")
            end
            self:rot_to_firepoint(self.target_fire_pt)
            self:set_shooting(self.state_shooting)
        else
            --printf("car <fire>: 2.cannon stopped.")
            self.state_cannon = state_cannon_stop
            if self.state_shooting ~= state_none then
                self.state_shooting = state_none
                self:set_shooting(self.state_shooting)
                self:set_signal("fire_end")
            end
        end
    end
end

--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
--+++++++++++++++++++-- COMMON SECTION --+++++++++++++++++++--
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
function action_car:set_signal(sig)
    local stor = db.storage[self.object:id()]
    stor[stor.active_scheme].signals[sig] = true
    --printf("car <sig>: %s", sig)
end

function angle_xz(npc, target_pos)
    local dir1 = npc:direction()
    dir1.y = 0
    local dir2 = utils.vector_copy_by_val(target_pos):sub(npc:position())
    dir2.y = 0
    local dp = dir1:dotproduct(dir2)
    if dp < 0 then
        return math.pi - yaw(dir1, dir2)
    end
    return yaw(dir1, dir2)
end

function get_katet(npc, target_pos)
    local p = utils.vector_copy_by_val(target_pos):sub(npc:position())
    local q = npc:direction()
    local k = p.x * q.x + p.y * q.y
    if k ~= 0 then
        return target_pos:distance_to(npc:position()) * (p.x * q.y - p.y * q.x) / k
    end
    return -1
end

function action_car:fastcall()
    if db.storage[self.object:id()].active_scheme ~= "ph_car" then
        -- Если активная схема - не машина, снять быстрый апдейт
        return true
    end
    
    if self.usable ~= nil then
        local cu = xr_logic.pick_section_from_condlist(db.actor, self.object, self.usable.condlist)
        local u = (cu == "true" or cu == "")

        if u then
            if self.show_tips and self.tip_use then
                self.object:set_tip_text(self.st.tip_use)
            end
        elseif self.show_tips and self.tip_locked then
            self.object:set_tip_text(self.st.tip_locked)
        end

        self.object:set_nonscript_usable(u)

        return false
    end

    return self:fast_update()
end

function action_car:update(delta)
    self:update_friends_and_target()
        
    if xr_logic.try_switch_to_another_section(self.object, self.st, db.actor) then
        return
    end
    
    if self.destroyed then
        xr_logic.switch_to_section(self.object, self.st, "nil")
        return
    end
    
    if self.st.invulnerable then
        self.object.health = 1
        self.car:SetfHealth(1)
    end
end

function action_car:destroy_car()
    --printf("car <destroy>: START ===============================")
    self.state_moving = state_moving_end
    self:stop_car()
    self.state_cannon = state_none
    self.state_firetarget = state_none
    self.state_shooting = state_none
    self.car:Action(CCar.eWpnAutoFire, 0)
    self:set_shooting(self.state_shooting)

    -- turn off lights
    xr_logic.mob_capture(self.object, true)
    action(self.object, object("left_light",  object.deactivate), cond(cond.time_end, time_infinite))
    xr_logic.mob_capture(self.object, true)
    action(self.object, object("right_light", object.deactivate), cond(cond.time_end, time_infinite))

    xr_logic.mob_release(self.object)
    if self.st.on_death_info ~= nil then
        db.actor:give_info_portion(self.st.on_death_info)
        --printf("car <destroy>: on_death_info [%s]", self.st.on_death_info)
    end
    if self.st.on_death_func then
        loadstring(self.st.on_death_func)()
    end
    self.destroyed = true
    --printf("car <destroy>: END =================================")
end

-- Вернуть true, если апдейты больше не нужны
function action_car:fast_update()
    --printf("car <state>: START FAST UPDATE ======================================================")
    --printf("car <state>: check moving1 - [%d][%d]", self.state_moving, self.target_walk_pt)
        --printf("car <state>: action_car:update(): state=%d", self.state_moving)

    --if not self.object:action() then
    --printf("_pc: CAR EXPLODE")
    --self.object:explode(0)
    --self.object:Explode()
    --end
    
    if self.car:GetfHealth() <= 0 then
        --printf("car <state>: killed.")
        --self:car_explode()
        self:destroy_car()
        return true
    end
    
    local cur_time = time_global()

    if self.fc_upd_num < def_max_fc_upd_num then
        local last_upd = self.fc_last_upd_tm
        if last_upd ~= -1 then
            local n = self.fc_upd_num
            if n < 3000 then
                self.fc_upd_avg = (self.fc_upd_avg * n + (cur_time - last_upd))/(n + 1)
                self.fc_upd_num = n + 1
            else
                self.fc_upd_num = 1
            end
        end
        self.fc_last_upd_tm = cur_time
        --printf("car <state>: average update = %f, time(%f)", self.fc_upd_avg, cur_time)
    end

    if self.state_moving == state_moving_end and
       self.state_cannon == state_cannon_stop and
       self.state_firetarget == state_none
    then
        if xr_logic.mob_captured(self.object) and not self.object:action() then
            --printf("car <state>: stop fast updating. moving(%s) cannon(%s)", utils.to_str(self.state_moving), utils.to_str(self.state_cannon))
            --xr_logic.mob_release(self.object)
            --if self.st.on_death_info ~= nil then
            --    printf("car <death>: stopped")
            --    db.actor:give_info_portion(self.st.on_death_info)
            --end
            printf("car <state>: stopped")
            self:destroy_car()
            return true -- апдейты больше не нужны
        end
        return false
    end

    if self.state_moving ~= state_moving_end and
       self.state_moving ~= state_moving_stop and 
       cur_time >= self.last_pos_time + self.min_car_explode_time
    then
        --printf("car <state>: moving(%s)", utils.to_str(self.state_moving))
        if not self.last_pos then
            self.last_pos = self.object:position()
            self.last_pos_time = cur_time
        else
            local cur_pos = self.object:position()
            local diff = self.last_pos:distance_to(cur_pos)
            if diff < self.min_delta_per_sec then
                --printf("car <move>: got stuck (%f < %f) - stop.", diff, self.min_delta_per_sec)
                self:stop_car()
                --self:car_explode()
                self.state_moving = state_moving_end
                --return false
            else
                self.last_pos = cur_pos
            end
            self.last_pos_time = cur_time
        end
    end
    
    --printf("car <state>: check moving2 - [%d][%d]", self.state_moving, self.target_walk_pt)
    if self.state_moving ~= state_moving_end and
       self.state_moving ~= state_none
    then
        --printf("car <move>: try")
        if self.target_walk_pt >= 0 then
            if self:at_target_walkpoint() then
                --printf("car <move>: at target point")
                -- если нет флага ожидания стрельбы или мы уже отстрелялись или пошли в цикле обратно
                if not self.fire_wait or self.state_cannon == state_cannon_stop then --self.fire_rot_dir == -1 then
                        --printf("car <move>: car go to the new point.")
                        -- Прибыли, выбрать новую точку
                        self:walk_arrival_callback(self.target_walk_pt)
                        --printf("car <move>: new target = %s", utils.to_str(self.target_walk_pt))
                        -- меняем точки отстрела
                        self:change_fire_pts()
                else
                    --printf("car <move>: 1.car stopped.")
                    if self.state_moving ~= state_moving_stop then
                        self:stop_car()
                    end
                    self.state_moving = state_moving_stop
                end
            else
                --printf("car <move>: car keep going.")
                -- Продолжать ехать, или поворачиваться
                self:go_to_walkpoint(self.target_walk_pt)
            end
        else
            --printf("car <move>: 2.car stopped.")
            if self.state_cannon ~= state_cannon_stop then
                self:stop_car()
                self.state_moving = state_moving_stop
            end
        end
    end
    
    --printf("car <fire>: TEST")
    if self.hasWeapon then
        --printf("car <fire>: target(%d)", self.state_firetarget)
        if self.on_target_vis and self.on_target_vis.v1:alive() and self.car:IsObjectVisible(self.on_target_vis.v1) then
            --printf("car <vis>: try")
            local new_section = xr_logic.pick_section_from_condlist(db.actor, self.object, self.on_target_vis.condlist)
            if new_section then
                --printf("car <vis>: switch to section [%s]", new_section)
                xr_logic.switch_to_section(self.object, self.st, new_section)
            end
        end

        if self.on_target_nvis and self.on_target_nvis.v1:alive() and not self.car:IsObjectVisible(self.on_target_nvis.v1) then
            --printf("car <nvis>: try")
            local new_section = xr_logic.pick_section_from_condlist(db.actor, self.object, self.on_target_nvis.condlist)
            if new_section then
                --printf("car <nvis>: switch to section [%s]", new_section)
                xr_logic.switch_to_section(self.object, self.st, new_section)
            end
        end

        if self.state_firetarget == state_firetarget_points then
            if self.fire_pt_count > 0 and self.state_cannon ~= state_cannon_stop then
                --printf("car <fire>: shooting points")
                if self.state_cannon == state_cannon_delay then
                    if self.fire_start_time + self.fire_time < cur_time then
                        --printf("car <fire>: stop delaying(%.2f + %.2f < %.2f)", self.fire_start_time, self.fire_time, time_global())
                        --printf("car <fire>: 1.new fire point.")
                        self:fire_arrival_callback(self.target_fire_pt_idx)
                    else
                        --printf("car <fire>: delaying(%.2f + %.2f < %.2f)", self.fire_start_time, self.fire_time, cur_time)
                    end
                else
                    if self.car:CanHit() or self.target_fire_pt_idx == 0 then
                        --printf("car <fire>: 2.new fire point.")
                        -- Прибыли, выбрать новую точку
                        self:fire_arrival_callback(self.target_fire_pt_idx)
                    end
                end
            end
        elseif self.state_firetarget == state_firetarget_enemy then
                
            local target_dist = self.object:position():distance_to_sqr(self.target_obj:position())
                
            local has_friends_on_fire_line = self:check_friends_on_fire_line()
                
            if self.target_obj:alive() and
               target_dist <= self.fire_range_sqr and
               self.car:IsObjectVisible(self.target_obj) and
                         not has_friends_on_fire_line
            then
                printf("car <fire>: enemy(%s) is visible.", self.target_obj:name())

                self.target_fire_pt = self:extrapolate_pos(self.target_obj)
                --[[
                if self.target_obj:id() ~= db.actor:id() then
                  if self.target_obj:target_body_state() == move.crouch then
                      self.target_fire_pt.y = self.target_fire_pt.y + 0.6 -- FAKE
                  elseif not xr_wounded.is_heavy_wounded_by_id(self.target_obj:id()) then
                      self.target_fire_pt.y = self.target_fire_pt.y + 1.4 -- FAKE
                  else
                      self.target_fire_pt.y = self.target_fire_pt.y + 0.15 -- FAKE
                  end
                end
                ]]
                self:rot_to_firepoint(self.target_fire_pt)

                if self.car:CanHit() then
                    if self.state_shooting == state_none then
                        printf("car <fire>: shooting enemy (first).")
                        self.state_shooting = state_shooting_on
                    else
                        self:set_shooting(self.state_shooting)
                        --self:set_signal("fire_start")
                    end
                    printf("car <fire>: shooting enemy.")
                else
                    if self.state_shooting ~= state_none then
                        printf("car <fire>: targeting enemy (first).")
                      self.state_shooting = state_none
                      self:set_shooting(self.state_shooting)
                      --self:set_signal("fire_end")
                    end
                    printf("car <fire>: targeting enemy.")
                end
            else
                if self.state_shooting ~= state_none then
                    --printf("car <fire>: enemy isn't visible (first).")
                    self.state_shooting = state_none
                    self:set_shooting(self.state_shooting)
                    --self:set_signal("fire_end")
                end
                --printf("car <fire>: enemy isn't visible.")

                if self.fire_track_target then
                    self.target_fire_pt = self:extrapolate_pos(self.target_obj)
                    self:rot_to_firepoint(self.target_fire_pt)
                    --printf("car <fire>: target tracking.")
                end
            end
        end
    end
    
    --printf("car <state>: check moving3 - [%d][%d]", self.state_moving, self.target_walk_pt)
    --printf("car <state>: END FAST UPDATE ========================================================\n")
    return false
end

function action_car:extrapolate_pos(obj)
  local mypos=self.object:position()
  if not self.prev_pos then
    self.prev_pos=obj:bone_position("bip01_spine1")
    self.prev_delta=vector():set(0,0,0)
  end
  local curpos=obj:bone_position("bip01_spine1")
  local hcorr=mypos:distance_to_sqr(curpos)/180/180*1.3
  local delta=obj:bone_position("bip01_spine1"):sub(self.prev_pos)
  self.prev_delta:mul(1):add(delta):mul(0.5)
  local extrapos=vector():set(self.prev_delta.x,self.prev_delta.y,self.prev_delta.z):mul(10):add(curpos):add(vector():set(0,hcorr,0))
  self.prev_pos=curpos
  return extrapos
end

function action_car:car_explode()
    self.object:explode(time_global())
end

function action_car:net_destroy()
    --self:destroy_car()
    if self.object and xr_logic.mob_captured(self.object) then
        xr_logic.mob_release(self.object)
        if self.st.on_death_info ~= nil then
            db.actor:give_info_portion(self.st.on_death_info)
            --printf("car <death>: give info")
        end
        if self.st.on_death_func then
            loadstring(self.st.on_death_func)()
        end
    end
end

function action_car:check_friends_on_fire_line()
    if self.target_fire_pt then
        local pos=self.object:bone_position("mashine_gun_fire_point")
        local dir_aim = vector():set(self.target_fire_pt.x - pos.x, self.target_fire_pt.y - pos.y , self.target_fire_pt.z - pos.z)    
        local target_dist = pos:distance_to(self.target_obj:position())
--проверяем позиции солдат и текущего сектора обстрела
        for a,v in pairs(self.friends) do
            tmp=level.object_by_id(a)
            if tmp and tmp:alive() then
                local pos_soldier = tmp:position()
                local radius=4
                if v=="vehicle_btr" then
                    radius=4
                else
                    radius=1.7
                end
                local friend_dist=self.object:position():distance_to(pos_soldier)-radius

                if friend_dist < target_dist then
                    --считаем попадает ли текущий солдат в сектор обстрела
                    local dir_soldier = vector():set(pos_soldier.x - pos.x, pos_soldier.y - pos.y , pos_soldier.z - pos.z)
                    local x = dir_soldier.x*dir_aim.x+dir_soldier.z*dir_aim.z
                    local y = -dir_soldier.z*dir_aim.x+dir_soldier.x*dir_aim.z -- повернули систему координат     
                    local angle = math.atan2(y,x) -- угол доворота от -180 до 180
                    local div = radius/friend_dist
                    if angle >= -div and angle <= div then return true end
                end
            end
        end
    end

    return false
end

function action_car:update_friends_and_target()

--get_console():execute("CHEKING!!!")
 if self.st.fire_target == "monsters" then
for k in pairs(db.monster_stock) do
    local obj = level.object_by_id(k)
if obj and IsMonster(obj) and obj:alive() and self.car:IsObjectVisible(obj) then
                    self.target_obj = obj
                    self.state_firetarget = state_firetarget_enemy
--get_console():execute(" !!_"..obj:name().."_!!")
end
end
end

 --end obj:section()=="vehicle_btr"
  if self.st.fire_target == "all_heli" then
--get_console():execute("CHEKING_HELI")
for a=1,65534,1 do
    local obj = level.object_by_id(a)
if obj and obj:section()=="helicopter" and obj:alive() and self.car:IsObjectVisible(obj) then
                    self.target_obj = obj
                    self.state_firetarget = state_firetarget_enemy
--get_console():execute(" !!_"..obj:name().."_!!")
end
end
end

 if self.st.fire_target == "stalker_group" then --- character_community() - группировка по которой БТР будет вести огонь.
--get_console():execute("CHEKING_STALKER")
for a=1,65534,1 do
    local obj = level.object_by_id(a)
if obj and IsStalker(obj) and obj:alive() and obj:character_community()=="stalker" and self.car:IsObjectVisible(obj) then
                    self.target_obj = obj
                    self.state_firetarget = state_firetarget_enemy
--get_console():execute(" !!_"..obj:name().."_!!")
end
end
end

end
---------------------------------------------------------------------------------------------------------------------
function add_to_binder(npc, ini, scheme, section, storage)
        --printf("DEBUG: add_to_binder: scheme='%s', section='%s'", scheme, section)
    local new_action = action_car(npc, storage)

    -- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы:
    xr_logic.subscribe_action_for_events(npc, storage, new_action)
end

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

    st.logic            = xr_logic.cfg_get_switch_conditions(ini, section, npc)

    st.usable          = xr_logic.cfg_get_condlist(ini, section, "usable", npc)
    if st.usable == nil then
        st.path_walk        = utils.cfg_get_string(ini, section, "path_walk",       npc, false, gulag_name)
        st.path_fire        = utils.cfg_get_string(ini, section, "path_fire",       npc, false, gulag_name, nil)
        st.auto_fire        = utils.cfg_get_bool(ini,   section, "auto_fire",       npc, false, false)
        st.fire_time        = utils.cfg_get_number(ini, section, "fire_time",       npc, false, def_min_fire_time)
        st.fire_rep         = utils.cfg_get_string(ini, section, "fire_repeat",     npc, false, gulag_name, nil)
        st.fire_range       = utils.cfg_get_number(ini, section, "fire_range",      npc, false, def_fire_range)
        st.fire_target      = utils.cfg_get_string(ini, section, "target",          npc, false, gulag_name, "points")
        st.fire_track_target= utils.cfg_get_bool(ini,   section, "track_target",    npc, false, false)

        st.on_target_vis    = xr_logic.cfg_get_string_and_condlist(ini, section, "on_target_vis", npc)
        st.on_target_nvis   = xr_logic.cfg_get_string_and_condlist(ini, section, "on_target_nvis", npc)

        st.path_walk_info   = nil -- Будут инициализированы в reset(), сейчас пути могут быть еще не загружены.
        st.path_fire_info   = nil
    else
        st.show_tips    = utils.cfg_get_bool(ini,   section, "show_tips",  npc, false, true)
        st.tip_use      = utils.cfg_get_string(ini, section, "tip_use",    npc, false, "", "tip_car_use")
        st.tip_locked   = utils.cfg_get_string(ini, section, "tip_locked", npc, false, "", "tip_car_locked")
    end

    st.invulnerable     = utils.cfg_get_bool(ini,   section, "invulnerable",    npc, false, false)
    st.headlights       = utils.cfg_get_string(ini, section, "headlights",      npc, false, gulag_name, "off")
    st.on_death_info    = utils.cfg_get_string(ini, section, "on_death_info",   npc, false, gulag_name, nil)
    st.on_death_func    = utils.cfg_get_string(ini, section, "on_death_func",   npc, false, gulag_name, nil)
end

 

 

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

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

AMK-Team.ru

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