Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- nv120412 support for Rulix/xStream's AI - ZRP-compatible version
- -- Modders: if bind_stalker.script is not valid, actor will be nil
- function init (obj)
- xr_motivator.AddToMotivator(obj)
- end
- function actor_init (npc)
- npc:bind_object(actor_binder(npc))
- end
- local game_difficulty_by_num = {
- [0] = "gd_novice",
- [1] = "gd_stalker",
- [2] = "gd_veteran",
- [3] = "gd_master"
- }
- -- nv130228 - added bind_stalker.quitting_game var to keep game from processing dropped items
- quitting_game = false
- -- debug flag (normally set by player in main menu; requires _z.script)
- nv_debug = false
- -- this is set true if tick update is needed (TM loss_workaround, ammo_fix, etc.)
- nv_need_update = false
- -- this is set true by events needing longer time delays
- nv_timer_pending = false
- -- time-on-hud flag (normally set by player via Modifier; requires _z.script)
- local nv_show_time = false
- -- set this true to automatically copy or rename autosaves to level_autosaves
- local level_autosaves = true
- -- set this true to rename autosave, false to copy it (if level_autosaves = true)
- local rename_autosave = true
- -- set this true to preserve your first access to a level if level_autosaves = true
- local keep_first_level_access = true
- -- set this true to preserve your first access to a level after key progress points
- local keep_progress_level_access = true
- -- set true if you want to use a sleeping bag in the game (see docs)
- local use_sleeping_bag = true
- -- lasthealth = 0
- -- lasttime = 0
- -- post_process = 0
- local weapon_hide = false
- local autosave_prefix
- ----------------------------------------------------------------------------------------------------------------------
- class "actor_binder" (object_binder)
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:__init (obj) super(obj)
- self.bCheckStart = false
- self.weather_manager = level_weathers.WeatherManager()
- self.actor_detector = xr_detector.actor_detector()
- autosave_prefix = ui_main_menu.save_prefix
- if autosave_prefix == nil then autosave_prefix = "" end
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:net_spawn(data)
- -- printf("actor net spawn")
- level.show_indicators()
- self.bCheckStart = true
- self.weapon_hide = false -- ńļš˙ņąķī čėč ķåņ īšóęčå ļšč šąēćīāīšå.
- weapon_hide = false -- óńņąķąāėčāąåģ ćėīįąėüķūé äåōīėņīāūé ōėąć.
- if object_binder.net_spawn(self,data) == false then
- return false
- end
- db.add_actor(self.object)
- -- nv100217 permanent radiation cure
- if self.actor_detector.init_time ~= -1 then
- self.actor_detector:actor_enter()
- dbglog("Permanent radiation bug fix applied")
- end
- if self.st.disable_input_time == nil then
- level.enable_input()
- end
- self.weather_manager:reset()
- -- game_stats.initialize ()
- if(actor_stats.add_to_ranking~=nil)then
- actor_stats.add_to_ranking(self.object:id())
- end
- --' Ēąćšóęąåģ ķąńņšīéźč äšīļą
- death_manager.init_drop_settings()
- if xrs_ai then xrs_ai.actor_net_spawn(self) end
- if rx_ai then rx_ai.actor_net_spawn() end
- return true
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:net_destroy()
- _z.remove_debug_static()
- _z.remove_time_static()
- if(actor_stats.remove_from_ranking~=nil)then
- actor_stats.remove_from_ranking(self.object:id())
- end
- -- game_stats.shutdown ()
- db.del_actor(self.object)
- sr_light.clean_up ()
- self.object:set_callback(callback.inventory_info, nil)
- self.object:set_callback(callback.article_info, nil)
- self.object:set_callback(callback.on_item_take, nil)
- self.object:set_callback(callback.on_item_drop, nil)
- --self.object:set_callback(callback.actor_sleep, nil)
- self.object:set_callback(callback.task_state, nil)
- self.object:set_callback(callback.level_border_enter, nil)
- self.object:set_callback(callback.level_border_exit, nil)
- self.object:set_callback(callback.take_item_from_box, nil)
- self.object:set_callback(callback.use_object, nil)
- self.object:set_callback(callback.death, nil)
- if sr_psy_antenna.psy_antenna then
- sr_psy_antenna.psy_antenna:destroy()
- sr_psy_antenna.psy_antenna = false
- end
- xr_sound.stop_all_sound_object()
- object_binder.net_destroy(self)
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:reinit()
- object_binder.reinit(self)
- local npc_id = self.object:id()
- db.storage[npc_id] = { }
- self.st = db.storage[npc_id]
- self.st.pstor = nil
- self.next_restrictors_update_time = -10000
- self.object:set_callback(callback.inventory_info, self.info_callback, self)
- self.object:set_callback(callback.article_info, self.article_callback, self)
- self.object:set_callback(callback.on_item_take, self.on_item_take, self)
- self.object:set_callback(callback.on_item_drop, self.on_item_drop, self)
- -- self.object:set_callback(callback.trade_sell_buy_item, self.on_trade, self) -- for game stats
- --self.object:set_callback(callback.actor_sleep, self.sleep_callback, self)
- self.object:set_callback(callback.task_state, self.task_callback, self)
- --self.object:set_callback(callback.map_location_added, self.map_location_added_callback, self)
- self.object:set_callback(callback.level_border_enter, self.level_border_enter, self)
- self.object:set_callback(callback.level_border_exit, self.level_border_exit, self)
- self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self)
- self.object:set_callback(callback.use_object, self.use_object, self)
- self.object:set_callback(callback.death, self.on_death, self)
- --play sound when using item in inventory
- self.object:set_callback(callback.use_object, self.on_use_item, self)
- end
- -- new method, will be called every time you use item in inventory
- function actor_binder:on_use_item(obj)
- item_usage.on_use_item(obj)
- end
- ----------------------------------------------------------------------------------------------------------------------
- -- use this (and the use_object set_callback()s above) if you want to handle object use
- function actor_binder:use_object(object)
- lurk_inv_effects.start(object)
- dbglog("use_object_%s,_section_%s",object:name(), object:section())
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:on_death(object)
- -- _z.nvDebug("You are dead.")
- -- kill all the controllers to eliminate the roar
- if _z.kill_online_controllers() > 0 then -- returns kill_count
- --_z.nvDebug("So are the controllers.")
- _z.show_blinking_msg("Please wait for any controller noise to fade.")
- end
- level.enable_input() -- for death while sleeping
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:take_item_from_box(box, item)
- local story_id = box:story_id()
- if story_id == nil then
- return
- end
- if story_id >= 5000 then
- treasure_manager.take_item_from_box(box, story_id)
- return
- end
- if _custom_ext then
- _custom_ext.on_take_item_from_box(box, item, story_id)
- end
- -- nv150313 re-enabled this as a better way to manage inventory box maximum amounts
- local respawner = se_respawn.get_respawner_by_parent(story_id)
- if respawner == nil then
- return
- end
- --' Ķåīįõīäčģī óģåķüųčņü ń÷åņ÷čź ā šåńļąāķåšå
- respawner:remove_spawned(item:id())
- --[[
- local smart_terrain = db.strn_by_respawn[respawner:name()]
- if smart_terrain == nil then
- return
- end
- local npc = smart_terrain.gulag:get_nearest_online_obj(db.actor:position())
- if npc ~= nil then
- xr_sound.set_sound_play(npc, "reac_box")
- xr_gulag.setGulagEnemy(smart_terrain:name() , db.actor)
- end
- ]]
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:level_border_enter(npc, info_id)
- self.actor_detector:actor_enter()
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:level_border_exit(npc, info_id)
- self.actor_detector:actor_exit()
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:info_callback(npc, info_id)
- if info_id == "ui_car_body" then
- xr_sound.get_safe_sound_object( "interface\\inv_open" ):play_no_feedback( db.actor, sound_object.s2d, 0, vector(), 1.0 )
- elseif info_id == "ui_car_body_hide" then
- xr_sound.get_safe_sound_object( "interface\\inv_close" ):play_no_feedback( db.actor, sound_object.s2d, 0, vector(), 1.0 )
- end
- -- printf("*INFO*: npc='%s' id='%s'", npc:name(), info_id)
- --' Ńžęåņ
- level_tasks.proceed(self.object)
- -- Īņģåņźč ķą źąšņå
- level_tasks.process_info_portion(info_id)
- end
- ----------------------------------------------------------------------------------------------------------------------
- --[[ restore if you need the function, but you probably don't need the game_stats stuff
- function actor_binder:on_trade (item, sell_bye, money)
- -- if sell_bye == true then
- -- -- game_stats.money_trade_update (money)
- -- else
- -- -- game_stats.money_trade_update (-money)
- -- end
- end
- --]]
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:article_callback(npc, group, name)
- --printf("article_callback [%s][%s]", group, name)
- if device().precache_frame >1 then return end
- if group == "Diary" then
- -- fix per Cpt. Borovich -- now 100% more annoying
- news_manager.send_encyclopedy(group, "diary")
- else
- news_manager.send_encyclopedy(group, "encyclopedy")
- end
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:on_item_take (obj)
- if has_alife_info( "ui_car_body" ) then
- xr_sound.get_safe_sound_object( "interface\\inv_ruck" ):play_no_feedback( db.actor, sound_object.s2d, 0, vector(), 1.0 )
- end
- if obj:clsid() ~= clsid.wpn_ammo then
- level_tasks.proceed(self.object)
- end
- if device().precache_frame >1 then return end
- if xrs_ai then xrs_ai.actor_item_take(obj) end
- if rx_ai then rx_ai.actor_item_take(obj) end
- --game_stats.update_take_item (obj, self.object)
- _z.on_item_take(obj, self.object)
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:on_item_drop (obj)
- if has_alife_info( "ui_car_body" ) then
- xr_sound.get_safe_sound_object( "interface\\inv_drop" ):play_no_feedback( db.actor, sound_object.s2d, 0, vector(), 1.0 )
- end
- if quitting_game then return end
- if obj:clsid() ~= clsid.wpn_ammo then
- level_tasks.proceed(self.object)
- end
- --game_stats.update_drop_item (obj, self.object)
- if _z.item_drop_is_intentional(obj, self.object) then
- if _z.on_item_drop(obj, self.object) then return end -- true = used item
- if use_sleeping_bag and abc_sleep and obj:section()=="sleep_bag" then
- if not has_alife_info("ui_inventory") then return end
- if _dev then
- _dev.queue_delayed_event({delay=1200,event="abc_sleep.show_sleep_dialog()"})
- else
- dbglog("sleep_bag needs valid _dev.script")
- end
- end
- end
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:task_callback(_task, _objective, _state)
- task_manager.task_callback(_task:get_id(), _objective:get_idx(), _state)
- _z.task_mapspot_cleanup(_task:get_id(), _objective:get_idx(), _state)
- if _objective:get_idx() == 0 then
- if _state == task.fail then
- news_manager.send_task(db.actor, "fail", _task, _objective)
- elseif _state == task.completed then
- task_manager.reward_by_task(_task)
- news_manager.send_task(db.actor, "complete", _task, _objective)
- else
- news_manager.send_task(db.actor, "new", _task, _objective)
- end
- else
- if _task:get_objective(0):get_state() == task.in_progress then
- news_manager.send_task(db.actor, "update", _task, _objective)
- end
- end
- end
- ----------------------------------------------------------------------------------------------------------------------
- -- function actor_binder:map_location_added_callback(spot_type_str, object_id)
- -- if (false==app_ready()) or (device().precache_frame>1) then return end
- -- --'news_manager.send_task(db.actor, "new")
- -- end
- ----------------------------------------------------------------------------------------------------------------------
- -- nv111103 check for autosave level copy or rename
- -- nv130223 rename fail check, optional progress autosaves added
- function manage_autosaves()
- local fs = getFS()
- local autosaveFile = string.lower(user_name()).."_autosave"
- local autosaveFile_sav = autosaveFile .. ".sav"
- local fs_path = "$game_saves$"
- if fs:exist(fs_path, autosaveFile_sav) then
- local sg = CSavedGameWrapper(autosaveFile)
- local level_name = level.name()
- if level_name == sg:level_name() then
- local target = autosave_prefix .. level_name .."_autosave"
- local target_save = target .. ".sav"
- -- update_path info per fluffy22
- local savedir = fs:update_path(fs_path, "")
- local target_exists = fs:exist(fs_path, target_save)
- if target_exists and sg:game_time() < CSavedGameWrapper(target):game_time() then
- return -- current autosave is earlier in-game time
- end
- if rename_autosave then
- fs:file_rename(savedir..autosaveFile_sav, savedir..target_save, true)
- else
- if target_exists then fs:file_delete(savedir..target_save) end
- fs:file_copy(savedir..autosaveFile_sav, savedir..target_save)
- end
- -- nv130223 keep game from attempting to load non-existent save if rename failed
- if fs:exist(fs_path, target_save) then get_console():execute("load_last_save "..target) end
- if keep_first_level_access then
- local first_target = autosave_prefix .. level_name -- .." - start.sav"
- local postfix = " - start.sav"
- if keep_progress_level_access then
- if level_name == "l01_escape" then
- if not has_alife_info("bar_darklab_document_gain") then
- return -- all.sav already made
- end
- postfix = "_post_x18_autosave.sav"
- elseif level_name == "l04_darkvalley" and has_alife_info("bar_darklab_document_gain") then
- postfix = "_post_x18_autosave.sav"
- elseif level_name == "l08_yantar" and has_alife_info("yan_x16_documents_gain") then
- postfix = "_post_x16_autosave.sav"
- elseif level_name == "l10_radar" and has_alife_info("bar_deactivate_radar_done") then
- postfix = "_post_x19_autosave.sav"
- --else use as is
- end
- else
- if level_name == "l01_escape" then return end
- end
- first_target = first_target..postfix
- if not fs:exist(fs_path, first_target) then
- if fs:exist(fs_path, target_save) then
- fs:file_copy(savedir..target_save, savedir..first_target)
- end
- end
- end
- end
- end
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:update(delta)
- lurk_inv_effects.weapontimer()
- object_binder.update(self, delta)
- -- DEBUG slowdown
- -- slowdown.update()
- local time = time_global()
- -- nv 100521 moved this below to reduce processing
- -- game_stats.update (delta, self.object)
- -- ąļäåéņ ļīćīäū
- self.weather_manager:update()
- -- nv 100521 moved this below to reduce processing
- -- ąļäåéņ ńõåģū äåņåźņīšą
- -- self.actor_detector:update()
- -- ąļäåéņ ēāóźīāīé ńõåģū ąźņåšą
- xr_sound.update_actor()
- rx_shoot_enable.shoot_effect()
- --' Ļšīāåšźą ļīņåšč ęčēķč
- --[[
- if self.object.health - lasthealth > 0.001 or
- self.object.health - lasthealth < -0.001 then
- printf("%f | %f", self.object.health, self.object.health - lasthealth, game.time() - lasttime)
- lasthealth = self.object.health
- lasttime = game.time()
- end
- ]]
- -- Īįķīāėåķčå īņźėž÷åķč˙ āāīäą ń źėąāčąņóšū.
- if self.st.disable_input_time ~= nil and
- game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle
- then
- level.enable_input()
- self.st.disable_input_time = nil
- end
- --[[ -- this is not currently used even in sleep mod stuff
- -- Īįķīāėåķčå ńķą ń ļåšåķīńīģ ÷óāąźą ā óźąēąķķóž ļīēčöčž
- if self.st.sleep_relocate_time ~= nil and
- game.get_game_time():diffSec(self.st.sleep_relocate_time) >= self.st.sleep_relocate_idle
- then
- self.object:set_actor_position(self.st.sleep_relocate_point)
- local dir = self.st.sleep_relocate_point:sub(self.st.sleep_relocate_look)
- self.object:set_actor_direction(dir:getH())
- self.st.sleep_relocate_time = nil
- end
- --]]
- -- Ąļäåéņ ļš˙ņąķčå īšóęč˙ čćšīźą āī āšåģ˙ äčąėīćą
- if weapon_hide == true or self.object:is_talking() then
- if self.weapon_hide == false then
- self.object:hide_weapon()
- self.weapon_hide = true
- end
- else
- if self.weapon_hide == true then
- self.object:restore_weapon()
- self.weapon_hide = false
- end
- end
- -- īįķīāėåķčå šåńņščźņīšīā, źīņīšūå ļīä ėīćčźīé, ńšąįąņūāąåņ ÷åšåē čķņåšāąėū āšåģåķč
- if self.next_restrictors_update_time < time then
- bind_restrictor.actor_update(delta)
- self.next_restrictors_update_time = time + 200
- -- nv 100521 moved these here to reduce processing
- -- game_stats.update (delta, self.object) --used only for debugging
- self.actor_detector:update()
- -- nv 070922 comment out for no auto-quests
- task_manager.actor_update()
- if nv_debug then _z.show_coords(delta) end
- if nv_show_time then _z.show_time() end
- if nv_timer_pending then _dev.check_timer() end
- -- nv130402 moved here to reduce loop load;
- -- checking five times a second is enough for a HUD message update
- --' Āūāīä ńīīįłåķč˙ ī įīėüųīé šąäčąöčč
- local rad_danger = "cs_radiation_danger"
- local hud = get_hud()
- local custom_static = hud:GetCustomStatic(rad_danger)
- if self.object.radiation >= 0.7 then
- if custom_static == nil then
- custom_static = hud:AddCustomStatic(rad_danger, true)
- custom_static:wnd():SetTextST("st_radiation_danger")
- end
- else
- if custom_static ~= nil then
- hud:RemoveCustomStatic(rad_danger)
- end
- end
- end
- --[[ -- īįķīāėåķčå ļīńņļšīöåńńīā
- if post_process ~= 0 then
- if post_process:update () == true then
- post_process = 0
- end
- end
- --]]
- -- īįķīāėåķčå ļńč-ąķņåķķū
- if sr_psy_antenna.psy_antenna then
- sr_psy_antenna.psy_antenna:update(delta)
- end
- if nv_need_update then
- nv_need_update = false
- _z.do_update(self.object)
- end
- if self.bCheckStart then
- -- level.hide_indicators() --enable this if you want no HUD at start (can still toggle in-game)
- -- printf("SET DEFAULT INFOS")
- -- nv 100722 tweaked to better support free play
- if (level.name() == "l01_escape") then
- if not has_alife_info("storyline_actor_start") then
- self.object:give_info_portion("storyline_actor_start")
- -- _G.g_start_avi = true -- not used
- -- printf("*AVI* RUN START AVI")
- elseif not has_alife_info("zrp_free_play") then
- --has game start, might be in free play
- if has_alife_info("aes2_monolit_teleport_ready_final") then
- -- C-Con is dead
- self.object:give_info_portion("zrp_free_play")
- end
- end
- end
- if level_autosaves then manage_autosaves() end
- -- if not has_alife_info("encyclopedy") then
- -- self.object:give_info_portion("encyclopedy")
- -- end
- if not has_alife_info("global_dialogs") then
- self.object:give_info_portion("global_dialogs")
- end
- -- nv140331 not used
- -- if not has_alife_info("level_changer_icons") then
- -- self.object:give_info_portion("level_changer_icons")
- -- end
- level_tasks.add_lchanger_location()
- if use_sleeping_bag and abc_sleep then abc_sleep.add_bag_if_needed(true) end
- -- if zx then zx.fix_weather() end
- self.bCheckStart = false
- end
- if xrs_ai then xrs_ai.actor_update(delta) end
- if rx_ai then rx_ai.actor_update() end
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:save(packet)
- local save_treasure_manager = true
- -- printf("actor_binder:save(): self.object:name()='%s'", self.object:name())
- object_binder.save(self, packet)
- --' Ńīõšąķ˙åģ óšīāåķü ńėīęķīńņč
- if save_treasure_manager == true then
- packet:w_u8(level.get_game_difficulty() + 128)
- else
- packet:w_u8(level.get_game_difficulty())
- end
- --' Ńīõšąķ˙åģ äąķķūå īį īņźėž÷åķķīģ āāīäå
- if self.st.disable_input_time == nil then
- packet:w_bool(false)
- else
- packet:w_bool(true)
- utils.w_CTime(packet, self.st.disable_input_time)
- -- enable following lines for your custom mod if needed; see load()
- -- -- 255 seconds of prohibiting action by player is more than plenty
- -- packet:w_u8(self.st.disable_input_idle)
- end
- xr_logic.pstor_save_all(self.object, packet)
- self.weather_manager:save(packet)
- sr_psy_antenna.save( packet )
- if save_treasure_manager == true then
- treasure_manager.save(packet)
- end
- task_manager.save(packet)
- self.actor_detector:save(packet)
- end
- ----------------------------------------------------------------------------------------------------------------------
- function show_load_error(reason)
- local corrupt_save_msg = "SAVE FILE IS CORRUPT - Load earlier save"
- if zrp_notice then zrp_notice.ShowMessage("\\n" .. corrupt_save_msg .. "\\n\\n" .. reason) end
- abort(corrupt_save_msg .. " - " .. reason) -- might exit, might not (default is "not")
- end
- ----------------------------------------------------------------------------------------------------------------------
- function actor_binder:load(reader)
- -- printf("actor_binder:load(): self.object:name()='%s'", self.object:name())
- object_binder.load(self, reader)
- -- printf("actor_binder:object_binder.load(): self.object:name()='%s'", self.object:name())
- --' Ēąćšóęąåģ óšīāåķü ńėīęķīńņč
- local game_difficulty = reader:r_u8()
- if game_difficulty == nil then
- -- nv - it's going to crash anyway; at least tell the player why
- show_load_error("Game difficulty is nil")
- return
- end
- local load_treasure_manager = false
- if game_difficulty >= 128 then
- game_difficulty = game_difficulty - 128
- load_treasure_manager = true
- end
- if game_difficulty < 0 or game_difficulty > 3 then
- -- nv - it's going to crash anyway; at least tell the player why
- show_load_error("Game difficulty should be 0-3, is " .. tostring(game_difficulty))
- return
- end
- get_console():execute("g_game_difficulty "..game_difficulty_by_num[game_difficulty])
- if reader:r_eof() then
- show_load_error("Unexpected end of save file encountered")
- return
- end
- -- local stored_input_time = reader:r_u8() --bool per barin
- local stored_input_time = reader:r_bool()
- if stored_input_time == true then
- self.st.disable_input_time = utils.r_CTime(reader)
- -- disable next line, enable following for your custom mod if needed; see also save()
- self.st.disable_input_idle = xr_effects.punch_recovery_time -- prevent CTD
- -- self.st.disable_input_idle = reader:r_u8()
- end
- xr_logic.pstor_load_all(self.object, reader)
- self.weather_manager:load(reader)
- sr_psy_antenna.load(reader)
- if load_treasure_manager == true then
- treasure_manager.load(reader)
- end
- task_manager.load(reader)
- self.actor_detector:load(reader)
- end
- ----------------------------------------------------------------------------------------------------------------------
- --ńņąšņ ļšåōåņ÷ą ēāóźīā
- -- if string.find(command_line(), "-noprefetch") ~= nil then
- -- sound_prefetch.prefetch_sounds()
- -- end
- -- Weapon functions
- function hide_weapon()
- weapon_hide = true
- end
- function restore_weapon()
- weapon_hide = false
- end
- if not _z then dbglog("No valid _z.script found") end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement