mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Ready | Not Ready | Observe is now a three way toggle The player ready status has been refactored into an ENUM of the three states, READY, NOT_READY and OBSERVING if the tickerstate is at least PREGAME they will spawn as observers, before then you can only register your interest in observing. All the observer code has been centralised into a single make_me_an_observer proc on new_player mobs
910 lines
29 KiB
Plaintext
910 lines
29 KiB
Plaintext
/datum/objective
|
|
var/datum/mind/owner = null //Who owns the objective.
|
|
var/explanation_text = "Nothing" //What that person is supposed to do.
|
|
var/datum/mind/target = null //If they are focused on a particular person.
|
|
var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter.
|
|
var/completed = 0 //currently only used for custom objectives.
|
|
var/dangerrating = 0 //How hard the objective is, essentially. Used for dishing out objectives and checking overall victory.
|
|
var/martyr_compatible = 0 //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
|
|
|
|
/datum/objective/New(var/text)
|
|
if(text)
|
|
explanation_text = text
|
|
|
|
/datum/objective/proc/check_completion()
|
|
return completed
|
|
|
|
/datum/objective/proc/is_unique_objective(possible_target)
|
|
for(var/datum/objective/O in owner.objectives)
|
|
if(istype(O, type) && O.get_target() == possible_target)
|
|
return 0
|
|
return 1
|
|
|
|
/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/mob/M = R.fields["reference"]
|
|
if(M && M.mind)
|
|
. += M.mind
|
|
|
|
/datum/objective/proc/find_target()
|
|
var/list/possible_targets = list()
|
|
for(var/datum/mind/possible_target in get_crewmember_minds())
|
|
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && is_unique_objective(possible_target))
|
|
possible_targets += possible_target
|
|
if(possible_targets.len > 0)
|
|
target = pick(possible_targets)
|
|
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"
|
|
for(var/datum/mind/possible_target in get_crewmember_minds())
|
|
if((possible_target != owner) && 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()
|
|
//Default does nothing, override where needed
|
|
|
|
/datum/objective/proc/give_special_equipment(special_equipment)
|
|
if(owner && owner.current)
|
|
if(ishuman(owner.current))
|
|
var/mob/living/carbon/human/H = owner.current
|
|
var/list/slots = list ("backpack" = slot_in_backpack)
|
|
for(var/eq_path in special_equipment)
|
|
var/obj/O = new eq_path
|
|
H.equip_in_one_of_slots(O, slots)
|
|
|
|
/datum/objective/assassinate
|
|
var/target_role_type=0
|
|
dangerrating = 10
|
|
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()
|
|
if(target && target.current)
|
|
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
|
|
return 1
|
|
return 0
|
|
return 1
|
|
|
|
/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/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
|
|
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 && target.current)
|
|
if(target.current.stat == DEAD || !ishuman(target.current) || !target.current.ckey)
|
|
return 1
|
|
var/turf/T = get_turf(target.current)
|
|
if(T && (T.z > ZLEVEL_STATION) || (target.current.client && target.current.client.is_afk())) //If they leave the station or go afk they count as dead for this
|
|
return 2
|
|
return 0
|
|
return 1
|
|
|
|
/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
|
|
var/target_role_type=0
|
|
dangerrating = 5
|
|
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()
|
|
if(target && target.current)
|
|
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
|
|
return 1
|
|
if(target.current.onCentcom() || target.current.onSyndieBase())
|
|
return 0
|
|
return 1
|
|
|
|
/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/debrain//I want braaaainssss
|
|
var/target_role_type=0
|
|
dangerrating = 20
|
|
|
|
/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 1
|
|
if( !owner.current || owner.current.stat==DEAD )//If you're otherwise dead.
|
|
return 0
|
|
if( !target.current || !isbrain(target.current) )
|
|
return 0
|
|
var/atom/A = target.current
|
|
while(A.loc) //check to see if the brainmob is on our person
|
|
A = A.loc
|
|
if(A == owner.current)
|
|
return 1
|
|
return 0
|
|
|
|
/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/protect//The opposite of killing a dude.
|
|
var/target_role_type=0
|
|
dangerrating = 10
|
|
martyr_compatible = 1
|
|
|
|
/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()
|
|
if(!target) //If it's a free objective.
|
|
return 1
|
|
if(target.current)
|
|
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current))
|
|
return 0
|
|
return 1
|
|
return 0
|
|
|
|
/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/hijack
|
|
explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody."
|
|
dangerrating = 25
|
|
martyr_compatible = 0 //Technically you won't get both anyway.
|
|
|
|
/datum/objective/hijack/check_completion()
|
|
if(!owner.current || owner.current.stat)
|
|
return 0
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return 0
|
|
if(issilicon(owner.current))
|
|
return 0
|
|
|
|
var/area/A = get_area(owner.current)
|
|
if(SSshuttle.emergency.areaInstance != A)
|
|
return 0
|
|
|
|
return SSshuttle.emergency.is_hijacked()
|
|
|
|
|
|
/datum/objective/hijackclone
|
|
explanation_text = "Hijack the emergency shuttle by ensuring only you (or your copies) escape."
|
|
dangerrating = 25
|
|
martyr_compatible = 0
|
|
|
|
/datum/objective/hijackclone/check_completion()
|
|
if(!owner.current)
|
|
return 0
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return 0
|
|
|
|
var/area/A = SSshuttle.emergency.areaInstance
|
|
|
|
for(var/mob/living/player in GLOB.player_list) //Make sure nobody else is onboard
|
|
if(player.mind && player.mind != owner)
|
|
if(player.stat != DEAD)
|
|
if(issilicon(player)) //Borgs are technically dead anyways
|
|
continue
|
|
if(isanimal(player)) //animals don't count
|
|
continue
|
|
if(isbrain(player)) //also technically dead
|
|
continue
|
|
if(get_area(player) == A)
|
|
var/location = get_turf(player.mind.current)
|
|
if(player.real_name != owner.current.real_name && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/brig))
|
|
return 0
|
|
|
|
for(var/mob/living/player in GLOB.player_list) //Make sure at least one of you is onboard
|
|
if(player.mind && player.mind != owner)
|
|
if(player.stat != DEAD)
|
|
if(issilicon(player)) //Borgs are technically dead anyways
|
|
continue
|
|
if(isanimal(player)) //animals don't count
|
|
continue
|
|
if(isbrain(player)) //also technically dead
|
|
continue
|
|
if(get_area(player) == A)
|
|
var/location = get_turf(player.mind.current)
|
|
if(player.real_name == owner.current.real_name && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/brig))
|
|
return 1
|
|
return 0
|
|
|
|
/datum/objective/block
|
|
explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive."
|
|
dangerrating = 25
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/block/check_completion()
|
|
if(!issilicon(owner.current))
|
|
return 0
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return 1
|
|
|
|
var/area/A = SSshuttle.emergency.areaInstance
|
|
|
|
for(var/mob/living/player in GLOB.player_list)
|
|
if(issilicon(player))
|
|
continue
|
|
if(player.mind)
|
|
if(player.stat != DEAD)
|
|
if(get_area(player) == A)
|
|
return 0
|
|
|
|
return 1
|
|
|
|
|
|
/datum/objective/purge
|
|
explanation_text = "Ensure no mutant humanoid species are present aboard the escape shuttle."
|
|
dangerrating = 25
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/purge/check_completion()
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return 1
|
|
|
|
var/area/A = SSshuttle.emergency.areaInstance
|
|
|
|
for(var/mob/living/player in GLOB.player_list)
|
|
if(get_area(player) == A && player.mind && player.stat != DEAD && ishuman(player))
|
|
var/mob/living/carbon/human/H = player
|
|
if(H.dna.species.id != "human")
|
|
return 0
|
|
|
|
return 1
|
|
|
|
|
|
/datum/objective/robot_army
|
|
explanation_text = "Have at least eight active cyborgs synced to you."
|
|
dangerrating = 25
|
|
martyr_compatible = 0
|
|
|
|
/datum/objective/robot_army/check_completion()
|
|
if(!isAI(owner.current))
|
|
return 0
|
|
var/mob/living/silicon/ai/A = owner.current
|
|
|
|
var/counter = 0
|
|
|
|
for(var/mob/living/silicon/robot/R in A.connected_robots)
|
|
if(R.stat != DEAD)
|
|
counter++
|
|
|
|
if(counter < 8)
|
|
return 0
|
|
return 1
|
|
|
|
/datum/objective/escape
|
|
explanation_text = "Escape on the shuttle or an escape pod alive and without being in custody."
|
|
dangerrating = 5
|
|
|
|
/datum/objective/escape/check_completion()
|
|
if(issilicon(owner.current))
|
|
return 0
|
|
if(isbrain(owner.current))
|
|
return 0
|
|
if(!owner.current || owner.current.stat == DEAD)
|
|
return 0
|
|
if(SSticker.force_ending) //This one isn't their fault, so lets just assume good faith
|
|
return 1
|
|
if(SSticker.mode.station_was_nuked) //If they escaped the blast somehow, let them win
|
|
return 1
|
|
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
|
return 0
|
|
var/turf/location = get_turf(owner.current)
|
|
if(!location)
|
|
return 0
|
|
|
|
if(istype(location, /turf/open/floor/plasteel/shuttle/red) || istype(location, /turf/open/floor/mineral/plastitanium/brig)) // Fails traitors if they are in the shuttle brig -- Polymorph
|
|
return 0
|
|
|
|
if(location.onCentcom() || location.onSyndieBase())
|
|
return 1
|
|
|
|
return 0
|
|
|
|
/datum/objective/escape/escape_with_identity
|
|
dangerrating = 10
|
|
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()
|
|
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_real_name)
|
|
return 1
|
|
if(!ishuman(owner.current))
|
|
return 0
|
|
var/mob/living/carbon/human/H = owner.current
|
|
if(..())
|
|
if(H.dna.real_name == target_real_name)
|
|
if(H.get_id_name()== target_real_name || target_missing_id)
|
|
return 1
|
|
return 0
|
|
|
|
|
|
/datum/objective/survive
|
|
explanation_text = "Stay alive until the end."
|
|
dangerrating = 3
|
|
|
|
/datum/objective/survive/check_completion()
|
|
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
|
|
return 0 //Brains no longer win survive objectives. --NEO
|
|
if(!is_special_character(owner.current)) //This fails borg'd traitors
|
|
return 0
|
|
return 1
|
|
|
|
|
|
/datum/objective/martyr
|
|
explanation_text = "Die a glorious death."
|
|
dangerrating = 1
|
|
|
|
/datum/objective/martyr/check_completion()
|
|
if(!owner.current) //Gibbed, etc.
|
|
return 1
|
|
if(owner.current && owner.current.stat == DEAD) //You're dead! Yay!
|
|
return 1
|
|
return 0
|
|
|
|
|
|
/datum/objective/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 1
|
|
return 0
|
|
|
|
GLOBAL_LIST_EMPTY(possible_items)
|
|
/datum/objective/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).
|
|
dangerrating = 5 //Overridden by the individual item's difficulty, but defaults to 5 for custom objectives.
|
|
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.
|
|
init_subtypes(/datum/objective_item/steal,GLOB.possible_items)
|
|
|
|
/datum/objective/steal/find_target()
|
|
var/approved_targets = list()
|
|
for(var/datum/objective_item/possible_item in GLOB.possible_items)
|
|
if(is_unique_objective(possible_item.targetitem) && !(owner.current.mind.assigned_role in possible_item.excludefromjob))
|
|
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]."
|
|
dangerrating = targetinfo.difficulty
|
|
give_special_equipment(targetinfo.special_equipment)
|
|
return steal_target
|
|
else
|
|
explanation_text = "Free objective"
|
|
return
|
|
|
|
/datum/objective/steal/proc/select_target() //For admins setting objectives manually.
|
|
var/list/possible_items_all = GLOB.possible_items+"custom"
|
|
var/new_target = input("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/obj/item/custom_target = input("Select type:","Type") as null|anything in typesof(/obj/item)
|
|
if (!custom_target) return
|
|
var/custom_name = initial(custom_target.name)
|
|
custom_name = stripped_input("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)
|
|
return steal_target
|
|
|
|
/datum/objective/steal/check_completion()
|
|
if(!steal_target)
|
|
return 1
|
|
if(!isliving(owner.current))
|
|
return 0
|
|
var/list/all_items = owner.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 1
|
|
else if(targetinfo.check_special_completion(I))//Returns 1 by default. Items with special checks will return 1 if the conditions are fulfilled.
|
|
return 1
|
|
|
|
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 0 if we don't though - then you could fail if you had 1 item that didn't pass and got checked first!
|
|
return 1
|
|
return 0
|
|
|
|
|
|
GLOBAL_LIST_EMPTY(possible_items_special)
|
|
/datum/objective/steal/special //ninjas are so special they get their own subtype good for them
|
|
|
|
/datum/objective/steal/special/New()
|
|
..()
|
|
if(!GLOB.possible_items_special.len)
|
|
init_subtypes(/datum/objective_item/special,GLOB.possible_items_special)
|
|
init_subtypes(/datum/objective_item/stack,GLOB.possible_items_special)
|
|
|
|
/datum/objective/steal/special/find_target()
|
|
return set_target(pick(GLOB.possible_items_special))
|
|
|
|
/datum/objective/steal/exchange
|
|
dangerrating = 10
|
|
martyr_compatible = 0
|
|
|
|
/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/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
|
|
dangerrating = 3
|
|
|
|
/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
|
|
dangerrating = 10
|
|
|
|
/datum/objective/download/proc/gen_amount_goal()
|
|
target_amount = rand(10,20)
|
|
explanation_text = "Download [target_amount] research level\s."
|
|
return target_amount
|
|
|
|
/datum/objective/download/check_completion()//NINJACODE
|
|
if(!ishuman(owner.current))
|
|
return 0
|
|
|
|
var/mob/living/carbon/human/H = owner.current
|
|
if(!H || H.stat == DEAD)
|
|
return 0
|
|
|
|
if(!istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
|
|
return 0
|
|
|
|
var/obj/item/clothing/suit/space/space_ninja/SN = H.wear_suit
|
|
if(!SN.s_initialized)
|
|
return 0
|
|
|
|
var/current_amount
|
|
if(!SN.stored_research.len)
|
|
return 0
|
|
else
|
|
for(var/datum/tech/current_data in SN.stored_research)
|
|
if(current_data.level)
|
|
current_amount += (current_data.level-1)
|
|
if(current_amount<target_amount)
|
|
return 0
|
|
return 1
|
|
|
|
|
|
|
|
/datum/objective/capture
|
|
dangerrating = 10
|
|
|
|
/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/check_completion()//Basically runs through all the mobs in the area to determine how much they are worth.
|
|
var/captured_amount = 0
|
|
var/area/centcom/holding/A = locate()
|
|
for(var/mob/living/carbon/human/M in A)//Humans.
|
|
if(M.stat==2)//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==2)
|
|
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==2)
|
|
captured_amount+=1.5
|
|
else
|
|
captured_amount+=3
|
|
continue
|
|
if(M.stat==2)
|
|
captured_amount+=1
|
|
continue
|
|
captured_amount+=2
|
|
if(captured_amount<target_amount)
|
|
return 0
|
|
return 1
|
|
|
|
|
|
|
|
/datum/objective/absorb
|
|
dangerrating = 10
|
|
|
|
/datum/objective/absorb/proc/gen_amount_goal(lowbound = 4, highbound = 6)
|
|
target_amount = rand (lowbound,highbound)
|
|
if (SSticker)
|
|
var/n_p = 1 //autowin
|
|
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!=owner)
|
|
n_p ++
|
|
else if (SSticker.IsRoundInProgress())
|
|
for(var/mob/living/carbon/human/P in GLOB.player_list)
|
|
if(P.client && !(P.mind in SSticker.mode.changelings) && P.mind!=owner)
|
|
n_p ++
|
|
target_amount = min(target_amount, n_p)
|
|
|
|
explanation_text = "Extract [target_amount] compatible genome\s."
|
|
return target_amount
|
|
|
|
/datum/objective/absorb/check_completion()
|
|
if(owner && owner.changeling && owner.changeling.stored_profiles && (owner.changeling.absorbedcount >= target_amount))
|
|
return 1
|
|
else
|
|
return 0
|
|
|
|
|
|
|
|
/datum/objective/destroy
|
|
dangerrating = 10
|
|
martyr_compatible = 1
|
|
|
|
/datum/objective/destroy/find_target()
|
|
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)
|
|
if(target.current.stat == DEAD || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
|
|
return 1
|
|
return 0
|
|
return 1
|
|
|
|
/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/internal
|
|
var/stolen = FALSE //Have we already eliminated this target?
|
|
|
|
/datum/objective/steal_five_of_type
|
|
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
|
|
explanation_text = "Steal at least five guns!"
|
|
wanted_items = list(/obj/item/weapon/gun)
|
|
|
|
/datum/objective/steal_five_of_type/summon_magic
|
|
explanation_text = "Steal at least five magical artefacts!"
|
|
wanted_items = list(/obj/item/weapon/spellbook, /obj/item/weapon/gun/magic, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/weapon/scrying, /obj/item/weapon/antag_spawner/contract, /obj/item/device/necromantic_stone)
|
|
|
|
/datum/objective/steal_five_of_type/check_completion()
|
|
if(!isliving(owner.current))
|
|
return 0
|
|
var/stolen_count = 0
|
|
var/list/all_items = owner.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++
|
|
if(stolen_count >= 5)
|
|
return 1
|
|
else
|
|
return 0
|
|
return 0
|
|
|
|
|
|
////////////////////////////////
|
|
// 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
|
|
|
|
|
|
//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 derpartment 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/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/ling_count = SSticker.mode.changelings
|
|
|
|
for(var/datum/mind/M in SSticker.minds)
|
|
if(M in SSticker.mode.changelings)
|
|
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")
|
|
owner.objectives -= src
|
|
qdel(src)
|
|
return
|
|
|
|
|
|
/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/needed_heads = rand(min_lings,GLOB.command_positions.len)
|
|
needed_heads = min(SSticker.mode.changelings.len,needed_heads)
|
|
|
|
var/list/heads = SSticker.mode.get_living_heads()
|
|
for(var/datum/mind/head in heads)
|
|
if(head in SSticker.mode.changelings) //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")
|
|
owner.objectives -= src
|
|
qdel(src)
|
|
return
|
|
|
|
|
|
/datum/objective/changeling_team_objective/impersonate_department/New(var/text)
|
|
..()
|
|
if(command_staff_only)
|
|
get_heads()
|
|
else
|
|
get_department_staff()
|
|
|
|
update_explanation_text()
|
|
|
|
|
|
/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 1 //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 centcomm alive, if they did it's an automatic fail
|
|
for(var/datum/mind/M in department_minds)
|
|
if(M in SSticker.mode.changelings) //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 0 //A Non-ling living target got to centcomm, 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 SSticker.mode.changelings)
|
|
if(success >= department_minds.len) //We did it, stop here!
|
|
return 1
|
|
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 centcomm....
|
|
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 centcomm
|
|
continue changelings
|
|
|
|
if(success >= department_minds.len)
|
|
return 1
|
|
return 0
|
|
|
|
|
|
|
|
|
|
//A subtype of impersonate_derpartment
|
|
//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
|
|
|
|
|
|
|