Divergent/mods/Mugging Squads/gamedata/scripts/demonized_mugging_squads.sc...

1733 lines
50 KiB
Plaintext
Raw Normal View History

-- demonized Mugging Squads
-- Generated with AnomalyModCreator
-- ; Original description by billwa
-- ; Basically they yell a quote, surround you and a guy comes up to talk and you have 3 dialogue [ptions. Pay mugging fee, get forced into kidnapping and the classic resist.
-- ; Obviously when if you start shooting them before you're they're able to open up their yappers, all bets are off and it's a normal gun fight
-- ; Monolith and sin will try kidnapping you always, no mugging. If you agree, it should bring you back to a base where all of your gear is removed until you convert and you have two options before you do, agree or fight, but lmao with no gear.
-- ; It is entirely random and happens anywhere on the map except interiors like labs or main
-- For the give me stuff part, it is possible to have the most common outcome being money/one item and then a rare chance of them taking all your shit
-- Oh, and playing a sound upon mugging, can you make it like only a 50% chance that it happens
-- Settings
delaySpawn = 30 -- real seconds
delayState = 5 -- real seconds
local id = 70000
local idOffset = 0
local gizmos = {
sphereSquad = nil,
}
local debugMode = false
local function printf(s, ...)
if debugMode then
_G.printf(s, ...)
end
return string.format(s, ...)
end
local function print_tip(...)
if debugMode and _G.print_tip then
return _G.print_tip(...)
end
end
local function print_err(s, ...)
s = "!" .. s
if debugMode and _G.print_tip then
_G.print_tip(s, ...)
else
_G.printf(s, ...)
end
return string.format(s, ...)
end
local gizmosInitialized = false
function initializeGizmos()
if gizmosInitialized then return end
gizmosInitialized = true
gizmos.sphereSquad = debug_render.add_object(id + idOffset, DBG_ScriptObject.sphere):cast_dbg_sphere()
end
function reset(gizmosArr, force)
if debugMode or force then
if gizmosArr then
for i = 1, #gizmosArr do
local gizmo = gizmosArr[i]
if gizmos[gizmo] then
local v = gizmos[gizmo]
if type(v) == "table" then
for i = 1, #v do
local p = v[i]
p.visible = false
end
else
v.visible = false
end
end
end
else
for k, v in pairs(gizmos) do
if type(v) == "table" then
for i = 1, #v do
local p = v[i]
p.visible = false
end
else
v.visible = false
end
end
end
end
end
function toggleDebugMode()
debugMode = not debugMode
if debugMode then
initializeGizmos()
else
reset(nil, true)
end
end
-- MCM
function load_defaults()
local t = {}
local op = demonized_mugging_squads_mcm.op
for i, v in ipairs(op.gr) do
if v.def ~= nil then
t[v.id] = v.def
end
end
return t
end
settings = load_defaults()
function load_settings()
settings = load_defaults()
if ui_mcm then
for k, v in pairs(settings) do
settings[k] = ui_mcm.get("demonized_mugging_squads/" .. k)
end
end
return settings
end
local function roundVec(v, num)
return vector():set(
round_idp(v.x, num),
round_idp(v.y, num),
round_idp(v.z, num)
)
end
local function shuffle(t)
local random = math.random
for i = #t, 2, -1 do
local j = random(i)
t[i], t[j] = t[j], t[i]
end
end
activeSquads = {} -- current active mugging squads
local lastSpawnTime -- the last time a mugging squad has been spawned
local currentLevelSmarts = {}
local linkedLevelSmarts = {}
squadStages = {
approach = 1,
talk = 2,
done = 3,
}
--====================================< Utilities >====================================--
function addToActiveSquads(squad)
activeSquads[squad.id] = {
name = squad:section_name(),
stage = squadStages.approach
}
end
function setSquadStage(squad, num)
activeSquads[squad.id].stage = num
end
function invalidateSquad(squad)
print_tip("-demonized_mugging_squads squad %s is invalidated", squad.id)
activeSquads[squad.id] = nil
end
function setSquadAsEnemy(squad)
print_tip("-demonized_mugging_squads squad %s is enemy!", squad.id)
if squad.force_set_goodwill then
squad:force_set_goodwill(-5000, db.actor)
end
for k in squad:squad_members() do
local obj = level.object_by_id(k.id)
local se_obj = alife_object(k.id)
if obj then
obj:set_relation(game_object.enemy, db.actor)
obj:force_set_goodwill(-5000, db.actor)
end
if se_obj then
se_obj:force_set_goodwill(-5000, db.actor)
end
end
end
function getFactions()
local factions = {}
for k, v in pairs(settings) do
if k:find("^muggingFactionsCanSpawn_") and v == true then
local faction = k:gsub("^muggingFactionsCanSpawn_", "")
factions[#factions + 1] = faction
end
end
return factions
end
function isFactionsEnemies(f1, f2)
return not game_relations.is_factions_friends(f1, f2)
end
function getSafeLevels()
return demonized_mugging_squads_options.safe_levels
end
function getSafeSmarts()
return demonized_mugging_squads_options.safe_smarts
end
function getFactionSquads()
local squads = {}
for k, v in pairs(demonized_mugging_squads_options.faction_squads) do
squads[k] = str_explode(v, ",")
end
return squads
end
function getDangerRanks()
return demonized_mugging_squads_options.danger_ranks
end
function getDangerReputations()
return demonized_mugging_squads_options.danger_reputations
end
function trySpawn()
-- gather factions
local enemy_factions = {}
local factions = getFactions()
for i, faction in ipairs(factions) do
if settings.allowSameSquads or get_actor_true_community() ~= faction then
if settings.allowFriendlySquads or isFactionsEnemies(get_actor_true_community(), faction) then
enemy_factions[#enemy_factions + 1] = faction
end
end
end
if is_empty(enemy_factions) then
print_err("-demonized_mugging_squads.trySpawn / no faction is possible to spawn, skip")
return
end
local picked_squad = enemy_factions[math.random(#enemy_factions)]
-- gather smarts
local spawn_smrts = {}
for name, smart in pairs(currentLevelSmarts) do
local dist = smart.position:distance_to_sqr(db.actor:position())
local spawnDistance = settings.spawnDistance * settings.spawnDistance
if dist > spawnDistance then
local smrt = SIMBOARD.smarts[smart.id]
if smrt then
local pass = true
for k, v in pairs(smrt.squads) do
local squad = alife_object(k)
if squad and squad.current_target_id and squad.current_target_id == smart.id and not squad:get_script_target() then
pass = false
break
end
end
if pass then
-- print_tip("-demonized_mugging_squads.trySpawn / [%s] is a possible smart found, distance: %s", name, dist)
spawn_smrts[#spawn_smrts+1] = name
end
end
end
end
if #spawn_smrts > 0 then
local squads = getFactionSquads()[picked_squad]
if is_empty(squads) then
print_err("-demonized_mugging_squads.trySpawn / no squad can be found for faction %s, skip", picked_squad)
return
end
local squad = squads[math.random(#squads)]
local spawn_smrt = spawn_smrts[math.random(#spawn_smrts)]
local level = alife():level_name(game_graph():vertex(alife_object(SIMBOARD.smarts_by_names[spawn_smrt].id).m_game_vertex_id):level_id())
print_err("-demonized_mugging_squads.trySpawn / [%s] has been spawned in [%s], level [%s]", squad, spawn_smrt, level)
-- Spawn squad and target the player
local sq = SIMBOARD:create_squad(SIMBOARD.smarts_by_names[spawn_smrt], squad)
sq.scripted_target = "actor"
sq.rush_to_target = true
addToActiveSquads(sq)
lastSpawnTime = game.get_game_time()
else
print_err("-demonized_mugging_squads.trySpawn / no smart can be found to spawn squad of %s", picked_squad)
end
end
function attack(state, rush)
for k, v in pairs(activeSquads) do
local se = alife_object(k)
if se and se:section_name() == v.name then
se.scripted_target = state and v.stage == squadStages.approach and "actor" or nil
se.rush_to_target = rush == true and v.stage == squadStages.approach
print_tip("-demonized_mugging_squads. - target: %s - rush: %s, %s",
se.scripted_target,
se.rush_to_target,
(function()
local commander = se:commander_id() and level.object_by_id(se:commander_id())
if commander then
return ("dist %s"):format(commander:position():distance_to(db.actor:position()))
else
local se_obj = alife_object(se:commander_id())
if se_obj then
local actor_level = level.name()
local squad_level = alife():level_name(game_graph():vertex(se_obj.m_game_vertex_id):level_id())
return ("level %s, actor level %s"):format(squad_level, actor_level)
else
return "failed to get distance, no commander se_obj"
end
end
end)()
)
end
end
end
function updateTalk()
if not load_var(db.actor, "force_all_talk", false) then
print_err("-demonized_mugging_squads actor not talking, updateTalk stop")
UnregisterScriptCallback("actor_on_update", updateTalk)
return
end
if not db.actor:is_talking() then
print_err("-demonized_mugging_squads actor stop talking, force_all_talk false and updateTalk stop")
save_var(db.actor, "force_all_talk", false)
UnregisterScriptCallback("actor_on_update", updateTalk)
return
end
end
function forceTalk(npc)
if not npc:is_talking() then
local meet = db.storage[npc:id()].meet
if meet then
local use = meet.meet_manager.use
meet.meet_manager.use = "true"
end
npc:enable_talk()
npc:set_start_dialog("muggingDialogGiveMeYourShit")
RegisterScriptCallback("actor_on_update", updateTalk)
save_var(db.actor, "force_all_talk", true)
npc:allow_break_talk_dialog(false)
db.actor:run_talk_dialog(npc, true)
end
end
--====================================< Callbacks >====================================--
function spawnTimer()
--printf("-mugging_squads.spawnTimer called")
ResetTimeEvent("demonized_mugging_squads", "mugging_squad_spawn", delaySpawn)
local num = settings.maxActiveSquads
-- -- check rank
-- local rank = ranks.get_obj_rank_name(db.actor)
-- if getDangerRanks()[rank] then
-- num = num + getDangerRanks()[rank]
-- end
-- -- check reputaion
-- local reputaion = utils_obj.get_reputation_name(db.actor:character_reputation())
-- if getDangerReputations()[reputaion] then
-- num = num + getDangerReputations()[reputaion]
-- end
-- -- ignore if rank or rep doesn't meet the requirements
-- if (num == 0) then
-- return false
-- end
-- read date
local current_time = game.get_game_time()
if not lastSpawnTime then
lastSpawnTime = current_time
return false
end
-- ignore if timer hasn't been reached yet
local delay = settings.delayBetweenSpawns * 60 * 60
if current_time:diffSec(lastSpawnTime) < delay then
return false
end
-- try to spawn if there isn't enough mugging squads
if size_table(activeSquads) < num then
print_tip("-demonized_mugging_squads.spawnTimer, is valid to spawn")
trySpawn()
end
return false
end
function isSquadCommanderVisible(squad)
local obj = squad:commander_id() and level.object_by_id(squad:commander_id())
if obj then
if obj:position():distance_to_sqr(db.actor:position()) < 50^2 then
return true
end
local screenpos = game.world2ui(obj)
if screenpos.x > 0 and screenpos.x < 1024 and screenpos.y > 0 and screenpos.y < 768 then
if db.actor:see(obj) then
return true
end
end
end
return false
end
function addMoreMembersToSquad(squad, num)
-- get squad positions
local commander = alife_object(squad:commander_id())
local pos = commander.position
local lvid = commander.m_level_vertex_id
local gvid = commander.m_game_vertex_id
local g_obj = level.object_by_id(squad:commander_id())
-- Spawn procedure when game object is available
if g_obj then
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, game_object is available %s : %s", squad:name(), g_obj:name())
-- get npc to spawn section
local random_spawn = ini_sys:r_string_ex(squad:section_name(), "npc_random")
if not random_spawn then
print_err("-demonized_mugging_squads.addMoreMembersToSquad, cant add members to %s, no random_spawn", squad:name())
return
end
random_spawn = parse_names(random_spawn)
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, add members to %s : %s", squad:name(), num)
for i = 1, num do
local random_sec = random_spawn[math.random(1, #random_spawn)]
-- add and setup new npc
local sim = alife()
local pos = g_obj:position()
local lvid = g_obj:level_vertex_id()
local gvid = g_obj:game_vertex_id()
local obj = alife_create(random_sec, pos, lvid, gvid)
if obj then
squad:register_member(obj.id)
local actor = sim:actor()
if (simulation_objects.is_on_the_same_level(obj, actor) and pos:distance_to_sqr(actor.position) <= sim:switch_distance()^2) then
db.spawned_vertex_by_id[obj.id] = lvid
end
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, spawned member %s of %s", random_sec, squad:name())
else
print_err("-demonized_mugging_squads.addMoreMembersToSquad, failed to spawn member %s of %s", random_sec, squad:name())
end
end
-- When isn't
else
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, game_object is not available, use server object : %s", squad:name())
-- get squad smart
local squad_smart = squad.smart_id and SIMBOARD.smarts[squad.smart_id].smrt
if not squad_smart then
print_err("-demonized_mugging_squads.addMoreMembersToSquad, cant add members to %s, no smart", squad:name())
return
end
-- get npc to spawn section
local random_spawn = ini_sys:r_string_ex(squad:section_name(), "npc_random")
if not random_spawn then
print_err("-demonized_mugging_squads.addMoreMembersToSquad, cant add members to %s, no random_spawn", squad:name())
return
end
random_spawn = parse_names(random_spawn)
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, add members to %s : %s", squad:name(), num)
for i = 1, num do
local random_sec = random_spawn[math.random(1, #random_spawn)]
-- add and setup new npc
local new_member_id = squad:add_squad_member(random_sec, pos, lvid, gvid)
local se_obj = new_member_id and alife_object(new_member_id)
if (se_obj) then
print_tip("-demonized_mugging_squads.addMoreMembersToSquad, spawned member %s of %s", random_sec, squad:name())
squad_smart:register_npc(se_obj)
SIMBOARD:setup_squad_and_group(se_obj)
else
print_err("-demonized_mugging_squads.addMoreMembersToSquad, failed to spawn member %s of %s", random_sec, squad:name())
end
end
squad:update()
end
end
-- Simplified parsing of condition list
defaultUseCond = "{=is_wounded} false, {!is_squad_commander} false, {=actor_enemy} false, {=has_enemy} false, {=dist_to_actor_le(3)} true, false"
local function parseConditionTable(npc, conditions)
for _, v in ipairs(conditions) do
local functions = v[2]
local val = v[1]
if functions then
for _, func in ipairs(functions) do
local f = func[1]
local args = func[3] or {}
local requiredResult = func[2] == 3
if xr_conditions[f] then
local result = not not xr_conditions[f](db.actor, npc, args)
local r = result == requiredResult
if r then
return val
end
end
end
else
return val
end
end
return false
end
function parseCondition(npc, condString)
local conditions = xr_logic.parse_condlist(npc, nil, nil, condString)
local result = parseConditionTable(npc, conditions)
if result == "true" then
result = true
elseif result == "false" then
result = false
end
return result
end
-- Check if mugging squad is still valid for mugging
function isValidActiveSquad(activeSquadId, activeSquadValue)
local id = activeSquadId
local v = activeSquadValue
local se = alife_object(id)
local squad = se
if not se then return false end
if se:section_name() ~= v.name then return false end
if squad:npc_count() == 0 then return false end
local allDead = true
for k in squad:squad_members() do
local npc_se = alife_object(k.id)
if npc_se and npc_se:alive() then
allDead = false
break
end
end
if allDead then return false end
return true
end
function stateTimer()
ResetTimeEvent("demonized_mugging_squads", "mugging_squad_state", delayState)
-- clean
local currentActorStage
for id, v in pairs(activeSquads) do
local se = alife_object(id)
local squad = se
if not isValidActiveSquad(id, v) then
print_tip("-demonized_mugging_squads.stateTimer cleaning [%s] | section: %s - actual: %s", id, v.name, se and se:section_name())
invalidateSquad(se)
else
-- If squad is one man -- fill them up to random 2-5
if squad:npc_count() <= 1 and not isSquadCommanderVisible(squad) and v.stage == squadStages.approach then
local min = 3 - squad:npc_count()
local max = 4
addMoreMembersToSquad(squad, math.random(min, max))
end
if v.stage == squadStages.talk then
currentActorStage = squadStages.talk
elseif v.stage == squadStages.done then
if not (
simulation_objects.is_on_the_same_level(alife():actor(), squad)
and isSquadCommanderVisible(squad)
) then
SIMBOARD:remove_squad(squad)
invalidateSquad(squad)
end
end
end
end
if is_empty(activeSquads) then
return false
end
-- Don't attack if actor is talking to mugging squad
if currentActorStage == squadStages.talk then
attack(false, false)
return false
end
-- don't attack if actor is in a safe level
if getSafeLevels()[level.name()] then
attack(false, false)
return false
end
-- don't attack if actor is in a safe smart
local pos = db.actor:position()
local se_actor = alife():actor()
local safeSmarts = getSafeSmarts()
for name, smart in pairs(currentLevelSmarts) do
if safeSmarts[name] then
local dist = smart.position:distance_to_sqr(pos)
local safeSmartDistance = settings.safeSmartDistance * settings.safeSmartDistance
if dist < safeSmartDistance then
attack(false, false)
return false
end
end
end
print_tip("-demonized_mugging_squads player is vulnerable to mugging, attack")
attack(true, true)
return false
end
function load_state(m_data)
local demonized_mugging_squads = m_data.demonized_mugging_squads
if not demonized_mugging_squads then
return
end
if DEV_DEBUG and demonized_mugging_squads then
for k, v in pairs(demonized_mugging_squads) do
print_err("-demonized_mugging_squads # LOADING: Mugging Squad | [%s]: %s", k, v)
end
end
lastSpawnTime = demonized_mugging_squads.last_spawn_time and utils_data.CTime_from_table(demonized_mugging_squads.last_spawn_time) or game.get_game_time()
activeSquads = demonized_mugging_squads.active_squads or {}
for k, v in pairs(activeSquads) do
if type(v) ~= "table" then
activeSquads[k] = {
name = v,
stage = 1
}
end
end
end
function save_state(m_data)
if not lastSpawnTime then
return
end
local demonized_mugging_squads = {}
demonized_mugging_squads.last_spawn_time = utils_data.CTime_to_table(lastSpawnTime)
demonized_mugging_squads.active_squads = activeSquads or {}
if DEV_DEBUG then
for k, v in pairs(demonized_mugging_squads) do
print_err("-demonized_mugging_squads # SAVING: Mugging Squad | [%s]: %s", k, v)
end
end
m_data.demonized_mugging_squads = demonized_mugging_squads
end
function server_entity_on_unregister(se_obj, typ)
activeSquads[se_obj.id] = nil
end
function actor_on_first_update()
if debugMode then
initializeGizmos()
end
for name, smart in pairs(SIMBOARD.smarts_by_names) do
if smart and simulation_objects.is_on_the_same_level(alife():actor(), smart) then
currentLevelSmarts[name] = smart
end
if smart and simulation_objects.is_on_the_linked_level(alife():actor(), smart) then
linkedLevelSmarts[name] = smart
end
end
CreateTimeEvent("demonized_mugging_squads", "mugging_squad_spawn", delaySpawn, spawnTimer)
CreateTimeEvent("demonized_mugging_squads", "mugging_squad_state", delayState, stateTimer)
end
function squad_on_update(squad)
local id = squad.id
if not activeSquads[id] then return end
local commander = squad:commander_id() and level.object_by_id(squad:commander_id())
local requiredGoodwill = 0
if commander then
if debugMode then
gizmos.sphereSquad.visible = true
gizmos.sphereSquad.color = fcolor():set(1, 0, 0, 1)
local scale_mat = matrix():identity():scale(0.1, 0.1, 0.1)
local pos_mat = matrix():translate(commander:position())
local mat = matrix():mul(pos_mat, scale_mat)
gizmos.sphereSquad.matrix = mat
end
requiredGoodwill = math.max(0, -relation_registry.community_relation(character_community(commander), character_community(db.actor)))
-- print_tip("setting goodwill to %s", requiredGoodwill)
end
if squad.force_set_goodwill then
squad:force_set_goodwill(requiredGoodwill, db.actor)
end
for k in squad:squad_members() do
local obj = level.object_by_id(k.id)
local se_obj = alife_object(k.id)
if obj then
obj:set_relation(game_object.neutral, db.actor)
obj:force_set_goodwill(requiredGoodwill, db.actor)
end
if se_obj then
se_obj:force_set_goodwill(requiredGoodwill, db.actor)
end
end
if activeSquads[id].stage == squadStages.approach then
local commander = squad:commander_id() and level.object_by_id(squad:commander_id())
if commander then
local condition = parseCondition(commander, defaultUseCond)
if condition then
print_err("-demonized_mugging_squads npc %s start to talk, pos %s, actor %s, distance %s",
commander:id(),
utils_data.vector_to_string(roundVec(commander:position())),
utils_data.vector_to_string(roundVec(db.actor:position())),
commander:position():distance_to_sqr(db.actor:position())
)
attack(false, false)
setSquadStage(squad, squadStages.talk)
if math.random() < settings.talkChance then
xr_sound.stop_sounds_by_id(commander:id())
xr_sound.set_sound_play(commander:id(), "mugging_hello")
end
forceTalk(commander)
end
end
end
end
function npc_on_before_hit(npc, shit, bone_id, flags)
if shit.draftsman:id() ~= AC_ID then return end
local squad = get_object_squad(npc)
if not squad then return end
if not activeSquads[squad.id] then return end
invalidateSquad(squad)
setSquadAsEnemy(squad)
end
function on_game_start()
RegisterScriptCallback("save_state", save_state)
RegisterScriptCallback("load_state", load_state)
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
RegisterScriptCallback("server_entity_on_unregister", server_entity_on_unregister)
RegisterScriptCallback("squad_on_update", squad_on_update)
RegisterScriptCallback("npc_on_before_hit", npc_on_before_hit)
RegisterScriptCallback("actor_on_first_update", load_settings)
RegisterScriptCallback("on_option_change", load_settings)
end
-- Scheme
actid = 188125
evaid = 188125
class "evaluator_muggingSquadBehaviour" (property_evaluator)
function evaluator_muggingSquadBehaviour:__init(npc, name, storage) super (nil, name)
self.st = storage
end
function evaluator_muggingSquadBehaviour:evaluate()
local npc = self.object
if not npc:alive() then
return false
end
if IsWounded(npc) then
return false
end
if not db.actor then
return false
end
if not db.actor:alive() then
return false
end
local squad = get_object_squad(npc)
if not squad then return false end
if not activeSquads[squad.id] then return false end
local sq = activeSquads[squad.id]
if sq.stage == squadStages.talk or sq.stage == squadStages.done then
return true
end
return false
end
class "action_muggingSquadBehaviour" (action_base)
function action_muggingSquadBehaviour:__init (npc, name, storage)
super(nil, name)
self.st = storage
end
function action_muggingSquadBehaviour:initialize()
action_base.initialize(self)
local npc = self.object
self.squad = get_object_squad(npc)
self.movement_type = npc:movement_type()
self.body_state = npc:body_state()
self.mental_state = npc:mental_state()
self.path = npc:path_type()
self.isCommander = self.squad:commander_id() and level.object_by_id(self.squad:commander_id()) and level.object_by_id(self.squad:commander_id()) == npc:id()
local activeMembers = {}
local squad = self.squad
for k in squad:squad_members() do
local obj = level.object_by_id(k.id)
if obj then
table.insert(activeMembers, obj)
end
end
self.squadMembersCount = 0
self.squadMemberNum = 1
for i, obj in ipairs(activeMembers) do
self.squadMembersCount = self.squadMembersCount + 1
if obj:id() == npc:id() then
self.squadMemberNum = self.squadMembersCount
end
end
npc:set_desired_position()
npc:set_desired_direction()
self.first_update = true
end
function action_muggingSquadBehaviour:validate(vid)
local npc = self.object
return vid and vid < 4294967295 and vid >= 0 -- Is existing lvid
and npc:accessible(vid) -- Accessible by npc
and vid ~= npc:level_vertex_id() -- Not current npc lvid
and not db.used_level_vertex_ids[vid] -- Not taken by another entity
and math.abs(level.vertex_position(vid).y - npc:position().y) < 2 -- Not higher or lower from npc position than this threshold so npcs wont run vertically
end
function action_muggingSquadBehaviour:lmove(vid)
-- Return if not valid
if not self:validate(vid) then
return
end
local npc = self.object
local st = self.st
if st.vid then
db.used_level_vertex_ids[st.vid] = nil
st.vid = nil
end
db.used_level_vertex_ids[vid] = npc:id()
npc:set_dest_level_vertex_id(vid)
st.vid = vid
return vid
end
function action_muggingSquadBehaviour:findPos()
local npc = self.object
local id = npc:id()
local base_point = npc:level_vertex_id()
local base_point_pos = npc:position()
local tries = 10
for i = 1, tries do
-- Set new lvid and direction
-- Commander stays at the front and talks
-- Member #2 goes to the left of player
-- Member #3 goes to the right
-- Additional members surround player from the front
local dir = db.actor:direction()
if self.squadMemberNum == 2 then
dir = vector_rotate_y(dir, math.random(-90, -60))
elseif self.squadMemberNum == 3 then
dir = vector_rotate_y(dir, math.random(60, 90))
else
dir = vector_rotate_y(dir, random_choice(math.random(-55, -15), math.random(15, 55)))
end
dir:normalize()
local pos = db.actor:position():mad(dir, 2)
local dist = pos:distance_to(base_point_pos)
dir = vector():set(pos):sub(base_point_pos):normalize()
for radius = dist, 1, -1 do
local lvid = level.vertex_in_direction(base_point, dir, radius)
if self:validate(lvid) then
self.initial_dir = level.vertex_position(lvid):sub(npc:position()):normalize()
return self:lmove(lvid)
end
end
end
end
function action_muggingSquadBehaviour:execute()
action_base.execute(self)
local npc = self.object
-- ensure and enforce path type
if npc:path_type() ~= game_object.level_path then
npc:set_path_type(game_object.level_path)
end
local squad = activeSquads[self.squad.id]
if squad.stage == squadStages.talk then
-- Set panic state
local bw = npc:active_item()
local new_state = "panic"
local lvid = self.isCommander and npc:level_vertex_id()
-- Find new lvid to reach
if not self.isCommander then
if self.st.vid then
if npc:level_vertex_id() == self.st.vid then
new_state = "threat_na"
else
npc:set_dest_level_vertex_id(self.st.vid)
end
lvid = self.st.vid
else
lvid = self:findPos()
end
else
new_state = "threat_na"
end
-- Set sight in direction of new lvid and confirm the state
-- npc:set_sight(look.direction, lvid and level.vertex_position(lvid):sub(npc:position()):normalize() or npc:direction())
state_mgr.set_state(npc, new_state, nil, nil, {
-- look_position = utils_obj.safe_bone_pos(db.actor, "bip01_head"),
look_object = db.actor,
-- look_dir = utils_obj.safe_bone_pos(npc, "bip01_head"):sub(utils_obj.safe_bone_pos(db.actor, "bip01_head")):normalize(),
}, {
fast_set = true,
animation = false,
})
elseif squad.stage == squadStages.done then
-- Find a smart for mugging squad to move
if not self.chosenSmart then
local safeSmarts = getSafeSmarts()
local smartCandidates = {}
local dir = db.actor:direction()
dir.y = 0
dir:normalize()
for name, smart in pairs(currentLevelSmarts) do
if not safeSmarts[name] then
local pos = vector():set(smart.position)
local dirToActor = pos:sub(db.actor:position()):normalize()
dirToActor.y = 0
dirToActor:normalize()
if dirToActor:dotproduct(dir) > 0 then
smartCandidates[#smartCandidates + 1] = smart
end
end
end
if is_empty(smartCandidates) then
for name, smart in pairs(currentLevelSmarts) do
if not safeSmarts[name] then
smartCandidates[#smartCandidates + 1] = smart
end
end
end
if is_empty(smartCandidates) then
for name, smart in pairs(currentLevelSmarts) do
smartCandidates[#smartCandidates + 1] = smart
end
end
local minDist = 0
for i, smart in ipairs(smartCandidates) do
local dist = smart.position:distance_to_sqr(db.actor:position())
if dist > minDist then
minDist = dist
self.chosenSmart = smart
end
end
end
if self.chosenSmart then
if self.isCommander then
if npc:level_vertex_id() == self.chosenSmart.m_level_vertex_id then
invalidateSquad(self.squad)
return
end
end
local se = alife_object(self.squad.id)
se.scripted_target = self.chosenSmart:name()
se.rush_to_target = true
local smart = self.chosenSmart
local new_state = "panic"
local lvid = smart.m_level_vertex_id
self.st.vid = lvid
npc:set_dest_level_vertex_id(lvid)
state_mgr.set_state(npc, new_state, nil, nil, {
-- look_position = utils_obj.safe_bone_pos(db.actor, "bip01_head"),
-- look_object = db.actor,
-- look_dir = utils_obj.safe_bone_pos(npc, "bip01_head"):sub(utils_obj.safe_bone_pos(db.actor, "bip01_head")):normalize(),
}, {
fast_set = false,
animation = true,
})
end
end
-- First update force movement
if self.first_update then
npc:clear_animations()
npc:movement_enabled(true)
npc:set_movement_type(move.run)
npc:set_body_state(move.standing)
npc:set_mental_state(anim.panic)
self.first_update = false
end
end
function action_muggingSquadBehaviour:finalize()
action_base.finalize(self)
self.first_update = true
self.initial_dir = nil
if (self.st.vid) then
db.used_level_vertex_ids[self.st.vid] = nil
end
self.st.vid = nil
self.chosenSmart = nil
local npc = self.object
npc:clear_animations()
npc:movement_enabled(true)
npc:set_movement_type(self.movement_type)
npc:set_body_state(self.body_state)
npc:set_mental_state(self.mental_state)
-- npc:set_path_type(self.path)
end
function setup_generic_scheme(npc, ini, scheme, section, stype, temp)
local st = xr_logic.assign_storage_and_bind(npc, ini, "muggingSquadBehaviour", section, temp)
end
function add_to_binder(npc, ini, scheme, section, storage, temp)
if not npc then return end
local manager = npc:motivation_action_manager()
if not manager then return end
if not npc:alive() or npc:section() == "actor_visual_stalker" then
manager:add_evaluator(evaid, property_evaluator_const(false))
temp.needs_configured = false
return
end
local evaluator = evaluator_muggingSquadBehaviour(npc, "eva_muggingSquadBehaviour", storage)
temp.action = action_muggingSquadBehaviour(npc, "act_muggingSquadBehaviour", storage)
if not evaluator or not temp.action then return end
manager:add_evaluator(evaid, evaluator)
temp.action:add_precondition(world_property(stalker_ids.property_alive, true))
-- temp.action:add_precondition(world_property(stalker_ids.property_danger, false))
temp.action:add_precondition(world_property(evaid, true))
temp.action:add_effect(world_property(evaid, false))
manager:add_action(actid, temp.action)
--xr_logic.subscribe_action_for_events(npc, storage, temp.action)
end
function configure_actions(npc, ini, scheme, section, stype, temp)
if not npc then return end
local manager = npc:motivation_action_manager()
if not manager or not temp.action then return end
temp.action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base, false))
temp.action:add_precondition(world_property(xr_evaluators_id.wounded_exist, false))
-- if (_G.schemes["rx_ff"]) then
-- temp.action:add_precondition(world_property(rx_ff.evaid, false))
-- end
if (_G.schemes["gl"]) then
temp.action:add_precondition(world_property(rx_gl.evid_gl_reload, false))
end
-- if (_G.schemes["facer"]) then
-- temp.action:add_precondition(world_property(xrs_facer.evid_facer, false))
-- temp.action:add_precondition(world_property(xrs_facer.evid_steal_up_facer, false))
-- end
local action
local p = {xr_danger.actid, stalker_ids.action_combat_planner, stalker_ids.action_danger_planner, xr_actions_id.state_mgr + 2, xr_actions_id.alife}
for i=1,#p do
--printf("ACTION_ALIFE_ID(demonized_muggingSquadBehaviour.configure_actions): " .. tostring(p[i]))
action = manager:action(p[i])
if (action) then
action:add_precondition(world_property(evaid, false))
else
printf("-demonized_mugging_squads axr_panic: no action id p[%s]", i)
end
end
end
function disable_generic_scheme(npc, scheme, stype)
local st = db.storage[npc:id()][scheme]
if st then
st.enabled = false
end
end
function npc_add_precondition(action)
if not action then return end
action:add_precondition(world_property(evaid, false))
end
LoadScheme(script_name(), "muggingSquadBehaviour", modules.stype_stalker)
-- Dialogs
local gt = game.translate_string
local function getNpcAndActor(a, b)
local npc = a:id() == AC_ID and b or a
local actor = a:id() == AC_ID and a or b
return npc, actor
end
local talkingMuggingSquadInfo
local function clearTalkingMuggingSquadInfo()
talkingMuggingSquadInfo = nil
math.randomseed(os.time())
end
function getRandomTranslatedText(st, faction, defaultSt)
faction = faction:gsub("_npc$", "")
local s = utils_data.collect_translations(st .. (faction or "") .. "_")
if is_empty(s) then
return gt(defaultSt) or ""
else
return gt(s[math.random(#s)]) or ""
end
end
-- These items will never be requested
ignoreItemsToMug = {
bolt = true,
bolt_bullet = true,
cash = true,
}
function relocateEverythingFromActor(npc)
local actor = db.actor
local function itr(_, obj)
if not ignoreItemsToMug[obj:section()] then
local amount = IsItem("multiuse", obj:section()) and obj:get_remaining_uses() or 1
news_manager.relocate_item(actor, "out", obj:section(), amount)
actor:transfer_item(obj, npc)
end
end
actor:iterate_inventory(itr, actor)
dialogs.relocate_money(npc, actor:money(), "out")
end
function chooseRandomItemsFromActor(npc, amount)
local actor = db.actor
local items = {}
local function itr(_, obj)
if not ignoreItemsToMug[obj:section()] then
items[#items + 1] = obj
end
end
actor:iterate_inventory(itr, actor)
--50% chance that they want max cost items
if math.random() < 0.5 then
table.sort(items, function(a, b) return a:cost() < b:cost() end)
else
shuffle(items)
end
talkingMuggingSquadInfo.chosenItems = {}
while is_not_empty(items) and amount > 0 do
table.insert(talkingMuggingSquadInfo.chosenItems, table.remove(items))
amount = amount - 1
end
return talkingMuggingSquadInfo.chosenItems
end
function relocateChosenItemsFromActor(npc, items)
local actor = db.actor
items = items or {}
for _, obj in ipairs(items) do
local amount = IsItem("multiuse", obj:section()) and obj:get_remaining_uses() or 1
news_manager.relocate_item(actor, "out", obj:section(), amount)
actor:transfer_item(obj, npc)
end
end
function relocateRandomMoneyFromActor(npc)
local actor = db.actor
-- 15% chance to request all money
if math.random() < 0.15 then
dialogs.relocate_money(npc, actor:money(), "out")
else
--Up to 50% of money, minimum 1000, in 100 fractions
local money = actor:money()
if money <= 1000 then
dialogs.relocate_money(npc, money, "out")
else
money = math.random(1000, math.floor(money / 2))
money = math.max(1000, math.floor(money / 100) * 100)
dialogs.relocate_money(npc, money, "out")
end
end
end
-- Determine what squad wants from actor
-- Below are lists of functions that returns a table with texts that will determine what squad wants and a function that will be applied in demonized_mugging_squads_give_my_stuff function
-- Defaults
function defaultMuggingOption(squad, npc, actor)
local faction = character_community(npc)
local whoAreYouText
local requestText
local requestFunc
local agreeText
local rejectText
local GTFOText
local GTFOOkText
whoAreYouText = function()
return getRandomTranslatedText("mugging_who_are_you_", faction, "mugging_who_are_you")
end
requestText = function()
return gt("mugging_give_me_stuff") or ""
end
requestFunc = function()
relocateRandomMoneyFromActor(npc)
end
agreeText = function()
return gt("mugging_here_is_my_stuff") or ""
end
rejectText = function()
return gt("mugging_fuck_you_and_start_fight") or ""
end
GTFOText = function()
return gt("mugging_thank_you") or ""
end
GTFOOkText = function()
return gt("mugging_ok") or ""
end
return {
whoAreYouText = whoAreYouText,
requestText = requestText,
requestFunc = requestFunc,
agreeText = agreeText,
rejectText = rejectText,
GTFOText = GTFOText,
GTFOOkText = GTFOOkText,
}
end
-- Get all items from actor
function allItemsMuggingOption(squad, npc, actor)
local faction = character_community(npc)
local whoAreYouText
local requestText
local requestFunc
local agreeText
local rejectText
local GTFOText
local GTFOOkText
whoAreYouText = function()
return getRandomTranslatedText("mugging_who_are_you_", faction, "mugging_who_are_you")
end
requestText = function()
return getRandomTranslatedText("mugging_give_me_all_stuff_", faction, "mugging_give_me_all_stuff")
end
requestFunc = function()
relocateEverythingFromActor(npc)
end
agreeText = function()
return getRandomTranslatedText("mugging_here_is_all_my_stuff_", faction, "mugging_here_is_all_my_stuff")
end
rejectText = function()
return getRandomTranslatedText("mugging_fuck_you_and_start_fight_", faction, "mugging_fuck_you_and_start_fight")
end
GTFOText = function()
return getRandomTranslatedText("mugging_thank_you_", faction, "mugging_thank_you")
end
GTFOOkText = function()
return getRandomTranslatedText("mugging_finish_", faction, "mugging_finish")
end
return {
whoAreYouText = whoAreYouText,
requestText = requestText,
requestFunc = requestFunc,
agreeText = agreeText,
rejectText = rejectText,
GTFOText = GTFOText,
GTFOOkText = GTFOOkText,
}
end
function moneyMuggingOption(squad, npc, actor)
local faction = character_community(npc)
local whoAreYouText
local requestText
local requestFunc
local agreeText
local rejectText
local GTFOText
local GTFOOkText
whoAreYouText = function()
return getRandomTranslatedText("mugging_who_are_you_", faction, "mugging_who_are_you")
end
requestText = function()
return getRandomTranslatedText("mugging_give_me_money_", faction, "mugging_give_me_money")
end
requestFunc = function()
relocateRandomMoneyFromActor(npc)
end
agreeText = function()
return getRandomTranslatedText("mugging_here_is_my_stuff_", faction, "mugging_here_is_my_stuff")
end
rejectText = function()
return getRandomTranslatedText("mugging_fuck_you_and_start_fight_", faction, "mugging_fuck_you_and_start_fight")
end
GTFOText = function()
return getRandomTranslatedText("mugging_thank_you_", faction, "mugging_thank_you")
end
GTFOOkText = function()
return getRandomTranslatedText("mugging_finish_", faction, "mugging_finish")
end
return {
whoAreYouText = whoAreYouText,
requestText = requestText,
requestFunc = requestFunc,
agreeText = agreeText,
rejectText = rejectText,
GTFOText = GTFOText,
GTFOOkText = GTFOOkText,
}
end
function someItemsMuggingOption(squad, npc, actor)
local faction = character_community(npc)
local whoAreYouText
local requestText
local requestFunc
local agreeText
local rejectText
local GTFOText
local GTFOOkText
whoAreYouText = function()
return getRandomTranslatedText("mugging_who_are_you_", faction, "mugging_who_are_you")
end
requestText = function()
local items = chooseRandomItemsFromActor(npc, math.random(5))
local s = getRandomTranslatedText("mugging_give_me_some_item_", faction, "mugging_give_me_some_item")
for _, item in ipairs(items) do
s = s .. "\\n <20> " .. ui_item.get_sec_name(item:section())
end
return s
end
requestFunc = function()
relocateChosenItemsFromActor(npc, talkingMuggingSquadInfo.chosenItems)
end
agreeText = function()
return getRandomTranslatedText("mugging_here_is_my_stuff_", faction, "mugging_here_is_my_stuff")
end
rejectText = function()
return getRandomTranslatedText("mugging_fuck_you_and_start_fight_", faction, "mugging_fuck_you_and_start_fight")
end
GTFOText = function()
return getRandomTranslatedText("mugging_thank_you_", faction, "mugging_thank_you")
end
GTFOOkText = function()
return getRandomTranslatedText("mugging_finish_", faction, "mugging_finish")
end
return {
whoAreYouText = whoAreYouText,
requestText = requestText,
requestFunc = requestFunc,
agreeText = agreeText,
rejectText = rejectText,
GTFOText = GTFOText,
GTFOOkText = GTFOOkText,
}
end
function convertToNewFaction(squad, npc, actor)
dialogs.break_dialog(npc, actor)
invalidateSquad(squad)
-- Set new community
local faction = character_community(npc)
-- Give default armor
local armorPriority = {
outfit_novice = 1,
outfit_light = 2,
outfit_medium = 3,
outfit_heavy = 4,
outfit_exo = 5,
}
local currentBestArmor
local currentBestArmorPriority = 1
local function itr(_, obj)
if IsOutfit(obj) then
local outfit = obj
local repair_type = SYS_GetParam(0, outfit:section(), "repair_type", "")
local priority = armorPriority[repair_type] or 1
if outfit:condition() >= 0.5 and priority >= currentBestArmorPriority then
currentBestArmor = outfit
currentBestArmorPriority = priority
end
end
end
actor:iterate_inventory(itr, actor)
-- Find best suited armor given initial armor
local newArmorCandidates = {}
local newArmor
ini_sys:section_for_each(function(section)
local community = SYS_GetParam(0, section, "community", "")
local repair_type = SYS_GetParam(0, section, "repair_type", "")
if community == faction and armorPriority[repair_type] and armorPriority[repair_type] <= currentBestArmorPriority then
newArmorCandidates[#newArmorCandidates + 1] = {
section = section,
priority = armorPriority[repair_type]
}
end
end)
-- Filter armor by the best
if is_not_empty(newArmorCandidates) then
local newArmors = {}
local newBestPriority = 1
table.sort(newArmorCandidates, function(a, b) return a.priority > b.priority end)
for i, v in ipairs(newArmorCandidates) do
if is_not_empty(newArmors) then
if v.priority == newBestPriority then
newArmors[#newArmors + 1] = v.section
else
break
end
else
if v.priority <= currentBestArmorPriority then
newBestPriority = v.priority
newArmors[#newArmors + 1] = v.section
end
end
end
if is_empty(newArmors) then
print_err("-demonized_mugging_squads Failed to find best suited armor of faction %s, pick random", faction)
newArmors[#newArmors + 1] = newArmorCandidates[math.random(#newArmorCandidates)].section
end
newArmor = newArmors[math.random(#newArmors)]
else
print_err("-demonized_mugging_squads Failed to find any armors of faction %s, dont do anything", faction)
end
-- Set teleport to main faction base
local startLocationCandidates = {}
local startLocation
local ini_map = ini_file("plugins\\new_game_start_locations.ltx")
ini_map:section_for_each(function(section)
if section:find("^" .. faction .. "_start_location") then
local n = ini_map:line_count(section)
if n > 0 then
for i = 0,n-1 do
local res,id,val = ini_map:r_line(section,i,"","")
local levelParams = str_explode(val, ",")
-- Only levels with defined story_only variable is available to ensure same location as in new game screen
if levelParams[2] == "true" or levelParams[2] == "false" then
print_err("-demonized_mugging_squads add location candidate for %s: %s, %s", faction, id, val)
startLocationCandidates[#startLocationCandidates + 1] = {
name = id,
params = val
}
end
end
end
end
end)
if is_not_empty(startLocationCandidates) then
local location = startLocationCandidates[1]
local level = str_explode(location.params, ",")[1]
local params = utils_data.collect_section(ini_map, location.name, true)
startLocation = {
name = location.name,
level = level,
lvid = tonumber(params.lvid),
gvid = tonumber(params.gvid),
x = tonumber(params.x),
y = tonumber(params.y),
z = tonumber(params.z)
}
else
print_err("-demonized_mugging_squads failed to find start location for faction %s", faction)
end
if not startLocation then
return
end
-- If all is well - do it
if newArmor then
if currentBestArmor then
alife_release(currentBestArmor)
end
local se_obj = alife_create_item(newArmor, actor)
CreateTimeEvent("newArmorMoveToRuck", 0, 0, function()
local obj = level.object_by_id(se_obj.id)
if obj then
actor:move_to_slot(obj, 7)
return true
end
return false
end)
end
print_err("-demonized_mugging_squads change faction to %s", faction)
set_actor_true_community(faction, true)
relation_registry.set_community_goodwill(faction, AC_ID, 200)
-- Give psy helmet if factions are Sin or Monolith
if (faction == "greh" or faction == "monolith") and not (db.actor:object("good_psy_helmet") or db.actor:object("bad_psy_helmet")) then
alife_create_item("good_psy_helmet", actor)
news_manager.relocate_item(actor, "in", "good_psy_helmet")
end
CreateTimeEvent("muggingConvertionChangeLevel", 0, 0.5, function()
print_err("-demonized_mugging_squads commence change location to %s: %s: %s;%s;%s, %s, %s", startLocation.name, startLocation.level, round_idp(startLocation.x, 2), round_idp(startLocation.y, 2), round_idp(startLocation.z, 2), startLocation.lvid, startLocation.gvid)
ChangeLevel(vector():set(startLocation.x, startLocation.y, startLocation.z), startLocation.lvid, startLocation.gvid, VEC_ZERO, true)
clearTalkingMuggingSquadInfo()
return true
end)
end
function factionConvertionOption(squad, npc, actor)
local faction = character_community(npc)
local whoAreYouText
local requestText
local requestFunc
local agreeText
local rejectText
local GTFOText
local GTFOOkText
whoAreYouText = function()
return getRandomTranslatedText("mugging_who_are_you_", faction, "mugging_who_are_you")
end
requestText = function()
return getRandomTranslatedText("mugging_convert_to_us_", faction, "mugging_convert_to_us")
end
requestFunc = function()
convertToNewFaction(squad, npc, actor)
end
agreeText = function()
return getRandomTranslatedText("mugging_convert_agree_", faction, "mugging_convert_agree")
end
rejectText = function()
return getRandomTranslatedText("mugging_fuck_you_and_start_fight_", faction, "mugging_fuck_you_and_start_fight")
end
GTFOText = function()
return getRandomTranslatedText("mugging_thank_you_", faction, "mugging_thank_you")
end
GTFOOkText = function()
return getRandomTranslatedText("mugging_finish_", faction, "mugging_finish")
end
return {
whoAreYouText = whoAreYouText,
requestText = requestText,
requestFunc = requestFunc,
agreeText = agreeText,
rejectText = rejectText,
GTFOText = GTFOText,
GTFOOkText = GTFOOkText,
}
end
function dialogs.demonized_mugging_squads_prepare_dialog_info(a, b)
local gameTime = game.get_game_time()
local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0
Y, M, D, h, m, s, ms = gameTime:get(Y, M, D, h, m, s, ms)
local seed = tonumber(Y .. M .. D .. h)
math.randomseed(seed)
local npc, actor = getNpcAndActor(a, b)
local squad = get_object_squad(npc)
talkingMuggingSquadInfo = {
count = squad:npc_count(),
squad = squad,
faction = character_community(npc),
option = pickMuggingOption(squad, npc, actor),
seed = seed
}
end
function dialogs.demonized_mugging_squads_text_stop_right_there()
local npc = mob_trade.GetTalkingNpc()
if npc then
local faction = character_community(npc)
return getRandomTranslatedText("mugging_stop_right_there_", faction, "mugging_stop_right_there")
end
return gt("mugging_stop_right_there") or ""
end
function dialogs.demonized_mugging_squads_text_who_are_you()
return talkingMuggingSquadInfo.option.whoAreYouText()
end
function dialogs.demonized_mugging_squads_text_give_me_stuff()
return talkingMuggingSquadInfo.option.requestText()
end
function dialogs.demonized_mugging_squads_text_here_is_my_stuff()
return talkingMuggingSquadInfo.option.agreeText()
end
function dialogs.demonized_mugging_squads_give_my_stuff()
talkingMuggingSquadInfo.option.requestFunc()
end
function dialogs.demonized_mugging_squads_text_thank_you_and_gtfo()
return talkingMuggingSquadInfo.option.GTFOText()
end
function dialogs.demonized_mugging_squads_text_ok()
return talkingMuggingSquadInfo.option.GTFOOkText()
end
function dialogs.demonized_mugging_squads_text_fuck_you_and_start_fight()
return talkingMuggingSquadInfo.option.rejectText()
end
function dialogs.demonized_mugging_squads_break_dialog(a, b)
dialogs.break_dialog(a, b)
local npc, actor = getNpcAndActor(a, b)
local squad = get_object_squad(npc)
setSquadStage(squad, squadStages.done)
clearTalkingMuggingSquadInfo()
end
function dialogs.demonized_mugging_squads_fuck_you_and_start_fight(a, b)
dialogs.break_dialog(a, b)
local npc, actor = getNpcAndActor(a, b)
local squad = get_object_squad(npc)
invalidateSquad(squad)
setSquadAsEnemy(squad)
if math.random() < settings.talkChance then
xr_sound.stop_sounds_by_id(npc:id())
xr_sound.set_sound_play(npc:id(), "mugging_fight")
end
clearTalkingMuggingSquadInfo()
end
-- Set mugging options per squad here
factionToMuggingOptions = {}
factionToMuggingOptions.bandit = function(squad, npc, actor)
-- 15% chance that they want all items
if math.random() < 0.15 then
return allItemsMuggingOption(squad, npc, actor)
else
-- choose either money or one item
if math.random() < 0.5 then
return someItemsMuggingOption(squad, npc, actor)
else
return moneyMuggingOption(squad, npc, actor)
end
end
end
factionToMuggingOptions.renegade = factionToMuggingOptions.bandit
factionToMuggingOptions.killer = function(squad, npc, actor)
return moneyMuggingOption(squad, npc, actor)
end
factionToMuggingOptions.isg = factionToMuggingOptions.killer
factionToMuggingOptions.monolith = function(squad, npc, actor)
return factionConvertionOption(squad, npc, actor)
end
factionToMuggingOptions.greh = factionToMuggingOptions.monolith
function pickMuggingOption(squad, npc, actor)
local faction = character_community(npc)
local result = factionToMuggingOptions[faction] and factionToMuggingOptions[faction](squad, npc, actor) or defaultMuggingOption(squad, npc, actor)
return result
end