890 lines
29 KiB
Plaintext
890 lines
29 KiB
Plaintext
|
--====================< Credits >====================--
|
||
|
|
||
|
-- Many thanks to two anonymous contributors, ravenascendant, and dan6642 for coding help.
|
||
|
-- Many thanks to Australian cunt#3627, RitualColt#7912, cubed#8023, shiyon, piscesblau, and ALostArchitect#9240 for writing help.
|
||
|
-- Many thanks to izperehoda, sasanito95., CV514#7004, and njaal for the Russian translation.
|
||
|
-- Many thanks to jinxovarrio, d.santi, and Spooky Usuala#2706 for the Spanish translation.
|
||
|
-- Many thanks to ishmaeel for their generous decision to allow their code to be re-used.
|
||
|
-- Many thanks to realdealflexseal for playtesting and ideas.
|
||
|
-- Many thanks to Abhishek Kumar and hookenz on stackoverflow for useful snippets of code.
|
||
|
|
||
|
-- Without them this would not have been possible.
|
||
|
|
||
|
--====================< Settings >====================--
|
||
|
|
||
|
local show_time
|
||
|
local show_time_long
|
||
|
local beep_before
|
||
|
local beep_after
|
||
|
|
||
|
--local name_state
|
||
|
--local name_rgb
|
||
|
local msg_state
|
||
|
|
||
|
--local clr_name
|
||
|
local clr_msg
|
||
|
|
||
|
local anomaly_state
|
||
|
local anomaly_timer
|
||
|
local clear_state
|
||
|
local campfire_state
|
||
|
local wpm
|
||
|
local npc_death_state
|
||
|
local npc_death_comment_state
|
||
|
local emission_state
|
||
|
local enemy_state
|
||
|
local headshot_state
|
||
|
local level_state
|
||
|
local level_chance
|
||
|
local npc_health_state
|
||
|
local player_death_state
|
||
|
local psistorm_state
|
||
|
local jammed_state
|
||
|
local reload_state
|
||
|
local reload_chance
|
||
|
local random_state
|
||
|
local random_chance
|
||
|
local safe_area_state
|
||
|
local safe_area_chance
|
||
|
|
||
|
function load_settings()
|
||
|
show_time = chatter_mcm.get_config("show_time")
|
||
|
show_time_long = chatter_mcm.get_config("show_time_long")
|
||
|
|
||
|
show_time = show_time*1000
|
||
|
show_time_long = show_time_long*1000
|
||
|
|
||
|
beep_before = chatter_mcm.get_config("beep_before")
|
||
|
beep_after = chatter_mcm.get_config("beep_after")
|
||
|
|
||
|
msg_state = chatter_mcm.get_config("msg_state")
|
||
|
|
||
|
if msg_state then
|
||
|
clr_msg = "%c[" .. chatter_mcm.get_config("msg_argb") .. "]"
|
||
|
else
|
||
|
clr_msg = ""
|
||
|
end
|
||
|
|
||
|
anomaly_state = chatter_mcm.get_config("anomaly_state")
|
||
|
anomaly_timer = chatter_mcm.get_config("anomaly_timer")
|
||
|
|
||
|
anomaly_timer = anomaly_timer*1000
|
||
|
|
||
|
clear_state = chatter_mcm.get_config("clear_state")
|
||
|
campfire_state = chatter_mcm.get_config("campfire_state")
|
||
|
wpm = chatter_mcm.get_config("wpm")
|
||
|
npc_death_state = chatter_mcm.get_config("npc_death_state")
|
||
|
npc_death_comment_state = chatter_mcm.get_config("npc_death_comment_state")
|
||
|
emission_state = chatter_mcm.get_config("emission_state")
|
||
|
enemy_state = chatter_mcm.get_config("enemy_state")
|
||
|
headshot_state = chatter_mcm.get_config("headshot_state")
|
||
|
level_state = chatter_mcm.get_config("level_state")
|
||
|
level_chance = chatter_mcm.get_config("level_chance")
|
||
|
npc_health_state = chatter_mcm.get_config("npc_health_state")
|
||
|
player_death_state = chatter_mcm.get_config("player_death_state")
|
||
|
psistorm_state = chatter_mcm.get_config("psistorm_state")
|
||
|
jammed_state = chatter_mcm.get_config("jammed_state")
|
||
|
reload_state = chatter_mcm.get_config("reload_state")
|
||
|
reload_chance = chatter_mcm.get_config("reload_chance")
|
||
|
random_state = chatter_mcm.get_config("random_state")
|
||
|
random_chance = chatter_mcm.get_config("random_chance")
|
||
|
safe_area_state = chatter_mcm.get_config("safe_area_state")
|
||
|
safe_area_chance = chatter_mcm.get_config("safe_area_chance")
|
||
|
end
|
||
|
|
||
|
--====================< Definitions >====================--
|
||
|
|
||
|
local number = {
|
||
|
["part_2"] = 10,
|
||
|
|
||
|
["actor_on_before_death"] = 10,
|
||
|
["anomaly_part_1"] = 5,
|
||
|
["anomaly_part_2"] = 5,
|
||
|
["campfire"] = 10,
|
||
|
["clear"] = 5,
|
||
|
["companion_death"] = 5,
|
||
|
["headshot"] = 5,
|
||
|
["near_death"] = 30,
|
||
|
["npc_on_death"] = 10,
|
||
|
["psi_storm"] = 10,
|
||
|
["random"] = 25,
|
||
|
["safe_area"] = 25,
|
||
|
["emission"] = 10,
|
||
|
["weapon_jammed"] = 5,
|
||
|
["weapon_reload"] = 5,
|
||
|
}
|
||
|
|
||
|
local campfire_radius = 5
|
||
|
local campfire_radius_far = 20
|
||
|
local max_delay = 420000
|
||
|
local max_timer = 120000
|
||
|
local min_delay = 240000
|
||
|
local min_timer = 60000
|
||
|
local n = 1
|
||
|
|
||
|
local base_radius = 50
|
||
|
local neutral_bases = true
|
||
|
local safe_area_timer = 30
|
||
|
|
||
|
local bonus_bases = {}
|
||
|
bonus_bases.pri_monolith = {monolith = true}
|
||
|
bonus_bases.pri_a18_smart_terrain = {killer = true}
|
||
|
|
||
|
-- companion_attitude ={
|
||
|
-- ["army"] = "tactical",
|
||
|
-- ["bandit"] = "casual",
|
||
|
-- ["csky"] = "casual",
|
||
|
-- ["dolg"] = "tactical",
|
||
|
-- ["ecolog"] = "tactical",
|
||
|
-- ["freedom"] = "casual",
|
||
|
-- ["greh"] = "cult",
|
||
|
-- ["isg"] = "tactical",
|
||
|
-- ["killer"] = "tactical",
|
||
|
-- ["monolith"] = "cult",
|
||
|
-- ["renegade"] = "casual",
|
||
|
-- ["stalker"] = "casual",
|
||
|
-- }
|
||
|
|
||
|
local level_responses = {
|
||
|
["l03_agroprom"] = {name = "agroprom" , number = 5},
|
||
|
["l03u_agr_underground"] = {name = "agroprom_underground" , number = 5},
|
||
|
["l07_military"] = {name = "army_warehouses" , number = 5},
|
||
|
["l12_stancia_2"] = {name = "chernobyl_npp_north" , number = 5},
|
||
|
["l12_stancia"] = {name = "chernobyl_npp_south" , number = 5},
|
||
|
["l01_escape"] = {name = "cordon" , number = 5},
|
||
|
["l04_darkvalley"] = {name = "dark_valley" , number = 5},
|
||
|
["k01_darkscape"] = {name = "darkscape" , number = 5},
|
||
|
["l09_deadcity"] = {name = "dead_city" , number = 5},
|
||
|
["l11_hospital"] = {name = "deserted_hospital" , number = 5},
|
||
|
["l02_garbage"] = {name = "garbage" , number = 5},
|
||
|
["l13_generators"] = {name = "generators" , number = 5},
|
||
|
["k00_marsh"] = {name = "great_swamp" , number = 5},
|
||
|
["jupiter"] = {name = "jupiter" , number = 5},
|
||
|
["jupiter_underground"] = {name = "jupiter_underground" , number = 5},
|
||
|
["l08u_brainlab"] = {name = "lab_x-16" , number = 5},
|
||
|
["l04u_labx18"] = {name = "lab_x-18" , number = 5},
|
||
|
["l10u_bunker"] = {name = "lab_x-19" , number = 5},
|
||
|
["labx8"] = {name = "lab_x-8" , number = 5},
|
||
|
["l10_limansk"] = {name = "limansk" , number = 5},
|
||
|
["y04_pole"] = {name = "meadow" , number = 5},
|
||
|
["l12u_control_monolith"] = {name = "monolith_control_center" , number = 5},
|
||
|
["l13u_warlab"] = {name = "monolith_war_lab" , number = 5},
|
||
|
["pripyat"] = {name = "pripyat_outskirts" , number = 5},
|
||
|
["l11_pripyat"] = {name = "pripyat" , number = 5},
|
||
|
["l10_radar"] = {name = "radar" , number = 5},
|
||
|
["l10_red_forest"] = {name = "red_forest" , number = 5},
|
||
|
["l05_bar"] = {name = "rostok" , number = 5},
|
||
|
["l12u_sarcofag"] = {name = "sarcophagus" , number = 5},
|
||
|
["k02_trucks_cemetery"] = {name = "truck_cemetery" , number = 5},
|
||
|
["l06_rostok"] = {name = "wild_territory" , number = 5},
|
||
|
["l08_yantar"] = {name = "yantar" , number = 5},
|
||
|
["zaton"] = {name = "zaton" , number = 5},
|
||
|
}
|
||
|
|
||
|
local mutant_responses = {
|
||
|
bloodsucker = 5,
|
||
|
boar = 5,
|
||
|
burer = 5,
|
||
|
cat = 5,
|
||
|
chimera = 5,
|
||
|
controller = 5,
|
||
|
dog = 5,
|
||
|
flesh = 5,
|
||
|
fracture = 5,
|
||
|
gigant = 5,
|
||
|
karlik = 5,
|
||
|
lurker = 5,
|
||
|
poltergeist = 5,
|
||
|
pseudodog = 5,
|
||
|
psy_dog = 5,
|
||
|
pyrogeist = 5,
|
||
|
psysucker = 5,
|
||
|
snork = 5,
|
||
|
tushkano = 5,
|
||
|
zombi = 5,
|
||
|
mutant = 1, --default case
|
||
|
}
|
||
|
|
||
|
local stalker_responses = {
|
||
|
army = 6,
|
||
|
bandit = 5,
|
||
|
csky = 5,
|
||
|
dolg = 5,
|
||
|
ecolog = 5,
|
||
|
freedom = 5,
|
||
|
greh = 5,
|
||
|
isg = 5,
|
||
|
killer = 5,
|
||
|
monolith = 5,
|
||
|
renegade = 5,
|
||
|
stalker = 5,
|
||
|
zombied = 5,
|
||
|
}
|
||
|
|
||
|
local stalker_table = {
|
||
|
"army",
|
||
|
"bandit",
|
||
|
"csky",
|
||
|
"c_sky",
|
||
|
"clearsky",
|
||
|
"clear_sky",
|
||
|
"dolg",
|
||
|
"duty",
|
||
|
"ecolog",
|
||
|
"freedom",
|
||
|
"greh",
|
||
|
"isg",
|
||
|
"killer",
|
||
|
"loner",
|
||
|
"military",
|
||
|
"monolith",
|
||
|
"merc",
|
||
|
"renegade",
|
||
|
"sin",
|
||
|
"stalker",
|
||
|
"zombied",
|
||
|
}
|
||
|
|
||
|
local word_table = {}
|
||
|
local person_table = {}
|
||
|
|
||
|
person_table[1] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2 }
|
||
|
person_table[2] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2, [5] = 1 }
|
||
|
person_table[3] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2 }
|
||
|
person_table[4] = { [1] = 1, [2] = 2, [3] = 3, [4] = 2, [5] = 3 }
|
||
|
person_table[5] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2 }
|
||
|
person_table[6] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2, [5] = 1 }
|
||
|
person_table[7] = { [1] = 1, [2] = 1, [3] = 2, [4] = 1, [5] = 2 }
|
||
|
person_table[8] = { [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 2, [7] = 1 }
|
||
|
person_table[9] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2, [5] = 1, [6] = 2 }
|
||
|
person_table[10] = { [1] = 1, [2] = 2, [3] = 1, [4] = 2, [5] = 1, [6] = 2, [7] = 1, [8] = 2, [9] = 1, [10] = 2, [11] = 1, [12] = 2 }
|
||
|
|
||
|
local cooldowns = {}
|
||
|
local enemy_table = {}
|
||
|
local near_campfire_table = {}
|
||
|
local npc_toggle = {}
|
||
|
local squad_table = {}
|
||
|
local time_table = {}
|
||
|
|
||
|
local FirstTime_safe_area = true
|
||
|
|
||
|
local level_change = false
|
||
|
|
||
|
--====================< Function Alias >====================--
|
||
|
|
||
|
gt = game.translate_string
|
||
|
|
||
|
function beep_func()
|
||
|
xr_sound.set_sound_play(AC_ID, "pda_tips")
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function cooldown(key, duration, obj)
|
||
|
local current_time = time_global()
|
||
|
if obj and obj:id() then
|
||
|
key = key .. obj:id()
|
||
|
end
|
||
|
|
||
|
if not cooldowns[key] or current_time - cooldowns[key] > duration then
|
||
|
cooldowns[key] = current_time + duration
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
function count(base, pattern)
|
||
|
return select(2, string.gsub(base, pattern, ""))
|
||
|
end
|
||
|
|
||
|
function dump(o)
|
||
|
if type(o) == 'table' then
|
||
|
s = '{ '
|
||
|
for k,v in pairs(o) do
|
||
|
if type(k) ~= 'number' then k = '"'..k..'"' end
|
||
|
s = s .. '['..k..'] = ' .. dump(v) .. ','
|
||
|
end
|
||
|
return s .. '} '
|
||
|
else
|
||
|
return tostring(o)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function enough_people()
|
||
|
local condition = false
|
||
|
if (campfire_random == 3 and near_campfire_table[2] and near_campfire_table[3]) or (campfire_random ~= 3 and near_campfire_table[2]) then
|
||
|
condition = true
|
||
|
end
|
||
|
|
||
|
return condition
|
||
|
end
|
||
|
|
||
|
function get_random_companion()
|
||
|
local companion_table = axr_companions.list_actor_squad_by_id()
|
||
|
return level.object_by_id(companion_table[math.random(#companion_table)])
|
||
|
end
|
||
|
|
||
|
function get_time_table()
|
||
|
for a = 1, number["campfire"] do
|
||
|
word_table[a] = {}
|
||
|
time_table[a] = {}
|
||
|
word_table[a][1] = 0
|
||
|
time_table[a][1] = 0
|
||
|
for b = 2, #person_table[a] do
|
||
|
c = b - 1
|
||
|
word_table[a][b] = count(gt("st_darkasleif_campfire_".. a .. "_" .. c), " ") + 1
|
||
|
time_table[a][b] = (60*word_table[a][b])/(wpm)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function in_combat()
|
||
|
area_clear = true
|
||
|
level.iterate_nearest(db.actor:position(), 50, iterate_func_clear)
|
||
|
return not area_clear
|
||
|
end
|
||
|
|
||
|
function iterate_func_clear(obj)
|
||
|
if stored_id ~= obj:id() and obj:id() ~= 0 and is_enemy(obj, db.actor, true) then
|
||
|
area_clear = false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function is_enemy(obj, who, memory)
|
||
|
-- If obj exists
|
||
|
if not obj then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj and who are the same
|
||
|
if obj:id() == who:id() then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj is a crow
|
||
|
if (obj:clsid() == clsid.crow) then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj is not a mutant or stalker
|
||
|
if not IsMonster(obj) and not IsStalker(obj) then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj is dead
|
||
|
if not obj:alive() then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
if IsStalker(obj) and ((who:id() == 0) or (who:id() == AC_ID)) then
|
||
|
local relation = relation_registry.community_relation(character_community(obj), gameplay_disguise.get_default_comm())
|
||
|
local goodwill = relation_registry.community_goodwill(character_community(obj), db.actor:id())
|
||
|
-- If faction is not enemy and not fighting with actor
|
||
|
if not game_relations.is_factions_enemies(obj:character_community(), character_community(db.actor):sub(7)) and not xr_combat_ignore.fighting_with_actor_npcs[obj:id()] then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj is companion and not pissed off
|
||
|
if obj:has_info("npcx_is_companion") and not xr_combat_ignore.fighting_with_actor_npcs[obj:id()] then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- if not gameplay_disguise.is_actor_disguised() and relation + goodwill >= 0 and not xr_combat_ignore.fighting_with_actor_npcs[obj:id()] then
|
||
|
-- return false
|
||
|
-- end
|
||
|
|
||
|
-- If player bribe is in effect
|
||
|
if xr_bribe.at_peace(character_community(obj), gameplay_disguise.get_default_comm(), obj:position():distance_to(db.actor:position())) and not xr_combat_ignore.fighting_with_actor_npcs[obj:id()] then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If "Rostok Under Duty Control" installed
|
||
|
if gameplay_peace_zone and level.name() == "l05_bar" and character_community(db.actor):sub(7) == "army" and (character_community(obj) == "csky" or character_community(obj) == "stalker") and not xr_combat_ignore.fighting_with_actor_npcs[obj:id()] then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
-- If obj has forgotten who
|
||
|
if memory then
|
||
|
local tg = time_global()
|
||
|
local time_in_memory = tg - obj:memory_time(who)
|
||
|
if (time_in_memory < 0) then
|
||
|
if (time_in_memory < -120000) or (time_in_memory < -60000) then
|
||
|
return false
|
||
|
end
|
||
|
else
|
||
|
if (time_in_memory > 120000) or (time_in_memory > 60000) then
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if IsStalker(obj) then
|
||
|
if npc_surrendered(obj) then
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function iterate_function_campfire(obj)
|
||
|
if IsStalker(obj) and (obj.alive and obj:alive()) and sr_camp.get_current_camp(obj:position()) and obj:id() ~= 0 and not obj:has_info("npcx_is_companion") then
|
||
|
near_campfire_table[#near_campfire_table + 1] = obj:id()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function level_func()
|
||
|
local level_name = level.name()
|
||
|
if level_name and level_responses[level_name] then
|
||
|
send_tip_random(gt("st_darkasleif_level_transition_" .. level_responses[level_name].name .. math.random(level_responses[level_name].number)), show_time_long)
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function msg_func(num)
|
||
|
if not bind_campfire.get_nearby_campfire(campfire_radius_far, true) or not bind_campfire.get_nearby_campfire(campfire_radius_far, true):is_on() then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
for i = 1, #near_campfire_table do
|
||
|
local obj = near_campfire_table[i]
|
||
|
if not (obj.alive and obj:alive()) then
|
||
|
table.remove(near_campfire_table, i)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not enough_people() then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
local person = person_table[campfire_random][num]
|
||
|
if not near_campfire_table[person] then
|
||
|
local msg = utils_xml.get_color("white") .. gt("st_darkasleif_campfire_".. campfire_random .. "_" .. num)
|
||
|
news_manager.send_tip(db.actor, msg, msg_delay, nil, show_time_long*1000)
|
||
|
else
|
||
|
local obj = level.object_by_id(near_campfire_table[person])
|
||
|
send_tip(gt("st_darkasleif_campfire_".. campfire_random .. "_" .. num), obj, show_time_long)
|
||
|
end
|
||
|
|
||
|
new_num = num + 1
|
||
|
if new_num and campfire_random and new_num<=#person_table[campfire_random] and time_table[campfire_random][new_num] then
|
||
|
CreateTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_" .. new_num, time_table[campfire_random][new_num], msg_func, new_num)
|
||
|
end
|
||
|
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function send_tip(msg, sender, showtime)
|
||
|
|
||
|
if beep_before then
|
||
|
xr_sound.set_sound_play(AC_ID, "pda_tips")
|
||
|
end
|
||
|
|
||
|
local actor = db.actor
|
||
|
local news_caption = sender:character_name()
|
||
|
local news_text = clr_msg .. msg
|
||
|
local texture = sender:character_icon()
|
||
|
|
||
|
actor:give_game_news(news_caption, news_text, texture, 0, showtime, 0)
|
||
|
|
||
|
if beep_after then
|
||
|
CreateTimeEvent("CC", "Beeping" .. time_global(), showtime/1000, beep_func)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function send_tip_random(msg, showtime)
|
||
|
local rnd_companion = get_random_companion()
|
||
|
if rnd_companion and rnd_companion:id() ~= 0 then
|
||
|
send_tip(msg, rnd_companion, showtime)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function shuffle(a)
|
||
|
if type(o) == 'table' then
|
||
|
if #a == 1 then
|
||
|
return
|
||
|
elseif #a == 2 then
|
||
|
if math.random(2) == 1 then
|
||
|
a[1], a[2] = a[2], a[1]
|
||
|
end
|
||
|
elseif #a >= 3 then
|
||
|
for i = #a, 2, -1 do
|
||
|
local j = math.random(i)
|
||
|
a[i], a[j] = a[j], a[i]
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
return tostring(o)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function sound_pda()
|
||
|
xr_sound.set_sound_play(AC_ID, "pda_tips")
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function npc_surrendered(npc)
|
||
|
local st = db.storage[npc:id()]
|
||
|
return st and st.victim_surrender and st.victim_surrender >= 0 and st.victim_surrender < 65534 or false
|
||
|
end
|
||
|
|
||
|
--====================< Actions >====================--
|
||
|
|
||
|
function actor_on_before_death()
|
||
|
if not player_death_state then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
send_tip_random(gt("st_darkasleif_companion_player_death" .. math.random(number["actor_on_before_death"])), show_time)
|
||
|
end
|
||
|
|
||
|
function actor_on_feeling_anomaly(obj)
|
||
|
if not anomaly_state then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local anomaly_type
|
||
|
local anomaly_strength
|
||
|
local message
|
||
|
local sec = obj:section()
|
||
|
|
||
|
if not cooldown("Anomaly", anomaly_timer) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if string.find(sec, "electric") then
|
||
|
anomaly_type = "electric"
|
||
|
elseif string.find(sec, "chemical") then
|
||
|
anomaly_type = "chemical"
|
||
|
elseif string.find(sec, "thermal") then
|
||
|
anomaly_type = "thermal"
|
||
|
elseif string.find(sec, "gravitational") then
|
||
|
anomaly_type = "gravitational"
|
||
|
else
|
||
|
printf("Anomaly Unable to be Identified")
|
||
|
printf("Anomaly Section: %s", obj:section())
|
||
|
printf("Anomaly Name: %s", obj:name())
|
||
|
end
|
||
|
|
||
|
if string.find(sec, "strong") then
|
||
|
anomaly_strength = "strong"
|
||
|
elseif string.find(sec, "normal") then
|
||
|
anomaly_strength = "normal"
|
||
|
elseif string.find(sec, "weak") then
|
||
|
anomaly_strength = "weak"
|
||
|
end
|
||
|
|
||
|
if anomaly_type and anomaly_strength then
|
||
|
message = gt("st_darkasleif_actor_on_feeling_anomaly_" .. anomaly_type .. math.random(number["anomaly_part_1"])) .. " " .. gt("st_darkasleif_actor_on_feeling_anomaly_" .. anomaly_strength .. math.random(number["anomaly_part_2"]))
|
||
|
elseif anomaly_type then
|
||
|
message = gt("st_darkasleif_actor_on_feeling_anomaly_" .. anomaly_type .. math.random(number["anomaly_part_1"]))
|
||
|
end
|
||
|
|
||
|
if message then
|
||
|
send_tip_random(message, show_time)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_first_update()
|
||
|
level_change = true
|
||
|
end
|
||
|
|
||
|
function actor_on_interaction(typ, obj, name)
|
||
|
if (typ == "anomalies") and (name == "psi_storm_start") and psistorm_state then
|
||
|
send_tip_random(gt("st_darkasleif_on_before_psi_storm" .. math.random(number["psi_storm"])), show_time)
|
||
|
elseif (typ == "anomalies") and (name == "emission_start") and emission_state then
|
||
|
send_tip_random(gt("st_darkasleif_on_before_surge" .. math.random(number["emission"])), show_time)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_update()
|
||
|
if not campfire_state and not random_state and not safe_area_state then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
n = n + 1
|
||
|
if n ~= 100 then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
n = 1
|
||
|
if random_state and math.random(10000*random_chance) == 1 and not in_combat() then
|
||
|
send_tip_random(gt("st_darkasleif_random" .. math.random(number["random"])), show_time)
|
||
|
end
|
||
|
|
||
|
local tg = time_global()
|
||
|
if not tg_previous then
|
||
|
tg_previous = tg
|
||
|
end
|
||
|
|
||
|
get_time_table()
|
||
|
if not bind_campfire.get_nearby_campfire(campfire_radius_far, true) or not bind_campfire.get_nearby_campfire(campfire_radius_far, true):is_on() then
|
||
|
if campfire_random and new_num then
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_" .. new_num)
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_1")
|
||
|
elseif campfire_random then
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_1")
|
||
|
end
|
||
|
|
||
|
timer = nil
|
||
|
near_campfire_table = {}
|
||
|
return
|
||
|
elseif not bind_campfire.get_nearby_campfire(campfire_radius, true) or not bind_campfire.get_nearby_campfire(campfire_radius, true):is_on() then
|
||
|
timer = nil
|
||
|
near_campfire_table = {}
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if in_combat() then
|
||
|
if campfire_random and new_num then
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_" .. new_num)
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_1")
|
||
|
elseif campfire_random then
|
||
|
RemoveTimeEvent("CC" .. campfire_random, "Campfire_" .. campfire_random .. "_1")
|
||
|
end
|
||
|
|
||
|
timer = nil
|
||
|
near_campfire_table = {}
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if delay and (tg <= delay) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
delay = nil
|
||
|
if not timer then
|
||
|
timer = tg + math.random(min_timer,max_timer)
|
||
|
elseif tg >= timer then
|
||
|
campfire_obj = bind_campfire.get_nearby_campfire(campfire_radius, false)
|
||
|
level.iterate_nearest(campfire_obj:position(), 3, iterate_function_campfire)
|
||
|
shuffle(near_campfire_table)
|
||
|
campfire_random = math.random(number["campfire"])
|
||
|
if (last_tale ~= campfire_random) and enough_people() and bind_campfire.get_nearby_campfire(campfire_radius_far, true) and bind_campfire.get_nearby_campfire(campfire_radius_far, true):is_on() and new_num and campfire_random and new_num<=#person_table[campfire_random] and time_table[campfire_random][1] then
|
||
|
CreateTimeEvent("CC" .. 1, "Campfire_" .. campfire_random .. "_" .. 1, 0, msg_func, 1)
|
||
|
last_tale = campfire_random
|
||
|
end
|
||
|
|
||
|
timer = nil
|
||
|
delay = tg + math.random(min_delay,max_delay)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_weapon_jammed()
|
||
|
if not jammed_state then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
send_tip_random(gt("st_darkasleif_jammed" .. math.random(number["weapon_jammed"])), show_time)
|
||
|
end
|
||
|
|
||
|
function actor_on_weapon_reload()
|
||
|
if not reload_state or not (math.random(100) <= reload_chance) or not in_combat() then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
send_tip_random(gt("st_darkasleif_reload" .. math.random(number["weapon_reload"])), show_time)
|
||
|
end
|
||
|
|
||
|
function monster_on_death_callback(obj)
|
||
|
id = obj:id()
|
||
|
stored_id = obj:id()
|
||
|
if enemy_table[id] then
|
||
|
table.remove(enemy_table, id)
|
||
|
npc_was_enemy = true
|
||
|
else
|
||
|
npc_was_enemy = false
|
||
|
end
|
||
|
|
||
|
if clear_state and npc_was_enemy and not in_combat() and area_clear then
|
||
|
send_tip_random(gt("st_darkasleif_clear" .. math.random(number["clear"])), show_time)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function npc_on_before_hit(npc,shit,bone_id,flags)
|
||
|
if (bone_id <= 14) or (bone_id >= 19) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
npc_stored = npc
|
||
|
end
|
||
|
|
||
|
function npc_on_death_callback(obj)
|
||
|
local id = obj:id()
|
||
|
stored_id = obj:id()
|
||
|
if enemy_table[id] then
|
||
|
table.remove(enemy_table, id)
|
||
|
npc_was_enemy = true
|
||
|
else
|
||
|
npc_was_enemy = false
|
||
|
end
|
||
|
|
||
|
if not npc_death_state and not npc_death_comment_state and not clear_state then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if npc_death_state and obj:has_info("npcx_is_companion") then
|
||
|
send_tip(gt("st_darkasleif_npc_on_death_callback" .. math.random(number["npc_on_death"])), obj, show_time)
|
||
|
if npc_toggle[id] then
|
||
|
table.remove(npc_toggle, id)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if npc_death_comment_state and obj:has_info("npcx_is_companion") then
|
||
|
send_tip_random(gt("st_darkasleif_companion_death" .. math.random(number["companion_death"])), show_time)
|
||
|
end
|
||
|
|
||
|
if clear_state and npc_was_enemy and not in_combat() then
|
||
|
send_tip_random(gt("st_darkasleif_clear" .. math.random(number["clear"])), show_time)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function npc_on_hit_callback(npc,amount,local_direction,who,bone_index)
|
||
|
if not npc_stored or not who:has_info("npcx_is_companion") or (who:id() == 0) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
send_tip(gt("st_darkasleif_headshot" .. math.random(number["headshot"])), who, show_time)
|
||
|
npc_stored = nil
|
||
|
end
|
||
|
|
||
|
function npc_on_update(npc)
|
||
|
if not npc_health_state or not npc:has_info("npcx_is_companion") or npc:id() == 0 then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local id = npc:id()
|
||
|
local health = npc.health
|
||
|
if health < 0.3 and not npc_toggle[id] then
|
||
|
send_tip(gt("st_darkasleif_near_death" .. math.random(number["near_death"])), npc, show_time)
|
||
|
npc_toggle[id] = true
|
||
|
elseif health >= 0.5 and npc_toggle[id] then
|
||
|
npc_toggle[id] = false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function on_enemy_eval(obj, enemy)
|
||
|
local id = enemy:id()
|
||
|
if not enemy_state or enemy_table[id] or not obj:has_info("npcx_is_companion") or not is_enemy(enemy, db.actor, false) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
enemy_table[id] = true
|
||
|
local squad_enemy = get_object_squad(enemy)
|
||
|
if squad_enemy then
|
||
|
local squad_id = squad_enemy.id
|
||
|
if squad_table[squad_id] then
|
||
|
return
|
||
|
else
|
||
|
squad_table[squad_id] = enemy:position()
|
||
|
end
|
||
|
|
||
|
squad_count = 0
|
||
|
for k in squad_enemy:squad_members() do
|
||
|
local se_obj = k.object or k.id and sim:object(k.id)
|
||
|
if se_obj.position:distance_to(squad_table[squad_id]) < 25 then
|
||
|
squad_count = squad_count + 1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local message
|
||
|
if IsStalker(enemy) then
|
||
|
local faction = enemy:character_community()
|
||
|
if not stalker_responses[faction] then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
message = gt("st_darkasleif_short_".. faction .. math.random(stalker_responses[faction]))
|
||
|
|
||
|
elseif IsMonster(enemy) then
|
||
|
local sec = enemy:section()
|
||
|
name = "mutant"
|
||
|
if string.find(sec, "pseudodog") then
|
||
|
name = "pseudodog"
|
||
|
elseif string.find(sec, "psy_dog") then
|
||
|
name = "psy_dog"
|
||
|
elseif string.find(sec, "zat_b18_dog_little") then
|
||
|
return
|
||
|
elseif string.find(sec, "dog") then
|
||
|
name = "dog"
|
||
|
elseif string.find(sec, "polter") then
|
||
|
name = "poltergeist"
|
||
|
elseif string.find(sec, "pyro") then
|
||
|
name = "pyrogeist"
|
||
|
else
|
||
|
for key, _ in pairs(mutant_responses) do
|
||
|
if string.find(sec, key) then
|
||
|
name = key
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not mutant_responses[name] then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if name == "mutant" then
|
||
|
for _, val in pairs(stalker_table) do
|
||
|
if string.find(sec, val) then
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
message = gt("st_darkasleif_short_" .. name .. math.random(mutant_responses[name]))
|
||
|
|
||
|
if name == "mutant" then
|
||
|
printf("Enemy Unable to be Identified")
|
||
|
printf("Enemy Section: %s", obj:section())
|
||
|
printf("Enemy Name: %s", obj:name())
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not message then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if squad_enemy and squad_count > 1 then
|
||
|
message = message .. " " .. gt("st_darkasleif_multiple"..math.random(number["part_2"]))
|
||
|
end
|
||
|
|
||
|
if message then
|
||
|
send_tip(message, obj, show_time)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function on_key_press()
|
||
|
if level_change then
|
||
|
level_change = false
|
||
|
local level_name = level.name()
|
||
|
if not level_state or not level_name or not (math.random(100) <= level_chance) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
CreateTimeEvent("CC", "Printing Level Response", 3, level_func)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--====================< Callbacks >====================--
|
||
|
|
||
|
function on_game_start()
|
||
|
RegisterScriptCallback("actor_on_before_death", actor_on_before_death)
|
||
|
RegisterScriptCallback("actor_on_feeling_anomaly", actor_on_feeling_anomaly)
|
||
|
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||
|
RegisterScriptCallback("actor_on_interaction", actor_on_interaction)
|
||
|
RegisterScriptCallback("actor_on_update", actor_on_update)
|
||
|
RegisterScriptCallback("actor_on_weapon_jammed", actor_on_weapon_jammed)
|
||
|
RegisterScriptCallback("actor_on_weapon_reload", actor_on_weapon_reload)
|
||
|
RegisterScriptCallback("monster_on_death_callback", monster_on_death_callback)
|
||
|
RegisterScriptCallback("npc_on_before_hit", npc_on_before_hit)
|
||
|
RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
|
||
|
RegisterScriptCallback("npc_on_hit_callback", npc_on_hit_callback)
|
||
|
RegisterScriptCallback("npc_on_update", npc_on_update)
|
||
|
RegisterScriptCallback("on_enemy_eval", on_enemy_eval)
|
||
|
RegisterScriptCallback("on_game_load", load_settings)
|
||
|
RegisterScriptCallback("on_key_press", on_key_press)
|
||
|
RegisterScriptCallback("on_option_change", load_settings)
|
||
|
end
|