---------------------------------------------------------------------------------------------------- -- Mob remarks ---------------------------------------------------------------------------------------------------- -- Разработчик: Andrey Fidrya (Zmey) af@svitonline.com -- Исходный скрипт (trader): Evgeniy Negrobov (Jon) jon@gsc-game.kiev.ua ---------------------------------------------------------------------------------------------------- local default_wait_time = 5000 -- время в ms, или nil для anim_end condition local default_anim_standing = anim.stand_idle local state_moving = 0 local state_standing = 1 class "mob_walker" function mob_walker:__init(obj, storage) self.object = obj self.st = storage end function mob_walker:reset_scheme() printf("_bp: mob_walker:reset_scheme: %s", self.object:name()) mob_state_mgr.set_state(self.object, db.actor, self.st.state) self.st.signals = {} xr_logic.mob_capture(self.object, true) self.patrol_walk = patrol(self.st.path_walk) if not self.patrol_walk then abort("object '%s': unable to find path_walk '%s' on the map", self.object:name(), self.st.path_walk) end if self.st.path_look then self.patrol_look = patrol(self.st.path_look) if not self.patrol_look then abort("object '%s': unable to find path_look '%s' on the map", self.object:name(), self.st.path_look) end else self.patrol_look = nil end if self.st.path_walk_info == nil then self.st.path_walk_info = utils.path_parse_waypoints(self.st.path_walk) self.path_walk_info = self.st.path_walk_info end if self.st.path_look_info == nil then self.st.path_look_info = utils.path_parse_waypoints(self.st.path_look) self.path_look_info = self.st.path_look_info end self.state = state_moving self.crouch = false self.running = false self.cur_anim_set = default_anim_standing self.pt_wait_time = default_wait_time -- сколько ждать в точке, где играем анимацию self.scheduled_snd = nil self.last_index = nil self.last_look_index = nil action(self.object, move(move.walk_fwd, patrol(self.st.path_walk, patrol.next, patrol.continue)), cond(cond.move_end)) end function mob_walker:update(delta) -- printf("__bp: mob_walker update: %d", time_global()) --if not xr_logic.is_active(self.object, self.st) then -- return --end local actor = db.actor -- Монстр после выхода из alife может уже быть не под скриптом, поэтому взять опять под скрипт if not xr_logic.mob_captured(self.object) then self:reset_scheme() return end --[[ if self:arrived_to_first_waypoint() then if xr_logic.try_switch_to_another_section(self.object, self.st, actor) then return end end ]] if self.state == state_standing then if not self.object:action() then local patrol_walk_count = self.patrol_walk:count() if patrol_walk_count == 1 and utils.stalker_at_waypoint(self.object, self.patrol_walk, 0) then self.state = state_moving self:waypoint_callback(self.object, nil, self.last_index) else self.last_look_index = nil self.state = state_moving self:update_movement_state() -- идти дальше end end end end function mob_walker:arrived_to_first_waypoint() return self.last_index ~= nil end function mob_walker:waypoint_callback(obj, action_type, index) printf("mob_walker:waypoint_callback(): name=%s, index=%d", self.object:name(), index) if index == -1 or index == nil then printf("ERROR: mob_walker: waypoint_callback: index is %s", if_then_else(index == -1, "-1", "nil")) return end self.last_index = index local suggested_snd = self.path_walk_info[index]["s"] if suggested_snd then self.scheduled_snd = suggested_snd end local suggested_crouch = self.path_walk_info[index]["c"] if suggested_crouch == "true" then self.crouch = true else self.crouch = false end local suggested_running = self.path_walk_info[index]["r"] if suggested_running == "true" then self.running = true else self.running = false end local sig = self.path_walk_info[index]["sig"] if sig then -- HACK, fixme: local npc_id = self.object:id() local scheme = db.storage[npc_id]["active_scheme"] local signals = db.storage[npc_id][scheme].signals signals[sig] = true printf("_bp: mob_walker [%s]: SIGNALLING: %s", self.object:name(), sig) end local beh = self.path_walk_info[index]["b"] if beh then mob_state_mgr.set_state(self.object, db.actor, beh) else mob_state_mgr.set_state(self.object, db.actor, self.st.state) end local search_for = self.path_walk_info[index].flags if search_for:get() == 0 then -- TODO: запретить одноточечные пути без соответствующего path_look по аналогии с move_mgr printf("_bp: no flags") self:update_movement_state() -- идти дальше return end local pt_chosen_idx = move_mgr.choose_look_point(self.patrol_look, self.path_look_info, search_for) if pt_chosen_idx then local suggested_wait_time = self.path_look_info[pt_chosen_idx]["t"] if suggested_wait_time then self.pt_wait_time = tonumber(suggested_wait_time) else local patrol_walk_count = self.patrol_walk:count() if patrol_walk_count == 1 and utils.stalker_at_waypoint(self.object, self.patrol_walk, 0) then self.pt_wait_time = time_infinite else self.pt_wait_time = default_wait_time end end local suggested_anim_set = self.path_look_info[pt_chosen_idx]["a"] if suggested_anim_set then if suggested_anim_set == "nil" then suggested_anim_set = nil end self.cur_anim_set = anim[xr_logic.pick_section_from_condlist(db.actor, self.object, suggested_anim_set)] else self.cur_anim_set = default_anim_standing end local beh = self.path_walk_info[index]["b"] if beh then mob_state_mgr.set_state(self.object, db.actor, beh) else mob_state_mgr.set_state(self.object, db.actor, self.st.state) end if pt_chosen_idx ~= self.last_look_index then -- если уже смотрели туда - не поворачиваться self:look_at_waypoint(pt_chosen_idx) -- поворачиваемся end self.state = state_standing self:update_standing_state() -- Сразу же стартовать update, не ждать execute. Тогда, если мы уже смотрим -- в нужную сторону - не будет паузы в несколько миллисекунд на поворот. self:update(true) else abort("object '%s': path_walk '%s', index %d: cannot find corresponding point(s) on path_look '%s'", self.object:name(), self.path_walk, index, self.path_look) end end function mob_walker:update_movement_state() printf("_bp [%s]: update_movement_state", self.object:name()) xr_logic.mob_capture(self.object, true) local m if self.running then m = move.run_fwd elseif self.crouch then m = move.steal else m = move.walk_fwd end if self.scheduled_snd then printf("_bp [%s]: playing scheduled sound", self.object:name()) action(self.object, move(m, patrol(self.st.path_walk, patrol.next, patrol.continue)), sound(sound[self.scheduled_snd]), cond(cond.move_end)) self.scheduled_snd = nil else action(self.object, move(m, patrol(self.st.path_walk, patrol.next, patrol.continue)), cond(cond.move_end)) end end function mob_walker:update_standing_state() printf("_bp [%s]: update_standing_state", self.object:name()) xr_logic.mob_capture(self.object, true) if self.scheduled_snd then printf("_bp [%s]: playing scheduled sound", self.object:name()) action(self.object, anim(self.cur_anim_set, 0), sound(sound[self.scheduled_snd]), cond(cond.time_end, self.pt_wait_time)) self.scheduled_snd = nil else action(self.object, anim(self.cur_anim_set, 0), cond(cond.time_end, self.pt_wait_time)) end end function mob_walker:deactivate() xr_logic.mob_capture(self.object, true) action(self.object, move(move.steal, self.patrol_walk:point(0)), cond(cond.move_end)) end function mob_walker:look_at_waypoint(pt) if not self.patrol_look then return end local look_pt = utils.vector_copy_by_val(self.patrol_look:point(pt)):sub(self.object:position()) look_pt:normalize() --self.object:set_sight(look.direction, look_pt, 0) xr_logic.mob_capture(self.object, true) action(self.object, look(look.direction, look_pt), cond(cond.look_end)) self.last_look_index = pt end --------------------------------------------------------------------------------------------------------------------- function add_to_binder(npc, ini, scheme, section, storage) printf("DEBUG: add_to_binder: npc:name()='%s', scheme='%s', section='%s'", npc:name(), scheme, section) local new_action = mob_walker(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.state = mob_state_mgr.get_state(ini, section, npc) st.no_reset = utils.cfg_get_bool(ini, section, "no_reset", npc, false) st.path_walk = utils.cfg_get_string(ini, section, "path_walk", npc, true, gulag_name) st.path_look = utils.cfg_get_string(ini, section, "path_look", npc, false, gulag_name) if st.path_walk == st.path_look then abort("You are trying to set 'path_look' equal to 'path_walk' in section [%s] for npc [%s]", section, npc:name()) end st.path_walk_info = nil -- Будут инициализированы в reset(), сейчас пути могут быть еще st.path_look_info = nil -- не загружены. end