Replaced most instances of Nanotrasen mentions into GATO, though I've kept some that have more sense to be kept as Nanotrasen (like nanotrasen marked stuff and such)
1311 lines
44 KiB
Plaintext
1311 lines
44 KiB
Plaintext
//CITADEL EDIT
|
|
GLOBAL_LIST_EMPTY(objectives)
|
|
//END EDIT
|
|
|
|
/datum/objective
|
|
var/datum/mind/owner //The primary owner of the objective. !!SOMEWHAT DEPRECATED!! Prefer using 'team' for new code.
|
|
var/datum/team/team //An alternative to 'owner': a team. Use this when writing new code.
|
|
var/name = "generic objective" //Name for admin prompts
|
|
var/explanation_text = "Nothing" //What that person is supposed to do.
|
|
var/team_explanation_text //For when there are multiple owners.
|
|
var/datum/mind/target = null //If they are focused on a particular person.
|
|
var/target_amount = FALSE //If they are focused on a particular number. Steal objectives have their own counter.
|
|
var/completed = FALSE //currently only used for custom objectives.
|
|
var/completable = TRUE //Whether this objective shows greentext when completed
|
|
var/martyr_compatible = FALSE //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
|
|
var/objective_name = "Objective" //name used in printing this objective (Objective #1)
|
|
|
|
/datum/objective/New(var/text)
|
|
GLOB.objectives += src // CITADEL EDIT FOR CRYOPODS
|
|
if(text)
|
|
explanation_text = text
|
|
|
|
/datum/objective/Destroy(force, ...)
|
|
GLOB.objectives -= src
|
|
if(owner)
|
|
for(var/datum/antagonist/A in owner.antag_datums)
|
|
A.objectives -= src
|
|
if(team)
|
|
team.objectives -= src
|
|
. = ..()
|
|
|
|
/datum/objective/proc/get_owners() // Combine owner and team into a single list.
|
|
. = (team && team.members) ? team.members.Copy() : list()
|
|
if(owner)
|
|
. += owner
|
|
|
|
/datum/objective/proc/admin_edit(mob/admin)
|
|
return
|
|
|
|
//Shared by few objective types
|
|
/datum/objective/proc/admin_simple_target_pick(mob/admin)
|
|
var/list/possible_targets = list("Free objective")
|
|
var/def_value
|
|
for(var/datum/mind/possible_target in SSticker.minds)
|
|
if ((possible_target != src) && ishuman(possible_target.current))
|
|
possible_targets += possible_target.current
|
|
|
|
|
|
if(target && target.current)
|
|
def_value = target.current
|
|
|
|
var/mob/new_target = input(admin,"Select target:", "Objective target", def_value) as null|anything in possible_targets
|
|
if (!new_target)
|
|
return
|
|
|
|
if (new_target == "Free objective")
|
|
target = null
|
|
else
|
|
target = new_target.mind
|
|
|
|
update_explanation_text()
|
|
|
|
/datum/objective/proc/considered_escaped(datum/mind/M)
|
|
if(!considered_alive(M))
|
|
return FALSE
|
|
if(M.force_escaped)
|
|
return TRUE
|
|
if(SSticker.force_ending || SSticker.mode.station_was_nuked) // Just let them win.
|
|
return TRUE
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return FALSE
|
|
var/turf/location = get_turf(M.current)
|
|
if(!location || istype(location, /turf/open/floor/plasteel/shuttle/red) || istype(location, /turf/open/floor/mineral/plastitanium/red/brig)) // Fails if they are in the shuttle brig
|
|
return FALSE
|
|
return location.onCentCom() || location.onSyndieBase()
|
|
|
|
/datum/objective/proc/check_completion()
|
|
return completed
|
|
|
|
/*
|
|
Used during the round to check if an objective has already been completed, generally should have harsher requirements that the default objective (no true because of short afk, etc)
|
|
If not set, defaults to check_completion instead. Set it. It's used by cryo.
|
|
*/
|
|
/datum/objective/proc/check_midround_completion()
|
|
return check_completion()
|
|
|
|
/datum/objective/proc/is_unique_objective(possible_target)
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
for(var/datum/objective/O in M.get_all_objectives()) //This scope is debatable, probably should be passed in by caller.
|
|
if(istype(O, type) && O.get_target() == possible_target)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/proc/get_target()
|
|
return target
|
|
|
|
/datum/objective/proc/get_crewmember_minds()
|
|
. = list()
|
|
for(var/V in GLOB.data_core.locked)
|
|
var/datum/data/record/R = V
|
|
var/datum/mind/M = R.fields["mindref"]
|
|
if(M)
|
|
. += M
|
|
|
|
/datum/objective/proc/find_target(dupe_search_range, blacklist)
|
|
var/list/datum/mind/owners = get_owners()
|
|
if(!dupe_search_range)
|
|
dupe_search_range = get_owners()
|
|
var/list/possible_targets = list()
|
|
var/try_target_late_joiners = FALSE
|
|
for(var/I in owners)
|
|
var/datum/mind/O = I
|
|
if(O.late_joiner)
|
|
try_target_late_joiners = TRUE
|
|
for(var/datum/mind/possible_target in get_crewmember_minds())
|
|
if(!(possible_target in owners) && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && is_unique_objective(possible_target))
|
|
if(!(possible_target in blacklist))
|
|
possible_targets += possible_target
|
|
if(try_target_late_joiners)
|
|
var/list/all_possible_targets = possible_targets.Copy()
|
|
for(var/I in all_possible_targets)
|
|
var/datum/mind/PT = I
|
|
if(!PT.late_joiner)
|
|
possible_targets -= PT
|
|
if(!possible_targets.len)
|
|
possible_targets = all_possible_targets
|
|
if(possible_targets.len > 0)
|
|
target = pick(possible_targets)
|
|
else
|
|
target = null//we'd rather have no target than an invalid one // CITADEL EDIT
|
|
update_explanation_text()
|
|
return target
|
|
|
|
/datum/objective/proc/find_target_by_role(role, role_type=0, invert=0)//Option sets either to check assigned role or special role. Default to assigned., invert inverts the check, eg: "Don't choose a Ling"
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/possible_target in get_crewmember_minds())
|
|
if(!(possible_target in owners) && ishuman(possible_target.current))
|
|
var/is_role = 0
|
|
if(role_type)
|
|
if(possible_target.special_role == role)
|
|
is_role++
|
|
else
|
|
if(possible_target.assigned_role == role)
|
|
is_role++
|
|
|
|
if(invert)
|
|
if(is_role)
|
|
continue
|
|
target = possible_target
|
|
break
|
|
else if(is_role)
|
|
target = possible_target
|
|
break
|
|
|
|
update_explanation_text()
|
|
|
|
/datum/objective/proc/update_explanation_text()
|
|
if(team_explanation_text && LAZYLEN(get_owners()) > 1)
|
|
explanation_text = team_explanation_text
|
|
|
|
/datum/objective/proc/give_special_equipment(special_equipment)
|
|
var/datum/mind/receiver = pick(get_owners())
|
|
. = list()
|
|
if(receiver && receiver.current)
|
|
if(ishuman(receiver.current))
|
|
var/mob/living/carbon/human/H = receiver.current
|
|
var/list/slots = list("backpack" = ITEM_SLOT_BACKPACK)
|
|
for(var/eq_path in special_equipment)
|
|
var/obj/O = new eq_path
|
|
. += O
|
|
H.equip_in_one_of_slots(O, slots, critical = TRUE)
|
|
|
|
/datum/objective/assassinate
|
|
name = "assasinate"
|
|
var/target_role_type=0
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/assassinate/find_target_by_role(role, role_type=0, invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/assassinate/check_completion()
|
|
return !considered_alive(target) || considered_afk(target)
|
|
|
|
/datum/objective/assassinate/check_midround_completion()
|
|
return FALSE //They need to be dead at the end of the round, silly!
|
|
|
|
/datum/objective/assassinate/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/assassinate/admin_edit(mob/admin)
|
|
admin_simple_target_pick(admin)
|
|
|
|
/datum/objective/assassinate/once
|
|
name = "kill once"
|
|
var/won = FALSE
|
|
|
|
/datum/objective/assassinate/once/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Kill [target.name], the [!target_role_type ? target.assigned_role : target.special_role]. You only need to kill them once; if they come back, you've still succeeded."
|
|
START_PROCESSING(SSprocessing,src)
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/assassinate/once/check_completion()
|
|
return won || ..()
|
|
|
|
/datum/objective/assassinate/once/process()
|
|
won = tick_check_completion()
|
|
if(won)
|
|
STOP_PROCESSING(SSprocessing,src)
|
|
|
|
/datum/objective/assassinate/once/proc/tick_check_completion()
|
|
return won || !considered_alive(target) //The target afking / logging off for a bit during the round doesn't complete it, but them being afk at roundend does.
|
|
|
|
/datum/objective/assassinate/once/check_midround_completion()
|
|
return won //If they cryoed, only keep it if we already won
|
|
|
|
/datum/objective/assassinate/internal
|
|
var/stolen = 0 //Have we already eliminated this target?
|
|
|
|
/datum/objective/assassinate/internal/update_explanation_text()
|
|
..()
|
|
if(target && !target.current)
|
|
explanation_text = "Assassinate [target.name], who was obliterated"
|
|
|
|
/datum/objective/mutiny
|
|
name = "mutiny"
|
|
var/target_role_type=0
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/mutiny/find_target_by_role(role, role_type=0,invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/mutiny/check_completion()
|
|
if(!target || !considered_alive(target) || considered_afk(target))
|
|
return TRUE
|
|
var/turf/T = get_turf(target.current)
|
|
return !T || !is_station_level(T.z)
|
|
|
|
/datum/objective/mutiny/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/mutiny/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Assassinate or exile [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/maroon
|
|
name = "maroon"
|
|
var/target_role_type=0
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/maroon/find_target_by_role(role, role_type=0, invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/maroon/check_completion()
|
|
return !target || !considered_alive(target) || (!target.current?.onCentCom() && !target.current?.onSyndieBase())
|
|
|
|
/datum/objective/maroon/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/maroon/update_explanation_text()
|
|
if(target && target.current)
|
|
explanation_text = "Prevent [target.name], the [!target_role_type ? target.assigned_role : target.special_role], from escaping alive."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/maroon/admin_edit(mob/admin)
|
|
admin_simple_target_pick(admin)
|
|
|
|
/datum/objective/debrain
|
|
name = "debrain"
|
|
var/target_role_type=0
|
|
|
|
/datum/objective/debrain/find_target_by_role(role, role_type=0, invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/debrain/check_completion()
|
|
if(!target)//If it's a free objective.
|
|
return TRUE
|
|
if(!target.current || !isbrain(target.current))
|
|
return FALSE
|
|
var/atom/A = target.current
|
|
var/list/datum/mind/owners = get_owners()
|
|
|
|
while(A.loc) // Check to see if the brainmob is on our person
|
|
A = A.loc
|
|
for(var/datum/mind/M in owners)
|
|
if(M.current && M.current.stat != DEAD && A == M.current)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/objective/debrain/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Steal the brain of [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/debrain/admin_edit(mob/admin)
|
|
admin_simple_target_pick(admin)
|
|
|
|
/datum/objective/protect//The opposite of killing a dude.
|
|
name = "protect"
|
|
martyr_compatible = 1
|
|
var/target_role_type = 0
|
|
var/human_check = TRUE
|
|
|
|
/datum/objective/protect/find_target_by_role(role, role_type=0, invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/protect/check_completion()
|
|
return !target || considered_alive(target, enforce_human = human_check)
|
|
|
|
/datum/objective/protect/check_midround_completion()
|
|
return FALSE //Nuh uh, you get a new objective
|
|
|
|
/datum/objective/protect/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Protect [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/protect/admin_edit(mob/admin)
|
|
admin_simple_target_pick(admin)
|
|
|
|
/datum/objective/protect/nonhuman
|
|
name = "protect nonhuman"
|
|
human_check = FALSE
|
|
|
|
/datum/objective/hijack
|
|
name = "hijack"
|
|
explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
|
team_explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console). Leave no team member behind."
|
|
martyr_compatible = 0 //Technically you won't get both anyway.
|
|
/// Overrides the hijack speed of any antagonist datum it is on ONLY, no other datums are impacted.
|
|
var/hijack_speed_override = 1
|
|
|
|
/datum/objective/hijack/check_completion() // Requires all owners to escape.
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return FALSE
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!considered_alive(M) || !SSshuttle.emergency.shuttle_areas[get_area(M.current)])
|
|
return FALSE
|
|
return SSshuttle.emergency.is_hijacked()
|
|
|
|
/datum/objective/block
|
|
name = "no organics on shuttle"
|
|
explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive."
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/block/check_completion()
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return TRUE
|
|
for(var/mob/living/player in GLOB.player_list)
|
|
if(player.mind && player.stat != DEAD && !issilicon(player))
|
|
if(get_area(player) in SSshuttle.emergency.shuttle_areas)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/purge
|
|
name = "no mutants on shuttle"
|
|
explanation_text = "Ensure no mutant humanoid species are present aboard the escape shuttle."
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/purge/check_completion()
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return TRUE
|
|
for(var/mob/living/player in GLOB.player_list)
|
|
if((get_area(player) in SSshuttle.emergency.shuttle_areas) && player.mind && player.stat != DEAD && ishuman(player))
|
|
var/mob/living/carbon/human/H = player
|
|
if(H.dna.species.id != "human")
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/robot_army
|
|
name = "robot army"
|
|
explanation_text = "Have at least eight active cyborgs synced to you."
|
|
martyr_compatible = 0
|
|
|
|
/datum/objective/robot_army/check_completion()
|
|
var/counter = 0
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!M.current || !isAI(M.current))
|
|
continue
|
|
var/mob/living/silicon/ai/A = M.current
|
|
for(var/mob/living/silicon/robot/R in A.connected_robots)
|
|
if(R.stat != DEAD)
|
|
counter++
|
|
return counter >= 8
|
|
|
|
/datum/objective/freedom
|
|
name = "freedom"
|
|
explanation_text = "Don't get captured by GATO."
|
|
team_explanation_text = "Have all members of your team free of GATO custody."
|
|
|
|
/datum/objective/freedom/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/m in owners)
|
|
var/datum/mind/M = m
|
|
if(!considered_alive(M))
|
|
return FALSE
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return FALSE
|
|
var/turf/location = get_turf(M.current)
|
|
if(!location || istype(location, /turf/open/floor/plasteel/shuttle/red) || istype(location, /turf/open/floor/mineral/plastitanium/red/brig)) // Fails if they are in the shuttle brig
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/escape
|
|
name = "escape"
|
|
explanation_text = "Escape on the shuttle or an escape pod alive and without being in custody."
|
|
team_explanation_text = "Have all members of your team escape on a shuttle or pod alive, without being in custody."
|
|
|
|
/datum/objective/escape/check_completion()
|
|
// Require all owners escape safely.
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!considered_escaped(M))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/breakout
|
|
name = "breakout"
|
|
martyr_compatible = 1
|
|
var/target_role_type = 0
|
|
var/human_check = TRUE
|
|
|
|
/datum/objective/breakout/check_completion()
|
|
return !target || considered_escaped(target)
|
|
|
|
/datum/objective/breakout/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/breakout/find_target_by_role(role, role_type=0, invert=0)
|
|
if(!invert)
|
|
target_role_type = role_type
|
|
..()
|
|
return target
|
|
|
|
/datum/objective/breakout/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Make sure [target.name], the [!target_role_type ? target.assigned_role : target.special_role] escapes on the shuttle or an escape pod alive and without being in custody."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/escape/escape_with_identity
|
|
name = "escape with identity"
|
|
var/target_real_name // Has to be stored because the target's real_name can change over the course of the round
|
|
var/target_missing_id
|
|
|
|
/datum/objective/escape/escape_with_identity/find_target(dupe_search_range, blacklist)
|
|
target = ..()
|
|
update_explanation_text()
|
|
|
|
/datum/objective/escape/escape_with_identity/update_explanation_text()
|
|
if(target && target.current)
|
|
target_real_name = target.current.real_name
|
|
explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role]"
|
|
var/mob/living/carbon/human/H
|
|
if(ishuman(target.current))
|
|
H = target.current
|
|
if(H && H.get_id_name() != target_real_name)
|
|
target_missing_id = 1
|
|
else
|
|
explanation_text += " while wearing their identification card"
|
|
explanation_text += "." //Proper punctuation is important!
|
|
|
|
else
|
|
explanation_text = "Free Objective."
|
|
|
|
/datum/objective/escape/escape_with_identity/check_completion()
|
|
if(!target || !target_real_name)
|
|
return TRUE
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!ishuman(M.current) || !considered_escaped(M))
|
|
continue
|
|
var/mob/living/carbon/human/H = M.current
|
|
if(H.dna.real_name == target_real_name && (H.get_id_name() == target_real_name || target_missing_id))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/objective/escape/escape_with_identity/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/escape/escape_with_identity/admin_edit(mob/admin)
|
|
admin_simple_target_pick(admin)
|
|
|
|
/datum/objective/survive
|
|
name = "survive"
|
|
explanation_text = "Stay alive until the end."
|
|
|
|
/datum/objective/survive/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!considered_alive(M))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/survive/exist //Like survive, but works for silicons and zombies and such.
|
|
name = "survive nonhuman"
|
|
|
|
/datum/objective/survive/exist/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!considered_alive(M, FALSE))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/martyr
|
|
name = "martyr"
|
|
explanation_text = "Die a glorious death."
|
|
|
|
/datum/objective/martyr/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(considered_alive(M))
|
|
return FALSE
|
|
if(M.current?.suiciding) //killing yourself ISN'T glorious.
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/nuclear
|
|
name = "nuclear"
|
|
explanation_text = "Destroy the station with a nuclear device."
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/nuclear/check_completion()
|
|
if(SSticker && SSticker.mode && SSticker.mode.station_was_nuked)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
GLOBAL_LIST_EMPTY(possible_items)
|
|
/datum/objective/steal
|
|
name = "steal"
|
|
var/datum/objective_item/targetinfo = null //Save the chosen item datum so we can access it later.
|
|
var/obj/item/steal_target = null //Needed for custom objectives (they're just items, not datums).
|
|
var/list/special_items_given = list()
|
|
martyr_compatible = 0
|
|
|
|
/datum/objective/steal/get_target()
|
|
return steal_target
|
|
|
|
/datum/objective/steal/New()
|
|
..()
|
|
if(!GLOB.possible_items.len)//Only need to fill the list when it's needed.
|
|
for(var/I in subtypesof(/datum/objective_item/steal))
|
|
new I
|
|
|
|
/datum/objective/steal/Destroy(force, ...)
|
|
if(length(special_items_given))
|
|
QDEL_LIST(special_items_given)
|
|
. = ..()
|
|
|
|
/datum/objective/steal/find_target(dupe_search_range, blacklist)
|
|
var/list/datum/mind/owners = get_owners()
|
|
var/approved_targets = list()
|
|
check_items:
|
|
for(var/datum/objective_item/possible_item in GLOB.possible_items)
|
|
if(!is_unique_objective(possible_item.targetitem))
|
|
continue
|
|
for(var/datum/mind/M in owners)
|
|
if(M.current.mind.assigned_role in possible_item.excludefromjob)
|
|
continue check_items
|
|
approved_targets += possible_item
|
|
return set_target(safepick(approved_targets))
|
|
|
|
/datum/objective/steal/proc/set_target(datum/objective_item/item)
|
|
if(item)
|
|
targetinfo = item
|
|
steal_target = targetinfo.targetitem
|
|
explanation_text = "Steal [targetinfo.name]"
|
|
special_items_given = give_special_equipment(targetinfo.special_equipment)
|
|
return steal_target
|
|
else
|
|
explanation_text = "Free objective"
|
|
return
|
|
|
|
/datum/objective/steal/admin_edit(mob/admin)
|
|
var/list/possible_items_all = GLOB.possible_items+"custom"
|
|
var/new_target = input(admin,"Select target:", "Objective target", steal_target) as null|anything in possible_items_all
|
|
if (!new_target)
|
|
return
|
|
|
|
if (new_target == "custom") //Can set custom items.
|
|
var/custom_path = input(admin,"Search for target item type:","Type") as null|text
|
|
if (!custom_path)
|
|
return
|
|
var/obj/item/custom_target = pick_closest_path(custom_path, make_types_fancy(subtypesof(/obj/item)))
|
|
var/custom_name = initial(custom_target.name)
|
|
custom_name = stripped_input(admin,"Enter target name:", "Objective target", custom_name)
|
|
if (!custom_name)
|
|
return
|
|
steal_target = custom_target
|
|
explanation_text = "Steal [custom_name]."
|
|
|
|
else
|
|
set_target(new_target)
|
|
|
|
/datum/objective/steal/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
if(!steal_target)
|
|
return TRUE
|
|
for(var/datum/mind/M in owners)
|
|
if(!isliving(M.current))
|
|
continue
|
|
|
|
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
|
|
|
|
for(var/obj/I in all_items) //Check for items
|
|
if(istype(I, steal_target))
|
|
if(!targetinfo) //If there's no targetinfo, then that means it was a custom objective. At this point, we know you have the item, so return 1.
|
|
return TRUE
|
|
else if(targetinfo.check_special_completion(I))//Returns 1 by default. Items with special checks will return TRUE if the conditions are fulfilled.
|
|
return TRUE
|
|
|
|
if(targetinfo && (I.type in targetinfo.altitems)) //Ok, so you don't have the item. Do you have an alternative, at least?
|
|
if(targetinfo.check_special_completion(I))//Yeah, we do! Don't return FALSE if we don't though - then you could fail if you had 1 item that didn't pass and got checked first!
|
|
return TRUE
|
|
return FALSE
|
|
|
|
|
|
GLOBAL_LIST_EMPTY(possible_items_special)
|
|
/datum/objective/steal/special //ninjas are so special they get their own subtype good for them
|
|
name = "steal special"
|
|
|
|
/datum/objective/steal/special/New()
|
|
..()
|
|
if(!GLOB.possible_items_special.len)
|
|
for(var/I in subtypesof(/datum/objective_item/special) + subtypesof(/datum/objective_item/stack))
|
|
new I
|
|
|
|
/datum/objective/steal/special/find_target(dupe_search_range, blacklist)
|
|
return set_target(pick(GLOB.possible_items_special))
|
|
|
|
/datum/objective/steal/exchange
|
|
name = "exchange"
|
|
martyr_compatible = 0
|
|
|
|
/datum/objective/steal/exchange/admin_edit(mob/admin)
|
|
return
|
|
|
|
/datum/objective/steal/exchange/proc/set_faction(faction,otheragent)
|
|
target = otheragent
|
|
if(faction == "red")
|
|
targetinfo = new/datum/objective_item/unique/docs_blue
|
|
else if(faction == "blue")
|
|
targetinfo = new/datum/objective_item/unique/docs_red
|
|
explanation_text = "Acquire [targetinfo.name] held by [target.current.real_name], the [target.assigned_role] and syndicate agent"
|
|
steal_target = targetinfo.targetitem
|
|
|
|
/datum/objective/steal/exchange/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/steal/exchange/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Acquire [targetinfo.name] held by [target.name], the [target.assigned_role] and syndicate agent"
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
|
|
/datum/objective/steal/exchange/backstab
|
|
name = "prevent exchange"
|
|
|
|
/datum/objective/steal/exchange/backstab/set_faction(faction)
|
|
if(faction == "red")
|
|
targetinfo = new/datum/objective_item/unique/docs_red
|
|
else if(faction == "blue")
|
|
targetinfo = new/datum/objective_item/unique/docs_blue
|
|
explanation_text = "Do not give up or lose [targetinfo.name]."
|
|
steal_target = targetinfo.targetitem
|
|
|
|
/datum/objective/download
|
|
name = "download"
|
|
|
|
/datum/objective/download/proc/gen_amount_goal()
|
|
target_amount = rand(20,40)
|
|
update_explanation_text()
|
|
return target_amount
|
|
|
|
/datum/objective/download/update_explanation_text()
|
|
..()
|
|
explanation_text = "Download [target_amount] research node\s."
|
|
|
|
/datum/objective/download/check_completion()
|
|
var/datum/techweb/checking = new
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/owner in owners)
|
|
if(ismob(owner.current))
|
|
var/mob/M = owner.current //Yeah if you get morphed and you eat a quantum tech disk with the RD's latest backup good on you soldier.
|
|
if(ishuman(M))
|
|
var/mob/living/carbon/human/H = M
|
|
if(H && (H.stat != DEAD) && istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
|
|
var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit
|
|
S.stored_research.copy_research_to(checking)
|
|
var/list/otherwise = M.GetAllContents()
|
|
for(var/obj/item/disk/tech_disk/TD in otherwise)
|
|
TD.stored_research.copy_research_to(checking)
|
|
return checking.researched_nodes.len >= target_amount
|
|
|
|
/datum/objective/download/admin_edit(mob/admin)
|
|
var/count = input(admin,"How many nodes ?","Nodes",target_amount) as num|null
|
|
if(count)
|
|
target_amount = count
|
|
update_explanation_text()
|
|
/*
|
|
/datum/objective/capture
|
|
name = "capture"
|
|
var/captured_amount = 0
|
|
|
|
/datum/objective/capture/proc/gen_amount_goal()
|
|
target_amount = rand(5,10)
|
|
explanation_text = "Capture [target_amount] lifeform\s with an energy net. Live, rare specimens are worth more."
|
|
return target_amount
|
|
|
|
/datum/objective/capture/update_explanation_text()
|
|
. = ..()
|
|
explanation_text = "Capture [target_amount] lifeform\s with an energy net. Live, rare specimens are worth more."
|
|
|
|
/datum/objective/capture/check_completion()//Basically runs through all the mobs in the area to determine how much they are worth.
|
|
/*var/area/centcom/holding/A = GLOB.areas_by_type[/area/centcom/holding]
|
|
for(var/mob/living/carbon/human/M in A)//Humans.
|
|
if(M.stat == DEAD)//Dead folks are worth less.
|
|
captured_amount+=0.5
|
|
continue
|
|
captured_amount+=1
|
|
for(var/mob/living/carbon/monkey/M in A)//Monkeys are almost worthless, you failure.
|
|
captured_amount+=0.1
|
|
for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research.
|
|
if(M.stat == DEAD)
|
|
captured_amount+=0.5
|
|
continue
|
|
captured_amount+=1
|
|
for(var/mob/living/carbon/alien/humanoid/M in A)//Aliens are worth twice as much as humans.
|
|
if(istype(M, /mob/living/carbon/alien/humanoid/royal/queen))//Queens are worth three times as much as humans.
|
|
if(M.stat == DEAD)
|
|
captured_amount+=1.5
|
|
else
|
|
captured_amount+=3
|
|
continue
|
|
if(M.stat == DEAD)
|
|
captured_amount+=1
|
|
continue
|
|
captured_amount+=2*/ //Removed in favour of adding points on capture, in energy_net_nets.dm
|
|
return captured_amount >= target_amount
|
|
|
|
/datum/objective/capture/admin_edit(mob/admin)
|
|
var/count = input(admin,"How many mobs to capture ?","capture",target_amount) as num|null
|
|
if(count)
|
|
target_amount = count
|
|
update_explanation_text()
|
|
*/
|
|
/datum/objective/protect_object
|
|
name = "protect object"
|
|
var/obj/protect_target
|
|
|
|
/datum/objective/protect_object/proc/set_target(obj/O)
|
|
protect_target = O
|
|
update_explanation_text()
|
|
|
|
/datum/objective/protect_object/update_explanation_text()
|
|
. = ..()
|
|
if(protect_target)
|
|
explanation_text = "Protect \the [protect_target] at all costs."
|
|
else
|
|
explanation_text = "Free objective."
|
|
|
|
/datum/objective/protect_object/check_completion()
|
|
return !QDELETED(protect_target)
|
|
|
|
//Changeling Objectives
|
|
|
|
/datum/objective/absorb
|
|
name = "absorb"
|
|
|
|
/datum/objective/absorb/proc/gen_amount_goal(lowbound = 4, highbound = 6)
|
|
target_amount = rand (lowbound,highbound)
|
|
var/n_p = 1 //autowin
|
|
var/list/datum/mind/owners = get_owners()
|
|
if (SSticker.current_state == GAME_STATE_SETTING_UP)
|
|
for(var/mob/dead/new_player/P in GLOB.player_list)
|
|
if(P.client && P.ready == PLAYER_READY_TO_PLAY && !(P.mind in owners))
|
|
n_p ++
|
|
else if (SSticker.IsRoundInProgress())
|
|
for(var/mob/living/carbon/human/P in GLOB.player_list)
|
|
if(P.client && !(P.mind.has_antag_datum(/datum/antagonist/changeling)) && !(P.mind in owners))
|
|
n_p ++
|
|
target_amount = min(target_amount, n_p)
|
|
|
|
update_explanation_text()
|
|
return target_amount
|
|
|
|
/datum/objective/absorb/update_explanation_text()
|
|
. = ..()
|
|
explanation_text = "Extract [target_amount] compatible genome\s."
|
|
|
|
/datum/objective/absorb/admin_edit(mob/admin)
|
|
var/count = input(admin,"How many people to absorb?","absorb",target_amount) as num|null
|
|
if(count)
|
|
target_amount = count
|
|
update_explanation_text()
|
|
|
|
/datum/objective/absorb/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
var/absorbedcount = 0
|
|
for(var/datum/mind/M in owners)
|
|
if(!M)
|
|
continue
|
|
var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling)
|
|
if(!changeling || !changeling.stored_profiles)
|
|
continue
|
|
absorbedcount += changeling.absorbedcount
|
|
return absorbedcount >= target_amount
|
|
|
|
/datum/objective/absorb_most
|
|
name = "absorb most"
|
|
explanation_text = "Extract more compatible genomes than any other Changeling."
|
|
|
|
/datum/objective/absorb_most/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
var/absorbedcount = 0
|
|
for(var/datum/mind/M in owners)
|
|
if(!M)
|
|
continue
|
|
var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling)
|
|
if(!changeling || !changeling.stored_profiles)
|
|
continue
|
|
absorbedcount += changeling.absorbedcount
|
|
|
|
for(var/datum/antagonist/changeling/changeling2 in GLOB.antagonists)
|
|
if(!changeling2.owner || changeling2.owner == owner || !changeling2.stored_profiles || changeling2.absorbedcount < absorbedcount)
|
|
continue
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/objective/absorb_changeling
|
|
name = "absorb changeling"
|
|
explanation_text = "Absorb another Changeling."
|
|
|
|
/datum/objective/absorb_changeling/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
for(var/datum/mind/M in owners)
|
|
if(!M)
|
|
continue
|
|
var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling)
|
|
if(!changeling)
|
|
continue
|
|
var/total_genetic_points = changeling.geneticpoints
|
|
|
|
for(var/datum/action/changeling/p in changeling.purchasedpowers)
|
|
total_genetic_points += p.dna_cost
|
|
|
|
if(total_genetic_points > initial(changeling.geneticpoints))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
//End Changeling Objectives
|
|
|
|
/datum/objective/destroy
|
|
name = "destroy AI"
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/destroy/find_target(dupe_search_range, blacklist)
|
|
var/list/possible_targets = active_ais(1)
|
|
var/mob/living/silicon/ai/target_ai = pick(possible_targets)
|
|
target = target_ai.mind
|
|
update_explanation_text()
|
|
return target
|
|
|
|
/datum/objective/destroy/check_completion()
|
|
if(target && target.current)
|
|
return target.current.stat == DEAD || target.current.z > 6 || !target.current.ckey //Borgs/brains/AIs count as dead for traitor objectives.
|
|
return TRUE
|
|
|
|
/datum/objective/destroy/check_midround_completion()
|
|
return FALSE
|
|
|
|
/datum/objective/destroy/update_explanation_text()
|
|
..()
|
|
if(target && target.current)
|
|
explanation_text = "Destroy [target.name], the experimental AI."
|
|
else
|
|
explanation_text = "Free Objective"
|
|
|
|
/datum/objective/destroy/admin_edit(mob/admin)
|
|
var/list/possible_targets = active_ais(1)
|
|
if(possible_targets.len)
|
|
var/mob/new_target = input(admin,"Select target:", "Objective target") as null|anything in possible_targets
|
|
target = new_target.mind
|
|
else
|
|
to_chat(admin, "No active AIs with minds")
|
|
update_explanation_text()
|
|
|
|
/datum/objective/destroy/internal
|
|
var/stolen = FALSE //Have we already eliminated this target?
|
|
|
|
/datum/objective/steal_five_of_type
|
|
name = "steal five of"
|
|
explanation_text = "Steal at least five items!"
|
|
var/list/wanted_items = list(/obj/item)
|
|
|
|
/datum/objective/steal_five_of_type/New()
|
|
..()
|
|
wanted_items = typecacheof(wanted_items)
|
|
|
|
/datum/objective/steal_five_of_type/summon_guns
|
|
name = "steal guns"
|
|
explanation_text = "Steal at least five guns!"
|
|
wanted_items = list(/obj/item/gun)
|
|
|
|
/datum/objective/steal_five_of_type/summon_magic
|
|
name = "steal magic"
|
|
explanation_text = "Steal at least five magical artefacts!"
|
|
wanted_items = list(/obj/item/spellbook, /obj/item/gun/magic, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/scrying, /obj/item/antag_spawner/contract, /obj/item/necromantic_stone)
|
|
|
|
/datum/objective/steal_five_of_type/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
var/stolen_count = 0
|
|
for(var/datum/mind/M in owners)
|
|
if(!isliving(M.current))
|
|
continue
|
|
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
|
|
for(var/obj/I in all_items) //Check for wanted items
|
|
if(is_type_in_typecache(I, wanted_items))
|
|
stolen_count++
|
|
return stolen_count >= 5
|
|
|
|
//Created by admin tools
|
|
/datum/objective/custom
|
|
name = "custom"
|
|
completable = FALSE
|
|
|
|
/datum/objective/custom/admin_edit(mob/admin)
|
|
var/expl = stripped_input(admin, "Custom objective:", "Objective", explanation_text)
|
|
if(expl)
|
|
explanation_text = expl
|
|
|
|
////////////////////////////////
|
|
// Changeling team objectives //
|
|
////////////////////////////////
|
|
|
|
/datum/objective/changeling_team_objective //Abstract type
|
|
martyr_compatible = 0 //Suicide is not teamwork!
|
|
explanation_text = "Changeling Friendship!"
|
|
var/min_lings = 3 //Minimum amount of lings for this team objective to be possible
|
|
var/escape_objective_compatible = FALSE
|
|
|
|
/datum/objective/changeling_team_objective/proc/prepare()
|
|
return FALSE
|
|
|
|
//Impersonate department
|
|
//Picks as many people as it can from a department (Security,Engineer,Medical,Science)
|
|
//and tasks the lings with killing and replacing them
|
|
/datum/objective/changeling_team_objective/impersonate_department
|
|
explanation_text = "Ensure X department are killed, impersonated, and replaced by Changelings"
|
|
var/command_staff_only = FALSE //if this is true, it picks command staff instead
|
|
var/list/department_minds = list()
|
|
var/list/department_real_names = list()
|
|
var/department_string = ""
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/prepare()
|
|
var/result = FALSE
|
|
if(command_staff_only)
|
|
result = get_heads()
|
|
else
|
|
result = get_department_staff()
|
|
if(result)
|
|
update_explanation_text()
|
|
return TRUE
|
|
else
|
|
return FALSE
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/proc/get_department_staff()
|
|
department_minds = list()
|
|
department_real_names = list()
|
|
|
|
var/list/departments = list("Head of Security","Research Director","Chief Engineer","Chief Medical Officer")
|
|
var/department_head = pick(departments)
|
|
switch(department_head)
|
|
if("Head of Security")
|
|
department_string = "security"
|
|
if("Research Director")
|
|
department_string = "science"
|
|
if("Chief Engineer")
|
|
department_string = "engineering"
|
|
if("Chief Medical Officer")
|
|
department_string = "medical"
|
|
|
|
var/list/lings = get_antag_minds(/datum/antagonist/changeling,TRUE)
|
|
var/ling_count = lings.len
|
|
|
|
for(var/datum/mind/M in SSticker.minds)
|
|
if(M in lings)
|
|
continue
|
|
if(department_head in get_department_heads(M.assigned_role))
|
|
if(ling_count)
|
|
ling_count--
|
|
department_minds += M
|
|
department_real_names += M.current.real_name
|
|
else
|
|
break
|
|
|
|
if(!department_minds.len)
|
|
log_game("[type] has failed to find department staff, and has removed itself. the round will continue normally")
|
|
return FALSE
|
|
return TRUE
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/proc/get_heads()
|
|
department_minds = list()
|
|
department_real_names = list()
|
|
|
|
//Needed heads is between min_lings and the maximum possible amount of command roles
|
|
//So at the time of writing, rand(3,6), it's also capped by the amount of lings there are
|
|
//Because you can't fill 6 head roles with 3 lings
|
|
var/list/lings = get_antag_minds(/datum/antagonist/changeling,TRUE)
|
|
var/needed_heads = rand(min_lings,GLOB.command_positions.len)
|
|
needed_heads = min(lings.len,needed_heads)
|
|
|
|
var/list/heads = SSjob.get_living_heads()
|
|
for(var/datum/mind/head in heads)
|
|
if(head in lings) //Looking at you HoP.
|
|
continue
|
|
if(needed_heads)
|
|
department_minds += head
|
|
department_real_names += head.current.real_name
|
|
needed_heads--
|
|
else
|
|
break
|
|
|
|
if(!department_minds.len)
|
|
log_game("[type] has failed to find department heads, and has removed itself. the round will continue normally")
|
|
return FALSE
|
|
return TRUE
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/update_explanation_text()
|
|
..()
|
|
if(!department_real_names.len || !department_minds.len)
|
|
explanation_text = "Free Objective"
|
|
return //Something fucked up, give them a win
|
|
|
|
if(command_staff_only)
|
|
explanation_text = "Ensure changelings impersonate and escape as the following heads of staff: "
|
|
else
|
|
explanation_text = "Ensure changelings impersonate and escape as the following members of \the [department_string] department: "
|
|
|
|
var/first = 1
|
|
for(var/datum/mind/M in department_minds)
|
|
var/string = "[M.name] the [M.assigned_role]"
|
|
if(!first)
|
|
string = ", [M.name] the [M.assigned_role]"
|
|
else
|
|
first--
|
|
explanation_text += string
|
|
|
|
if(command_staff_only)
|
|
explanation_text += ", while the real heads are dead. This is a team objective."
|
|
else
|
|
explanation_text += ", while the real members are dead. This is a team objective."
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/check_completion()
|
|
if(!department_real_names.len || !department_minds.len)
|
|
return TRUE //Something fucked up, give them a win
|
|
|
|
var/list/check_names = department_real_names.Copy()
|
|
|
|
//Check each department member's mind to see if any of them made it to centcom alive, if they did it's an automatic fail
|
|
for(var/datum/mind/M in department_minds)
|
|
if(M.has_antag_datum(/datum/antagonist/changeling)) //Lings aren't picked for this, but let's be safe
|
|
continue
|
|
|
|
if(M.current)
|
|
var/turf/mloc = get_turf(M.current)
|
|
if(mloc.onCentCom() && (M.current.stat != DEAD))
|
|
return FALSE //A Non-ling living target got to centcom, fail
|
|
|
|
//Check each staff member has been replaced, by cross referencing changeling minds, changeling current dna, the staff minds and their original DNA names
|
|
var/success = 0
|
|
changelings:
|
|
for(var/datum/mind/changeling in get_antag_minds(/datum/antagonist/changeling,TRUE))
|
|
if(success >= department_minds.len) //We did it, stop here!
|
|
return TRUE
|
|
if(ishuman(changeling.current))
|
|
var/mob/living/carbon/human/H = changeling.current
|
|
var/turf/cloc = get_turf(changeling.current)
|
|
if(cloc && cloc.onCentCom() && (changeling.current.stat != DEAD)) //Living changeling on centcom....
|
|
for(var/name in check_names) //Is he (disguised as) one of the staff?
|
|
if(H.dna.real_name == name)
|
|
check_names -= name //This staff member is accounted for, remove them, so the team don't succeed by escape as 7 of the same engineer
|
|
success++ //A living changeling staff member made it to centcom
|
|
continue changelings
|
|
|
|
if(success >= department_minds.len)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
//A subtype of impersonate_department
|
|
//This subtype always picks as many command staff as it can (HoS,HoP,Cap,CE,CMO,RD)
|
|
//and tasks the lings with killing and replacing them
|
|
/datum/objective/changeling_team_objective/impersonate_department/impersonate_heads
|
|
explanation_text = "Have X or more heads of staff escape on the shuttle disguised as heads, while the real heads are dead"
|
|
command_staff_only = TRUE
|
|
|
|
|
|
/datum/objective/hoard
|
|
name = "hoard"
|
|
var/obj/item/hoarded_item = null
|
|
|
|
/datum/objective/hoard/get_target()
|
|
return hoarded_item
|
|
|
|
/datum/objective/hoard/proc/set_target(obj/item/I)
|
|
if(I)
|
|
hoarded_item = I
|
|
explanation_text = "Keep [I] on your person at all times."
|
|
return hoarded_item
|
|
else
|
|
explanation_text = "Free objective"
|
|
return
|
|
|
|
/datum/objective/hoard/check_completion()
|
|
var/list/datum/mind/owners = get_owners()
|
|
if(!hoarded_item)
|
|
return TRUE
|
|
for(var/datum/mind/M in owners)
|
|
if(!isliving(M.current))
|
|
continue
|
|
|
|
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
|
|
|
|
for(var/obj/I in all_items) //Check for items
|
|
if(I == hoarded_item)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/objective/hoard/heirloom
|
|
name = "steal heirloom"
|
|
|
|
/datum/objective/hoard/heirloom/find_target(dupe_search_range, blacklist)
|
|
set_target(pick(GLOB.family_heirlooms))
|
|
|
|
GLOBAL_LIST_EMPTY(traitor_contraband)
|
|
|
|
GLOBAL_LIST_EMPTY(cult_contraband)
|
|
|
|
/datum/objective/hoard/collector
|
|
name = "Hoard contraband"
|
|
|
|
/datum/objective/collector/New()
|
|
..()
|
|
if(!GLOB.traitor_contraband.len)//Only need to fill the list when it's needed.
|
|
GLOB.traitor_contraband = list(/obj/item/card/emag/empty,/obj/item/clothing/glasses/phantomthief,/obj/item/clothing/gloves/chameleon/broken)
|
|
if(!GLOB.cult_contraband.len)
|
|
GLOB.cult_contraband = list(/obj/item/clockwork/slab,/obj/item/clockwork/component/belligerent_eye,/obj/item/clockwork/component/belligerent_eye/lens_gem,/obj/item/shuttle_curse,/obj/item/cult_shift)
|
|
|
|
/datum/objective/hoard/collector/find_target(dupe_search_range, blacklist)
|
|
var/obj/item/I
|
|
var/I_type
|
|
if(prob(50))
|
|
I_type = pick_n_take(GLOB.traitor_contraband) // always unique unless it's run out, in which case we refill it anyway
|
|
else
|
|
I_type = pick_n_take(GLOB.cult_contraband)
|
|
I = new I_type
|
|
I.forceMove(get_turf(owner))
|
|
if(ishuman(owner))
|
|
var/mob/living/carbon/human/H = owner
|
|
H.equip_in_one_of_slots(I, list("backpack" = ITEM_SLOT_BACKPACK), critical = TRUE)
|
|
hoarded_item = I
|
|
|
|
|
|
|
|
GLOBAL_LIST_EMPTY(possible_sabotages)
|
|
// For saboteurs. Go in and cause some trouble somewhere. Not necessarily breaking things, just sufficiently troublemaking.
|
|
/datum/objective/sabotage
|
|
name = "sabotage"
|
|
var/datum/sabotage_objective/targetinfo = null //composition > inheritance.
|
|
var/list/special_items_given = list()
|
|
|
|
/datum/objective/sabotage/get_target()
|
|
return targetinfo.sabotage_type
|
|
|
|
/datum/objective/sabotage/New()
|
|
..()
|
|
if(!GLOB.possible_sabotages.len)//Only need to fill the list when it's needed.
|
|
for(var/I in subtypesof(/datum/sabotage_objective))
|
|
new I
|
|
|
|
/datum/objective/sabotage/Destroy()
|
|
if(length(special_items_given))
|
|
QDEL_LIST(special_items_given)
|
|
. = ..()
|
|
|
|
/datum/objective/sabotage/find_target(dupe_search_range, blacklist)
|
|
var/list/datum/mind/owners = get_owners()
|
|
var/approved_targets = list()
|
|
check_sabotages:
|
|
for(var/datum/sabotage_objective/possible_sabotage in GLOB.possible_sabotages)
|
|
if(!is_unique_objective(possible_sabotage.sabotage_type) || possible_sabotage.check_conditions() || !possible_sabotage.can_run())
|
|
continue
|
|
for(var/datum/mind/M in owners)
|
|
if(M.current.mind.assigned_role in possible_sabotage.excludefromjob)
|
|
continue check_sabotages
|
|
approved_targets += possible_sabotage
|
|
return set_target(safepick(approved_targets))
|
|
|
|
/datum/objective/sabotage/proc/set_target(datum/sabotage_objective/sabo)
|
|
if(sabo)
|
|
targetinfo = sabo
|
|
explanation_text = "[targetinfo.name]"
|
|
special_items_given = give_special_equipment(targetinfo.special_equipment)
|
|
return sabo
|
|
else
|
|
explanation_text = "Free objective"
|
|
return
|
|
|
|
/datum/objective/sabotage/check_completion()
|
|
return targetinfo.check_conditions()
|
|
|
|
/datum/objective/flavor
|
|
name = "flavor"
|
|
completable = FALSE
|
|
var/flavor_file
|
|
|
|
/datum/objective/flavor/proc/get_flavor_list()
|
|
return world.file2list(flavor_file)
|
|
|
|
/datum/objective/flavor/proc/forge_objective()
|
|
var/flavor_list = get_flavor_list()
|
|
explanation_text = pick(flavor_list)
|
|
|
|
/datum/objective/flavor/traitor
|
|
name = "traitor flavor"
|
|
flavor_file = "strings/flavor_objectives/traitor.txt"
|
|
|
|
/datum/objective/flavor/traitor/get_flavor_list()
|
|
. = ..()
|
|
switch(owner.assigned_role)
|
|
if("Station Engineer", "Atmospheric Technician")
|
|
. += world.file2list("strings/flavor_objectives/traitor/engineering.txt")
|
|
if("Medical Doctor","Chemist","Virologist","Geneticist")
|
|
. += world.file2list("strings/flavor_objectives/traitor/medical.txt")
|
|
if("Scientist","Roboticist","Geneticist")
|
|
. += world.file2list("strings/flavor_objectives/traitor/science.txt")
|
|
if("Assistant")
|
|
. += world.file2list("strings/flavor_objectives/traitor/assistant.txt")
|
|
|
|
/datum/objective/flavor/ninja_helping
|
|
flavor_file = "strings/flavor_objectives/ninja_helping.txt"
|
|
|
|
/datum/objective/flavor/ninja_syndie
|
|
flavor_file = "strings/flavor_objectives/ninja_syndie.txt"
|
|
|
|
/datum/objective/flavor/wizard
|
|
flavor_file = "strings/flavor_objectives/wizard.txt"
|
|
|
|
/datum/objective/contract
|
|
var/payout = 0
|
|
var/payout_bonus = 0
|
|
var/area/dropoff = null
|
|
var/static/list/blacklisted_areas = typecacheof(list(/area/ai_monitored/turret_protected,
|
|
/area/solars,
|
|
/area/ruin, //thank you station space ruins
|
|
/area/science/test_area,
|
|
/area/shuttle/))
|
|
|
|
/datum/objective/contract/proc/generate_dropoff() // Generate a random valid area on the station that the dropoff will happen.
|
|
var/found = FALSE
|
|
while(!found)
|
|
var/area/dropoff_area = pick(GLOB.sortedAreas)
|
|
if(dropoff_area && is_station_level(dropoff_area.z) && !dropoff_area.outdoors && !is_type_in_typecache(dropoff_area, blacklisted_areas))
|
|
dropoff = dropoff_area
|
|
found = TRUE
|
|
|
|
/datum/objective/contract/proc/dropoff_check(mob/user, mob/target) // Check if both the contractor and contract target are at the dropoff point.
|
|
var/area/user_area = get_area(user)
|
|
var/area/target_area = get_area(target)
|
|
return (istype(user_area, dropoff) && istype(target_area, dropoff))
|