mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Traitorbro gamemode (#30344)
A dead-simple traitor variant. It's like traitor, except instead of an uplink you get a buddy: your blood brother. You must team up with your brother to complete your objectives. It runs along side regular traitor mode, thus the name "traitorbro".
This commit is contained in:
@@ -18,3 +18,4 @@
|
||||
#define ANTAG_DATUM_IAA_HUMAN_CUSTOM /datum/antagonist/traitor/human/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI_CUSTOM /datum/antagonist/traitor/AI/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
|
||||
#define ANTAG_DATUM_BROTHER /datum/antagonist/brother
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define ANTAG_HUD_SINTOUCHED 16
|
||||
#define ANTAG_HUD_SOULLESS 17
|
||||
#define ANTAG_HUD_CLOCKWORK 18
|
||||
#define ANTAG_HUD_BROTHER 19
|
||||
|
||||
// Notification action types
|
||||
#define NOTIFY_JUMP "jump"
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
#define ROLE_REVENANT "revenant"
|
||||
#define ROLE_DEVIL "devil"
|
||||
#define ROLE_SERVANT_OF_RATVAR "servant of Ratvar"
|
||||
#define ROLE_BROTHER "blood brother"
|
||||
|
||||
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
|
||||
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
|
||||
//(in game days played) to play that role
|
||||
GLOBAL_LIST_INIT(special_roles, list(
|
||||
ROLE_TRAITOR = /datum/game_mode/traitor,
|
||||
ROLE_BROTHER = /datum/game_mode/traitor/bros,
|
||||
ROLE_OPERATIVE = /datum/game_mode/nuclear,
|
||||
ROLE_CHANGELING = /datum/game_mode/changeling,
|
||||
ROLE_WIZARD = /datum/game_mode/wizard,
|
||||
@@ -48,4 +50,4 @@ GLOBAL_LIST_INIT(special_roles, list(
|
||||
//Job defines for what happens when you fail to qualify for any job during job selection
|
||||
#define BEASSISTANT 1
|
||||
#define BERANDOMJOB 2
|
||||
#define RETURNTOLOBBY 3
|
||||
#define RETURNTOLOBBY 3
|
||||
|
||||
@@ -147,11 +147,13 @@ GLOBAL_PROTECT(config_dir)
|
||||
var/irc_first_connection_alert = 0 // do we notify the irc channel when somebody is connecting for the first time?
|
||||
|
||||
var/traitor_scaling_coeff = 6 //how much does the amount of players get divided by to determine traitors
|
||||
var/brother_scaling_coeff = 25 //how many players per brother team
|
||||
var/changeling_scaling_coeff = 6 //how much does the amount of players get divided by to determine changelings
|
||||
var/security_scaling_coeff = 8 //how much does the amount of players get divided by to determine open security officer positions
|
||||
var/abductor_scaling_coeff = 15 //how many players per abductor team
|
||||
|
||||
var/traitor_objectives_amount = 2
|
||||
var/brother_objectives_amount = 2
|
||||
var/protect_roles_from_antagonist = 0 //If security and such can be traitor/cult/other
|
||||
var/protect_assistant_from_antagonist = 0 //If assistants can be traitor/cult/other
|
||||
var/enforce_human_authority = 0 //If non-human species are barred from joining as a head of staff
|
||||
@@ -692,6 +694,8 @@ GLOBAL_PROTECT(config_dir)
|
||||
ghost_interaction = 1
|
||||
if("traitor_scaling_coeff")
|
||||
traitor_scaling_coeff = text2num(value)
|
||||
if("brother_scaling_coeff")
|
||||
brother_scaling_coeff = text2num(value)
|
||||
if("changeling_scaling_coeff")
|
||||
changeling_scaling_coeff = text2num(value)
|
||||
if("security_scaling_coeff")
|
||||
@@ -700,6 +704,8 @@ GLOBAL_PROTECT(config_dir)
|
||||
abductor_scaling_coeff = text2num(value)
|
||||
if("traitor_objectives_amount")
|
||||
traitor_objectives_amount = text2num(value)
|
||||
if("brother_objectives_amount")
|
||||
brother_objectives_amount = text2num(value)
|
||||
if("probability")
|
||||
var/prob_pos = findtext(value, " ")
|
||||
var/prob_name = null
|
||||
|
||||
48
code/datums/antagonists/datum_brother.dm
Normal file
48
code/datums/antagonists/datum_brother.dm
Normal file
@@ -0,0 +1,48 @@
|
||||
/datum/antagonist/brother
|
||||
name = "Brother"
|
||||
var/special_role = "blood brother"
|
||||
var/datum/objective_team/brother_team/team
|
||||
|
||||
/datum/antagonist/brother/New(datum/mind/new_owner, datum/objective_team/brother_team/T)
|
||||
team = T
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/brother/on_gain()
|
||||
SSticker.mode.brothers += owner
|
||||
owner.special_role = special_role
|
||||
owner.objectives += team.objectives
|
||||
finalize_brother()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/brother/on_removal()
|
||||
SSticker.mode.brothers -= owner
|
||||
team.members -= owner
|
||||
owner.objectives -= team.objectives
|
||||
if(owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'>You are no longer the [special_role]!</span>")
|
||||
owner.special_role = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/brother/proc/give_meeting_area()
|
||||
if(!owner.current || !team || !team.meeting_area)
|
||||
return
|
||||
to_chat(owner.current, "<B>Your designated meeting area:</B> [team.meeting_area]")
|
||||
owner.store_memory("<b>Meeting Area</b>: [team.meeting_area]")
|
||||
|
||||
/datum/antagonist/brother/greet()
|
||||
var/brother_text = ""
|
||||
var/list/brothers = team.members - owner
|
||||
for(var/i = 1 to brothers.len)
|
||||
var/datum/mind/M = brothers[i]
|
||||
brother_text += M.name
|
||||
if(i == brothers.len - 1)
|
||||
brother_text += " and "
|
||||
else if(i != brothers.len)
|
||||
brother_text += ", "
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role] of [brother_text].</font></B>")
|
||||
to_chat(owner.current, "The Syndicate only accepts those that have proven themself. Prove yourself and prove your [team.member_name]s by completing your objectives together!")
|
||||
owner.announce_objectives()
|
||||
give_meeting_area()
|
||||
|
||||
/datum/antagonist/brother/proc/finalize_brother()
|
||||
SSticker.mode.update_brother_icons_added(owner)
|
||||
@@ -20,6 +20,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
))
|
||||
|
||||
/datum/atom_hud
|
||||
|
||||
@@ -127,10 +127,10 @@
|
||||
memory = null
|
||||
|
||||
// Datum antag mind procs
|
||||
/datum/mind/proc/add_antag_datum(datum_type)
|
||||
/datum/mind/proc/add_antag_datum(datum_type, team)
|
||||
if(!datum_type)
|
||||
return
|
||||
var/datum/antagonist/A = new datum_type(src)
|
||||
var/datum/antagonist/A = new datum_type(src, team)
|
||||
if(!A.can_be_owned(src))
|
||||
qdel(A)
|
||||
return
|
||||
@@ -190,6 +190,11 @@
|
||||
src.remove_antag_datum(ANTAG_DATUM_TRAITOR)
|
||||
SSticker.mode.update_traitor_icons_removed(src)
|
||||
|
||||
/datum/mind/proc/remove_brother()
|
||||
if(src in SSticker.mode.brothers)
|
||||
src.remove_antag_datum(ANTAG_DATUM_BROTHER)
|
||||
SSticker.mode.update_brother_icons_removed(src)
|
||||
|
||||
/datum/mind/proc/remove_nukeop()
|
||||
if(src in SSticker.mode.syndicates)
|
||||
SSticker.mode.syndicates -= src
|
||||
@@ -345,6 +350,12 @@
|
||||
var/obj_count = 1
|
||||
for(var/datum/objective/objective in objectives)
|
||||
output += "<br><B>Objective #[obj_count++]</B>: [objective.explanation_text]"
|
||||
var/list/datum/mind/other_owners = objective.get_owners() - src
|
||||
if(other_owners.len)
|
||||
output += "<ul>"
|
||||
for(var/datum/mind/M in other_owners)
|
||||
output += "<li>Conspirator: [M.name]</li>"
|
||||
output += "</ul>"
|
||||
|
||||
if(window)
|
||||
recipient << browse(output,"window=memory")
|
||||
@@ -381,7 +392,7 @@
|
||||
|
||||
/** TRAITOR ***/
|
||||
text = "traitor"
|
||||
if (SSticker.mode.config_tag=="traitor" || SSticker.mode.config_tag=="traitorchan")
|
||||
if (SSticker.mode.config_tag=="traitor" || SSticker.mode.config_tag=="traitorchan" || SSticker.mode.config_tag=="traitorbro")
|
||||
text = uppertext(text)
|
||||
text = "<i><b>[text]</b></i>: "
|
||||
if (src in SSticker.mode.traitors)
|
||||
@@ -401,6 +412,21 @@
|
||||
|
||||
if(ishuman(current) || ismonkey(current))
|
||||
|
||||
/** BROTHER **/
|
||||
text = "brother"
|
||||
if(SSticker.mode.config_tag == "traitorbro")
|
||||
text = uppertext(text)
|
||||
text = "<i><b>[text]</b></i>: "
|
||||
if(src in SSticker.mode.brothers)
|
||||
text += "<b>Brother</b> | <a href='?src=\ref[src];brother=clear'>no</a>"
|
||||
|
||||
if(current && current.client && (ROLE_BROTHER in current.client.prefs.be_special))
|
||||
text += " | Enabled in Prefs"
|
||||
else
|
||||
text += " | Disabled in Prefs"
|
||||
|
||||
sections["brother"] = text
|
||||
|
||||
/** CHANGELING ***/
|
||||
text = "changeling"
|
||||
if (SSticker.mode.config_tag=="changeling" || SSticker.mode.config_tag=="traitorchan")
|
||||
@@ -1275,6 +1301,13 @@
|
||||
if(H)
|
||||
src = H.mind
|
||||
|
||||
else if (href_list["brother"])
|
||||
switch(href_list["brother"])
|
||||
if("clear")
|
||||
remove_brother()
|
||||
log_admin("[key_name(usr)] has de-brother'ed [current].")
|
||||
SSticker.mode.update_brother_icons_removed(src)
|
||||
|
||||
else if (href_list["silicon"])
|
||||
switch(href_list["silicon"])
|
||||
if("unemag")
|
||||
|
||||
137
code/game/gamemodes/brother/traitor_bro.dm
Normal file
137
code/game/gamemodes/brother/traitor_bro.dm
Normal file
@@ -0,0 +1,137 @@
|
||||
/datum/objective_team/brother_team
|
||||
name = "brotherhood"
|
||||
member_name = "blood brother"
|
||||
var/list/objectives = list()
|
||||
var/meeting_area
|
||||
|
||||
/datum/objective_team/brother_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/objective_team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
|
||||
O.team = src
|
||||
if(needs_target)
|
||||
O.find_target()
|
||||
O.update_explanation_text()
|
||||
objectives += O
|
||||
|
||||
/datum/objective_team/brother_team/proc/forge_brother_objectives()
|
||||
objectives = list()
|
||||
var/is_hijacker = prob(10)
|
||||
for(var/i = 1 to max(1, config.brother_objectives_amount + (members.len > 2) - is_hijacker))
|
||||
forge_single_objective()
|
||||
if(is_hijacker)
|
||||
if(!locate(/datum/objective/hijack) in objectives)
|
||||
add_objective(new/datum/objective/hijack)
|
||||
else if(!locate(/datum/objective/escape) in objectives)
|
||||
add_objective(new/datum/objective/escape)
|
||||
|
||||
/datum/objective_team/brother_team/proc/forge_single_objective()
|
||||
if(prob(50))
|
||||
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
|
||||
add_objective(new/datum/objective/destroy, TRUE)
|
||||
else if(prob(30))
|
||||
add_objective(new/datum/objective/maroon, TRUE)
|
||||
else
|
||||
add_objective(new/datum/objective/assassinate, TRUE)
|
||||
else
|
||||
add_objective(new/datum/objective/steal, TRUE)
|
||||
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/brothers = list()
|
||||
var/list/datum/objective_team/brother_team/brother_teams = list()
|
||||
|
||||
/datum/game_mode/traitor/bros
|
||||
name = "traitor+brothers"
|
||||
config_tag = "traitorbro"
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
|
||||
announce_span = "danger"
|
||||
announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\
|
||||
<span class='danger'>Traitors</span>: Accomplish your objectives.\n\
|
||||
<span class='danger'>Blood Brothers</span>: Accomplish your objectives.\n\
|
||||
<span class='notice'>Crew</span>: Do not let the traitors or brothers succeed!"
|
||||
|
||||
var/list/datum/objective_team/brother_team/pre_brother_teams = list()
|
||||
var/const/team_amount = 2 //hard limit on brother teams if scaling is turned off
|
||||
var/const/min_team_size = 2
|
||||
|
||||
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
|
||||
|
||||
/datum/game_mode/traitor/bros/pre_setup()
|
||||
if(config.protect_roles_from_antagonist)
|
||||
restricted_jobs += protected_jobs
|
||||
if(config.protect_assistant_from_antagonist)
|
||||
restricted_jobs += "Assistant"
|
||||
|
||||
var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER)
|
||||
|
||||
var/num_teams = team_amount
|
||||
if(config.brother_scaling_coeff)
|
||||
num_teams = max(1, round(num_players()/config.brother_scaling_coeff))
|
||||
|
||||
for(var/j = 1 to num_teams)
|
||||
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
|
||||
break
|
||||
var/datum/objective_team/brother_team/team = new
|
||||
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
|
||||
for(var/k = 1 to team_size)
|
||||
var/datum/mind/bro = pick(possible_brothers)
|
||||
possible_brothers -= bro
|
||||
antag_candidates -= bro
|
||||
team.members += bro
|
||||
bro.restricted_roles = restricted_jobs
|
||||
log_game("[key_name(bro)] has been selected as a Brother")
|
||||
pre_brother_teams += team
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/traitor/bros/post_setup()
|
||||
for(var/datum/objective_team/brother_team/team in pre_brother_teams)
|
||||
team.meeting_area = pick(meeting_areas)
|
||||
meeting_areas -= team.meeting_area
|
||||
team.forge_brother_objectives()
|
||||
for(var/datum/mind/M in team.members)
|
||||
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
|
||||
modePlayer += M
|
||||
brother_teams += pre_brother_teams
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_brother()
|
||||
if(!LAZYLEN(brother_teams))
|
||||
return
|
||||
var/text = "<br><font size=4><b>The blood brothers were:</b></font>"
|
||||
var/teamnumber = 1
|
||||
for(var/datum/objective_team/brother_team/team in brother_teams)
|
||||
if(!team.members.len)
|
||||
continue
|
||||
text += "<br><font size=3><b>Team #[teamnumber++]</b></font>"
|
||||
for(var/datum/mind/M in team.members)
|
||||
text += printplayer(M)
|
||||
var/win = TRUE
|
||||
var/objective_count = 1
|
||||
for(var/datum/objective/objective in team.objectives)
|
||||
if(objective.check_completion())
|
||||
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font>"
|
||||
SSblackbox.add_details("traitor_objective","[objective.type]|SUCCESS")
|
||||
else
|
||||
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='red'>Fail.</font>"
|
||||
SSblackbox.add_details("traitor_objective","[objective.type]|FAIL")
|
||||
win = FALSE
|
||||
objective_count++
|
||||
if(win)
|
||||
text += "<br><font color='green'><B>The blood brothers were successful!</B></font>"
|
||||
SSblackbox.add_details("brother_success","SUCCESS")
|
||||
else
|
||||
text += "<br><font color='red'><B>The blood brothers have failed!</B></font>"
|
||||
SSblackbox.add_details("brother_success","FAIL")
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
/datum/game_mode/proc/update_brother_icons_added(datum/mind/brother_mind)
|
||||
var/datum/atom_hud/antag/brotherhud = GLOB.huds[ANTAG_HUD_BROTHER]
|
||||
brotherhud.join_hud(brother_mind.current)
|
||||
set_antag_hud(brother_mind.current, "brother")
|
||||
|
||||
/datum/game_mode/proc/update_brother_icons_removed(datum/mind/brother_mind)
|
||||
var/datum/atom_hud/antag/brotherhud = GLOB.huds[ANTAG_HUD_BROTHER]
|
||||
brotherhud.leave_hud(brother_mind.current)
|
||||
set_antag_hud(brother_mind.current, null)
|
||||
@@ -47,7 +47,7 @@
|
||||
team_names[team_number] = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
|
||||
//Team Objective
|
||||
var/datum/objective/experiment/team_objective = new
|
||||
team_objective.team = team_number
|
||||
team_objective.team_number = team_number
|
||||
team_objectives[team_number] = team_objective
|
||||
//Team Members
|
||||
|
||||
@@ -212,13 +212,13 @@
|
||||
// OBJECTIVES
|
||||
/datum/objective/experiment
|
||||
target_amount = 6
|
||||
var/team
|
||||
var/team_number
|
||||
|
||||
/datum/objective/experiment/New()
|
||||
explanation_text = "Experiment on [target_amount] humans."
|
||||
|
||||
/datum/objective/experiment/check_completion()
|
||||
var/ab_team = team
|
||||
var/ab_team = team_number
|
||||
if(owner)
|
||||
if(!owner.current || !ishuman(owner.current))
|
||||
return 0
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/objective
|
||||
var/datum/mind/owner = null //Who owns the objective.
|
||||
var/datum/mind/owner //The primary owner of the objective. !!SOMEWHAT DEPRECATED!! Prefer using 'team' for new code.
|
||||
var/datum/objective_team/team //An alternative to 'owner': a team. Use this when writing new code.
|
||||
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 = 0 //If they are focused on a particular number. Steal objectives have their own counter.
|
||||
var/completed = 0 //currently only used for custom objectives.
|
||||
@@ -10,19 +12,48 @@
|
||||
if(text)
|
||||
explanation_text = text
|
||||
|
||||
/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/considered_alive(var/datum/mind/M)
|
||||
if(M && M.current)
|
||||
var/mob/living/carbon/human/H
|
||||
if(ishuman(M.current))
|
||||
H = M.current
|
||||
return M.current.stat != DEAD && !issilicon(M.current) && !isbrain(M.current) && (!H || H.dna.species.id != "memezombies")
|
||||
return FALSE
|
||||
|
||||
/datum/objective/proc/considered_escaped(datum/mind/M)
|
||||
if(!considered_alive(M))
|
||||
return FALSE
|
||||
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/brig)) // Fails if they are in the shuttle brig
|
||||
return FALSE
|
||||
return location.onCentCom() || location.onSyndieBase()
|
||||
|
||||
/datum/objective/proc/considered_afk(datum/mind/M)
|
||||
return !M || !M.current || !M.current.client || M.current.client.is_afk()
|
||||
|
||||
/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
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
for(var/datum/mind/M in owners)
|
||||
for(var/datum/objective/O in M.objectives)
|
||||
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)
|
||||
@@ -32,9 +63,10 @@
|
||||
. += M
|
||||
|
||||
/datum/objective/proc/find_target()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
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 != DEAD) && is_unique_objective(possible_target))
|
||||
if(!(possible_target in owners) && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && is_unique_objective(possible_target))
|
||||
possible_targets += possible_target
|
||||
if(possible_targets.len > 0)
|
||||
target = pick(possible_targets)
|
||||
@@ -42,8 +74,9 @@
|
||||
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 != owner) && ishuman(possible_target.current))
|
||||
if(!(possible_target in owners) && ishuman(possible_target.current))
|
||||
var/is_role = 0
|
||||
if(role_type)
|
||||
if(possible_target.special_role == role)
|
||||
@@ -64,13 +97,15 @@
|
||||
update_explanation_text()
|
||||
|
||||
/datum/objective/proc/update_explanation_text()
|
||||
//Default does nothing, override where needed
|
||||
if(team_explanation_text && LAZYLEN(get_owners()) > 1)
|
||||
explanation_text = team_explanation_text
|
||||
|
||||
/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)
|
||||
var/datum/mind/receiver = pick(get_owners())
|
||||
if(receiver && receiver.current)
|
||||
if(ishuman(receiver.current))
|
||||
var/mob/living/carbon/human/H = receiver.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)
|
||||
@@ -86,14 +121,7 @@
|
||||
return target
|
||||
|
||||
/datum/objective/assassinate/check_completion()
|
||||
if(target && target.current)
|
||||
var/mob/living/carbon/human/H
|
||||
if(ishuman(target.current))
|
||||
H = target.current
|
||||
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey || (H && H.dna.species.id == "memezombies")) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
return !target || !considered_alive(target)
|
||||
|
||||
/datum/objective/assassinate/update_explanation_text()
|
||||
..()
|
||||
@@ -110,7 +138,6 @@
|
||||
if(target && !target.current)
|
||||
explanation_text = "Assassinate [target.name], who was obliterated"
|
||||
|
||||
|
||||
/datum/objective/mutiny
|
||||
var/target_role_type=0
|
||||
martyr_compatible = 1
|
||||
@@ -122,14 +149,10 @@
|
||||
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 in GLOB.station_z_levels)) || (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
|
||||
if(!target || !considered_alive(target) || considered_afk(target))
|
||||
return TRUE
|
||||
var/turf/T = get_turf(target.current)
|
||||
return T && !(T.z in GLOB.station_z_levels)
|
||||
|
||||
/datum/objective/mutiny/update_explanation_text()
|
||||
..()
|
||||
@@ -138,8 +161,6 @@
|
||||
else
|
||||
explanation_text = "Free Objective"
|
||||
|
||||
|
||||
|
||||
/datum/objective/maroon
|
||||
var/target_role_type=0
|
||||
martyr_compatible = 1
|
||||
@@ -151,15 +172,7 @@
|
||||
return target
|
||||
|
||||
/datum/objective/maroon/check_completion()
|
||||
if(target && target.current)
|
||||
var/mob/living/carbon/human/H
|
||||
if(ishuman(target.current))
|
||||
H = target.current
|
||||
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey || (H && H.dna.species.id == "memezombies")) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
|
||||
return 1
|
||||
if(target.current.onCentCom() || target.current.onSyndieBase())
|
||||
return 0
|
||||
return 1
|
||||
return !target || !considered_alive(target) || (!target.current.onCentCom() && !target.current.onSyndieBase())
|
||||
|
||||
/datum/objective/maroon/update_explanation_text()
|
||||
if(target && target.current)
|
||||
@@ -167,9 +180,7 @@
|
||||
else
|
||||
explanation_text = "Free Objective"
|
||||
|
||||
|
||||
|
||||
/datum/objective/debrain//I want braaaainssss
|
||||
/datum/objective/debrain
|
||||
var/target_role_type=0
|
||||
|
||||
/datum/objective/debrain/find_target_by_role(role, role_type=0, invert=0)
|
||||
@@ -180,17 +191,20 @@
|
||||
|
||||
/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
|
||||
return TRUE
|
||||
|
||||
if(!target.current || !isbrain(target.current))
|
||||
return FALSE
|
||||
|
||||
var/atom/A = target.current
|
||||
while(A.loc) //check to see if the brainmob is on our person
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
|
||||
while(A.loc) // Check to see if the brainmob is on our person
|
||||
A = A.loc
|
||||
if(A == owner.current)
|
||||
return 1
|
||||
return 0
|
||||
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()
|
||||
..()
|
||||
@@ -199,8 +213,6 @@
|
||||
else
|
||||
explanation_text = "Free Objective"
|
||||
|
||||
|
||||
|
||||
/datum/objective/protect//The opposite of killing a dude.
|
||||
var/target_role_type=0
|
||||
martyr_compatible = 1
|
||||
@@ -212,13 +224,7 @@
|
||||
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
|
||||
return !target || considered_alive(target)
|
||||
|
||||
/datum/objective/protect/update_explanation_text()
|
||||
..()
|
||||
@@ -227,76 +233,32 @@
|
||||
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."
|
||||
team_explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody. Leave no team member behind."
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
|
||||
/datum/objective/hijack/check_completion()
|
||||
if(!owner.current || owner.current.stat)
|
||||
return 0
|
||||
/datum/objective/hijack/check_completion() // Requires all owners to escape.
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return 0
|
||||
if(issilicon(owner.current))
|
||||
return 0
|
||||
if(!SSshuttle.emergency.shuttle_areas[get_area(owner.current)])
|
||||
return 0
|
||||
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/hijackclone
|
||||
explanation_text = "Hijack the emergency shuttle by ensuring only you (or your copies) escape."
|
||||
martyr_compatible = 0
|
||||
|
||||
/datum/objective/hijackclone/check_completion()
|
||||
if(!owner.current)
|
||||
return FALSE
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return FALSE
|
||||
|
||||
var/in_shuttle = FALSE
|
||||
for(var/mob/living/player in GLOB.player_list) //Make sure nobody else is onboard
|
||||
if(SSshuttle.emergency.shuttle_areas[get_area(player)])
|
||||
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
|
||||
var/location = get_turf(player.mind.current)
|
||||
if(istype(location, /turf/open/floor/plasteel/shuttle/red))
|
||||
continue
|
||||
if(istype(location, /turf/open/floor/mineral/plastitanium/brig))
|
||||
continue
|
||||
if(player.real_name != owner.current.real_name)
|
||||
return FALSE
|
||||
else
|
||||
in_shuttle = TRUE
|
||||
return in_shuttle
|
||||
|
||||
/datum/objective/block
|
||||
explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive."
|
||||
martyr_compatible = 1
|
||||
|
||||
/datum/objective/block/check_completion()
|
||||
if(!issilicon(owner.current))
|
||||
return 0
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return 1
|
||||
|
||||
return TRUE
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(issilicon(player))
|
||||
continue
|
||||
if(player.mind)
|
||||
if(player.stat != DEAD)
|
||||
if(get_area(player) in SSshuttle.emergency.shuttle_areas)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
if(player.mind && player.stat != DEAD && !issilicon(player))
|
||||
if(get_area(player) in SSshuttle.emergency.shuttle_areas)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/purge
|
||||
explanation_text = "Ensure no mutant humanoid species are present aboard the escape shuttle."
|
||||
@@ -304,63 +266,41 @@
|
||||
|
||||
/datum/objective/purge/check_completion()
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return 1
|
||||
|
||||
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 0
|
||||
|
||||
return 1
|
||||
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/robot_army
|
||||
explanation_text = "Have at least eight active cyborgs synced to you."
|
||||
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
|
||||
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/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()
|
||||
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
|
||||
// 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/escape/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
|
||||
@@ -387,39 +327,36 @@
|
||||
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
|
||||
|
||||
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/survive
|
||||
explanation_text = "Stay alive until the end."
|
||||
|
||||
/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
|
||||
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
for(var/datum/mind/M in owners)
|
||||
if(!considered_alive(M))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/martyr
|
||||
explanation_text = "Die a glorious death."
|
||||
|
||||
/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
|
||||
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
for(var/datum/mind/M in owners)
|
||||
if(considered_alive(M))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/nuclear
|
||||
explanation_text = "Destroy the station with a nuclear device."
|
||||
@@ -427,8 +364,8 @@
|
||||
|
||||
/datum/objective/nuclear/check_completion()
|
||||
if(SSticker && SSticker.mode && SSticker.mode.station_was_nuked)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
GLOBAL_LIST_EMPTY(possible_items)
|
||||
/datum/objective/steal
|
||||
@@ -446,16 +383,21 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
new I
|
||||
|
||||
/datum/objective/steal/find_target()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
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))
|
||||
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]"
|
||||
give_special_equipment(targetinfo.special_equipment)
|
||||
@@ -483,23 +425,26 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
return steal_target
|
||||
|
||||
/datum/objective/steal/check_completion()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
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.
|
||||
return TRUE
|
||||
for(var/datum/mind/M in owners)
|
||||
if(!isliving(M.current))
|
||||
continue
|
||||
|
||||
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
|
||||
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
|
||||
|
||||
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
|
||||
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 1 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 0 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)
|
||||
@@ -553,31 +498,22 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
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
|
||||
/datum/objective/download/check_completion()//NINJACODE.
|
||||
var/current_amount = 0
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
for(var/datum/mind/M in owners)
|
||||
if(!ishuman(owner.current))
|
||||
continue
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(!H || H.stat == DEAD || !istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
|
||||
continue
|
||||
var/obj/item/clothing/suit/space/space_ninja/SN = H.wear_suit
|
||||
if(!SN.s_initialized)
|
||||
continue
|
||||
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
|
||||
return current_amount >= target_amount
|
||||
|
||||
|
||||
|
||||
@@ -614,10 +550,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
captured_amount+=1
|
||||
continue
|
||||
captured_amount+=2
|
||||
if(captured_amount<target_amount)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
return captured_amount >= target_amount
|
||||
|
||||
|
||||
/datum/objective/absorb
|
||||
@@ -625,13 +558,14 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
/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!=owner)
|
||||
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 in SSticker.mode.changelings) && P.mind!=owner)
|
||||
if(P.client && !(P.mind in SSticker.mode.changelings) && !(P.mind in owners))
|
||||
n_p ++
|
||||
target_amount = min(target_amount, n_p)
|
||||
|
||||
@@ -639,10 +573,13 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
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
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
var/absorbedcount = 0
|
||||
for(var/datum/mind/M in owners)
|
||||
if(!owner || !owner.changeling || !owner.changeling.stored_profiles)
|
||||
continue
|
||||
absorbedcount += M.changeling.absorbedcount
|
||||
return absorbedcount >= target_amount
|
||||
|
||||
|
||||
|
||||
@@ -658,10 +595,8 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
|
||||
/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
|
||||
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/update_explanation_text()
|
||||
..()
|
||||
@@ -690,18 +625,16 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
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/device/necromantic_stone)
|
||||
|
||||
/datum/objective/steal_five_of_type/check_completion()
|
||||
if(!isliving(owner.current))
|
||||
return 0
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
13
code/game/gamemodes/objective_team.dm
Normal file
13
code/game/gamemodes/objective_team.dm
Normal file
@@ -0,0 +1,13 @@
|
||||
//A barebones antagonist team.
|
||||
/datum/objective_team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
|
||||
/datum/objective_team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
members += starting_members
|
||||
|
||||
/datum/objective_team/proc/is_solo()
|
||||
return members.len == 1
|
||||
@@ -54,10 +54,7 @@
|
||||
log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
|
||||
antag_candidates.Remove(traitor)
|
||||
|
||||
|
||||
if(pre_traitors.len < required_enemies)
|
||||
return 0
|
||||
return 1
|
||||
return pre_traitors.len > 0
|
||||
|
||||
|
||||
/datum/game_mode/traitor/post_setup()
|
||||
|
||||
@@ -517,6 +517,21 @@
|
||||
dat += "<td><A href='?priv_msg=[traitor.key]'>PM</A></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
if(SSticker.mode.brother_teams.len > 0)
|
||||
dat += "<br><table cellspacing=5><tr><td><B>Brothers</B></td><td></td><td></td></tr>"
|
||||
for(var/datum/objective_team/brother_team/team in SSticker.mode.brother_teams)
|
||||
for(var/datum/mind/brother in team.members)
|
||||
var/mob/M = brother.current
|
||||
if(M)
|
||||
dat += "<tr><td><a href='?_src_=holder;[HrefToken()];adminplayeropts=\ref[M]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
|
||||
dat += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>"
|
||||
dat += "<td><A href='?_src_=holder;[HrefToken()];adminplayerobservefollow=\ref[M]'>FLW</a></td>"
|
||||
dat += "<td><A HREF='?_src_=holder;[HrefToken()];traitor=\ref[M]'>Show Objective</A></td></tr>"
|
||||
else
|
||||
dat += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=\ref[brother]'>[brother.name]([brother.key])</a><i>Brother body destroyed!</i></td>"
|
||||
dat += "<td><A href='?priv_msg=[brother.key]'>PM</A></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
if(SSticker.mode.abductors.len)
|
||||
dat += "<br><table cellspacing=5><tr><td><B>Abductors</B></td><td></td><td></td></tr>"
|
||||
for(var/datum/mind/abductor in SSticker.mode.abductors)
|
||||
|
||||
@@ -48,8 +48,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
var/B_monkey = 2048
|
||||
var/B_gang = 4096
|
||||
var/B_abductor = 16384
|
||||
var/B_brother = 32768
|
||||
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_abductor)
|
||||
var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_blob,B_ninja,B_monkey,B_gang,B_abductor,B_brother)
|
||||
|
||||
be_special = list()
|
||||
|
||||
@@ -83,6 +84,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
be_special += ROLE_MONKEY
|
||||
if(16384)
|
||||
be_special += ROLE_ABDUCTOR
|
||||
if(32768)
|
||||
be_special += ROLE_BROTHER
|
||||
|
||||
|
||||
/datum/preferences/proc/update_preferences(current_version, savefile/S)
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
if(shuttle_areas[get_area(player)])
|
||||
has_people = TRUE
|
||||
var/location = get_turf(player.mind.current)
|
||||
if(!(player.mind.special_role == "traitor" || player.mind.special_role == "Syndicate") && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/brig))
|
||||
if(!(player.mind.special_role == "traitor" || player.mind.special_role == "Syndicate" || player.mind.special_role == "blood brother") && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/brig))
|
||||
return FALSE
|
||||
|
||||
return has_people
|
||||
|
||||
@@ -81,11 +81,11 @@ ALERT_DELTA Destruction of the station is imminent. All crew are instructed to o
|
||||
## Set to 0 to disable that mode.
|
||||
|
||||
PROBABILITY TRAITOR 5
|
||||
PROBABILITY TRAITORBRO 2
|
||||
PROBABILITY TRAITORCHAN 4
|
||||
PROBABILITY INTERNAL_AFFAIRS 3
|
||||
PROBABILITY NUCLEAR 2
|
||||
PROBABILITY REVOLUTION 2
|
||||
PROBABILITY GANG 2
|
||||
PROBABILITY CULT 2
|
||||
PROBABILITY CHANGELING 2
|
||||
PROBABILITY WIZARD 4
|
||||
@@ -109,11 +109,11 @@ REPEATED_MODE_ADJUST 45 30 10
|
||||
## Modes that aren't continuous will end the instant all antagonists are dead.
|
||||
|
||||
CONTINUOUS TRAITOR
|
||||
CONTINUOUS TRAITORBRO
|
||||
CONTINUOUS TRAITORCHAN
|
||||
CONTINUOUS INTERNAL_AFFAIRS
|
||||
#CONTINUOUS NUCLEAR
|
||||
#CONTINUOUS REVOLUTION
|
||||
CONTINUOUS GANG
|
||||
CONTINUOUS CULT
|
||||
CONTINUOUS CLOCKWORK_CULT
|
||||
CONTINUOUS CHANGELING
|
||||
@@ -134,11 +134,11 @@ CONTINUOUS SECRET_EXTENDED
|
||||
## In modes that are continuous, if all antagonists should die then a new set of antagonists will be created.
|
||||
|
||||
MIDROUND_ANTAG TRAITOR
|
||||
#MIDROUND_ANTAG TRAITORBRO
|
||||
MIDROUND_ANTAG TRAITORCHAN
|
||||
MIDROUND_ANTAG INTERNAL_AFFAIRS
|
||||
#MIDROUND_ANTAG NUCLEAR
|
||||
#MIDROUND_ANTAG REVOLUTION
|
||||
#MIDROUND_ANTAG GANG
|
||||
MIDROUND_ANTAG CULT
|
||||
MIDROUND_ANTAG CLOCKWORK_CULT
|
||||
MIDROUND_ANTAG CHANGELING
|
||||
@@ -157,6 +157,9 @@ MIDROUND_ANTAG ABDUCTION
|
||||
#MIN_POP TRAITOR 0
|
||||
#MAX_POP TRAITOR -1
|
||||
|
||||
#MIN_POP TRAITORBRO 0
|
||||
#MAX_POP TRAITORBRO -1
|
||||
|
||||
#MIN_POP TRAITORCHAN 15
|
||||
#MAX_POP TRAITORCHAN -1
|
||||
|
||||
@@ -169,9 +172,6 @@ MIDROUND_ANTAG ABDUCTION
|
||||
#MIN_POP REVOLUTION 20
|
||||
#MAX_POP REVOLUTION -1
|
||||
|
||||
#MIN_POP GANG 20
|
||||
#MAX_POP GANG -1
|
||||
|
||||
#MIN_POP CULT 24
|
||||
#MAX_POP CULT -1
|
||||
|
||||
@@ -212,6 +212,7 @@ SHUTTLE_REFUEL_DELAY 12000
|
||||
## Used as (Antagonists = Population / Coeff)
|
||||
## Set to 0 to disable scaling and use default numbers instead.
|
||||
TRAITOR_SCALING_COEFF 6
|
||||
BROTHER_SCALING_COEFF 6
|
||||
CHANGELING_SCALING_COEFF 6
|
||||
|
||||
## Variables calculate how number of open security officer positions will scale to population.
|
||||
@@ -222,6 +223,7 @@ SECURITY_SCALING_COEFF 8
|
||||
## The number of objectives traitors get.
|
||||
## Not including escaping/hijacking.
|
||||
TRAITOR_OBJECTIVES_AMOUNT 2
|
||||
BROTHER_OBJECTIVES_AMOUNT 2
|
||||
|
||||
## Uncomment to prohibit jobs that start with loyalty
|
||||
## implants from being most antagonists.
|
||||
|
||||
@@ -244,6 +244,7 @@
|
||||
#include "code\datums\spawners_menu.dm"
|
||||
#include "code\datums\verbs.dm"
|
||||
#include "code\datums\antagonists\antag_datum.dm"
|
||||
#include "code\datums\antagonists\datum_brother.dm"
|
||||
#include "code\datums\antagonists\datum_clockcult.dm"
|
||||
#include "code\datums\antagonists\datum_cult.dm"
|
||||
#include "code\datums\antagonists\datum_internal_affairs.dm"
|
||||
@@ -374,6 +375,8 @@
|
||||
#include "code\game\gamemodes\game_mode.dm"
|
||||
#include "code\game\gamemodes\objective.dm"
|
||||
#include "code\game\gamemodes\objective_items.dm"
|
||||
#include "code\game\gamemodes\objective_team.dm"
|
||||
#include "code\game\gamemodes\brother\traitor_bro.dm"
|
||||
#include "code\game\gamemodes\blob\blob.dm"
|
||||
#include "code\game\gamemodes\blob\blob_finish.dm"
|
||||
#include "code\game\gamemodes\blob\blob_report.dm"
|
||||
|
||||
Reference in New Issue
Block a user