"
+ parts += "
You managed to survive the events on [station_name()] as [M.real_name]."
+
+ else
+ parts += "
"
+ parts += "
You did not survive the events on [station_name()]..."
+ else
+ parts += "
"
+ parts += "
"
+ if(GLOB.survivor_report)
+ parts += GLOB.survivor_report
+ else
+ parts += survivor_report()
+
+ parts += "
"
+
+ return parts.Join()
+
+/datum/controller/subsystem/ticker/proc/display_report()
+ GLOB.common_report = build_roundend_report()
+ for(var/client/C in GLOB.clients)
+ show_roundend_report(C,GLOB.common_report)
+ give_show_report_button(C)
+ CHECK_TICK
+
+/datum/controller/subsystem/ticker/proc/law_report()
+ var/list/parts = list()
+ //Silicon laws report
+ for (var/i in GLOB.ai_list)
+ var/mob/living/silicon/ai/aiPlayer = i
+ if(aiPlayer.mind)
+ parts += "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:"
+ parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
+
+ parts += "
Total law changes: [aiPlayer.law_change_counter]"
+
+ if (aiPlayer.connected_robots.len)
+ var/robolist = "
[aiPlayer.real_name]'s minions were: "
+ for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
+ if(robo.mind)
+ robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
+ parts += "[robolist]"
+
+ for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
+ if (!robo.connected_ai && robo.mind)
+ if (robo.stat != DEAD)
+ parts += "
[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:"
+ else
+ parts += "
[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:"
+
+ if(robo) //How the hell do we lose robo between here and the world messages directly above this?
+ parts += robo.laws.get_law_list(include_zeroth=TRUE)
+ if(parts.len)
+ return "
[parts.Join("
")]
"
+ else
+ return ""
+
+/datum/controller/subsystem/ticker/proc/goal_report()
+ var/list/parts = list()
+ if(mode.station_goals.len)
+ for(var/V in mode.station_goals)
+ var/datum/station_goal/G = V
+ parts += G.get_result()
+ return "
"
+
+/datum/controller/subsystem/ticker/proc/medal_report()
+ if(GLOB.commendations.len)
+ var/list/parts = list()
+ parts += ""
+ for (var/com in GLOB.commendations)
+ parts += com
+ return "
[parts.Join("
")]
"
+ return ""
+
+/datum/controller/subsystem/ticker/proc/antag_report()
+ var/list/result = list()
+ var/list/all_teams = list()
+ var/list/all_antagonists = list()
+
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ all_teams |= A.get_team()
+ all_antagonists += A
+
+ for(var/datum/objective_team/T in all_teams)
+ result += T.roundend_report()
+ for(var/datum/antagonist/X in all_antagonists)
+ if(X.get_team() == T)
+ all_antagonists -= X
+ result += " "//newline between teams
+
+ var/currrent_category
+ var/datum/antagonist/previous_category
+
+ sortTim(all_antagonists, /proc/cmp_antag_category)
+
+ for(var/datum/antagonist/A in all_antagonists)
+ if(!A.show_in_roundend)
+ continue
+ if(A.roundend_category != currrent_category)
+ if(previous_category)
+ result += previous_category.roundend_report_footer()
+ result += "
"
+ result += "
"
+ result += A.roundend_report_header()
+ currrent_category = A.roundend_category
+ previous_category = A
+ result += A.roundend_report()
+ result += "
"
+
+ if(all_antagonists.len)
+ var/datum/antagonist/last = all_antagonists[all_antagonists.len]
+ result += last.roundend_report_footer()
+ result += "
"
+
+ return result.Join()
+
+/proc/cmp_antag_category(datum/antagonist/A,datum/antagonist/B)
+ return sorttext(B.roundend_category,A.roundend_category)
+
+
+/datum/controller/subsystem/ticker/proc/give_show_report_button(client/C)
+ var/datum/action/report/R = new
+ C.player_details.player_actions += R
+ R.Grant(C.mob)
+ to_chat(C,"
Show roundend report again")
+
+/datum/action/report
+ name = "Show roundend report"
+ button_icon_state = "vote"
+
+/datum/action/report/Trigger()
+ if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
+ SSticker.show_roundend_report(owner.client,GLOB.common_report)
+
+/datum/action/report/IsAvailable()
+ return 1
+
+/datum/action/report/Topic(href,href_list)
+ if(usr != owner)
+ return
+ if(href_list["report"])
+ Trigger()
+ return
+
+
+/proc/printplayer(datum/mind/ply, fleecheck)
+ var/text = "
[ply.key] was
[ply.name] the
[ply.assigned_role] and"
+ if(ply.current)
+ if(ply.current.stat == DEAD)
+ text += "
died"
+ else
+ text += "
survived"
+ if(fleecheck)
+ var/turf/T = get_turf(ply.current)
+ if(!T || !(T.z in GLOB.station_z_levels))
+ text += " while
fleeing the station"
+ if(ply.current.real_name != ply.name)
+ text += " as
[ply.current.real_name]"
+ else
+ text += "
had their body destroyed"
+ return text
+
+/proc/printplayerlist(list/players,fleecheck)
+ var/list/parts = list()
+
+ parts += "
"
+ for(var/datum/mind/M in players)
+ parts += "- [printplayer(M,fleecheck)]
"
+ parts += "
"
+ return parts.Join()
+
+
+/proc/printobjectives(datum/mind/ply)
+ var/list/objective_parts = list()
+ var/count = 1
+ for(var/datum/objective/objective in ply.objectives)
+ if(objective.check_completion())
+ objective_parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ objective_parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ count++
+ return objective_parts.Join("
")
\ No newline at end of file
diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm
index 9c3af923f186..3822f7077d1f 100644
--- a/code/_globalvars/game_modes.dm
+++ b/code/_globalvars/game_modes.dm
@@ -1,18 +1,12 @@
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret", the secret rotation will forceably choose this mode
+GLOBAL_VAR(common_report) //Contains commmon part of roundend report
+GLOBAL_VAR(survivor_report) //Contains shared surivor report for roundend report (part of personal report)
+
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
-// Cult, needs to be global so admin cultists are functional
-GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
-GLOBAL_DATUM(blood_target_image, /image)
-GLOBAL_VAR_INIT(blood_target_reset_timer, null)
-GLOBAL_DATUM(sac_mind, /datum/mind)
-GLOBAL_VAR_INIT(sac_image, null)
-GLOBAL_VAR_INIT(cult_vote_called, FALSE)
-GLOBAL_VAR_INIT(cult_mastered, FALSE)
-GLOBAL_VAR_INIT(reckoning_complete, FALSE)
-GLOBAL_VAR_INIT(sac_complete, FALSE)
-GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
-GLOBAL_LIST_EMPTY(summon_spots)
\ No newline at end of file
+
+//TODO clear this one up too
+GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
\ No newline at end of file
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index bb86b4cbb0ef..8b8b81758632 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -16,3 +16,5 @@ GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a perce
GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
+
+GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
\ No newline at end of file
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 0006d72d3b47..2ad2eb76f5f7 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -302,32 +302,41 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
- if(GLOB.blood_target)
- if(!get_turf(GLOB.blood_target))
- GLOB.blood_target = null
+
+ var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!antag)
+ return
+ var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
+
+ if(antag.cult_team.blood_target)
+ if(!get_turf(antag.cult_team.blood_target))
+ antag.cult_team.blood_target = null
else
- blood_target = GLOB.blood_target
+ blood_target = antag.cult_team.blood_target
if(Cviewer && Cviewer.seeking && Cviewer.master)
blood_target = Cviewer.master
desc = "Your blood sense is leading you to [Cviewer.master]"
if(!blood_target)
- if(!GLOB.sac_complete)
+ if(sac_objective && !sac_objective.check_completion())
if(icon_state == "runed_sense0")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense0"
- desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
- add_overlay(GLOB.sac_image)
+ desc = "Nar-Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
+ add_overlay(sac_objective.sac_image)
else
+ var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
+ if(!summon_objective)
+ return
if(icon_state == "runed_sense1")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense1"
- desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
+ desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!"
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
@@ -388,11 +397,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "
CHETR
NYY
HAGEHUGF-NAQ-UBABE
RATVAR."
else
var/servants = 0
- var/list/textlist
+ var/list/textlist = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
- textlist = list("[SSticker.mode.eminence ? "There is an Eminence." : "
There is no Eminence! Get one ASAP!"]
")
+ var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(C && C.clock_team)
+ textlist += "[C.clock_team.eminence ? "There is an Eminence." : "
There is no Eminence! Get one ASAP!"]
"
textlist += "There are currently
[servants] servant[servants > 1 ? "s" : ""] of Ratvar.
"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 4cf5f7df1a29..0d14999a338d 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -9,7 +9,8 @@ SUBSYSTEM_DEF(blackbox)
var/triggertime = 0
var/sealed = FALSE //time to stop tracking stats?
var/list/versions = list("time_dilation_current" = 2,
- "science_techweb_unlock" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
+ "science_techweb_unlock" = 2,
+ "antagonists" = 3) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
@@ -218,7 +219,10 @@ Versioning
var/pos = length(FV.json["data"]) + 1
FV.json["data"]["[pos]"] = list() //in 512 "pos" can be replaced with "[FV.json["data"].len+1]"
for(var/i in data)
- FV.json["data"]["[pos]"]["[i]"] = "[data[i]]" //and here with "[FV.json["data"].len]"
+ if(islist(data[i]))
+ FV.json["data"]["[pos]"]["[i]"] = data[i] //and here with "[FV.json["data"].len]"
+ else
+ FV.json["data"]["[pos]"]["[i]"] = "[data[i]]"
else
CRASH("Invalid feedback key_type: [key_type]")
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 7c1880070f35..1a6c0fcd0e8f 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -373,170 +373,6 @@ SUBSYSTEM_DEF(ticker)
var/mob/living/L = I
L.notransform = FALSE
-/datum/controller/subsystem/ticker/proc/declare_completion()
- set waitfor = FALSE
- var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
- var/num_survivors = 0
- var/num_escapees = 0
- var/num_shuttle_escapees = 0
-
- to_chat(world, "
The round has ended.")
- if(LAZYLEN(GLOB.round_end_notifiees))
- send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
-
- for(var/client/C in GLOB.clients)
- if(!C.credits)
- C.RollCredits()
- C.playtitlemusic(40)
-
- //Player status report
- for(var/i in GLOB.mob_list)
- var/mob/Player = i
- if(Player.mind && !isnewplayer(Player))
- if(Player.stat != DEAD && !isbrain(Player))
- num_survivors++
- if(station_evacuated) //If the shuttle has already left the station
- var/list/area/shuttle_areas
- if(SSshuttle && SSshuttle.emergency)
- shuttle_areas = SSshuttle.emergency.shuttle_areas
- if(!Player.onCentCom() && !Player.onSyndieBase())
- to_chat(Player, "
You managed to survive, but were marooned on [station_name()]...")
- else
- num_escapees++
- to_chat(Player, "
You managed to survive the events on [station_name()] as [Player.real_name].")
- if(shuttle_areas[get_area(Player)])
- num_shuttle_escapees++
- else
- to_chat(Player, "
You managed to survive the events on [station_name()] as [Player.real_name].")
- else
- to_chat(Player, "
You did not survive the events on [station_name()]...")
-
- CHECK_TICK
-
- //Round statistics report
- var/datum/station_state/end_state = new /datum/station_state()
- end_state.count()
- var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
-
- to_chat(world, "
[GLOB.TAB]Shift Duration:
[DisplayTimeText(world.time - SSticker.round_start_time)]")
- to_chat(world, "
[GLOB.TAB]Station Integrity:
[mode.station_was_nuked ? "Destroyed" : "[station_integrity]%"]")
- if(mode.station_was_nuked)
- SSticker.news_report = STATION_DESTROYED_NUKE
- var/total_players = GLOB.joined_player_list.len
- if(total_players)
- to_chat(world, "
[GLOB.TAB]Total Population:
[total_players]")
- if(station_evacuated)
- to_chat(world, "
[GLOB.TAB]Evacuation Rate:
[num_escapees] ([PERCENT(num_escapees/total_players)]%)")
- to_chat(world, "
[GLOB.TAB](on emergency shuttle):
[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)")
- news_report = STATION_EVACUATED
- if(SSshuttle.emergency.is_hijacked())
- news_report = SHUTTLE_HIJACK
- to_chat(world, "
[GLOB.TAB]Survival Rate:
[num_survivors] ([PERCENT(num_survivors/total_players)]%)")
- to_chat(world, "
")
-
- CHECK_TICK
-
- //Silicon laws report
- for (var/i in GLOB.ai_list)
- var/mob/living/silicon/ai/aiPlayer = i
- if (aiPlayer.stat != DEAD && aiPlayer.mind)
- to_chat(world, "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws at the end of the round were:")
- aiPlayer.show_laws(1)
- else if (aiPlayer.mind) //if the dead ai has a mind, use its key instead
- to_chat(world, "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws when it was deactivated were:")
- aiPlayer.show_laws(1)
-
- to_chat(world, "
Total law changes: [aiPlayer.law_change_counter]")
-
- if (aiPlayer.connected_robots.len)
- var/robolist = "
[aiPlayer.real_name]'s minions were: "
- for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
- if(robo.mind)
- robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
- to_chat(world, "[robolist]")
-
- CHECK_TICK
-
- for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
- if (!robo.connected_ai && robo.mind)
- if (robo.stat != DEAD)
- to_chat(world, "
[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:")
- else
- to_chat(world, "
[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:")
-
- if(robo) //How the hell do we lose robo between here and the world messages directly above this?
- robo.laws.show_laws(world)
-
- CHECK_TICK
-
- mode.declare_completion()//To declare normal completion.
-
- CHECK_TICK
-
- //calls auto_declare_completion_* for all modes
- for(var/handler in typesof(/datum/game_mode/proc))
- if (findtext("[handler]","auto_declare_completion_"))
- call(mode, handler)(force_ending)
-
- CHECK_TICK
-
- if(CONFIG_GET(string/cross_server_address))
- send_news_report()
-
- CHECK_TICK
-
- //Print a list of antagonists to the server log
- var/list/total_antagonists = list()
- //Look into all mobs in world, dead or alive
- for(var/datum/mind/Mind in minds)
- var/temprole = Mind.special_role
- if(temprole) //if they are an antagonist of some sort.
- if(temprole in total_antagonists) //If the role exists already, add the name to it
- total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
- else
- total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
- total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
-
- CHECK_TICK
-
- //Now print them all into the log!
- log_game("Antagonists at round end were...")
- for(var/i in total_antagonists)
- log_game("[i]s[total_antagonists[i]].")
-
- CHECK_TICK
-
- mode.declare_station_goal_completion()
-
- CHECK_TICK
- //medals, placed far down so that people can actually see the commendations.
- if(GLOB.commendations.len)
- to_chat(world, "
Medal Commendations:")
- for (var/com in GLOB.commendations)
- to_chat(world, com)
-
- CHECK_TICK
-
- //Collects persistence features
- if(mode.allow_persistence_save)
- SSpersistence.CollectData()
-
- //stop collecting feedback during grifftime
- SSblackbox.Seal()
-
- sleep(50)
- ready_for_reboot = TRUE
- standard_reboot()
-
-/datum/controller/subsystem/ticker/proc/standard_reboot()
- if(ready_for_reboot)
- if(mode.station_was_nuked)
- Reboot("Station destroyed by Nuclear Device.", "nuke")
- else
- Reboot("Round ended.", "proper completion")
- else
- CRASH("Attempted standard reboot without ticker roundend completion")
-
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
if(selected_tip)
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index a6ba190658eb..0fdc6fbb5b15 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -197,6 +197,7 @@ SUBSYSTEM_DEF(vote)
var/datum/action/vote/V = new
if(question)
V.name = "Vote: [question]"
+ C.player_details.player_actions += V
V.Grant(C.mob)
generated_actions += V
return 1
@@ -290,6 +291,7 @@ SUBSYSTEM_DEF(vote)
for(var/v in generated_actions)
var/datum/action/vote/V = v
if(!QDELETED(V))
+ V.remove_from_client()
V.Remove(V.owner)
generated_actions = list()
@@ -309,7 +311,16 @@ SUBSYSTEM_DEF(vote)
/datum/action/vote/Trigger()
if(owner)
owner.vote()
+ remove_from_client()
Remove(owner)
/datum/action/vote/IsAvailable()
return 1
+
+/datum/action/vote/proc/remove_from_client()
+ if(owner.client)
+ owner.client.player_details.player_actions -= src
+ else if(owner.ckey)
+ var/datum/player_details/P = GLOB.player_details[owner.ckey]
+ if(P)
+ P.player_actions -= src
\ No newline at end of file
diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm
index 8d86507271e1..c12a08a79283 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -373,32 +373,9 @@
ion = list()
/datum/ai_laws/proc/show_laws(who)
-
- if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
- for(var/i in devillaws)
- to_chat(who, "666. [i]")
-
- if (zeroth)
- to_chat(who, "0. [zeroth]")
-
- for (var/index = 1, index <= ion.len, index++)
- var/law = ion[index]
- var/num = ionnum()
- to_chat(who, "[num]. [law]")
-
- var/number = 1
- for (var/index = 1, index <= inherent.len, index++)
- var/law = inherent[index]
-
- if (length(law) > 0)
- to_chat(who, "[number]. [law]")
- number++
-
- for (var/index = 1, index <= supplied.len, index++)
- var/law = supplied[index]
- if (length(law) > 0)
- to_chat(who, "[number]. [law]")
- number++
+ var/list/printable_laws = get_law_list(include_zeroth = TRUE)
+ for(var/law in printable_laws)
+ to_chat(who,law)
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
if(force)
diff --git a/code/datums/antagonists/abductor.dm b/code/datums/antagonists/abductor.dm
index 8d13c48e7c85..3b8935d9fa7e 100644
--- a/code/datums/antagonists/abductor.dm
+++ b/code/datums/antagonists/abductor.dm
@@ -1,5 +1,6 @@
/datum/antagonist/abductor
name = "Abductor"
+ roundend_category = "abductors"
job_rank = ROLE_ABDUCTOR
var/datum/objective_team/abductor_team/team
var/sub_role
@@ -70,3 +71,65 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
+
+
+/datum/objective_team/abductor_team
+ member_name = "abductor"
+ var/team_number
+ var/list/datum/mind/abductees = list()
+
+/datum/objective_team/abductor_team/is_solo()
+ return FALSE
+
+/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
+ O.team = src
+ O.update_explanation_text()
+ objectives += O
+
+/datum/objective_team/abductor_team/roundend_report()
+ var/list/result = list()
+
+ var/won = TRUE
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ won = FALSE
+ if(won)
+ result += "
[name] team fulfilled its mission!"
+ else
+ result += "
[name] team failed its mission."
+
+ result += ""
+ for(var/datum/mind/abductor_mind in members)
+ result += printplayer(abductor_mind)
+ result += printobjectives(abductor_mind)
+
+ return result.Join("
")
+
+
+/datum/antagonist/abductee
+ name = "Abductee"
+ roundend_category = "abductees"
+
+/datum/antagonist/abductee/on_gain()
+ give_objective()
+ . = ..()
+
+/datum/antagonist/abductee/greet()
+ to_chat(owner, "
Your mind snaps!")
+ to_chat(owner, "
You can't remember how you got here...")
+ owner.announce_objectives()
+
+/datum/antagonist/abductee/proc/give_objective()
+ var/mob/living/carbon/human/H = owner.current
+ if(istype(H))
+ H.gain_trauma_type(BRAIN_TRAUMA_MILD)
+ var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
+ var/datum/objective/abductee/O = new objtype()
+ objectives += O
+ owner.objectives += objectives
+
+/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
+ SSticker.mode.update_abductor_icons_added(mob_override ? mob_override.mind : owner)
+
+/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
+ SSticker.mode.update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
\ No newline at end of file
diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm
index 0a7b2aa22fa0..6b5a573eff6a 100644
--- a/code/datums/antagonists/antag_datum.dm
+++ b/code/datums/antagonists/antag_datum.dm
@@ -2,6 +2,8 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist
var/name = "Antagonist"
+ var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
+ var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
var/datum/mind/owner //Mind that owns this datum
var/silent = FALSE //Silent will prevent the gain/lose texts to show
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
@@ -9,6 +11,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/delete_on_mind_deletion = TRUE
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
+ var/list/objectives = list()
/datum/antagonist/New(datum/mind/new_owner)
GLOB.antagonists += src
@@ -96,9 +99,62 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/get_team()
return
+//Individual roundend report
+/datum/antagonist/proc/roundend_report()
+ var/list/report = list()
+
+ if(!owner)
+ CRASH("antagonist datum without owner")
+
+ report += printplayer(owner)
+
+ var/objectives_complete = TRUE
+ if(owner.objectives.len)
+ report += printobjectives(owner)
+ for(var/datum/objective/objective in owner.objectives)
+ if(!objective.check_completion())
+ objectives_complete = FALSE
+ break
+
+ if(owner.objectives.len == 0 || objectives_complete)
+ report += "
The [name] was successful!"
+ else
+ report += "
The [name] has failed!"
+
+ return report.Join("
")
+
+//Displayed at the start of roundend_category section, default to roundend_category header
+/datum/antagonist/proc/roundend_report_header()
+ return "
"
+
+//Displayed at the end of roundend_category section
+/datum/antagonist/proc/roundend_report_footer()
+ return
+
//Should probably be on ticker or job ss ?
/proc/get_antagonists(antag_type,specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
if(!specific && istype(A,antag_type) || specific && A.type == antag_type)
- . += A.owner
\ No newline at end of file
+ . += A.owner
+
+
+
+//This datum will autofill the name with special_role
+//Used as placeholder for minor antagonists, please create proper datums for these
+/datum/antagonist/auto_custom
+
+/datum/antagonist/auto_custom/on_gain()
+ ..()
+ name = owner.special_role
+ //Add all objectives not already owned by other datums to this one.
+ var/list/already_registered_objectives = list()
+ for(var/datum/antagonist/A in owner.antag_datums)
+ if(A == src)
+ continue
+ else
+ already_registered_objectives |= A.objectives
+ objectives = owner.objectives - already_registered_objectives
+
+//This one is created by admin tools for custom objectives
+/datum/antagonist/custom
\ No newline at end of file
diff --git a/code/datums/antagonists/brother.dm b/code/datums/antagonists/brother.dm
index 6458e6da091e..dd3bdef9d2be 100644
--- a/code/datums/antagonists/brother.dm
+++ b/code/datums/antagonists/brother.dm
@@ -55,3 +55,71 @@
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
+
+
+/datum/objective_team/brother_team
+ name = "brotherhood"
+ member_name = "blood brother"
+ var/meeting_area
+
+/datum/objective_team/brother_team/is_solo()
+ return FALSE
+
+/datum/objective_team/brother_team/proc/update_name()
+ var/list/last_names = list()
+ for(var/datum/mind/M in members)
+ var/list/split_name = splittext(M.name," ")
+ last_names += split_name[split_name.len]
+
+ name = last_names.Join(" & ")
+
+/datum/objective_team/brother_team/roundend_report()
+ var/list/parts = list()
+
+ parts += ""
+ for(var/datum/mind/M in members)
+ parts += printplayer(M)
+ var/win = TRUE
+ var/objective_count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[objective_count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[objective_count]: [objective.explanation_text]
Fail."
+ win = FALSE
+ objective_count++
+ if(win)
+ parts += "
The blood brothers were successful!"
+ else
+ parts += "
The blood brothers have failed!"
+
+ return "
[parts.Join("
")]
"
+
+/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_GET(number/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)
\ No newline at end of file
diff --git a/code/datums/antagonists/changeling.dm b/code/datums/antagonists/changeling.dm
index ebcb5aed400c..83886a98ad59 100644
--- a/code/datums/antagonists/changeling.dm
+++ b/code/datums/antagonists/changeling.dm
@@ -4,11 +4,11 @@
/datum/antagonist/changeling
name = "Changeling"
+ roundend_category = "changelings"
job_rank = ROLE_CHANGELING
var/you_are_greet = TRUE
var/give_objectives = TRUE
- var/list/objectives = list()
var/team_mode = FALSE //Should assign team objectives ?
//Changeling Stuff
@@ -478,4 +478,35 @@
/datum/antagonist/changeling/xenobio
name = "Xenobio Changeling"
give_objectives = FALSE
+ show_in_roundend = FALSE //These are here for admin tracking purposes only
you_are_greet = FALSE
+
+/datum/antagonist/changeling/roundend_report()
+ var/list/parts = list()
+
+ var/changelingwin = 1
+ if(!owner.current)
+ changelingwin = 0
+
+ parts += printplayer(owner)
+
+ //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
+ parts += "
Changeling ID: [changelingID]."
+ parts += "
Genomes Extracted: [absorbedcount]"
+ parts += " "
+ if(objectives.len)
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ changelingwin = 0
+ count++
+
+ if(changelingwin)
+ parts += "
The changeling was successful!"
+ else
+ parts += "
The changeling has failed."
+
+ return parts.Join("
")
\ No newline at end of file
diff --git a/code/datums/antagonists/clockcult.dm b/code/datums/antagonists/clockcult.dm
index 8cc1c9e9a7e5..5f99ccc5dddb 100644
--- a/code/datums/antagonists/clockcult.dm
+++ b/code/datums/antagonists/clockcult.dm
@@ -1,8 +1,11 @@
//CLOCKCULT PROOF OF CONCEPT
/datum/antagonist/clockcult
name = "Clock Cultist"
- var/datum/action/innate/hierophant/hierophant_network = new()
+ roundend_category = "clock cultists"
job_rank = ROLE_SERVANT_OF_RATVAR
+ var/datum/action/innate/hierophant/hierophant_network = new()
+ var/datum/objective_team/clockcult/clock_team
+ var/make_team = TRUE //This should be only false for tutorial scarabs
/datum/antagonist/clockcult/silent
silent = TRUE
@@ -11,6 +14,22 @@
qdel(hierophant_network)
return ..()
+/datum/antagonist/clockcult/get_team()
+ return clock_team
+
+/datum/antagonist/clockcult/create_team(datum/objective_team/clockcult/new_team)
+ if(!new_team && make_team)
+ //TODO blah blah same as the others, allow multiple
+ for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
+ if(H.clock_team)
+ clock_team = H.clock_team
+ return
+ clock_team = new /datum/objective_team/clockcult
+ return
+ if(make_team && !istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ clock_team = new_team
+
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -164,3 +183,35 @@
if(iscyborg(owner.current))
to_chat(owner.current, "
Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.")
. = ..()
+
+
+/datum/objective_team/clockcult
+ name = "Clockcult"
+ var/list/objective
+ var/datum/mind/eminence
+
+/datum/objective_team/clockcult/proc/check_clockwork_victory()
+ if(GLOB.clockwork_gateway_activated)
+ return TRUE
+ return FALSE
+
+/datum/objective_team/clockcult/roundend_report()
+ var/list/parts = list()
+
+ if(check_clockwork_victory())
+ parts += "
Ratvar's servants defended the Ark until its activation!"
+ else
+ parts += "
The Ark was destroyed! Ratvar will rust away for all eternity!"
+ parts += " "
+ parts += "
The servants' objective was: [CLOCKCULT_OBJECTIVE]."
+ parts += "
Construction Value(CV) was:
[GLOB.clockwork_construction_value]"
+ for(var/i in SSticker.scripture_states)
+ if(i != SCRIPTURE_DRIVER)
+ parts += "
[i] scripture was:
[SSticker.scripture_states[i] ? "UN":""]LOCKED"
+ if(eminence)
+ parts += " [printplayer(eminence)]"
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members - eminence)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/cult.dm b/code/datums/antagonists/cult.dm
index c26b0f8108e2..bce9123fb3a9 100644
--- a/code/datums/antagonists/cult.dm
+++ b/code/datums/antagonists/cult.dm
@@ -2,84 +2,103 @@
/datum/antagonist/cult
name = "Cultist"
+ roundend_category = "cultists"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
+ var/give_equipment = FALSE
+
+ var/datum/objective_team/cult/cult_team
+
+/datum/antagonist/cult/get_team()
+ return cult_team
+
+/datum/antagonist/cult/create_team(datum/objective_team/cult/new_team)
+ if(!new_team)
+ //todo remove this and allow admin buttons to create more than one cult
+ for(var/datum/antagonist/cult/H in GLOB.antagonists)
+ if(H.cult_team)
+ cult_team = H.cult_team
+ return
+ cult_team = new /datum/objective_team/cult
+ cult_team.setup_objectives()
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ cult_team = new_team
+
+/datum/antagonist/cult/proc/add_objectives()
+ objectives |= cult_team.objectives
+ owner.objectives |= objectives
+
+/datum/antagonist/cult/proc/remove_objectives()
+ owner.objectives -= objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
QDEL_NULL(vote)
return ..()
-/datum/antagonist/cult/proc/add_objectives()
- var/list/target_candidates = list()
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- if(target_candidates.len == 0)
- message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- listclearnulls(target_candidates)
- if(LAZYLEN(target_candidates))
- GLOB.sac_mind = pick(target_candidates)
- if(!GLOB.sac_mind)
- message_admins("Cult Sacrifice: ERROR - Null target chosen!")
- else
- var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
- var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- GLOB.sac_image = reshape
- else
- message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
- GLOB.sac_complete = TRUE
- SSticker.mode.cult_objectives += "sacrifice"
- if(!GLOB.summon_spots.len)
- while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
- var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
- if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
- GLOB.summon_spots += summon
- SSticker.mode.cult_objectives += "eldergod"
-
-/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
- var/mob/living/current = cult_mind.current
- for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
- var/explanation
- switch(SSticker.mode.cult_objectives[obj_count])
- if("sacrifice")
- if(GLOB.sac_mind)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
- else
- explanation = "The veil has already been weakened here, proceed to the final objective."
- GLOB.sac_complete = TRUE
- if("eldergod")
- explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin."
- if(!silent)
- to_chat(current, "
Objective #[obj_count]: [explanation]")
- cult_mind.memory += "
Objective #[obj_count]: [explanation]
"
-
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
- . = is_convertable_to_cult(new_owner.current)
+ . = is_convertable_to_cult(new_owner.current,cult_team)
+
+/datum/antagonist/cult/greet()
+ to_chat(owner, "
You are a member of the cult!")
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
+ owner.announce_objectives()
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
- if(!LAZYLEN(SSticker.mode.cult_objectives))
- add_objectives()
+ add_objectives()
+ if(give_equipment)
+ equip_cultist()
SSticker.mode.cult += owner // Only add after they've been given objectives
- cult_memorization(owner)
SSticker.mode.update_cult_icons_added(owner)
current.log_message("
Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && current.client)
- current.client.images += GLOB.blood_target_image
+
+ if(cult_team.blood_target && cult_team.blood_target_image && current.client)
+ current.client.images += cult_team.blood_target_image
+
+
+/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
+ var/mob/living/carbon/H = owner.current
+ if(!istype(H))
+ return
+ if (owner.assigned_role == "Clown")
+ to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
+ H.dna.remove_mutation(CLOWNMUT)
+
+ if(tome)
+ . += cult_give_item(/obj/item/tome, H)
+ else
+ . += cult_give_item(/obj/item/paper/talisman/supply, H)
+ to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
+
+
+/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
+ var/list/slots = list(
+ "backpack" = slot_in_backpack,
+ "left pocket" = slot_l_store,
+ "right pocket" = slot_r_store
+ )
+
+ var/T = new item_path(mob)
+ var/item_name = initial(item_path.name)
+ var/where = mob.equip_in_one_of_slots(T, slots)
+ if(!where)
+ to_chat(mob, "
Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).")
+ return 0
+ else
+ to_chat(mob, "
You have a [item_name] in your [where].")
+ if(where == "backpack")
+ var/obj/item/storage/B = mob.back
+ B.orient2hud(mob)
+ B.show_to(mob)
+ return 1
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -89,7 +108,7 @@
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
- if(!GLOB.cult_mastered)
+ if(!cult_team.cult_mastered)
vote.Grant(current)
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
@@ -107,6 +126,7 @@
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
+ remove_objectives()
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
@@ -114,8 +134,8 @@
owner.current.visible_message("
[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!", ignored_mob = owner.current)
to_chat(owner.current, "
An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
owner.current.log_message("
Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
- owner.current.client.images -= GLOB.blood_target_image
+ if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
+ owner.current.client.images -= cult_team.blood_target_image
. = ..()
/datum/antagonist/cult/master
@@ -145,7 +165,7 @@
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
- if(!GLOB.reckoning_complete)
+ if(!cult_team.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
@@ -162,3 +182,118 @@
throwing.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
+
+/datum/objective_team/cult
+ name = "Cult"
+
+ var/blood_target
+ var/image/blood_target_image
+ var/blood_target_reset_timer
+
+ var/cult_vote_called = FALSE
+ var/cult_mastered = FALSE
+ var/reckoning_complete = FALSE
+
+
+/datum/objective_team/cult/proc/setup_objectives()
+ //SAC OBJECTIVE , todo: move this to objective internals
+ var/list/target_candidates = list()
+ var/datum/objective/sacrifice/sac_objective = new
+ sac_objective.team = src
+
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && player.stat != DEAD)
+ target_candidates += player.mind
+
+ if(target_candidates.len == 0)
+ message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && player.stat != DEAD)
+ target_candidates += player.mind
+ listclearnulls(target_candidates)
+ if(LAZYLEN(target_candidates))
+ sac_objective.target = pick(target_candidates)
+ sac_objective.update_explanation_text()
+
+ var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
+ var/datum/preferences/sacface = sac_objective.target.current.client.prefs
+ var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
+ reshape.Shift(SOUTH, 4)
+ reshape.Shift(EAST, 1)
+ reshape.Crop(7,4,26,31)
+ reshape.Crop(-5,-3,26,30)
+ sac_objective.sac_image = reshape
+
+ objectives += sac_objective
+ else
+ message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
+
+
+ //SUMMON OBJECTIVE
+
+ var/datum/objective/eldergod/summon_objective = new()
+ summon_objective.team = src
+ objectives += summon_objective
+
+/datum/objective/sacrifice
+ var/sacced = FALSE
+ var/sac_image
+
+/datum/objective/sacrifice/check_completion()
+ return sacced || completed
+
+/datum/objective/sacrifice/update_explanation_text()
+ if(target && !sacced)
+ explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
+ else
+ explanation_text = "The veil has already been weakened here, proceed to the final objective."
+
+/datum/objective/eldergod
+ var/summoned = FALSE
+ var/list/summon_spots = list()
+
+/datum/objective/eldergod/New()
+ ..()
+ var/sanity = 0
+ while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
+ var/area/summon = pick(GLOB.sortedAreas - summon_spots)
+ if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
+ summon_spots += summon
+ sanity++
+ update_explanation_text()
+
+/datum/objective/eldergod/update_explanation_text()
+ explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin."
+
+/datum/objective/eldergod/check_completion()
+ return summoned || completed
+
+/datum/objective_team/cult/proc/check_cult_victory()
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ return FALSE
+ return TRUE
+
+/datum/objective_team/cult/roundend_report()
+ var/list/parts = list()
+
+ if(check_cult_victory())
+ parts += "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!"
+ else
+ parts += "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!"
+
+ if(objectives.len)
+ parts += "
The cultists' objectives were:"
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ count++
+
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index 8ba2ca7038a5..80c6f64a963a 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -1,5 +1,6 @@
/datum/antagonist/traitor
name = "Traitor"
+ roundend_category = "traitors"
job_rank = ROLE_TRAITOR
var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
@@ -8,7 +9,6 @@
var/employer = "The Syndicate"
var/give_objectives = TRUE
var/should_give_codewords = TRUE
- var/list/objectives_given = list()
/datum/antagonist/traitor/human
var/should_equip = TRUE
@@ -52,9 +52,9 @@
if(should_specialise)
return ..()//we never did any of this anyway
SSticker.mode.traitors -= owner
- for(var/O in objectives_given)
+ for(var/O in objectives)
owner.objectives -= O
- objectives_given = list()
+ objectives = list()
if(!silent && owner.current)
to_chat(owner.current,"
You are no longer the [special_role]! ")
owner.special_role = null
@@ -71,11 +71,11 @@
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
owner.objectives += O
- objectives_given += O
+ objectives += O
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
owner.objectives -= O
- objectives_given -= O
+ objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
@@ -290,3 +290,53 @@
where = "In your [equipped_slot]"
to_chat(mob, "
[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.")
+//TODO Collate
+/datum/antagonist/traitor/roundend_report()
+ var/list/result = list()
+
+ var/traitorwin = TRUE
+
+ result += printplayer(owner)
+
+ var/TC_uses = 0
+ var/uplink_true = FALSE
+ var/purchases = ""
+ for(var/datum/component/uplink/H in GLOB.uplinks)
+ if(H && H.owner && H.owner == owner.key)
+ TC_uses += H.spent_telecrystals
+ uplink_true = TRUE
+ purchases += H.purchase_log.generate_render(FALSE)
+
+ var/objectives_text = ""
+ if(objectives.len)//If the traitor had no objectives, don't need to process this.
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Fail."
+ traitorwin = FALSE
+ count++
+
+ if(uplink_true)
+ var/uplink_text = "(used [TC_uses] TC) [purchases]"
+ if(TC_uses==0 && traitorwin)
+ var/static/icon/badass = icon('icons/badass.dmi', "badass")
+ uplink_text += "
[icon2html(badass, world)]"
+ result += uplink_text
+
+ result += objectives_text
+
+ var/special_role_text = lowertext(name)
+
+ if(traitorwin)
+ result += "
The [special_role_text] was successful!"
+ else
+ result += "
The [special_role_text] has failed!"
+ SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
+
+ return result.Join("
")
+
+/datum/antagonist/traitor/roundend_report_footer()
+ return "
The code phrases were: [GLOB.syndicate_code_phrase]\
+
The code responses were: [GLOB.syndicate_code_response]"
\ No newline at end of file
diff --git a/code/datums/antagonists/devil.dm b/code/datums/antagonists/devil.dm
index 416a8f3752ae..97e0d8c18aa7 100644
--- a/code/datums/antagonists/devil.dm
+++ b/code/datums/antagonists/devil.dm
@@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon",
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
name = "Devil"
+ roundend_category = "devils"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
@@ -508,6 +509,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
owner.RemoveSpell(S)
.=..()
+/datum/antagonist/devil/proc/printdevilinfo()
+ var/list/parts = list()
+ parts += "The devil's true name is: [truename]"
+ parts += "The devil's bans were:"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report()
+ var/list/parts = list()
+ parts += printplayer(owner)
+ parts += printdevilinfo()
+ parts += printobjectives(owner)
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report_footer()
+ //sintouched go here for now as a hack , TODO proper antag datum for these
+ var/list/parts = list()
+ if(SSticker.mode.sintouched.len)
+ parts += ""
+ var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
+ for(var/S in sintouchedUnique)
+ var/datum/mind/sintouched_mind = S
+ parts += printplayer(sintouched_mind)
+ parts += printobjectives(sintouched_mind)
+ return parts.Join("
")
+
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm
index ab4822dd79ed..8201cd879d16 100644
--- a/code/datums/antagonists/ninja.dm
+++ b/code/datums/antagonists/ninja.dm
@@ -37,19 +37,20 @@
else if(M.assigned_role in GLOB.command_positions)
possible_targets[M] = 1 //good-guy
- var/list/objectives = list(1,2,3,4)
- while(owner.objectives.len < quantity)
- switch(pick_n_take(objectives))
+ var/list/possible_objectives = list(1,2,3,4)
+
+ while(objectives.len < quantity)
+ switch(pick_n_take(possible_objectives))
if(1) //research
var/datum/objective/download/O = new /datum/objective/download()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
if(2) //steal
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
O.owner = owner
- owner.objectives += O
+ objectives += O
if(3) //protect/kill
if(!possible_targets.len) continue
@@ -63,13 +64,13 @@
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
- owner.objectives += O
+ objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
O.owner = owner
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
- owner.objectives += O
+ objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
@@ -82,17 +83,17 @@
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
- owner.objectives += O
+ objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
else
break
var/datum/objective/O = new /datum/objective/survive()
O.owner = owner
- owner.objectives += O
+ owner.objectives |= objectives
/proc/remove_ninja(mob/living/L)
diff --git a/code/datums/antagonists/nukeop.dm b/code/datums/antagonists/nukeop.dm
index 46e1ac360273..d0f24e7d7be4 100644
--- a/code/datums/antagonists/nukeop.dm
+++ b/code/datums/antagonists/nukeop.dm
@@ -10,6 +10,7 @@
/datum/antagonist/nukeop
name = "Nuclear Operative"
+ roundend_category = "syndicate operatives" //just in case
job_rank = ROLE_OPERATIVE
var/datum/objective_team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
@@ -201,7 +202,6 @@
nuke_team.memorized_code = null
/datum/objective_team/nuclear
- var/list/objectives
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
@@ -212,12 +212,10 @@
syndicate_name = syndicate_name()
/datum/objective_team/nuclear/proc/update_objectives()
- objectives = list()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
- return
/datum/objective_team/nuclear/proc/disk_rescued()
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
@@ -264,47 +262,47 @@
else
return //Undefined result
-/datum/objective_team/nuclear/proc/roundend_display()
- to_chat(world,"
[syndicate_name] Operatives:")
+/datum/objective_team/nuclear/roundend_report()
+ var/list/parts = list()
+ parts += ""
switch(get_result())
if(NUKE_RESULT_FLUKE)
- to_chat(world, "
Humiliating Syndicate Defeat")
- to_chat(world, "
The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed! Next time, don't lose the nuke!")
+ parts += "
Humiliating Syndicate Defeat"
+ parts += "
The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed! Next time, don't lose the nuke!"
if(NUKE_RESULT_NUKE_WIN)
- to_chat(world, "
Syndicate Major Victory!")
- to_chat(world, "
[syndicate_name] operatives have destroyed [station_name()]!")
+ parts += "
Syndicate Major Victory!"
+ parts += "
[syndicate_name] operatives have destroyed [station_name()]!"
if(NUKE_RESULT_NOSURVIVORS)
- to_chat(world, "
Total Annihilation")
- to_chat(world, "
[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!")
+ parts += "
Total Annihilation"
+ parts += "
[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!"
if(NUKE_RESULT_WRONG_STATION)
- to_chat(world, "
Crew Minor Victory")
- to_chat(world, "
[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't do that!")
+ parts += "
Crew Minor Victory"
+ parts += "
[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't do that!"
if(NUKE_RESULT_WRONG_STATION_DEAD)
- to_chat(world, "
[syndicate_name] operatives have earned Darwin Award!")
- to_chat(world, "
[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't do that!")
+ parts += "
[syndicate_name] operatives have earned Darwin Award!"
+ parts += "
[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't do that!"
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
- to_chat(world, "
Crew Major Victory!")
- to_chat(world, "
The Research Staff has saved the disk and killed the [syndicate_name] Operatives")
+ parts += "
Crew Major Victory!"
+ parts += "
The Research Staff has saved the disk and killed the [syndicate_name] Operatives"
if(NUKE_RESULT_CREW_WIN)
- to_chat(world, "
Crew Major Victory")
- to_chat(world, "
The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!")
+ parts += "
Crew Major Victory"
+ parts += "
The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!"
if(NUKE_RESULT_DISK_LOST)
- to_chat(world, "
Neutral Victory!")
- to_chat(world, "
The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!")
+ parts += "
Neutral Victory!"
+ parts += "
The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!"
if(NUKE_RESULT_DISK_STOLEN)
- to_chat(world, "
Syndicate Minor Victory!")
- to_chat(world, "
[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()]. Next time, don't lose the disk!")
+ parts += "
Syndicate Minor Victory!"
+ parts += "
[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()]. Next time, don't lose the disk!"
else
- to_chat(world, "
Neutral Victory")
- to_chat(world, "
Mission aborted!")
+ parts += "
Neutral Victory"
+ parts += "
Mission aborted!"
- var/text = "
The syndicate operatives were:"
+ var/text = "
"
var/purchases = ""
var/TC_uses = 0
for(var/I in members)
var/datum/mind/syndicate = I
- text += SSticker.mode.printplayer(syndicate) //to be moved
for(var/U in GLOB.uplinks)
var/datum/component/uplink/H = U
if(H.owner == syndicate.key)
@@ -313,8 +311,12 @@
purchases += H.purchase_log.generate_render(show_key = FALSE)
else
stack_trace("WARNING: Nuke Op uplink with no purchase_log Owner: [H.owner]")
+ text += printplayerlist(members)
text += "
"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && SSticker.mode.station_was_nuked && !operatives_dead())
text += "
[icon2html('icons/badass.dmi', world, "badass")]"
- to_chat(world, text)
+
+ parts += text
+
+ return "
[parts.Join("
")]
"
diff --git a/code/datums/antagonists/pirate.dm b/code/datums/antagonists/pirate.dm
index ad32e0915106..e0ce38c1e466 100644
--- a/code/datums/antagonists/pirate.dm
+++ b/code/datums/antagonists/pirate.dm
@@ -1,6 +1,7 @@
/datum/antagonist/pirate
name = "Space Pirate"
job_rank = ROLE_TRAITOR
+ roundend_category = "space pirates"
var/datum/objective_team/pirate/crew
/datum/antagonist/pirate/greet()
@@ -36,7 +37,6 @@
/datum/objective_team/pirate
name = "Pirate crew"
- var/list/objectives = list()
/datum/objective_team/pirate/proc/forge_objectives()
var/datum/objective/loot/getbooty = new()
@@ -84,11 +84,11 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
loot_table[lootname] = count
else
loot_table[lootname] += count
- var/text = ""
+ var/list/loot_texts = list()
for(var/key in loot_table)
var/amount = loot_table[key]
- text += "[amount] [key][amount > 1 ? "s":""], "
- return text
+ loot_texts += "[amount] [key][amount > 1 ? "s":""]"
+ return loot_texts.Join(", ")
/datum/objective/loot/proc/get_loot_value()
if(!storage_area)
@@ -105,31 +105,26 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
return ..() || get_loot_value() >= target_value
-//These need removal ASAP as everything is converted to datum antags.
-/datum/game_mode/proc/auto_declare_completion_pirates()
- var/list/datum/mind/pirates = get_antagonists(/datum/antagonist/pirate)
- var/datum/objective_team/pirate/crew
- var/text = ""
- if(pirates.len)
- text += "
Space Pirates were:"
- for(var/datum/mind/M in pirates)
- text += printplayer(M)
- if(!crew)
- var/datum/antagonist/pirate/P = M.has_antag_datum(/datum/antagonist/pirate)
- crew = P.crew
- if(crew)
- text += "
Loot stolen: "
- var/datum/objective/loot/L = locate() in crew.objectives
- text += L.loot_listing()
- text += "
Total loot value : [L.get_loot_value()]/[L.target_value] credits"
- var/all_dead = TRUE
- for(var/datum/mind/M in crew.members)
- if(considered_alive(M))
- all_dead = FALSE
- break
- if(L.check_completion() && !all_dead)
- text += "
The pirate crew was successful!"
- else
- text += "
The pirate crew has failed."
- to_chat(world, text)
\ No newline at end of file
+/datum/objective_team/pirate/roundend_report()
+ var/list/parts = list()
+
+ parts += ""
+
+ var/all_dead = TRUE
+ for(var/datum/mind/M in members)
+ if(considered_alive(M))
+ all_dead = FALSE
+ parts += printplayerlist(members)
+
+ parts += "Loot stolen: "
+ var/datum/objective/loot/L = locate() in objectives
+ parts += L.loot_listing()
+ parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits"
+
+ if(L.check_completion() && !all_dead)
+ parts += "
The pirate crew was successful!"
+ else
+ parts += "
The pirate crew has failed."
+
+ return parts.Join("
")
\ No newline at end of file
diff --git a/code/datums/antagonists/revolution.dm b/code/datums/antagonists/revolution.dm
index 9db86bdf0819..14c6d1ab0e43 100644
--- a/code/datums/antagonists/revolution.dm
+++ b/code/datums/antagonists/revolution.dm
@@ -3,6 +3,7 @@
/datum/antagonist/rev
name = "Revolutionary"
+ roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
job_rank = ROLE_REV
var/hud_type = "rev"
var/datum/objective_team/revolution/rev_team
@@ -184,7 +185,6 @@
/datum/objective_team/revolution
name = "Revolution"
- var/list/objectives = list()
var/max_headrevs = 3
/datum/objective_team/revolution/proc/update_objectives(initial = FALSE)
@@ -227,3 +227,56 @@
rev.promote()
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
+
+
+/datum/objective_team/revolution/roundend_report()
+ if(!members.len)
+ return
+
+ var/list/result = list()
+
+ result += "
"
+
+ var/num_revs = 0
+ var/num_survivors = 0
+ for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
+ if(survivor.ckey)
+ num_survivors++
+ if(survivor.mind)
+ if(is_revolutionary(survivor))
+ num_revs++
+ if(num_survivors)
+ result += "Command's Approval Rating:
[100 - round((num_revs/num_survivors)*100, 0.1)]%"
+
+
+ var/list/targets = list()
+ var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
+ var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
+ if(headrevs.len)
+ var/list/headrev_part = list()
+ headrev_part += ""
+ headrev_part += printplayerlist(headrevs,TRUE)
+ result += headrev_part.Join("
")
+
+ if(revs.len)
+ var/list/rev_part = list()
+ rev_part += ""
+ rev_part += printplayerlist(revs,TRUE)
+ result += rev_part.Join("
")
+
+ var/list/heads = SSjob.get_all_heads()
+ if(heads.len)
+ var/head_text = ""
+ head_text += "
"
+ for(var/datum/mind/head in heads)
+ var/target = (head in targets)
+ head_text += "- "
+ if(target)
+ head_text += "Target"
+ head_text += "[printplayer(head, 1)]
"
+ head_text += "
"
+ result += head_text
+
+ result += "
"
+
+ return result.Join()
\ No newline at end of file
diff --git a/code/datums/antagonists/wizard.dm b/code/datums/antagonists/wizard.dm
index e1e6dc09c8e3..7f23215d6c5a 100644
--- a/code/datums/antagonists/wizard.dm
+++ b/code/datums/antagonists/wizard.dm
@@ -5,13 +5,13 @@
/datum/antagonist/wizard
name = "Space Wizard"
+ roundend_category = "wizards/witches"
job_rank = ROLE_WIZARD
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
var/allow_rename = TRUE
var/hud_version = "wizard"
var/datum/objective_team/wizard/wiz_team //Only created if wizard summons apprentices
- var/list/objectives = list() //this should be base datum antag proc and list, todo make lazy
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
@@ -45,10 +45,12 @@
/datum/objective_team/wizard
name = "wizard team"
+ var/datum/antagonist/wizard/master_wizard
/datum/antagonist/wizard/proc/create_wiz_team()
wiz_team = new(owner)
wiz_team.name = "[owner.current.real_name] team"
+ wiz_team.master_wizard = src
update_wiz_icons_added(owner.current)
/datum/antagonist/wizard/proc/send_to_lair()
@@ -283,4 +285,46 @@
var/datum/objective/new_objective = new("Protect Wizard Academy from the intruders")
new_objective.owner = owner
owner.objectives += new_objective
- objectives += new_objective
\ No newline at end of file
+ objectives += new_objective
+
+//Solo wizard report
+/datum/antagonist/wizard/roundend_report()
+ var/list/parts = list()
+
+ parts += printplayer(owner)
+
+ var/count = 1
+ var/wizardwin = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ wizardwin = 0
+ count++
+
+ if(wizardwin)
+ parts += "
The wizard was successful!"
+ else
+ parts += "
The wizard has failed!"
+
+ if(owner.spell_list.len>0)
+ parts += "
[owner.name] used the following spells: "
+ var/list/spell_names = list()
+ for(var/obj/effect/proc_holder/spell/S in owner.spell_list)
+ spell_names += S.name
+ parts += spell_names.Join(", ")
+
+ return parts.Join("
")
+
+//Wizard with apprentices report
+/datum/objective_team/wizard/roundend_report()
+ var/list/parts = list()
+
+ parts += ""
+ parts += master_wizard.roundend_report()
+ parts += " "
+ parts += ""
+ parts += printplayerlist(members - master_wizard.owner)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 4348ef5ccf99..2baeec63d8d4 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -180,12 +180,6 @@
objectives, uplinks, powers etc are all handled.
*/
-/datum/mind/proc/remove_objectives()
- if(objectives.len)
- for(var/datum/objective/O in objectives)
- objectives -= O
- qdel(O)
-
/datum/mind/proc/remove_changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
@@ -216,7 +210,6 @@
if(src in SSticker.mode.cult)
SSticker.mode.remove_cultist(src, 0, 0)
special_role = null
- remove_objectives()
remove_antag_equip()
/datum/mind/proc/remove_rev()
@@ -769,17 +762,44 @@
var/objective_pos
var/def_value
+
+
+ var/datum/antagonist/target_antag
+
if (href_list["obj_edit"])
objective = locate(href_list["obj_edit"])
if (!objective)
return
- objective_pos = objectives.Find(objective)
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ target_antag = A
+ objective_pos = A.objectives.Find(objective)
+ break
+
+ if(!target_antag) //Shouldn't happen
+ stack_trace("objective without antagonist found")
+ objective_pos = objectives.Find(objective)
//Text strings are easy to manipulate. Revised for simplicity.
var/temp_obj_type = "[objective.type]"//Convert path into a text string.
def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
+ else
+ switch(antag_datums.len)
+ if(0)
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ if(1)
+ target_antag = antag_datums[1]
+ else
+ var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
+ if (QDELETED(target))
+ return
+ else if(target == "(new custom antag)")
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ else
+ target_antag = target
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -895,11 +915,15 @@
return
if (objective)
+ if(target_antag)
+ target_antag.objectives -= objective
objectives -= objective
- objectives.Insert(objective_pos, new_objective)
+ target_antag.objectives.Insert(objective_pos, new_objective)
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
else
+ if(target_antag)
+ target_antag.objectives += new_objective
objectives += new_objective
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
@@ -908,6 +932,11 @@
var/datum/objective/objective = locate(href_list["obj_delete"])
if(!istype(objective))
return
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ A.objectives -= objective
+ break
objectives -= objective
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
@@ -990,11 +1019,13 @@
message_admins("[key_name_admin(usr)] has cult'ed [current].")
log_admin("[key_name(usr)] has cult'ed [current].")
if("tome")
- if (!SSticker.mode.equip_cultist(current,1))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current,1))
to_chat(usr, "
Spawning tome failed!")
if("amulet")
- if (!SSticker.mode.equip_cultist(current))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current))
to_chat(usr, "
Spawning amulet failed!")
else if(href_list["clockcult"])
@@ -1335,16 +1366,11 @@
/datum/mind/proc/make_Cultist()
- if(!(src in SSticker.mode.cult))
- SSticker.mode.add_cultist(src,FALSE)
+ if(!has_antag_datum(/datum/antagonist/cult,TRUE))
+ SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
special_role = "Cultist"
to_chat(current, "
You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.")
to_chat(current, "
Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.")
- var/datum/antagonist/cult/C
- C.cult_memorization(src)
- var/mob/living/carbon/human/H = current
- if (!SSticker.mode.equip_cultist(current))
- to_chat(H, "Spawning an amulet from your Master failed.")
/datum/mind/proc/make_Rev()
var/datum/antagonist/rev/head/head = new(src)
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index bd2158289b13..38b5fb0c0062 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -247,6 +247,7 @@
new_objective2.owner = S.mind
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
S.mind.objectives += new_objective2
+ S.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "
You are currently not currently in the same plane of existence as the station. \
Ctrl+Click a blood pool to manifest.")
diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index be662ed35e32..978f871ba2ab 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -1,41 +1,3 @@
-/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_GET(number/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()
@@ -54,6 +16,7 @@
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
+ traitors_required = FALSE //Only teams are possible
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
@@ -92,44 +55,13 @@
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
+ team.update_name()
brother_teams += pre_brother_teams
return ..()
/datum/game_mode/traitor/bros/generate_report()
return "It's Syndicate recruiting season. Be alert for potential Syndicate infiltrators, but also watch out for disgruntled employees trying to defect. Unlike Nanotrasen, the Syndicate prides itself in teamwork and will only recruit pairs that share a brotherly trust."
-/datum/game_mode/proc/auto_declare_completion_brother()
- if(!LAZYLEN(brother_teams))
- return
- var/text = "
The blood brothers were:"
- var/teamnumber = 1
- for(var/datum/objective_team/brother_team/team in brother_teams)
- if(!team.members.len)
- continue
- text += "
Team #[teamnumber++]"
- 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 += "
Objective #[objective_count]: [objective.explanation_text]
Success!"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[objective_count]: [objective.explanation_text]
Fail."
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
- win = FALSE
- objective_count++
- if(win)
- text += "
The blood brothers were successful!"
- SSblackbox.record_feedback("tally", "brother_success", 1, "SUCCESS")
- else
- text += "
The blood brothers have failed!"
- SSblackbox.record_feedback("tally", "brother_success", 1, "FAIL")
-
- text += "
"
- 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)
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index a2525f68e4ec..ad76d41d473f 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -94,46 +94,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
as paranoia may spread and inhibit workplace efficiency."
-/datum/game_mode/proc/auto_declare_completion_changeling()
- var/list/changelings = get_antagonists(/datum/antagonist/changeling,TRUE) //Only real lings get a mention
- if(changelings.len)
- var/text = "
The changelings were:"
- for(var/datum/mind/changeling in changelings)
- var/datum/antagonist/changeling/ling = changeling.has_antag_datum(/datum/antagonist/changeling)
- var/changelingwin = 1
- if(!changeling.current)
- changelingwin = 0
-
- text += printplayer(changeling)
-
- //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
- text += "
Changeling ID: [ling.changelingID]."
- text += "
Genomes Extracted: [ling.absorbedcount]"
-
- if(changeling.objectives.len)
- var/count = 1
- for(var/datum/objective/objective in changeling.objectives)
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text]
Success!"
- SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text]
Fail."
- SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "FAIL"))
- changelingwin = 0
- count++
-
- if(changelingwin)
- text += "
The changeling was successful!"
- SSblackbox.record_feedback("tally", "changeling_success", 1, "SUCCESS")
- else
- text += "
The changeling has failed."
- SSblackbox.record_feedback("tally", "changeling_success", 1, "FAIL")
- text += "
"
-
- to_chat(world, text)
-
- return 1
-
/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof)
var/datum/dna/chosen_dna = chosen_prof.dna
user.real_name = chosen_prof.name
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 069921767d62..85a90cce988b 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -65,13 +65,16 @@ Credit where due:
return TRUE
return FALSE
-/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
+/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
if(!L || !L.mind)
return
var/update_type = ANTAG_DATUM_CLOCKCULT
if(silent)
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
- . = L.mind.add_antag_datum(update_type)
+ var/datum/antagonist/clockcult/C = new update_type(L.mind)
+ C.make_team = create_team
+ C.show_in_roundend = create_team //tutorial scarabs begone
+ . = L.mind.add_antag_datum(C)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
@@ -88,7 +91,6 @@ Credit where due:
///////////////
/datum/game_mode
- var/datum/mind/eminence //The clockwork Eminence
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
@@ -110,6 +112,8 @@ Credit where due:
var/servants_to_serve = list()
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
+
+ var/datum/objective_team/clockcult/main_clockcult
/datum/game_mode/clockwork_cult/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
@@ -190,16 +194,16 @@ Credit where due:
return ..()
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
+ return main_clockcult.check_clockwork_victory()
+
+/datum/game_mode/clock_cult/set_round_result()
+ ..()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_SUMMON
- return TRUE
+ SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
SSticker.news_report = CULT_FAILURE
- return FALSE
-
-/datum/game_mode/clockwork_cult/declare_completion()
- ..()
- return //Doesn't end until the round does
+ SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
/datum/game_mode/clockwork_cult/generate_report()
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
@@ -209,30 +213,6 @@ Credit where due:
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
your crew to dispatch it in a timely manner."
-/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
- var/text = ""
- if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
- var/datum/game_mode/clockwork_cult/C = SSticker.mode
- if(C.check_clockwork_victory())
- text += "
Ratvar's servants defended the Ark until its activation!"
- SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
- else
- text += "
The Ark was destroyed! Ratvar will rust away for all eternity!"
- SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
- text += "
The servants' objective was: [CLOCKCULT_OBJECTIVE]."
- text += "
Ratvar's servants had
[GLOB.clockwork_caches] Tinkerer's Caches."
- text += "
Construction Value(CV) was:
[GLOB.clockwork_construction_value]"
- for(var/i in SSticker.scripture_states)
- if(i != SCRIPTURE_DRIVER)
- text += "
[i] scripture was:
[SSticker.scripture_states[i] ? "UN":""]LOCKED"
- if(SSticker.mode.eminence)
- text += "
The Eminence was: [printplayer(SSticker.mode.eminence)]"
- if(servants_of_ratvar.len)
- text += "
Ratvar's servants were:"
- for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
- text += printplayer(M)
- to_chat(world, text)
-
/datum/game_mode/proc/update_servant_icons_added(datum/mind/M)
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
A.join_hud(M.current)
diff --git a/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm b/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
index acf6e43974a0..1b2b867aa5cb 100644
--- a/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
@@ -91,7 +91,8 @@
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
if(infinite_resources)
- construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar //During rounds where they can't interact with the station, let them experiment with builds
+ //During rounds where they can't interact with the station, let them experiment with builds
+ construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
if(infinite_resources) //Allow them to build stuff and recite scripture
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
index cc91feeb9890..8416e4651d4d 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
@@ -14,16 +14,6 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/static/superheated_walls = 0
-/mob/camera/eminence/Initialize()
- if(SSticker.mode.eminence)
- return INITIALIZE_HINT_QDEL
- . = ..()
-
-/mob/camera/eminence/Destroy(force)
- if(!force && mind && SSticker.mode.eminence == mind)
- return QDEL_HINT_LETMELIVE
- return ..()
-
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
@@ -39,12 +29,20 @@
/mob/camera/eminence/Login()
..()
- add_servant_of_ratvar(src, TRUE)
+ var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(!C)
+ add_servant_of_ratvar(src, TRUE)
+ C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(C && C.clock_team)
+ if(C.clock_team.eminence)
+ remove_servant_of_ratvar(src,TRUE)
+ qdel(src)
+ else
+ C.clock_team.eminence = src
to_chat(src, "
You have been selected as the Eminence!")
to_chat(src, "
As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.")
to_chat(src, "
Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.")
to_chat(src, "
Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.")
- SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
diff --git a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
index 8d4e936658df..495bfaeaa85b 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
@@ -17,7 +17,11 @@
return
if(kingmaking)
return
- if(SSticker.mode.eminence)
+
+ var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
+ if(!C || !C.clock_team)
+ return
+ if(C.clock_team.eminence)
to_chat(user, "
There's already an Eminence!")
return
if(!GLOB.servants_active)
@@ -34,7 +38,9 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
- if(SSticker.mode.eminence)
+
+ var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
+ if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "
There's already an Eminence - too late!")
return
if(!GLOB.servants_active)
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index f20dd2580295..67e222577295 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -2,24 +2,23 @@
/datum/game_mode
var/list/datum/mind/cult = list()
- var/list/cult_objectives = list()
- var/eldergod = 1 //for the summon god objective
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
-/proc/is_sacrifice_target(datum/mind/mind)
- if(mind == GLOB.sac_mind)
- return TRUE
+/datum/objective_team/cult/proc/is_sacrifice_target(datum/mind/mind)
+ for(var/datum/objective/sacrifice/sac_objective in objectives)
+ if(mind == sac_objective.target)
+ return TRUE
return FALSE
-
-/proc/is_convertable_to_cult(mob/living/M)
+
+/proc/is_convertable_to_cult(mob/living/M,datum/objective_team/cult/specific_cult)
if(!istype(M))
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return FALSE
- if(is_sacrifice_target(M.mind))
+ if(specific_cult && specific_cult.is_sacrifice_target(M.mind))
return FALSE
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return FALSE
@@ -55,10 +54,10 @@
var/list/cultists_to_cult = list() //the cultists we'll convert
+ var/datum/objective_team/cult/main_cult
+
/datum/game_mode/cult/pre_setup()
- cult_objectives += "sacrifice"
-
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -86,82 +85,19 @@
/datum/game_mode/cult/post_setup()
- if("sacrifice" in cult_objectives)
- var/list/possible_targets = get_unconvertables()
- if(!possible_targets.len)
- message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !(player.mind in cultists_to_cult))
- possible_targets += player.mind
- if(possible_targets.len > 0)
- GLOB.sac_mind = pick(possible_targets)
- if(!GLOB.sac_mind)
- message_admins("Cult Sacrifice: ERROR - Null target chosen!")
- else
- var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
- var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- GLOB.sac_image = reshape
- else
- message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
- if(!GLOB.summon_spots.len)
- while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
- var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
- if((summon.z in GLOB.station_z_levels) && summon.valid_territory)
- GLOB.summon_spots += summon
- cult_objectives += "eldergod"
-
for(var/datum/mind/cult_mind in cultists_to_cult)
- equip_cultist(cult_mind.current)
- update_cult_icons_added(cult_mind)
- to_chat(cult_mind.current, "
You are a member of the cult!")
- cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
- add_cultist(cult_mind, 0)
+ add_cultist(cult_mind, 0, equip=TRUE)
..()
-/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob,tome = 0)
- if(!istype(mob))
- return
- if (mob.mind)
- if (mob.mind.assigned_role == "Clown")
- to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
- mob.dna.remove_mutation(CLOWNMUT)
- if(tome)
- . += cult_give_item(/obj/item/tome, mob)
- else
- . += cult_give_item(/obj/item/paper/talisman/supply, mob)
- to_chat(mob, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
-
-/datum/game_mode/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
- var/list/slots = list(
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store
- )
-
- var/T = new item_path(mob)
- var/item_name = initial(item_path.name)
- var/where = mob.equip_in_one_of_slots(T, slots)
- if(!where)
- to_chat(mob, "
Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).")
- return 0
- else
- to_chat(mob, "
You have a [item_name] in your [where].")
- if(where == "backpack")
- var/obj/item/storage/B = mob.back
- B.orient2hud(mob)
- B.show_to(mob)
- return 1
-
-/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
+/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun , equip = FALSE) //BASE
if (!istype(cult_mind))
return 0
- if(cult_mind.add_antag_datum(ANTAG_DATUM_CULT))
+
+ var/datum/antagonist/cult/new_cultist = new(cult_mind)
+ new_cultist.give_equipment = equip
+
+ if(cult_mind.add_antag_datum(new_cultist))
if(stun)
cult_mind.current.Unconscious(100)
return 1
@@ -187,25 +123,19 @@
culthud.leave_hud(cult_mind.current)
set_antag_hud(cult_mind.current, null)
-/datum/game_mode/cult/proc/get_unconvertables()
- var/list/ucs = list()
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
- ucs += player.mind
- return ucs
-
/datum/game_mode/cult/proc/check_cult_victory()
- var/cult_fail = 0
- if(cult_objectives.Find("survive"))
- cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise
- if(cult_objectives.Find("eldergod"))
- cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
- if(cult_objectives.Find("sacrifice"))
- if(GLOB.sac_mind && !GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
- cult_fail++
- return cult_fail //if any objectives aren't met, failure
+ return main_cult.check_cult_victory()
+/datum/game_mode/cult/set_round_result()
+ ..()
+ if(check_cult_victory())
+ SSticker.mode_result = "win - cult win"
+ SSticker.news_report = CULT_SUMMON
+ else
+ SSticker.mode_result = "loss - staff stopped the cult"
+ SSticker.news_report = CULT_FAILURE
+
/datum/game_mode/cult/proc/check_survive()
var/acolytes_survived = 0
for(var/datum/mind/cult_mind in cult)
@@ -218,57 +148,6 @@
return 1
-/datum/game_mode/cult/declare_completion()
-
- if(!check_cult_victory())
- SSticker.mode_result = "win - cult win"
- to_chat(world, "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!")
- else
- SSticker.mode_result = "loss - staff stopped the cult"
- to_chat(world, "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!")
-
- var/text = ""
-
- if(cult_objectives.len)
- text += "
The cultists' objectives were:"
- for(var/obj_count=1, obj_count <= cult_objectives.len, obj_count++)
- var/explanation
- switch(cult_objectives[obj_count])
- if("survive")
- if(!check_survive())
- explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped)
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "SUCCESS"))
- SSticker.news_report = CULT_ESCAPE
- else
- explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped)
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "FAIL"))
- SSticker.news_report = CULT_FAILURE
- if("sacrifice")
- if(GLOB.sac_complete)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
- else
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
- if("eldergod")
- if(!eldergod)
- explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
- SSticker.news_report = CULT_SUMMON
- else
- explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)]
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
- SSticker.news_report = CULT_FAILURE
-
- text += "
Objective #[obj_count]: [explanation]"
- if(cult.len)
- text += "
The cultists were:"
- for(var/datum/mind/M in cult)
- text += printplayer(M)
- to_chat(world, text)
- ..()
- return 1
-
/datum/game_mode/cult/generate_report()
return "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
@@ -276,41 +155,4 @@
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
altogether."
-/datum/game_mode/proc/datum_cult_completion()
- var/text = ""
- var/cult_fail = 0
- cult_fail += eldergod
- if(!GLOB.sac_complete)
- cult_fail++
- if(!cult_fail)
- SSticker.mode_result = "win - cult win"
- to_chat(world, "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!")
- else
- SSticker.mode_result = "loss - staff stopped the cult"
- to_chat(world, "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!")
- if(cult_objectives.len)
- text += "
The cultists' objectives were:"
- for(var/obj_count in 1 to 2)
- var/explanation
- switch(cult_objectives[obj_count])
- if("sacrifice")
- if(GLOB.sac_mind)
- if(GLOB.sac_complete)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
- else
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
- if("eldergod")
- if(!eldergod)
- explanation = "Summon Nar-Sie.
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
- SSticker.news_report = CULT_SUMMON
- else
- explanation = "Summon Nar-Sie.
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
- SSticker.news_report = CULT_FAILURE
- text += "
Objective #[obj_count]: [explanation]"
- to_chat(world, text)
-
#undef CULT_SCALING_COEFFICIENT
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index 530b6ebb2087..2938f5abf46b 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -88,19 +88,21 @@
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
- if(GLOB.cult_vote_called || !ishuman(owner))
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
/datum/action/innate/cult/mastervote/Activate()
- pollCultists(owner)
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ pollCultists(owner,C.cult_team)
-/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
+/proc/pollCultists(var/mob/living/Nominee,datum/objective_team/cult/team) //Cult Master Poll
if(world.time < CULT_POLL_WAIT)
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
return
- GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
@@ -108,39 +110,39 @@
to_chat(B.current, "
Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.")
sleep(100)
var/list/asked_cultists = list()
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in team.members)
if(B.current && B.current != Nominee && !B.current.incapacitated())
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
asked_cultists += B.current
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
if(QDELETED(Nominee) || Nominee.incapacitated())
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"
[Nominee] has died in the process of attempting to win the cult's support!")
return FALSE
if(!Nominee.mind)
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"
[Nominee] has gone catatonic in the process of attempting to win the cult's support!")
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current, "
[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
return FALSE
- GLOB.cult_mastered = TRUE
+ team.cult_mastered = TRUE
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in team.members)
if(B.current)
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
vote.Remove(B.current)
@@ -159,6 +161,9 @@
button_icon_state = "sintouch"
/datum/action/innate/cult/master/finalreck/Activate()
+ var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!antag)
+ return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -169,7 +174,7 @@
to_chat(owner, "
You need more space to summon the cult!")
return
if(do_after(owner, 30, target = owner))
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in antag.cult_team.members)
if(B.current && B.current.stat != DEAD)
var/turf/mobloc = get_turf(B.current)
switch(i)
@@ -194,7 +199,7 @@
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
- GLOB.reckoning_complete = TRUE
+ antag.cult_team.reckoning_complete = TRUE
Remove(owner)
/mob/proc/reckon(turf/final)
@@ -269,34 +274,37 @@
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
+
+ var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+
if(target in view(7, get_turf(ranged_ability_user)))
- GLOB.blood_target = target
+ C.cult_team.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
- GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
- GLOB.blood_target_image.appearance_flags = RESET_COLOR
- GLOB.blood_target_image.pixel_x = -target.pixel_x
- GLOB.blood_target_image.pixel_y = -target.pixel_y
+ C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
+ C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
+ C.cult_team.blood_target_image.pixel_x = -target.pixel_x
+ C.cult_team.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
- to_chat(B.current, "
Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
+ to_chat(B.current, "
Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
- B.current.client.images += GLOB.blood_target_image
+ B.current.client.images += C.cult_team.blood_target_image
attached_action.owner.update_action_buttons_icon()
remove_ranged_ability("
The marking rite is complete! It will last for 90 seconds.")
- GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE)
+ C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
return TRUE
return FALSE
-/proc/reset_blood_target()
- for(var/datum/mind/B in SSticker.mode.cult)
+/proc/reset_blood_target(datum/objective_team/cult/team)
+ for(var/datum/mind/B in team.members)
if(B.current && B.current.stat != DEAD && B.current.client)
- if(GLOB.blood_target)
+ if(team.blood_target)
to_chat(B.current,"
The blood mark has expired!")
- B.current.client.images -= GLOB.blood_target_image
- QDEL_NULL(GLOB.blood_target_image)
- GLOB.blood_target = null
+ B.current.client.images -= team.blood_target_image
+ QDEL_NULL(team.blood_target_image)
+ team.blood_target = null
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 0992393581e4..8aebf1d19696 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -179,6 +179,13 @@ This file contains the arcane tome files.
var/list/shields = list()
var/area/A = get_area(src)
+ var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!user_antag)
+ return
+
+ var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
+ var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
+
if(!check_rune_turf(Turf, user))
return
entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types
@@ -196,18 +203,20 @@ This file contains the arcane tome files.
A = get_area(src)
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
return
+
+ //AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
- if(!("eldergod" in SSticker.mode.cult_objectives))
+ if(!summon_objective)
to_chat(user, "
Nar-Sie does not wish to be summoned!")
return
- if(!GLOB.sac_complete)
+ if(sac_objective && !sac_objective.check_completion())
to_chat(user, "
The sacrifice is not complete. The portal would lack the power to open if you tried!")
return
- if(!SSticker.mode.eldergod)
+ if(summon_objective.check_completion())
to_chat(user, "
\"I am already here. There is no need to try to summon me now.\"")
return
- if(!(A in GLOB.summon_spots))
- to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
+ if(!(A in summon_objective.summon_spots))
+ to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
@@ -215,8 +224,8 @@ This file contains the arcane tome files.
return
Turf = get_turf(user)
A = get_area(src)
- if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
- to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
+ if(!(A in summon_objective.summon_spots)) // Check again to make sure they didn't move
+ to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!")
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/ai/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index be1c2ccaffb3..1bab1d90f428 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
- var/is_convertable = is_convertable_to_cult(L)
+
+ var/mob/living/F = invokers[1]
+ var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+
+ var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && (is_clock || is_convertable))
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
+ var/mob/living/first_invoker = invokers[1]
+ if(!first_invoker)
+ return FALSE
+ var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C)
+ return
+
+
var/big_sac = FALSE
- if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
+ if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "
[sacrificial] is too greatly linked to the world! You need three acolytes!")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
- if(is_sacrifice_target(sacrificial.mind))
- GLOB.sac_complete = TRUE
- big_sac = TRUE
+ for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
+ if(sac_objective.target == sacrificial.mind)
+ sac_objective.sacced = TRUE
+ sac_objective.update_explanation_text()
+ big_sac = TRUE
else
GLOB.sacrificed += sacrificial
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
sleep(40)
if(src)
color = RUNE_COLOR_RED
- SSticker.mode.eldergod = FALSE
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm
index 957e2619333d..44f3368febc3 100644
--- a/code/game/gamemodes/devil/game_mode.dm
+++ b/code/game/gamemodes/devil/game_mode.dm
@@ -3,32 +3,6 @@
var/list/datum/mind/devils = list()
var/devil_ascended = 0 // Number of arch devils on station
-/datum/game_mode/proc/auto_declare_completion_sintouched()
- var/text = ""
- if(sintouched.len)
- text += "
The sintouched were:"
- var/list/sintouchedUnique = uniqueList(sintouched)
- for(var/S in sintouchedUnique)
- var/datum/mind/sintouched_mind = S
- text += printplayer(sintouched_mind)
- text += printobjectives(sintouched_mind)
- text += "
"
- text += "
"
- to_chat(world, text)
-
-/datum/game_mode/proc/auto_declare_completion_devils()
- /var/text = ""
- if(devils.len)
- text += "
The devils were:"
- for(var/D in devils)
- var/datum/mind/devil = D
- text += printplayer(devil)
- text += printdevilinfo(devil.current)
- text += printobjectives(devil)
- text += "
"
- text += "
"
- to_chat(world, text)
-
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
for(var/i = 1 to quantity)
@@ -41,18 +15,6 @@
else
objective.find_target()
-/datum/game_mode/proc/printdevilinfo(mob/living/ply)
- var/datum/antagonist/devil/devilinfo = is_devil(ply)
- if(!devilinfo)
- return "Target is not a devil."
- var/text = "The devil's true name is: [devilinfo.truename]"
- text += "The devil's bans were:"
- text += " [GLOB.lawlorify[LORE][devilinfo.ban]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.bane]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.banish]]"
- return text
-
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
hud.join_hud(devil_mind.current)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index d001f08a33cb..a0e5a9f147e0 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -74,7 +74,6 @@
/datum/game_mode/proc/pre_setup()
return 1
-
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
@@ -242,55 +241,9 @@
return 0
-/datum/game_mode/proc/declare_completion()
- var/clients = 0
- var/surviving_humans = 0
- var/surviving_total = 0
- var/ghosts = 0
- var/escaped_humans = 0
- var/escaped_total = 0
-
- for(var/mob/M in GLOB.player_list)
- if(M.client)
- clients++
- if(ishuman(M))
- if(!M.stat)
- surviving_humans++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_humans++
- if(!M.stat)
- surviving_total++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_total++
-
-
- if(isobserver(M))
- ghosts++
-
- if(clients)
- SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
- if(ghosts)
- SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
- if(surviving_humans)
- SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
- if(surviving_total)
- SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
- if(escaped_humans)
- SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
- if(escaped_total)
- SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
-
- send2irc("Server", "Round just ended.")
- if(cult.len && !istype(SSticker.mode, /datum/game_mode/cult))
- datum_cult_completion()
-
- return 0
-
-
/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
return 0
-
/datum/game_mode/proc/send_intercept()
var/intercepttext = "
Central Command Status Summary
"
intercepttext += "
Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
@@ -452,34 +405,6 @@
for (var/C in GLOB.admins)
to_chat(C, msg)
-/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
- var/text = "
[ply.key] was [ply.name] the [ply.assigned_role] and"
- if(ply.current)
- if(ply.current.stat == DEAD)
- text += " died"
- else
- text += " survived"
- if(fleecheck)
- var/turf/T = get_turf(ply.current)
- if(!T || !(T.z in GLOB.station_z_levels))
- text += " while fleeing the station"
- if(ply.current.real_name != ply.name)
- text += " as [ply.current.real_name]"
- else
- text += " had their body destroyed"
- return text
-
-/datum/game_mode/proc/printobjectives(datum/mind/ply)
- var/text = ""
- var/count = 1
- for(var/datum/objective/objective in ply.objectives)
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- count++
- return text
-
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/game_mode/proc/age_check(client/C)
if(get_remaining_days(C) == 0)
@@ -519,11 +444,6 @@
station_goals += new picked
-/datum/game_mode/proc/declare_station_goal_completion()
- for(var/V in station_goals)
- var/datum/station_goal/G = V
- G.print_result()
-
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
return "Gamemode report for [name] not set. Contact a coder."
@@ -531,4 +451,18 @@
/datum/game_mode/proc/OnNukeExplosion(off_station)
nuke_off_station = off_station
if(off_station < 2)
- station_was_nuked = TRUE //Will end the round on next check.
\ No newline at end of file
+ station_was_nuked = TRUE //Will end the round on next check.
+
+//Additional report section in roundend report
+/datum/game_mode/proc/special_report()
+ return
+
+//Set result and news report here
+/datum/game_mode/proc/set_round_result()
+ SSticker.mode_result = "undefined"
+ if(station_was_nuked)
+ SSticker.news_report = STATION_DESTROYED_NUKE
+ if(EMERGENCY_ESCAPED_OR_ENDGAMED)
+ SSticker.news_report = STATION_EVACUATED
+ if(SSshuttle.emergency.is_hijacked())
+ SSticker.news_report = SHUTTLE_HIJACK
\ No newline at end of file
diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm
index b7a6580570d5..f8e066601590 100644
--- a/code/game/gamemodes/meteor/meteor.dm
+++ b/code/game/gamemodes/meteor/meteor.dm
@@ -30,30 +30,29 @@
spawn_meteors(ramp_up_final, wavetype)
-/datum/game_mode/meteor/declare_completion()
- var/text
+/datum/game_mode/meteor/special_report()
var/survivors = 0
+ var/list/survivor_list = list()
for(var/mob/living/player in GLOB.player_list)
if(player.stat != DEAD)
++survivors
if(player.onCentCom())
- text += "
[player.real_name] escaped to the safety of CentCom."
+ survivor_list += "[player.real_name] escaped to the safety of CentCom."
else if(player.onSyndieBase())
- text += "
[player.real_name] escaped to the (relative) safety of Syndicate Space."
+ survivor_list += "[player.real_name] escaped to the (relative) safety of Syndicate Space."
else
- text += "
[player.real_name] survived but is stranded without any hope of rescue."
-
+ survivor_list += "[player.real_name] survived but is stranded without any hope of rescue."
if(survivors)
- to_chat(world, "The following survived the meteor storm:[text]")
+ return "
[survivor_list.Join("
")]"
else
- to_chat(world, "Nobody survived the meteor storm!")
+ return "Nobody survived the meteor storm!"
- SSticker.mode_result = "end - evacuation"
+/datum/game_mode/meteor/set_round_result()
..()
- return 1
+ SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/generate_report()
return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \
diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm
index fec933a4f2cb..12987124acff 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction.dm
@@ -1,19 +1,5 @@
-/datum/objective_team/abductor_team
- member_name = "abductor"
- var/list/objectives = list()
- var/team_number
-
-/datum/objective_team/abductor_team/is_solo()
- return FALSE
-
-/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
- O.team = src
- O.update_explanation_text()
- objectives += O
-
/datum/game_mode
var/list/datum/mind/abductors = list()
- var/list/datum/mind/abductees = list()
/datum/game_mode/abduction
name = "abduction"
@@ -101,35 +87,6 @@
return ..()
return ..()
-/datum/game_mode/abduction/declare_completion()
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
- var/won = TRUE
- for(var/datum/objective/O in team.objectives)
- if(!O.check_completion())
- won = FALSE
- if(won)
- to_chat(world, "[team.name] team fulfilled its mission!")
- else
- to_chat(world, "[team.name] team failed its mission.")
- ..()
- return TRUE
-
-/datum/game_mode/proc/auto_declare_completion_abduction()
- var/text = ""
- if(abductors.len)
- text += "
The abductors were:"
- for(var/datum/mind/abductor_mind in abductors)
- text += printplayer(abductor_mind)
- text += printobjectives(abductor_mind)
- text += "
"
- if(abductees.len)
- text += "
The abductees were:"
- for(var/datum/mind/abductee_mind in abductees)
- text += printplayer(abductee_mind)
- text += printobjectives(abductee_mind)
- text += "
"
- to_chat(world, text)
-
// LANDMARKS
/obj/effect/landmark/abductor
var/team_number = 1
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index c3a591a2780b..cf1329aec992 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -151,13 +151,18 @@
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat != DEAD)
if(href_list["experiment"])
- flash = Experiment(occupant,href_list["experiment"])
+ flash = Experiment(occupant,href_list["experiment"],usr)
updateUsrDialog()
add_fingerprint(usr)
-/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
+/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
LAZYINITLIST(history)
var/mob/living/carbon/human/H = occupant
+
+ var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
+ if(!user_abductor)
+ return "Authorization failure. Contact mothership immidiately."
+
var/point_reward = 0
if(H in history)
return "Specimen already in database."
@@ -182,15 +187,8 @@
if(3)
to_chat(H, "You feel intensely watched.")
sleep(5)
- to_chat(H, "Your mind snaps!")
- H.gain_trauma_type(BRAIN_TRAUMA_MILD)
- to_chat(H, "You can't remember how you got here...")
- var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
- var/datum/objective/abductee/O = new objtype()
- SSticker.mode.abductees += H.mind
- H.mind.objectives += O
- H.mind.announce_objectives()
- SSticker.mode.update_abductor_icons_added(H.mind)
+ user_abductor.team.abductees += H.mind
+ H.mind.add_antag_datum(/datum/antagonist/abductee)
for(var/obj/item/organ/heart/gland/G in H.internal_organs)
G.Start()
diff --git a/code/game/gamemodes/miniantags/monkey/monkey.dm b/code/game/gamemodes/miniantags/monkey/monkey.dm
index 379031dce9c1..8e02d4144166 100644
--- a/code/game/gamemodes/miniantags/monkey/monkey.dm
+++ b/code/game/gamemodes/miniantags/monkey/monkey.dm
@@ -105,13 +105,18 @@
monkey_mind.special_role = null
-/datum/game_mode/monkey/declare_completion()
+/datum/game_mode/monkey/set_round_result()
+ ..()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
- to_chat(world, "The monkeys have overthrown their captors! Eeek eeeek!!")
else
SSticker.mode_result = "loss - staff stopped the monkeys"
- to_chat(world, "The staff managed to contain the monkey infestation!")
+
+/datum/game_mode/monkey/special_report()
+ if(check_monkey_victory())
+ return "The monkeys have overthrown their captors! Eeek eeeek!!"
+ else
+ return "The staff managed to contain the monkey infestation!"
/datum/game_mode/monkey/generate_report()
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 5e1a97675b91..2ebc21adac33 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -227,6 +227,7 @@
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
SSticker.mode.traitors |= player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
message_admins("[key_name_admin(S)] has been made into a morph by an event.")
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index 727203b1503c..78d39673eb00 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -87,6 +87,7 @@
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
SSticker.mode.traitors |= mind //Necessary for announcing
+ mind.add_antag_datum(/datum/antagonist/auto_custom)
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
index f1f962438003..e62665f21bd7 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
@@ -38,6 +38,7 @@
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
SSticker.mode.traitors |= player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.")
SEND_SOUND(S, 'sound/magic/demon_dies.ogg')
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index a5b1ea1d8bc7..5807a7aacb9a 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -69,7 +69,7 @@
return FALSE //its a static var btw
..()
-/datum/game_mode/nuclear/declare_completion()
+/datum/game_mode/nuclear/set_round_result()
var result = nuke_team.get_result()
switch(result)
if(NUKE_RESULT_FLUKE)
@@ -109,15 +109,6 @@
transport containing a nuclear fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \
can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders."
-/datum/game_mode/proc/auto_declare_completion_nuclear()
- var/list/nuke_teams = list()
- for(var/datum/antagonist/nukeop/N in GLOB.antagonists) //collect all nuke teams
- nuke_teams |= N.nuke_team
- for(var/datum/objective_team/nuclear/nuke_team in nuke_teams)
- nuke_team.roundend_display()
- return TRUE
-
-
/proc/is_nuclear_operative(mob/M)
return M && istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/nukeop)
diff --git a/code/game/gamemodes/objective_team.dm b/code/game/gamemodes/objective_team.dm
index 7789a167c719..1483f356d2b6 100644
--- a/code/game/gamemodes/objective_team.dm
+++ b/code/game/gamemodes/objective_team.dm
@@ -3,6 +3,7 @@
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
+ var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/objective_team/New(starting_members)
. = ..()
@@ -12,7 +13,6 @@
add_member(M)
else
add_member(starting_members)
- members += starting_members
/datum/objective_team/proc/is_solo()
return members.len == 1
@@ -21,4 +21,14 @@
members |= new_member
/datum/objective_team/proc/remove_member(datum/mind/member)
- members -= member
\ No newline at end of file
+ members -= member
+
+//Display members/victory/failure/objectives for the team
+/datum/objective_team/proc/roundend_report()
+ var/list/report = list()
+
+ report += "[name]:"
+ report += "The [member_name]s were:"
+ report += printplayerlist(members)
+
+ return report.Join("
")
\ No newline at end of file
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 4fa9532b42a9..cbfdb98c6938 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -169,62 +169,22 @@
return FALSE
return TRUE
-//////////////////////////////////////////////////////////////////////
-//Announces the end of the game with all relavent information stated//
-//////////////////////////////////////////////////////////////////////
-/datum/game_mode/revolution/declare_completion()
+
+/datum/game_mode/revolution/set_round_result()
+ ..()
if(finished == 1)
SSticker.mode_result = "win - heads killed"
- to_chat(world, "The heads of staff were killed or exiled! The revolutionaries win!")
-
SSticker.news_report = REVS_WIN
-
else if(finished == 2)
SSticker.mode_result = "loss - rev heads killed"
- to_chat(world, "The heads of staff managed to stop the revolution!")
-
SSticker.news_report = REVS_LOSE
- ..()
- return TRUE
-/datum/game_mode/proc/auto_declare_completion_revolution()
- var/list/targets = list()
- var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
- var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
- if(headrevs.len)
- var/num_revs = 0
- var/num_survivors = 0
- for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
- if(survivor.ckey)
- num_survivors++
- if(survivor.mind)
- if(is_revolutionary(survivor))
- num_revs++
- if(num_survivors)
- to_chat(world, "[GLOB.TAB]Command's Approval Rating: [100 - round((num_revs/num_survivors)*100, 0.1)]%" )
- var/text = "
The head revolutionaries were:"
- for(var/datum/mind/headrev in headrevs)
- text += printplayer(headrev, 1)
- text += "
"
- to_chat(world, text)
-
- if(revs.len)
- var/text = "
The revolutionaries were:"
- for(var/datum/mind/rev in revs)
- text += printplayer(rev, 1)
- text += "
"
- to_chat(world, text)
-
- if(revs.len || headrevs.len)
- var/text = "
The heads of staff were:"
- var/list/heads = SSjob.get_all_heads()
- for(var/datum/mind/head in heads)
- var/target = (head in targets)
- if(target)
- text += "Target"
- text += printplayer(head, 1)
- text += "
"
- to_chat(world, text)
+//TODO What should be displayed for revs in non-rev rounds
+/datum/game_mode/revolution/special_report()
+ if(finished == 1)
+ return "The heads of staff were killed or exiled! The revolutionaries win!"
+ else if(finished == 2)
+ return "The heads of staff managed to stop the revolution!"
/datum/game_mode/revolution/generate_report()
return "Employee unrest has spiked in recent weeks, with several attempted mutinies on heads of staff. Some crew have been observed using flashbulb devices to blind their colleagues, \
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index c687c0305383..42c96cb5c0ee 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -27,6 +27,7 @@
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
var/antag_datum = ANTAG_DATUM_TRAITOR //what type of antag to create
+ var/traitors_required = TRUE //Will allow no traitors
/datum/game_mode/traitor/pre_setup()
@@ -55,7 +56,7 @@
log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
antag_candidates.Remove(traitor)
- return pre_traitors.len > 0
+ return !traitors_required || pre_traitors.len > 0
/datum/game_mode/traitor/post_setup()
@@ -85,79 +86,10 @@
new_antag.should_specialise = TRUE
character.add_antag_datum(new_antag)
-
-
-/datum/game_mode/traitor/declare_completion()
- ..()
- return//Traitors will be checked as part of check_extra_completion. Leaving this here as a reminder.
-
-
-/datum/game_mode/proc/auto_declare_completion_traitor()
- if(traitors.len)
- var/text = "
The [traitor_name]s were:"
- for(var/datum/mind/traitor in traitors)
- var/traitorwin = TRUE
-
- text += printplayer(traitor)
-
- var/TC_uses = 0
- var/uplink_true = FALSE
- var/purchases = ""
- for(var/datum/component/uplink/H in GLOB.uplinks)
- if(H && H.owner && H.owner == traitor.key)
- TC_uses += H.spent_telecrystals
- uplink_true = TRUE
- purchases += H.purchase_log.generate_render(FALSE)
-
- var/objectives = ""
- if(traitor.objectives.len)//If the traitor had no objectives, don't need to process this.
- var/count = 1
- for(var/datum/objective/objective in traitor.objectives)
- if(objective.check_completion())
- objectives += "
Objective #[count]: [objective.explanation_text] Success!"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- objectives += "
Objective #[count]: [objective.explanation_text] Fail."
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
- traitorwin = FALSE
- count++
-
- if(uplink_true)
- text += " (used [TC_uses] TC) [purchases]"
- if(TC_uses==0 && traitorwin)
- var/static/icon/badass = icon('icons/badass.dmi', "badass")
- text += "[icon2html(badass, world)]"
-
- text += objectives
-
- var/special_role_text
- if(traitor.special_role)
- special_role_text = lowertext(traitor.special_role)
- else
- special_role_text = "antagonist"
-
-
- if(traitorwin)
- text += "
The [special_role_text] was successful!"
- SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
- else
- text += "
The [special_role_text] has failed!"
- SSblackbox.record_feedback("tally", "traitor_success", 1, "FAIL")
- SEND_SOUND(traitor.current, 'sound/ambience/ambifailure.ogg')
-
- text += "
"
-
- text += "
The code phrases were: [GLOB.syndicate_code_phrase]
\
- The code responses were: [GLOB.syndicate_code_response]
"
- to_chat(world, text)
-
- return TRUE
-
/datum/game_mode/traitor/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
-
/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind)
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
traitorhud.join_hud(traitor_mind.current)
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index 1d500b147c2b..8b80b9ab6991 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -141,7 +141,8 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
- if(is_sacrifice_target(T.mind))
+ var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(C && C.cult_team.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "\"This soul is mine. SACRIFICE THEM!\"")
else
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index ca64e9e15cfd..1d423802d1c7 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -58,64 +58,16 @@
return TRUE
-/datum/game_mode/wizard/declare_completion()
+/datum/game_mode/wizard/set_round_result()
+ ..()
if(finished)
SSticker.mode_result = "loss - wizard killed"
- to_chat(world, "The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!")
-
SSticker.news_report = WIZARD_KILLED
- ..()
- return 1
+/datum/game_mode/wizard/special_report()
+ if(finished)
+ return "The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!"
-/datum/game_mode/proc/auto_declare_completion_wizard()
- if(wizards.len)
- var/text = "
the wizards/witches were:"
-
- for(var/datum/mind/wizard in wizards)
-
- text += "
[wizard.key] was [wizard.name] ("
- if(wizard.current)
- if(wizard.current.stat == DEAD)
- text += "died"
- else
- text += "survived"
- if(wizard.current.real_name != wizard.name)
- text += " as [wizard.current.real_name]"
- else
- text += "body destroyed"
- text += ")"
-
- var/count = 1
- var/wizardwin = 1
- for(var/datum/objective/objective in wizard.objectives)
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
- wizardwin = 0
- count++
-
- if(wizard.current && wizardwin)
- text += "
The wizard was successful!"
- SSblackbox.record_feedback("tally", "wizard_success", 1, "SUCCESS")
- else
- text += "
The wizard has failed!"
- SSblackbox.record_feedback("tally", "wizard_success", 1, "FAIL")
- if(wizard.spell_list.len>0)
- text += "
[wizard.name] used the following spells: "
- var/i = 1
- for(var/obj/effect/proc_holder/spell/S in wizard.spell_list)
- text += "[S.name]"
- if(wizard.spell_list.len > i)
- text += ", "
- i++
- text += "
"
-
- to_chat(world, text)
- return 1
//returns whether the mob is a wizard (or apprentice)
/proc/iswizard(mob/living/M)
return M.mind && M.mind.has_antag_datum(/datum/antagonist/wizard,TRUE)
diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm
index fdb481401e83..59465cf5b2e8 100644
--- a/code/game/machinery/wishgranter.dm
+++ b/code/game/machinery/wishgranter.dm
@@ -45,6 +45,7 @@
var/datum/objective/hijack/hijack = new
hijack.owner = user.mind
user.mind.objectives += hijack
+ user.mind.add_antag_datum(/datum/antagonist/auto_custom)
user.mind.announce_objectives()
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 22365c4584fe..c0859cc31823 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -705,15 +705,17 @@
/datum/admins/proc/output_all_devil_info()
var/devil_number = 0
- for(var/D in SSticker.mode.devils)
+ for(var/datum/mind/D in SSticker.mode.devils)
devil_number++
- to_chat(usr, "Devil #[devil_number]:
" + SSticker.mode.printdevilinfo(D))
+ var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil)
+ to_chat(usr, "Devil #[devil_number]:
" + devil.printdevilinfo())
if(!devil_number)
to_chat(usr, "No Devils located" )
/datum/admins/proc/output_devil_info(mob/living/M)
if(is_devil(M))
- to_chat(usr, SSticker.mode.printdevilinfo(M))
+ var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil)
+ to_chat(usr, devil.printdevilinfo())
else
to_chat(usr, "[M] is not a devil.")
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 5ceef95469e8..2c59ce21f202 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -308,11 +308,14 @@
//Assign antag status and the mission
SSticker.mode.traitors += Commando.mind
Commando.mind.special_role = "deathsquad"
+
var/datum/objective/missionobj = new
missionobj.owner = Commando.mind
missionobj.explanation_text = mission
missionobj.completed = 1
Commando.mind.objectives += missionobj
+
+ Commando.mind.add_antag_datum(/datum/antagonist/auto_custom)
//Greet the commando
to_chat(Commando, "You are the [numagents==1?"Deathsquad Officer":"Death Commando"].")
@@ -360,11 +363,14 @@
//Assign antag status and the mission
SSticker.mode.traitors += newmob.mind
newmob.mind.special_role = "official"
+
var/datum/objective/missionobj = new
missionobj.owner = newmob.mind
missionobj.explanation_text = mission
missionobj.completed = 1
newmob.mind.objectives += missionobj
+
+ newmob.mind.add_antag_datum(/datum/antagonist/auto_custom)
if(CONFIG_GET(flag/enforce_human_authority))
newmob.set_species(/datum/species/human)
@@ -465,12 +471,15 @@
//Assign antag status and the mission
SSticker.mode.traitors += ERTOperative.mind
ERTOperative.mind.special_role = "ERT"
+
var/datum/objective/missionobj = new
missionobj.owner = ERTOperative.mind
missionobj.explanation_text = mission
missionobj.completed = 1
ERTOperative.mind.objectives += missionobj
+ ERTOperative.mind.add_antag_datum(/datum/antagonist/auto_custom)
+
//Greet the commando
to_chat(ERTOperative, "You are [numagents==1?"the Emergency Response Team Commander":"an Emergency Response Officer"].")
var/missiondesc = "Your squad is being sent on a Code [alert] mission to [station_name()] by Nanotrasen's Security Division."
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index b675815602cc..d09041aaf334 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -28,6 +28,7 @@ GLOBAL_VAR_INIT(highlander, FALSE)
/mob/living/carbon/human/proc/make_scottish()
SSticker.mode.traitors += mind
mind.special_role = "highlander"
+
dna.species.species_traits |= NOGUNS //nice try jackass
var/datum/objective/steal/steal_objective = new
@@ -40,6 +41,8 @@ GLOBAL_VAR_INIT(highlander, FALSE)
hijack_objective.owner = mind
mind.objectives += hijack_objective
+ mind.add_antag_datum(/datum/antagonist/auto_custom)
+
mind.announce_objectives()
for(var/obj/item/I in get_equipped_items())
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index 3031936d4398..1fe8baba012c 100644
--- a/code/modules/awaymissions/mission_code/wildwest.dm
+++ b/code/modules/awaymissions/mission_code/wildwest.dm
@@ -115,9 +115,11 @@
to_chat(user, "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart.")
SSticker.mode.traitors += user.mind
user.mind.special_role = "traitor"
+
var/datum/objective/hijack/hijack = new
hijack.owner = user.mind
user.mind.objectives += hijack
+ user.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(user, "Your inhibitions are swept away, the bonds of loyalty broken, you are free to murder as you please!")
user.mind.announce_objectives()
user.set_species(/datum/species/shadow)
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 32e074855cf7..9ae87488ce01 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -68,4 +68,6 @@
var/datum/chatOutput/chatOutput
- var/list/credits //lazy list of all credit object bound to this client
\ No newline at end of file
+ var/list/credits //lazy list of all credit object bound to this client
+
+ var/datum/player_details/player_details //these persist between logins/logouts during the same round.
\ No newline at end of file
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 7b30bbd59fb8..ff912a5dd67d 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -220,6 +220,13 @@ GLOBAL_LIST(external_rsc_urls)
message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ")
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).")
+ if(GLOB.player_details[ckey])
+ player_details = GLOB.player_details[ckey]
+ else
+ player_details = new
+ GLOB.player_details[ckey] = player_details
+
+
. = ..() //calls mob.Login()
set_macros()
diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm
new file mode 100644
index 000000000000..a842607235cd
--- /dev/null
+++ b/code/modules/client/player_details.dm
@@ -0,0 +1,2 @@
+/datum/player_details
+ var/list/player_actions = list()
\ No newline at end of file
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index f983ca256357..7ec7d75bac55 100755
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -135,7 +135,7 @@
"You pin \the [src] on [M]'s chest.")
if(input)
SSblackbox.record_feedback("associative", "commendation", 1, list("commender" = "[user.real_name]", "commendee" = "[M.real_name]", "medal" = "[src]", "reason" = input))
- GLOB.commendations += "[user.real_name] awarded [M.real_name] the [name]! \n- [input]"
+ GLOB.commendations += "[user.real_name] awarded [M.real_name] the [name]! \n- [input]"
commended = TRUE
log_game("[key_name(M)] was given the following commendation by [key_name(user)]: [input]")
message_admins("[key_name(M)] was given the following commendation by [key_name(user)]: [input]")
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index 41ff90407d85..abb5a0639dd4 100644
--- a/code/modules/events/holiday/vday.dm
+++ b/code/modules/events/holiday/vday.dm
@@ -45,19 +45,26 @@
to_chat(L, "You didn't get a date! They're all having fun without you! you'll show them though...")
var/datum/objective/martyr/normiesgetout = new
normiesgetout.owner = L.mind
+ L.mind.special_role = "heartbreaker"
SSticker.mode.traitors |= L.mind
L.mind.objectives += normiesgetout
+ L.mind.add_antag_datum(/datum/antagonist/auto_custom)
+
/proc/forge_valentines_objective(mob/living/lover,mob/living/date)
SSticker.mode.traitors |= lover.mind
lover.mind.special_role = "valentine"
+
var/datum/objective/protect/protect_objective = new /datum/objective/protect
protect_objective.owner = lover.mind
protect_objective.target = date.mind
protect_objective.explanation_text = "Protect [date.real_name], your date."
lover.mind.objectives += protect_objective
+
+ lover.mind.add_antag_datum(/datum/antagonist/auto_custom)
+
to_chat(lover, "You're on a date with [date]! Protect them at all costs. This takes priority over all other loyalties.")
diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm
index 073ef8aea3a1..76188cb5b7a5 100644
--- a/code/modules/events/nightmare.dm
+++ b/code/modules/events/nightmare.dm
@@ -35,6 +35,7 @@
player_mind.assigned_role = "Nightmare"
player_mind.special_role = "Nightmare"
SSticker.mode.traitors += player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
S.set_species(/datum/species/shadow/nightmare)
playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
message_admins("[key_name_admin(S)] has been made into a Nightmare by an event.")
diff --git a/code/modules/events/wizard/departmentrevolt.dm b/code/modules/events/wizard/departmentrevolt.dm
index 618c746a65b5..3227f81d5833 100644
--- a/code/modules/events/wizard/departmentrevolt.dm
+++ b/code/modules/events/wizard/departmentrevolt.dm
@@ -44,6 +44,7 @@
citizens += H
SSticker.mode.traitors += M
M.special_role = "separatist"
+ M.add_antag_datum(/datum/antagonist/auto_custom)
H.log_message("Was made into a separatist, long live [nation]!", INDIVIDUAL_ATTACK_LOG)
to_chat(H, "You are a separatist! [nation] forever! Protect the sovereignty of your newfound land with your comrades in arms!")
if(citizens.len)
diff --git a/code/modules/events/wizard/greentext.dm b/code/modules/events/wizard/greentext.dm
index 6ee000249b4e..1cf4858ce79d 100644
--- a/code/modules/events/wizard/greentext.dm
+++ b/code/modules/events/wizard/greentext.dm
@@ -67,6 +67,7 @@
O.completed = 1 //YES!
O.owner = new_holder.mind
new_holder.mind.objectives += O
+ new_holder.mind.add_antag_datum(/datum/antagonist/auto_custom)
new_holder.log_message("Won with greentext!!!", INDIVIDUAL_ATTACK_LOG)
color_altered_mobs -= new_holder
resistance_flags |= ON_FIRE
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index aab1f204f680..d09f8cd4a236 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -50,6 +50,7 @@
if(!mind.special_role)
mind.special_role = "traitor"
SSticker.mode.traitors += mind
+ mind.add_antag_datum(/datum/antagonist/auto_custom) // ????
/mob/living/silicon/robot/update_health_hud()
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0e6ecf167293..8046daf55db6 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -360,8 +360,14 @@
..()
/datum/action/innate/seek_master/Activate()
- if(!SSticker.mode.eldergod)
- the_construct.master = GLOB.blood_target
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult)
+ if(!C)
+ return
+ var/datum/objective/eldergod/summon_objective = locate() in C.cult_team.objectives
+
+ if(summon_objective.check_completion())
+ the_construct.master = C.cult_team.blood_target
+
if(!the_construct.master)
to_chat(the_construct, "You have no master to seek!")
the_construct.seeking = FALSE
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index 3aa1153133bb..65ef28baee03 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -153,7 +153,7 @@
/mob/living/simple_animal/drone/cogscarab/Login()
..()
- add_servant_of_ratvar(src, TRUE)
+ add_servant_of_ratvar(src, TRUE, GLOB.servants_active)
to_chat(src,"You yourself are one of these servants, and will be able to utilize almost anything they can[GLOB.ratvar_awakens ? "":", excluding a clockwork slab"].") // this can't go with flavortext because i'm assuming it requires them to be ratvar'd
/mob/living/simple_animal/drone/cogscarab/binarycheck()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index f988d054e7d0..fc9455796e58 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -46,6 +46,10 @@
client.change_view(CONFIG_GET(string/default_view)) // Resets the client.view in case it was changed.
+ if(client.player_details.player_actions.len)
+ for(var/datum/action/A in client.player_details.player_actions)
+ A.Grant(src)
+
if(!GLOB.individual_log_list[ckey])
GLOB.individual_log_list[ckey] = logging
else
diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm
index 1656a435050d..b26d01d880cd 100644
--- a/code/modules/ninja/ninja_event.dm
+++ b/code/modules/ninja/ninja_event.dm
@@ -95,7 +95,7 @@ Contents:
var/datum/mind/Mind = new /datum/mind(key)
Mind.assigned_role = "Space Ninja"
Mind.special_role = "Space Ninja"
- SSticker.mode.traitors |= Mind //Adds them to current traitor list. Which is really the extra antagonist list.
+ SSticker.mode.traitors |= Mind //Adds them to current traitor list. TODO : Remove this in admin tools refeactor.
return Mind
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 22712e970dee..9801e9861465 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -47,8 +47,15 @@
/obj/singularity/narsie/large/cult/Initialize()
. = ..()
GLOB.cult_narsie = src
- deltimer(GLOB.blood_target_reset_timer)
- GLOB.blood_target = src
+ var/list/all_cults = list()
+ for(var/datum/antagonist/cult/C in GLOB.antagonists)
+ all_cults |= C.cult_team
+ for(var/datum/objective_team/cult/T in all_cults)
+ deltimer(T.blood_target_reset_timer)
+ T.blood_target = src
+ var/datum/objective/eldergod/summon_objective = locate() in T.objectives
+ if(summon_objective)
+ summon_objective.summoned = TRUE
for(var/datum/mind/cult_mind in SSticker.mode.cult)
if(isliving(cult_mind.current))
var/mob/living/L = cult_mind.current
diff --git a/code/modules/spells/spell_types/rightandwrong.dm b/code/modules/spells/spell_types/rightandwrong.dm
index 0cb7e6c47dea..bb454a3b19d1 100644
--- a/code/modules/spells/spell_types/rightandwrong.dm
+++ b/code/modules/spells/spell_types/rightandwrong.dm
@@ -22,12 +22,14 @@
guns.owner = H.mind
H.mind.objectives += guns
H.mind.special_role = "survivalist"
+ H.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(H, "You are the survivalist! Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way.")
else
var/datum/objective/steal_five_of_type/summon_magic/magic = new
magic.owner = H.mind
H.mind.objectives += magic
H.mind.special_role = "amateur magician"
+ H.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(H, "You are the amateur magician! Grow your newfound talent! Grab as many magical artefacts as possible, by any means necessary. Kill anyone who gets in your way.")
var/datum/objective/survive/survive = new
survive.owner = H.mind
diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm
index 98ec01f64195..88377455c6a1 100644
--- a/code/modules/station_goals/station_goal.dm
+++ b/code/modules/station_goals/station_goal.dm
@@ -26,11 +26,11 @@
/datum/station_goal/proc/check_completion()
return completed
-/datum/station_goal/proc/print_result()
+/datum/station_goal/proc/get_result()
if(check_completion())
- to_chat(world, "Station Goal : [name] : Completed!")
+ return "[name] : Completed!"
else
- to_chat(world, "Station Goal : [name] : Failed!")
+ return "[name] : Failed!"
/datum/station_goal/Destroy()
SSticker.mode.station_goals -= src
diff --git a/html/browser/roundend.css b/html/browser/roundend.css
new file mode 100644
index 000000000000..82235f127315
--- /dev/null
+++ b/html/browser/roundend.css
@@ -0,0 +1,67 @@
+.greentext {
+ color: #90ee90;
+ font-weight: bold;
+}
+
+.greentext_alt {
+ color: green;
+}
+.redtext {
+ color: #ef2f3c;
+ font-weight: bold;
+}
+.neutraltext {
+ font-weight: bold; /* If you feel these should have some color feel free to change */
+}
+
+.marooned {
+ color: rgb(109, 109, 255); font-weight: bold;
+}
+
+.header {
+ font-size: 24px; font-weight: bold;
+}
+
+.big {
+ font-size: 24px;
+}
+
+.medaltext {
+ color: #add8e6;
+}
+
+.codephrase {
+ color : #ef2f3c;
+}
+
+.redborder {
+ border-bottom: 2px solid #ef2f3c;
+}
+
+.greenborder {
+ border-bottom: 2px solid #90ee90;
+}
+
+.clockborder {
+ border-bottom: 2px solid #B18B25;
+}
+
+.stationborder {
+ border-bottom: 2px solid #add8e6;
+}
+
+li {
+ margin-bottom: 0.2rem;
+}
+
+.panel {
+ background-color: #313131;
+ padding: 10px;
+ border-radius: 10px;
+ margin-bottom: 5px;
+}
+
+body {
+ background-color: #272727;
+ color: #efefef;
+}
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index 097c60ff7324..259adc309749 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -107,6 +107,7 @@
#include "code\__HELPERS\pronouns.dm"
#include "code\__HELPERS\radiation.dm"
#include "code\__HELPERS\radio.dm"
+#include "code\__HELPERS\roundend.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\shell.dm"
#include "code\__HELPERS\stat_tracking.dm"
@@ -1246,6 +1247,7 @@
#include "code\modules\client\client_colour.dm"
#include "code\modules\client\client_defines.dm"
#include "code\modules\client\client_procs.dm"
+#include "code\modules\client\player_details.dm"
#include "code\modules\client\message.dm"
#include "code\modules\client\preferences.dm"
#include "code\modules\client\preferences_savefile.dm"