"
+ 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/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("
")
diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm
index 9c3af923f1..3822f7077d 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 bb86b4cbb0..8b8b817586 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 0006d72d3b..2ad2eb76f5 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/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index f411bd65d3..e5e999f003 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -22,7 +22,7 @@ GLOBAL_PROTECT(config_dir)
config = src
InitEntries()
LoadModes()
- if(!LoadEntries("config.txt"))
+ if(LoadEntries("config.txt") <= 1)
log_config("No $include directives found in config.txt! Loading legacy game_options/dbconfig/comms files...")
LoadEntries("game_options.txt")
LoadEntries("dbconfig.txt")
@@ -97,6 +97,13 @@ GLOBAL_PROTECT(config_dir)
if(!entry)
continue
+ if(entry == "$include")
+ if(!value)
+ log_config("Warning: Invalid $include directive: [value]")
+ else
+ LoadEntries(value, stack)
+ ++.
+ continue
if(entry == "$include")
if(!value)
@@ -123,8 +130,8 @@ GLOBAL_PROTECT(config_dir)
if(validated)
E.modified = TRUE
-
- . = TRUE
+
+ ++.
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 941fcbbcd6..e638de668e 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -10,7 +10,8 @@ SUBSYSTEM_DEF(blackbox)
var/sealed = FALSE //time to stop tracking stats?
var/list/research_levels = list() //list of highest tech levels attained that isn't lost lost by destruction of RD computers
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()
@@ -225,7 +226,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 881bb7fcb7..0f06caa20d 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -398,204 +398,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
- var/list/successfulCrew = list()
- var/list/miscreants = list()
-
- to_chat(world, "
The round has ended.")
- if(LAZYLEN(GLOB.round_end_notifiees))
- send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
-
-/* var/nocredits = config.no_credits_round_end
- for(var/client/C in GLOB.clients)
- if(!C.credits && !nocredits)
- 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
-
- for(var/datum/mind/crewMind in minds)
- if(!crewMind.current || !crewMind.objectives.len)
- continue
- for(var/datum/objective/miscreant/MO in crewMind.objectives)
- miscreants += "
[crewMind.current.real_name] (Played by:
[crewMind.key])
Objective: [MO.explanation_text]
(Optional)"
- for(var/datum/objective/crew/CO in crewMind.objectives)
- if(CO.check_completion())
- to_chat(crewMind.current, "
Your optional objective: [CO.explanation_text]
Success!")
- successfulCrew += "
[crewMind.current.real_name] (Played by:
[crewMind.key])
Objective: [CO.explanation_text]
Success! (Optional)"
- else
- to_chat(crewMind.current, "
Your optional objective: [CO.explanation_text]
Failed.")
-
- if (successfulCrew.len)
- var/completedObjectives = "
The following crew members completed their Crew Objectives:"
- for(var/i in successfulCrew)
- completedObjectives += "[i]
"
- to_chat(world, "[completedObjectives]
")
- else
- if(CONFIG_GET(flag/allow_crew_objectives))
- to_chat(world, "
Nobody completed their Crew Objectives!")
-
- CHECK_TICK
-
- if (miscreants.len)
- var/miscreantObjectives = "
The following crew members were miscreants:"
- for(var/i in miscreants)
- miscreantObjectives += "[i]
"
- to_chat(world, "[miscreantObjectives]
")
-
- 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 37811c183f..acb873dd5b 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -206,6 +206,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
@@ -299,6 +300,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()
@@ -318,7 +320,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 8d86507271..c12a08a792 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 8d13c48e7c..a98acf054e 100644
--- a/code/datums/antagonists/abductor.dm
+++ b/code/datums/antagonists/abductor.dm
@@ -1,7 +1,8 @@
/datum/antagonist/abductor
name = "Abductor"
+ roundend_category = "abductors"
job_rank = ROLE_ABDUCTOR
- var/datum/objective_team/abductor_team/team
+ var/datum/team/abductor_team/team
var/sub_role
var/outfit
var/landmark_type
@@ -19,7 +20,7 @@
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
-/datum/antagonist/abductor/create_team(datum/objective_team/abductor_team/new_team)
+/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -70,3 +71,65 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
+
+
+/datum/team/abductor_team
+ member_name = "abductor"
+ var/team_number
+ var/list/datum/mind/abductees = list()
+
+/datum/team/abductor_team/is_solo()
+ return FALSE
+
+/datum/team/abductor_team/proc/add_objective(datum/objective/O)
+ O.team = src
+ O.update_explanation_text()
+ objectives += O
+
+/datum/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 0a7b2aa22f..9b5dbb6d75 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
@@ -46,7 +49,7 @@ GLOBAL_LIST_EMPTY(antagonists)
return
//Assign default team and creates one for one of a kind team antagonists
-/datum/antagonist/proc/create_team(datum/objective_team/team)
+/datum/antagonist/proc/create_team(datum/team/team)
return
//Proc called when the datum is given to a mind.
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(antagonists)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
farewell()
- var/datum/objective_team/team = get_team()
+ var/datum/team/team = get_team()
if(team)
team.remove_member(owner)
qdel(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 6458e6da09..b06c75e4fa 100644
--- a/code/datums/antagonists/brother.dm
+++ b/code/datums/antagonists/brother.dm
@@ -2,12 +2,12 @@
name = "Brother"
job_rank = ROLE_BROTHER
var/special_role = "blood brother"
- var/datum/objective_team/brother_team/team
+ var/datum/team/brother_team/team
/datum/antagonist/brother/New(datum/mind/new_owner)
return ..()
-/datum/antagonist/brother/create_team(datum/objective_team/brother_team/new_team)
+/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -55,3 +55,71 @@
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
+
+
+/datum/team/brother_team
+ name = "brotherhood"
+ member_name = "blood brother"
+ var/meeting_area
+
+/datum/team/brother_team/is_solo()
+ return FALSE
+
+/datum/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/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/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/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/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 e98bfed782..4f8af2dc8a 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 8cc1c9e9a7..48f9b53425 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/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/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/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(.)
@@ -156,7 +175,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
- owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
+ owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
to_chat(owner, "
A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
owner.current.log_message("
Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG)
owner.wipe_memory()
@@ -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/team/clockcult
+ name = "Clockcult"
+ var/list/objective
+ var/datum/mind/eminence
+
+/datum/team/clockcult/proc/check_clockwork_victory()
+ if(GLOB.clockwork_gateway_activated)
+ return TRUE
+ return FALSE
+
+/datum/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 c26b0f8108..916123ddff 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/team/cult/cult_team
+
+/datum/antagonist/cult/get_team()
+ return cult_team
+
+/datum/antagonist/cult/create_team(datum/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/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/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/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/team/cult/proc/check_cult_victory()
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ return FALSE
+ return TRUE
+
+/datum/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 d386c79c25..3ccdc7ddfb 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
@@ -294,3 +294,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 416a8f3752..97e0d8c18a 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 ab4822dd79..8201cd879d 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 46e1ac3602..8b7fc7826f 100644
--- a/code/datums/antagonists/nukeop.dm
+++ b/code/datums/antagonists/nukeop.dm
@@ -10,8 +10,9 @@
/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/datum/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.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
var/nukeop_outfit = /datum/outfit/syndicate
@@ -38,7 +39,7 @@
if(!ishuman(owner.current))
return
var/mob/living/carbon/human/H = owner.current
-
+
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
H.equipOutfit(nukeop_outfit)
@@ -102,14 +103,14 @@
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
-/datum/antagonist/nukeop/create_team(datum/objective_team/nuclear/new_team)
+/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
if(!new_team)
if(!always_new_team)
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
if(N.nuke_team)
nuke_team = N.nuke_team
return
- nuke_team = new /datum/objective_team/nuclear
+ nuke_team = new /datum/team/nuclear
nuke_team.update_objectives()
assign_nuke() //This is bit ugly
return
@@ -157,7 +158,7 @@
return
nuke_team.rename_team(ask_name())
-/datum/objective_team/nuclear/proc/rename_team(new_name)
+/datum/team/nuclear/proc/rename_team(new_name)
syndicate_name = new_name
name = "[syndicate_name] Team"
for(var/I in members)
@@ -200,43 +201,40 @@
stack_trace("Station self destruct ot found during lone op team creation.")
nuke_team.memorized_code = null
-/datum/objective_team/nuclear
- var/list/objectives
+/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
var/memorized_code
-/datum/objective_team/nuclear/New()
+/datum/team/nuclear/New()
..()
syndicate_name = syndicate_name()
-/datum/objective_team/nuclear/proc/update_objectives()
- objectives = list()
+/datum/team/nuclear/proc/update_objectives()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
- return
-/datum/objective_team/nuclear/proc/disk_rescued()
+/datum/team/nuclear/proc/disk_rescued()
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
if(!D.onCentCom())
return FALSE
return TRUE
-/datum/objective_team/nuclear/proc/operatives_dead()
+/datum/team/nuclear/proc/operatives_dead()
for(var/I in members)
var/datum/mind/operative_mind = I
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
-/datum/objective_team/nuclear/proc/syndies_escaped()
+/datum/team/nuclear/proc/syndies_escaped()
var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
return (S && (S.z == ZLEVEL_CENTCOM || S.z == ZLEVEL_TRANSIT))
-/datum/objective_team/nuclear/proc/get_result()
+/datum/team/nuclear/proc/get_result()
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
var/disk_rescued = disk_rescued()
var/syndies_didnt_escape = !syndies_escaped()
@@ -264,57 +262,61 @@
else
return //Undefined result
-/datum/objective_team/nuclear/proc/roundend_display()
- to_chat(world,"
[syndicate_name] Operatives:")
-
+/datum/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)
- TC_uses += H.spent_telecrystals
+ TC_uses += H.purchase_log.total_spent
if(H.purchase_log)
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 ad32e09151..9bf20a4bf5 100644
--- a/code/datums/antagonists/pirate.dm
+++ b/code/datums/antagonists/pirate.dm
@@ -1,7 +1,8 @@
/datum/antagonist/pirate
name = "Space Pirate"
job_rank = ROLE_TRAITOR
- var/datum/objective_team/pirate/crew
+ roundend_category = "space pirates"
+ var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
to_chat(owner, "
You are a Space Pirate!")
@@ -11,15 +12,16 @@
/datum/antagonist/pirate/get_team()
return crew
-/datum/antagonist/pirate/create_team(datum/objective_team/pirate/new_team)
+/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
if(!new_team)
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
if(P.crew)
- new_team = P.crew
+ crew = P.crew
+ return
if(!new_team)
- crew = new /datum/objective_team/pirate
+ crew = new /datum/team/pirate
crew.forge_objectives()
- return
+ return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
crew = new_team
@@ -34,11 +36,10 @@
owner.objectives -= crew.objectives
. = ..()
-/datum/objective_team/pirate
+/datum/team/pirate
name = "Pirate crew"
- var/list/objectives = list()
-/datum/objective_team/pirate/proc/forge_objectives()
+/datum/team/pirate/proc/forge_objectives()
var/datum/objective/loot/getbooty = new()
getbooty.team = src
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
@@ -84,11 +85,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)
@@ -104,32 +105,25 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
/datum/objective/loot/check_completion()
return ..() || get_loot_value() >= target_value
+/datum/team/pirate/roundend_report()
+ var/list/parts = list()
-//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"
+ parts += ""
- 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
+ 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 9db86bdf08..3209b9221c 100644
--- a/code/datums/antagonists/revolution.dm
+++ b/code/datums/antagonists/revolution.dm
@@ -3,9 +3,10 @@
/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
+ var/datum/team/revolution/rev_team
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
@@ -39,17 +40,17 @@
. = ..()
/datum/antagonist/rev/greet()
- to_chat(owner, "
You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!")
+ to_chat(owner, "
You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!")
owner.announce_objectives()
-/datum/antagonist/rev/create_team(datum/objective_team/revolution/new_team)
+/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
if(!new_team)
//For now only one revolution at a time
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
if(H.rev_team)
rev_team = H.rev_team
return
- rev_team = new /datum/objective_team/revolution
+ rev_team = new /datum/team/revolution
rev_team.update_objectives()
rev_team.update_heads()
return
@@ -77,7 +78,7 @@
old_owner.add_antag_datum(new_revhead,old_team)
new_revhead.silent = FALSE
to_chat(old_owner, "
You have proved your devotion to revolution! You are a head revolutionary now!")
-
+
/datum/antagonist/rev/head
name = "Head Revolutionary"
@@ -131,14 +132,14 @@
old_owner.add_antag_datum(new_rev,old_team)
new_rev.silent = FALSE
to_chat(old_owner, "
Revolution has been disappointed of your leader traits! You are a regular revolutionary now!")
-
+
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
- owner.current.visible_message("[owner.current] looks like they just remembered their real allegiance!")
- to_chat(owner, "
You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...")
+ owner.current.visible_message("
[owner.current] looks like they just remembered their real allegiance!", ignored_mob = owner.current)
+ to_chat(owner, "
You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...")
else if(issilicon(owner.current))
- owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.")
- to_chat(owner, "
The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.")
+ owner.current.visible_message("
The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.", ignored_mob = owner.current)
+ to_chat(owner, "
The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.")
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
@@ -163,7 +164,7 @@
if(remove_clumsy && 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(give_flash)
var/obj/item/device/assembly/flash/T = new(H)
var/list/slots = list (
@@ -176,18 +177,17 @@
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
else
to_chat(H, "The flash in your [where] will help you to persuade the crew to join your cause.")
-
+
if(give_hud)
var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(H)
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
-/datum/objective_team/revolution
+/datum/team/revolution
name = "Revolution"
- var/list/objectives = list()
var/max_headrevs = 3
-/datum/objective_team/revolution/proc/update_objectives(initial = FALSE)
+/datum/team/revolution/proc/update_objectives(initial = FALSE)
var/untracked_heads = SSjob.get_all_heads()
for(var/datum/objective/mutiny/O in objectives)
untracked_heads -= O.target
@@ -199,16 +199,16 @@
objectives += new_target
for(var/datum/mind/M in members)
M.objectives |= objectives
-
+
addtimer(CALLBACK(src,.proc/update_objectives),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
-/datum/objective_team/revolution/proc/head_revolutionaries()
+/datum/team/revolution/proc/head_revolutionaries()
. = list()
for(var/datum/mind/M in members)
if(M.has_antag_datum(/datum/antagonist/rev/head))
. += M
-/datum/objective_team/revolution/proc/update_heads()
+/datum/team/revolution/proc/update_heads()
if(SSticker.HasRoundStarted())
var/list/datum/mind/head_revolutionaries = head_revolutionaries()
var/list/datum/mind/heads = SSjob.get_all_heads()
@@ -227,3 +227,56 @@
rev.promote()
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
+
+
+/datum/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 e1e6dc09c8..e856a6642f 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/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
@@ -33,7 +33,7 @@
/datum/antagonist/wizard/proc/unregister()
SSticker.mode.wizards -= src
-/datum/antagonist/wizard/create_team(datum/objective_team/wizard/new_team)
+/datum/antagonist/wizard/create_team(datum/team/wizard/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -43,12 +43,14 @@
/datum/antagonist/wizard/get_team()
return wiz_team
-/datum/objective_team/wizard
+/datum/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/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/components/README.md b/code/datums/components/README.md
index 574e628741..026b387e27 100644
--- a/code/datums/components/README.md
+++ b/code/datums/components/README.md
@@ -40,6 +40,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
+ * `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
1. `/datum/component/var/dupe_type` (protected, type)
* Definition of a duplicate component type
* `null` means exact match on `type` (default)
@@ -66,6 +67,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* All components a datum owns are deleted with the datum
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
+ * Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
@@ -104,9 +106,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
* Clears `parent` and removes the component from it's component list
-1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final)
+1. `/datum/component/proc/_JoinParent` (private, final)
* Tries to add the component to it's `parent`s `datum_components` list
- * Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index c54376d787..fcd4651459 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -6,54 +6,16 @@
var/datum/parent
/datum/component/New(datum/P, ...)
- if(type == /datum/component)
- qdel(src)
- CRASH("[type] instantiated!")
-
- //check for common mishaps
- if(!isnum(dupe_mode))
- qdel(src)
- CRASH("[type]: Invalid dupe_mode!")
- var/dt = dupe_type
- if(dt && !ispath(dt))
- qdel(src)
- CRASH("[type]: Invalid dupe_type!")
-
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
return
- _CheckDupesAndJoinParent(P)
+ _JoinParent(P)
-/datum/component/proc/_CheckDupesAndJoinParent()
+/datum/component/proc/_JoinParent()
var/datum/P = parent
- var/dm = dupe_mode
-
- var/datum/component/old
- if(dm != COMPONENT_DUPE_ALLOWED)
- var/dt = dupe_type
- if(!dt)
- old = P.GetExactComponent(type)
- else
- old = P.GetComponent(dt)
- if(old)
- //One or the other has to die
- switch(dm)
- if(COMPONENT_DUPE_UNIQUE)
- old.InheritComponent(src, TRUE)
- qdel(src, TRUE, TRUE)
- return
- if(COMPONENT_DUPE_HIGHLANDER)
- InheritComponent(old, FALSE)
- qdel(old, FALSE, TRUE)
-
- //provided we didn't eat someone
- if(!old)
- //let the others know
- P.SendSignal(COMSIG_COMPONENT_ADDED, src)
-
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
@@ -212,10 +174,59 @@
return list(.)
/datum/proc/AddComponent(new_type, ...)
- var/nt = new_type
+ var/datum/component/nt = new_type
+ var/dm = initial(nt.dupe_mode)
+ var/dt = initial(nt.dupe_type)
+
+ var/datum/component/old_comp
+ var/datum/component/new_comp
+
+ if(ispath(nt))
+ if(nt == /datum/component)
+ CRASH("[nt] attempted instantiation!")
+ if(!isnum(dm))
+ CRASH("[nt]: Invalid dupe_mode ([dm])!")
+ if(dt && !ispath(dt))
+ CRASH("[nt]: Invalid dupe_type ([dt])!")
+ else
+ new_comp = nt
+
args[1] = src
- var/datum/component/C = new nt(arglist(args))
- return QDELING(C) ? GetExactComponent(new_type) : C
+
+ if(dm != COMPONENT_DUPE_ALLOWED)
+ if(!dt)
+ old_comp = GetExactComponent(nt)
+ else
+ old_comp = GetComponent(dt)
+ if(old_comp)
+ switch(dm)
+ if(COMPONENT_DUPE_UNIQUE)
+ if(!new_comp)
+ new_comp = new nt(arglist(args))
+ if(!QDELETED(new_comp))
+ old_comp.InheritComponent(new_comp, TRUE)
+ qdel(new_comp)
+ if(COMPONENT_DUPE_HIGHLANDER)
+ if(!new_comp)
+ new_comp = new nt(arglist(args))
+ if(!QDELETED(new_comp))
+ new_comp.InheritComponent(old_comp, FALSE)
+ qdel(old_comp)
+ if(COMPONENT_DUPE_UNIQUE_PASSARGS)
+ if(!new_comp)
+ var/list/arguments = args.Copy(2)
+ old_comp.InheritComponent(null, TRUE, arguments)
+ else
+ old_comp.InheritComponent(new_comp, TRUE)
+ else if(!new_comp)
+ new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
+ else if(!new_comp)
+ new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
+
+ if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
+ SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
+ return new_comp
+ return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
@@ -235,7 +246,8 @@
C._RemoveFromParent()
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
C.parent = src
- C._CheckDupesAndJoinParent()
+ if(C == AddComponent(C))
+ C._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index 20cc9cd134..a79de32898 100644
--- a/code/datums/components/decal.dm
+++ b/code/datums/components/decal.dm
@@ -48,8 +48,7 @@
if(old_dir == new_dir)
return
remove()
- var/rotation = SIMPLIFY_DEGREES(dir2angle(new_dir)-dir2angle(old_dir))
- pic.dir = turn(pic.dir, rotation)
+ pic.dir = turn(pic.dir, dir2angle(old_dir) - dir2angle(new_dir))
apply()
/datum/component/decal/proc/clean_react(strength)
@@ -57,4 +56,4 @@
qdel(src)
/datum/component/decal/proc/examine(mob/user)
- to_chat(user, description)
\ No newline at end of file
+ to_chat(user, description)
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
index c149fd8492..fc0456ad10 100644
--- a/code/datums/components/radioactive.dm
+++ b/code/datums/components/radioactive.dm
@@ -4,7 +4,7 @@
#define RAD_AMOUNT_EXTREME 1000
/datum/component/radioactive
- dupe_mode = COMPONENT_DUPE_UNIQUE
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/source
@@ -47,13 +47,16 @@
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
-/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original)
+/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments)
if(!i_am_original)
return
if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
return
- var/datum/component/radioactive/other = C
- strength = max(strength, other.strength)
+ if(C)
+ var/datum/component/radioactive/other = C
+ strength = max(strength, other.strength)
+ else
+ strength = max(strength, arguments[1])
/datum/component/radioactive/proc/rad_examine(mob/user, atom/thing)
var/atom/master = parent
diff --git a/code/datums/components/thermite.dm b/code/datums/components/thermite.dm
index f76178213d..11611cadfb 100644
--- a/code/datums/components/thermite.dm
+++ b/code/datums/components/thermite.dm
@@ -1,5 +1,5 @@
/datum/component/thermite
- dupe_mode = COMPONENT_DUPE_UNIQUE
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/amount
var/overlay
@@ -46,10 +46,13 @@
master.cut_overlay(overlay)
return ..()
-/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original)
+/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments)
if(!i_am_original)
return
- amount += newC.amount
+ if(newC)
+ amount += newC.amount
+ else
+ amount += arguments[1]
/datum/component/thermite/proc/thermite_melt(mob/user)
var/turf/master = parent
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index b41dadc95a..231ce66f28 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -149,7 +149,7 @@
return
LAZYADD(antag_datums, A)
A.create_team(team)
- var/datum/objective_team/antag_team = A.get_team()
+ var/datum/team/antag_team = A.get_team()
if(antag_team)
antag_team.add_member(src)
A.on_gain()
@@ -185,12 +185,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)
@@ -207,6 +201,7 @@
remove_antag_datum(ANTAG_DATUM_BROTHER)
SSticker.mode.update_brother_icons_removed(src)
+
/datum/mind/proc/remove_nukeop()
var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(nuke)
@@ -221,7 +216,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()
@@ -339,7 +333,7 @@
N.send_to_spawnpoint = FALSE
N.nukeop_outfit = null
add_antag_datum(N,converter.nuke_team)
-
+
enslaved_to = creator
@@ -773,17 +767,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", "late-assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -905,11 +926,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]")
@@ -918,6 +943,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]")
@@ -1000,11 +1030,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"])
@@ -1345,16 +1377,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/atoms.dm b/code/game/atoms.dm
index b7d377fb61..211f9dea59 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -194,27 +194,22 @@
set waitfor = FALSE
return
-// Convenience proc to see if a container is open for chemistry handling
-// returns true if open
-// false if closed
+// Convenience procs to see if a container is open for chemistry handling
/atom/proc/is_open_container()
- return container_type & OPENCONTAINER_1
-
-/atom/proc/is_transparent()
- return container_type & TRANSPARENT_1
+ return is_refillable() && is_drainable()
/atom/proc/is_injectable(allowmobs = TRUE)
- if(isliving(src) && allowmobs)
- var/mob/living/L = src
- return L.can_inject()
- if(container_type & OPENCONTAINER_1)
- return TRUE
- return container_type & INJECTABLE_1
+ return reagents && (container_type & (INJECTABLE | REFILLABLE))
/atom/proc/is_drawable(allowmobs = TRUE)
- if(is_injectable(allowmobs)) //Everything that can be injected can also be drawn from, but not vice versa
- return TRUE
- return container_type & DRAWABLE_1
+ return reagents && (container_type & (DRAWABLE | DRAINABLE))
+
+/atom/proc/is_refillable()
+ return reagents && (container_type & REFILLABLE)
+
+/atom/proc/is_drainable()
+ return reagents && (container_type & DRAINABLE)
+
/atom/proc/AllowDrop()
return FALSE
@@ -256,19 +251,26 @@
if(desc)
to_chat(user, desc)
- if(reagents && (is_open_container() || is_transparent())) //is_open_container() isn't really the right proc for this, but w/e
- to_chat(user, "It contains:")
- if(reagents.reagent_list.len)
- if(user.can_see_reagents()) //Show each individual reagent
- for(var/datum/reagent/R in reagents.reagent_list)
- to_chat(user, "[R.volume] units of [R.name]")
- else //Otherwise, just show the total volume
- var/total_volume = 0
- for(var/datum/reagent/R in reagents.reagent_list)
- total_volume += R.volume
- to_chat(user, "[total_volume] units of various reagents")
- else
- to_chat(user, "Nothing.")
+ if(reagents)
+ if(container_type & TRANSPARENT)
+ to_chat(user, "It contains:")
+ if(reagents.reagent_list.len)
+ if(user.can_see_reagents()) //Show each individual reagent
+ for(var/datum/reagent/R in reagents.reagent_list)
+ to_chat(user, "[R.volume] units of [R.name]")
+ else //Otherwise, just show the total volume
+ var/total_volume = 0
+ for(var/datum/reagent/R in reagents.reagent_list)
+ total_volume += R.volume
+ to_chat(user, "[total_volume] units of various reagents")
+ else
+ to_chat(user, "Nothing.")
+ else if(container_type & AMOUNT_VISIBLE)
+ if(reagents.total_volume)
+ to_chat(user, "
It has [reagents.total_volume] unit\s left.")
+ else
+ to_chat(user, "
It's empty.")
+
SendSignal(COMSIG_PARENT_EXAMINE, user)
/atom/proc/relaymove(mob/user)
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index e62c91168b..d8ba1f5fa1 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -73,7 +73,7 @@
C.prefs.copy_to(M)
M.key = C.key
var/datum/mind/app_mind = M.mind
-
+
var/datum/antagonist/wizard/apprentice/app = new(app_mind)
app.master = user
app.school = kind
@@ -165,7 +165,7 @@
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(!creator_op)
return
-
+
switch(borg_to_spawn)
if("Medical")
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
@@ -187,7 +187,7 @@
R.real_name = R.name
R.key = C.key
-
+
var/datum/antagonist/nukeop/new_borg = new(R.mind)
new_borg.send_to_spawnpoint = FALSE
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
@@ -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/antag_team.dm b/code/game/gamemodes/antag_team.dm
new file mode 100644
index 0000000000..372ee26dfa
--- /dev/null
+++ b/code/game/gamemodes/antag_team.dm
@@ -0,0 +1,34 @@
+//A barebones antagonist team.
+/datum/team
+ 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/team/New(starting_members)
+ . = ..()
+ if(starting_members)
+ if(islist(starting_members))
+ for(var/datum/mind/M in starting_members)
+ add_member(M)
+ else
+ add_member(starting_members)
+
+/datum/team/proc/is_solo()
+ return members.len == 1
+
+/datum/team/proc/add_member(datum/mind/new_member)
+ members |= new_member
+
+/datum/team/proc/remove_member(datum/mind/member)
+ members -= member
+
+//Display members/victory/failure/objectives for the team
+/datum/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/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index c1af1601ce..609f5bb6ab 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -1,44 +1,6 @@
-/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()
+ var/list/datum/team/brother_team/brother_teams = list()
/datum/game_mode/traitor/bros
name = "traitor+brothers"
@@ -51,9 +13,10 @@
Blood Brothers: Accomplish your objectives.\n\
Crew: Do not let the traitors or brothers succeed!"
- var/list/datum/objective_team/brother_team/pre_brother_teams = list()
+ var/list/datum/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")
@@ -73,7 +36,7 @@
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
break
- var/datum/objective_team/brother_team/team = new
+ var/datum/team/brother_team/team = new
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
for(var/k = 1 to team_size)
var/datum/mind/bro = pick(possible_brothers)
@@ -86,50 +49,19 @@
return ..()
/datum/game_mode/traitor/bros/post_setup()
- for(var/datum/objective_team/brother_team/team in pre_brother_teams)
+ for(var/datum/team/brother_team/team in pre_brother_teams)
team.meeting_area = pick(meeting_areas)
meeting_areas -= team.meeting_area
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
+ 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! [istype(objective, /datum/objective/crew) ? "
(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[objective_count]: [objective.explanation_text]
Fail. [istype(objective, /datum/objective/crew) ? "
(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
- if(!(istype(objective, /datum/objective/crew)))
- 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 a70f392d4f..ad76d41d47 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -94,47 +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! [istype(objective, /datum/objective/crew) ? "
(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text]
Fail. [istype(objective, /datum/objective/crew) ? "
(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "FAIL"))
- if(!(istype(objective, /datum/objective/crew)))
- 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 61bd9bb496..e4f75ea563 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
@@ -111,6 +113,8 @@ Credit where due:
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/team/clockcult/main_clockcult
+
/datum/game_mode/clockwork_cult/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -185,22 +189,21 @@ Credit where due:
return FALSE
/datum/game_mode/clockwork_cult/check_finished()
- var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
- if(G && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
+ if(GLOB.ark_of_the_clockwork_justiciar && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
return FALSE
- . = ..()
+ 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 \
@@ -210,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_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
index 19f9e37319..29655a0ac9 100644
--- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
+++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
@@ -275,7 +275,6 @@
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
return
- visible_message("
[src] begins to glow bright blue!")
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
sleep(10)
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
@@ -355,5 +354,4 @@
if(sigil_active)
animation_number = initial(animation_number)
sigil_active = FALSE
- visible_message("
[src] slowly stops glowing!")
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
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 acf6e43974..1b2b867aa5 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 f232ba3def..1092d6763d 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
@@ -18,16 +18,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
@@ -46,20 +36,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 && C.clock_team)
- if(C.clock_team.eminence)
- remove_servant_of_ratvar(src,TRUE)
- qdel(src)
- return
- else
- C.clock_team.eminence = src
+ 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 0eb8084feb..2edaba3b23 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)
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index f20dd25802..697a5c8eba 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/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/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/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 530b6ebb20..b809f2419c 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -30,7 +30,7 @@
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
var/title = "Acolyte"
- var/span = "cultitalic"
+ var/span = "cult italic"
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
span = "cultlarge"
if(ishuman(user))
@@ -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/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/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 2adaa57a2f..f0934b524f 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 33d5f49661..ff85499029 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.
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
..()
-//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
+//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
/obj/effect/rune/raise_dead
- cultist_name = "Revive Cultist"
- cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
+ cultist_name = "Resurrect Cultist"
+ cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = TRUE
for(var/mob/living/M in T.contents)
- if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
+ if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
to_chat(user, "
There are no dead cultists on the rune!")
- log_game("Raise Dead rune failed - no cultists to revive")
+ log_game("Raise Dead rune failed - no corpses to revive")
+ fail_invoke()
+ rune_in_use = FALSE
+ return
+ if(LAZYLEN(GLOB.sacrificed) <= revives_used)
+ to_chat(user, "
You have sacrificed too few people to revive a cultist!")
fail_invoke()
rune_in_use = FALSE
return
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
else
invocation = initial(invocation)
..()
- if(mob_to_revive.stat == DEAD)
- if(LAZYLEN(GLOB.sacrificed) <= revives_used)
- to_chat(user, "
Your cult must carry out another sacrifice before it can revive a cultist!")
- fail_invoke()
- rune_in_use = FALSE
- return
- revives_used++
- mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
- mob_to_revive.grab_ghost()
- else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
- set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
- var/mob/dead/observer/theghost = null
- if(candidates.len)
- theghost = pick(candidates)
- to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
- message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
- mob_to_revive.ghostize(0)
- mob_to_revive.key = theghost.key
+ revives_used++
+ mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
+ mob_to_revive.grab_ghost()
to_chat(mob_to_revive, "
\"PASNAR SAVRAE YAM'TOTH. Arise.\"")
mob_to_revive.visible_message("
[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.", \
"
You awaken suddenly from the void. You're alive!")
diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm
index 957e261933..44f3368feb 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 ca6755dbd3..a0e5a9f147 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."
@@ -532,3 +452,17 @@
nuke_off_station = off_station
if(off_station < 2)
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 4918e94131..efe6dc69e9 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 4eb8642c02..f9e8f8d752 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"
@@ -24,7 +10,7 @@
required_players = 15
maximum_players = 50
var/max_teams = 4
- var/list/datum/objective_team/abductor_team/abductor_teams = list()
+ var/list/datum/team/abductor_team/abductor_teams = list()
var/finished = FALSE
var/static/team_count = 0
@@ -51,7 +37,7 @@
if(team_number > max_teams)
return //or should it try to stuff them in anway ?
- var/datum/objective_team/abductor_team/team = new
+ var/datum/team/abductor_team/team = new
team.team_number = team_number
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
team.add_objective(new/datum/objective/experiment)
@@ -64,6 +50,7 @@
antag_candidates -= scientist
team.members |= scientist
scientist.assigned_role = "Abductor Scientist"
+ scientist.special_role = "Abductor Scientist"
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
if(!agent)
@@ -71,18 +58,19 @@
antag_candidates -= agent
team.members |= agent
agent.assigned_role = "Abductor Agent"
+ agent.special_role = "Abductor Agent"
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
abductor_teams += team
return team
/datum/game_mode/abduction/post_setup()
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ for(var/datum/team/abductor_team/team in abductor_teams)
post_setup_team(team)
return ..()
//Used for create antag buttons
-/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
+/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
for(var/datum/mind/M in team.members)
if(M.assigned_role == "Abductor Scientist")
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
@@ -91,7 +79,7 @@
/datum/game_mode/abduction/check_finished()
if(!finished)
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ for(var/datum/team/abductor_team/team in abductor_teams)
for(var/datum/objective/O in team.objectives)
if(O.check_completion())
SSshuttle.emergency.request(null, set_coefficient = 0.5)
@@ -99,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
@@ -144,9 +103,9 @@
/datum/objective/experiment/check_completion()
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
- if(!istype(team, /datum/objective_team/abductor_team))
+ if(!istype(team, /datum/team/abductor_team))
return FALSE
- var/datum/objective_team/abductor_team/T = team
+ var/datum/team/abductor_team/T = team
if(E.team_number == T.team_number)
return E.points >= target_amount
return FALSE
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index c3a591a278..cf1329aec9 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 379031dce9..8e02d41441 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 5e1a97675b..2ebc21adac 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 b4dc0794cc..441689fb9b 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 f1f9624380..e62665f21b 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 4fcde56a72..890a3bb456 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -17,7 +17,7 @@
var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
var/list/pre_nukeops = list()
- var/datum/objective_team/nuclear/nuke_team
+ var/datum/team/nuclear/nuke_team
/datum/game_mode/nuclear/pre_setup()
var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
@@ -69,7 +69,8 @@
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)
@@ -102,22 +103,12 @@
else
SSticker.mode_result = "halfwin - interrupted"
SSticker.news_report = OPERATIVE_SKIRMISH
- return ..()
/datum/game_mode/nuclear/generate_report()
return "One of Central Command's trading routes was recently disrupted by a raid carried out by the Gorlex Marauders. They seemed to only be after one ship - a highly-sensitive \
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)
@@ -132,7 +123,8 @@
l_pocket = /obj/item/pinpointer/nuke/syndicate
id = /obj/item/card/id/syndicate
belt = /obj/item/gun/ballistic/automatic/pistol
- backpack_contents = list(/obj/item/storage/box/syndie=1)
+ backpack_contents = list(/obj/item/storage/box/syndie=1,\
+ /obj/item/kitchen/knife/combat/survival)
var/tc = 25
var/command_radio = FALSE
@@ -177,4 +169,5 @@
r_hand = /obj/item/gun/ballistic/automatic/shotgun/bulldog
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/tank/jetpack/oxygen/harness=1,\
- /obj/item/gun/ballistic/automatic/pistol=1)
+ /obj/item/gun/ballistic/automatic/pistol=1,\
+ /obj/item/kitchen/knife/combat/survival)
diff --git a/code/game/gamemodes/objective_team.dm b/code/game/gamemodes/objective_team.dm
index 7789a167c7..1483f356d2 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 4fa9532b42..f20e16b36b 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -26,7 +26,7 @@
var/finished = 0
var/check_counter = 0
var/max_headrevs = 3
- var/datum/objective_team/revolution/revolution
+ var/datum/team/revolution/revolution
var/list/datum/mind/headrev_candidates = list()
///////////////////////////
@@ -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 7c93a89a36..42c96cb5c0 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,80 +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! [istype(objective, /datum/objective/crew) ? "(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- objectives += "
Objective #[count]: [objective.explanation_text] Fail. [istype(objective, /datum/objective/crew) ? "(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
- if(!(istype(objective, /datum/objective/crew)))
- 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 6b6780e6be..8b80b9ab69 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -64,7 +64,6 @@
to_chat(user, "\"Come now, do not capture your bretheren's soul.\"")
return
add_logs(user, M, "captured [M.name]'s soul", src)
-
transfer_soul("VICTIM", M, user)
///////////////////Options for using captured souls///////////////////////////////////////
@@ -142,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 5302ebd39b..0d9655ae8e 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -58,65 +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! [istype(objective, /datum/objective/crew) ? "(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail. [istype(objective, /datum/objective/crew) ? "(Optional)" : ""]"
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
- if(!(istype(objective, /datum/objective/crew)))
- 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/limbgrower.dm b/code/game/machinery/limbgrower.dm
index 47fee66b9e..e661bc24c5 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -10,7 +10,7 @@
icon = 'icons/obj/machines/limbgrower.dmi'
icon_state = "limbgrower_idleoff"
density = TRUE
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm
index fdb481401e..59465cf5b2 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/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 799344fe54..2d148b4ff4 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -571,9 +571,9 @@
if(bumpsmash && occupant) //Need a pilot to push the PUNCH button.
if(nextsmash < world.time)
obstacle.mech_melee_attack(src)
- if(!obstacle || !obstacle.density)
- step(src,dir)
nextsmash = world.time + smashcooldown
+ if(!obstacle || obstacle.CanPass(src,get_step(src,dir)))
+ step(src,dir)
if(isobj(obstacle))
var/obj/O = obstacle
if(!O.anchored)
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index 0e0c7c606e..f06525863d 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -47,10 +47,8 @@
return
else
var/hotness = W.is_hot()
- var/added_heat = (hotness / 100)
- src.reagents.chem_temp = min(src.reagents.chem_temp + added_heat, hotness)
- src.reagents.handle_reactions()
- to_chat(user, "You heat [src] with [W]!")
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [W]!")
else
return ..()
@@ -62,8 +60,7 @@
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
if(reagents)
- reagents.chem_temp += 30
- reagents.handle_reactions()
+ reagents.expose_temperature(exposed_temperature)
..()
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index fd414b8d9a..372eb56bfe 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -102,7 +102,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "cigoff"
throw_speed = 0.5
item_state = "cigoff"
- container_type = INJECTABLE_1
+ container_type = INJECTABLE
w_class = WEIGHT_CLASS_TINY
body_parts_covered = null
grind_results = list()
@@ -660,7 +660,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
item_state = "[param_color]_vape"
/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/reagent_containers) && (O.container_type & OPENCONTAINER_1))
+ if(O.is_drainable())
if(reagents.total_volume < chem_volume)
if(O.reagents.total_volume > 0)
O.reagents.trans_to(src,25)
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index d334d12193..5f582b9e15 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -16,6 +16,7 @@
attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
dog_fashion = /datum/dog_fashion/back
resistance_flags = FIRE_PROOF
+ container_type = AMOUNT_VISIBLE
var/max_water = 50
var/last_use = 1
var/safety = TRUE
@@ -48,7 +49,6 @@
/obj/item/extinguisher/attack_self(mob/user)
safety = !safety
src.icon_state = "[sprite_name][!safety]"
- src.desc = "The safety is [safety ? "on" : "off"]."
to_chat(user, "The safety is [safety ? "on" : "off"].")
return
@@ -67,11 +67,10 @@
/obj/item/extinguisher/examine(mob/user)
..()
+ to_chat(user, "The safety is [safety ? "on" : "off"].")
+
if(reagents.total_volume)
- to_chat(user, "It contains [round(reagents.total_volume)] unit\s.")
to_chat(user, "Alt-click to empty it.")
- else
- to_chat(user, "It is empty.")
/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
if(istype(target, /obj/structure/reagent_dispensers/watertank) && target.Adjacent(user))
diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm
index 1e3e9ccd73..0fe53f293c 100644
--- a/code/game/objects/items/gift.dm
+++ b/code/game/objects/items/gift.dm
@@ -7,6 +7,9 @@
/*
* Gifts
*/
+
+GLOBAL_LIST_EMPTY(possible_gifts)
+
/obj/item/a_gift
name = "gift"
desc = "PRESENTS!!!! eek!"
@@ -30,6 +33,14 @@
to_chat(M, "You're supposed to be spreading gifts, not opening them yourself!")
return
+ var/gift_type = get_gift_type()
+
+ qdel(src)
+ var/obj/item/I = new gift_type(M)
+ M.put_in_hands(I)
+ I.add_fingerprint(M)
+
+/obj/item/a_gift/proc/get_gift_type()
var/gift_type_list = list(/obj/item/sord,
/obj/item/storage/wallet,
/obj/item/storage/photo_album,
@@ -72,10 +83,21 @@
var/gift_type = pick(gift_type_list)
- if(!ispath(gift_type, /obj/item))
- return
+ return gift_type
- qdel(src)
- var/obj/item/I = new gift_type(M)
- M.put_in_hands(I)
- I.add_fingerprint(M)
+
+/obj/item/a_gift/anything
+ name = "christmas gift"
+ desc = "It could be anything!"
+
+/obj/item/a_gift/anything/get_gift_type()
+ if(!GLOB.possible_gifts.len)
+ var/list/gift_types_list = subtypesof(/obj/item)
+ for(var/V in gift_types_list)
+ var/obj/item/I = V
+ if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.flags_1) & ABSTRACT_1))
+ gift_types_list -= V
+ GLOB.possible_gifts = gift_types_list
+ var/gift_type = pick(GLOB.possible_gifts)
+
+ return gift_type
diff --git a/code/game/objects/items/implants/implant_chem.dm b/code/game/objects/items/implants/implant_chem.dm
index 509784a699..e266f3ab09 100644
--- a/code/game/objects/items/implants/implant_chem.dm
+++ b/code/game/objects/items/implants/implant_chem.dm
@@ -2,7 +2,7 @@
name = "chem implant"
desc = "Injects things."
icon_state = "reagents"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
/obj/item/implant/chem/get_data()
var/dat = {"Implant Specifications:
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 14529b4078..533858b748 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -419,7 +419,7 @@
name = "suspicious looking duffel bag"
desc = "A large duffel bag for holding extra tactical supplies."
icon_state = "duffel-syndie"
- item_state = "duffel-syndie"
+ item_state = "duffel-syndieammo"
silent = 1
slowdown = 0
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index fa7d14d572..8a3dc21dbe 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -114,7 +114,7 @@
possible_transfer_amounts = list(25,50,100)
volume = 500
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = 0
var/obj/item/watertank/tank
@@ -351,7 +351,7 @@
var/usage_ratio = 5 //5 unit added per 1 removed
var/injection_amount = 1
amount_per_transfer_from_this = 5
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = FALSE
possible_transfer_amounts = list(5,10,15)
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 6e3fab7212..12c056c9af 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -120,7 +120,7 @@
/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity)
if(!proximity)
return
- if(!status && istype(O, /obj/item/reagent_containers) && O.is_open_container())
+ if(!status && O.is_refillable())
reagents.trans_to(O, reagents.total_volume)
to_chat(user, "You empty [src]'s fuel tank into [O].")
update_icon()
@@ -241,7 +241,7 @@
container_type = NONE
else
to_chat(user, "[src] can now be attached, modified, and refuelled.")
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
add_fingerprint(user)
/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user)
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index f7071cd0a5..393ff3886d 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -36,9 +36,6 @@
else
return ..()
-
-
-
/obj/structure/flora/tree/pine
name = "pine tree"
desc = "A coniferous pine tree."
@@ -53,6 +50,21 @@
name = "xmas tree"
desc = "A wondrous decorated Christmas tree."
icon_state = "pine_c"
+ var/gifts_under_tree = FALSE
+ var/list/ckeys_that_took = list()
+
+/obj/structure/flora/tree/pine/xmas/attack_hand(mob/living/user)
+ if(!gifts_under_tree)
+ return
+ if(!user.ckey)
+ return
+ if(ckeys_that_took[user.ckey])
+ to_chat(user, "You already took your gift.")
+ return
+ to_chat(user, "After a bit of rummaging, you locate a gift with your name on it!")
+ ckeys_that_took[user.ckey] = TRUE
+ var/obj/item/a_gift/anything/A = new
+ user.put_in_hands(A)
/obj/structure/flora/tree/pine/xmas/Initialize()
. = ..()
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index b6332492dd..0f12f847d7 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -5,7 +5,7 @@
icon_state = "cart"
anchored = FALSE
density = TRUE
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
//copypaste sorry
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
var/obj/item/storage/bag/trash/mybag = null
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 711f9baf0b..44c12a21a1 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -89,7 +89,7 @@
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
- var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
+ var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm
index b2dc64fec7..d468e87a34 100644
--- a/code/game/objects/structures/mop_bucket.dm
+++ b/code/game/objects/structures/mop_bucket.dm
@@ -1,24 +1,24 @@
-/obj/structure/mopbucket
- name = "mop bucket"
- desc = "Fill it with water, but don't forget a mop!"
- icon = 'icons/obj/janitor.dmi'
- icon_state = "mopbucket"
+/obj/structure/mopbucket
+ name = "mop bucket"
+ desc = "Fill it with water, but don't forget a mop!"
+ icon = 'icons/obj/janitor.dmi'
+ icon_state = "mopbucket"
density = TRUE
- container_type = OPENCONTAINER_1
- var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
-
-
-/obj/structure/mopbucket/New()
- create_reagents(100)
- ..()
-
-/obj/structure/mopbucket/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/mop))
- if(reagents.total_volume < 1)
- to_chat(user, "[src] is out of water!")
- else
- reagents.trans_to(I, 5)
- to_chat(user, "You wet [I] in [src].")
- playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
- else
- return ..()
\ No newline at end of file
+ container_type = OPENCONTAINER
+ var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
+
+
+/obj/structure/mopbucket/New()
+ create_reagents(100)
+ ..()
+
+/obj/structure/mopbucket/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/mop))
+ if(reagents.total_volume < 1)
+ to_chat(user, "[src] is out of water!")
+ else
+ reagents.trans_to(I, 5)
+ to_chat(user, "You wet [I] in [src].")
+ playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
+ else
+ return ..()
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 9009a7171d..77b992704a 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -483,9 +483,9 @@
if(istype(O, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RG = O
- if(RG.container_type & OPENCONTAINER_1)
+ if(RG.is_refillable())
if(!RG.reagents.holder_full())
- RG.reagents.add_reagent("[dispensedreagent]", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
+ RG.reagents.add_reagent(dispensedreagent, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
to_chat(user, "You fill [RG] from [src].")
return TRUE
to_chat(user, "\The [RG] is full.")
@@ -533,7 +533,7 @@
O.clean_blood()
O.acid_level = 0
create_reagents(5)
- reagents.add_reagent("[dispensedreagent]", 5)
+ reagents.add_reagent(dispensedreagent, 5)
reagents.reaction(O, TOUCH)
user.visible_message("[user] washes [O] using [src].", \
"You wash [O] using [src].")
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index b1e8215592..5399b748e6 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -139,9 +139,11 @@
if(isliving(A))
var/mob/living/L = A
- if(L.pulling)
+ var/atom/movable/AM = L.pulling
+ if(AM)
var/turf/T = get_step(L.loc,turn(A.dir, 180))
- L.pulling.forceMove(T)
+ AM.forceMove(T)
+ L.start_pulling(AM)
//now we're on the new z_level, proceed the space drifting
stoplag()//Let a diagonal move finish, if necessary
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 0b0957e072..43651cebef 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/chat_commands.dm b/code/modules/admin/chat_commands.dm
index 744455bb9a..bc41b489c0 100644
--- a/code/modules/admin/chat_commands.dm
+++ b/code/modules/admin/chat_commands.dm
@@ -94,6 +94,7 @@ GLOBAL_LIST(round_end_notifiees)
return "Unable to run query, another admin proc call is in progress. Try again later."
GLOB.AdminProcCaller = "CHAT_[sender]" //_ won't show up in ckeys so it'll never match with a real admin
var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller)
+ GLOB.AdminProcCaller = null
if(!results)
return "Query produced no output"
var/list/text_res = results.Copy(1, 3)
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index b5d908d669..2a3812be3b 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -524,7 +524,7 @@
if(SSticker.mode.brother_teams.len > 0)
dat += "
| Brothers | | |
"
- for(var/datum/objective_team/brother_team/team in SSticker.mode.brother_teams)
+ for(var/datum/team/brother_team/team in SSticker.mode.brother_teams)
for(var/datum/mind/brother in team.members)
var/mob/M = brother.current
if(M)
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 836a6e26be..ece3775872 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -240,14 +240,13 @@
//Let's find the spawn locations
var/leader_chosen = FALSE
-
- var/datum/objective_team/nuclear/nuke_team
+ var/datum/team/nuclear/nuke_team
for(var/mob/c in chosen)
var/mob/living/carbon/human/new_character=makeBody(c)
if(!leader_chosen)
leader_chosen = TRUE
var/datum/antagonist/nukeop/N = new_character.mind.add_antag_datum(/datum/antagonist/nukeop/leader)
- nuke_team = N.nuke_team
+ nuke_team = N.nuke_team
else
new_character.mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
return 1
@@ -309,12 +308,15 @@
//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"].")
var/missiondesc = "Your squad is being sent on a mission to [station_name()] by Nanotrasen's Security Division."
@@ -361,12 +363,15 @@
//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)
@@ -466,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 b675815602..d09041aaf3 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/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index eed265598e..8f13d887aa 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -1207,7 +1207,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(!holder)
return
- var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL)
+ var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1229,6 +1229,12 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
bluespace_artillery(target)
if(ADMIN_PUNISHMENT_FIREBALL)
new /obj/effect/temp_visual/target(get_turf(target))
+ if(ADMIN_PUNISHMENT_ROD)
+ var/turf/T = get_turf(target)
+ var/startside = pick(GLOB.cardinals)
+ var/turf/startT = spaceDebrisStartLoc(startside, T.z)
+ var/turf/endT = spaceDebrisFinishLoc(startside, T.z)
+ new /obj/effect/immovablerod(startT, endT,target)
var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]."
message_admins(msg)
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index 3031936d43..1fe8baba01 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 dbbe6ea512..10d3866672 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -68,3 +68,6 @@
var/datum/chatOutput/chatOutput
+ 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.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 411816227f..407e9aa37c 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -227,6 +227,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()
chatOutput.start() // Starts the chat
diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm
new file mode 100644
index 0000000000..a842607235
--- /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 94ca764384..49364e76d9 100644
--- 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/crafting/craft.dm b/code/modules/crafting/craft.dm
index 3e4e93ca4c..85ae7c3b18 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -98,7 +98,7 @@
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
- if(RC.container_type & OPENCONTAINER_1)
+ if(RC.is_drainable())
for(var/datum/reagent/A in RC.reagents.reagent_list)
.[A.type] += A.volume
.[I.type] += 1
diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm
index 9415bef33d..793805977c 100644
--- a/code/modules/detectivework/footprints_and_rag.dm
+++ b/code/modules/detectivework/footprints_and_rag.dm
@@ -13,7 +13,7 @@
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
amount_per_transfer_from_this = 5
possible_transfer_amounts = list()
volume = 5
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index 41ff90407d..abb5a0639d 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/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index 2f5618714d..956a214009 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -1,19 +1,3 @@
-/datum/round_event_control/treevenge
- name = "Treevenge (Christmas)"
- holidayID = CHRISTMAS
- typepath = /datum/round_event/treevenge
- max_occurrences = 1
- weight = 20
-
-/datum/round_event/treevenge/start()
- for(var/obj/structure/flora/tree/pine/xmas in world)
- var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc)
- evil_tree.icon_state = xmas.icon_state
- evil_tree.icon_living = evil_tree.icon_state
- evil_tree.icon_dead = evil_tree.icon_state
- evil_tree.icon_gib = evil_tree.icon_state
- qdel(xmas) //b-but I don't want to delete xmas...
-
//this is an example of a possible round-start event
/datum/round_event_control/presents
name = "Presents under Trees (Christmas)"
@@ -24,12 +8,11 @@
earliest_start = 0
/datum/round_event/presents/start()
- for(var/obj/structure/flora/tree/pine/xmas in world)
+ for(var/obj/structure/flora/tree/pine/xmas/xmas in world)
if(!(xmas.z in GLOB.station_z_levels))
continue
- for(var/turf/open/floor/T in orange(1,xmas))
- for(var/i=1,i<=rand(1,5),i++)
- new /obj/item/a_gift(T)
+ xmas.icon_state = "pinepresents"
+ xmas.gifts_under_tree = TRUE
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/Ian in GLOB.mob_living_list)
Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
for(var/obj/machinery/computer/security/telescreen/entertainment/Monitor in GLOB.machines)
@@ -98,7 +81,7 @@
name = "Santa is coming to town! (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/santa
- weight = 150
+ weight = 20
max_occurrences = 1
earliest_start = 20000
diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm
index b933e566be..9612fd8018 100644
--- a/code/modules/events/immovable_rod.dm
+++ b/code/modules/events/immovable_rod.dm
@@ -12,6 +12,16 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
typepath = /datum/round_event/immovable_rod
min_players = 15
max_occurrences = 5
+ var/atom/special_target
+
+
+/datum/round_event_control/immovable_rod/admin_setup()
+ if(!check_rights(R_FUN))
+ return
+
+ var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No")
+ if(aimed == "Yes")
+ special_target = get_turf(usr)
/datum/round_event/immovable_rod
announceWhen = 5
@@ -20,10 +30,11 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
priority_announce("What the fuck was that?!", "General Alert")
/datum/round_event/immovable_rod/start()
+ var/datum/round_event_control/immovable_rod/C = control
var/startside = pick(GLOB.cardinals)
var/turf/startT = spaceDebrisStartLoc(startside, ZLEVEL_STATION_PRIMARY)
var/turf/endT = spaceDebrisFinishLoc(startside, ZLEVEL_STATION_PRIMARY)
- new /obj/effect/immovablerod(startT, endT)
+ new /obj/effect/immovablerod(startT, endT, C.special_target)
/obj/effect/immovablerod
name = "immovable rod"
@@ -36,18 +47,28 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
var/z_original = 0
var/destination
var/notify = TRUE
+ var/atom/special_target
-/obj/effect/immovablerod/New(atom/start, atom/end)
+/obj/effect/immovablerod/New(atom/start, atom/end, aimed_at)
..()
SSaugury.register_doom(src, 2000)
z_original = z
destination = end
+ special_target = aimed_at
if(notify)
notify_ghosts("\A [src] is inbound!",
enter_link="(Click to orbit)",
source=src, action=NOTIFY_ORBIT)
GLOB.poi_list += src
- if(end && end.z==z_original)
+
+ var/special_target_valid = FALSE
+ if(special_target)
+ var/turf/T = get_turf(special_target)
+ if(T.z == z_original)
+ special_target_valid = TRUE
+ if(special_target_valid)
+ walk_towards(src, special_target, 1)
+ else if(end && end.z==z_original)
walk_towards(src, destination, 1)
/obj/effect/immovablerod/Topic(href, href_list)
@@ -60,11 +81,20 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
GLOB.poi_list -= src
. = ..()
-/obj/effect/immovablerod/Move()
+/obj/effect/immovablerod/Moved()
if((z != z_original) || (loc == destination))
qdel(src)
+ if(special_target && loc == get_turf(special_target))
+ complete_trajectory()
return ..()
+/obj/effect/immovablerod/proc/complete_trajectory()
+ //We hit what we wanted to hit, time to go
+ special_target = null
+ destination = get_edge_target_turf(src, dir)
+ walk(src,0)
+ walk_towards(src, destination, 1)
+
/obj/effect/immovablerod/ex_act(severity, target)
return 0
@@ -83,6 +113,9 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
x = clong.x
y = clong.y
+ if(special_target && clong == special_target)
+ complete_trajectory()
+
if(isturf(clong) || isobj(clong))
if(clong.density)
clong.ex_act(EXPLODE_HEAVY)
diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm
index 073ef8aea3..76188cb5b7 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 618c746a65..3227f81d58 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 6ee000249b..1cf4858ce7 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/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 6fb712ea41..5eae2b80d8 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -8,7 +8,7 @@
icon_state = null
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
var/gulp_size = 5 //This is now officially broken ... need to think of a nice way to fix it.
possible_transfer_amounts = list(5,10,15,20,25,30,50)
volume = 50
@@ -30,7 +30,7 @@
if(!canconsume(M, user))
return 0
- if (!is_open_container())
+ if (!is_drainable())
to_chat(user, "[src]'s lid hasn't been opened!")
return 0
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("[user] feeds the contents of [src] to [M].", "[user] feeds the contents of [src] to [M].")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
var/fraction = min(gulp_size/reagents.total_volume, 1)
checkLiked(fraction, M)
@@ -56,31 +56,16 @@
/obj/item/reagent_containers/food/drinks/afterattack(obj/target, mob/user , proximity)
if(!proximity)
return
- if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
- if (!is_open_container())
- to_chat(user, "[target]'s tab isn't open!")
- return
-
- if(!target.reagents.total_volume)
- to_chat(user, "[target] is empty.")
- return
-
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "[src] is full.")
- return
-
- var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
- to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
-
- else if(target.is_open_container()) //Something like a glass. Player probably wants to transfer TO it.
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "[src] is empty.")
return
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
+ if(target.reagents.holder_full())
to_chat(user, "[target] is full.")
return
+
var/refill = reagents.get_master_reagent_id()
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "You transfer [trans] units of the solution to [target].")
@@ -90,13 +75,29 @@
bro.cell.use(30)
addtimer(CALLBACK(reagents, /datum/reagents.proc/add_reagent, refill, trans), 600)
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if (!is_refillable())
+ to_chat(user, "[src]'s tab isn't open!")
+ return
+
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty.")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
+
+ else
+
/obj/item/reagent_containers/food/drinks/attackby(obj/item/I, mob/user, params)
- if(I.is_hot())
- var/added_heat = (I.is_hot() / 100) //ishot returns a temperature
- if(reagents)
- reagents.chem_temp += added_heat
- to_chat(user, "You heat [src] with [I].")
- reagents.handle_reactions()
+ var/hotness = I.is_hot()
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
..()
/obj/item/reagent_containers/food/drinks/throw_impact(atom/target, mob/thrower)
@@ -142,7 +143,7 @@
possible_transfer_amounts = list()
volume = 5
flags_1 = CONDUCT_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = TRUE
resistance_flags = FIRE_PROOF
isGlass = FALSE
@@ -406,9 +407,9 @@
/obj/item/reagent_containers/food/drinks/soda_cans/attack_self(mob/user)
- if(!is_open_container())
+ if(!is_drainable())
to_chat(user, "You pull back the tab of \the [src] with a satisfying pop.") //Ahhhhhhhh
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
playsound(src, "can_open", 50, 1)
spillable = TRUE
return
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index e23f6b98a9..765f118c5e 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -4,7 +4,7 @@
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
volume = 50 //Sets the default container amount for all food items.
- container_type = INJECTABLE_1
+ container_type = INJECTABLE
resistance_flags = FLAMMABLE
var/foodtype = NONE
var/last_check_time
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index 3e6e2e8450..445e8e6534 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -10,7 +10,7 @@
desc = "Just your average condiment container."
icon = 'icons/obj/food/containers.dmi'
icon_state = "emptycondiment"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
possible_transfer_amounts = list(1, 5, 10, 15, 20, 25, 30, 50)
volume = 50
//Possible_states has the reagent id as key and a list of, in order, the icon_state, the name and the desc as values. Used in the on_reagent_change(changetype) to change names, descs and sprites.
@@ -45,7 +45,7 @@
if(!reagents || !reagents.total_volume)
return // The condiment might be empty after the delay.
user.visible_message("[user] feeds [M] from [src].")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
var/fraction = min(10/reagents.total_volume, 1)
reagents.reaction(M, INGEST, fraction)
@@ -70,7 +70,7 @@
to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
//Something like a glass or a food item. Player probably wants to transfer TO it.
- else if(target.is_open_container() || istype(target, /obj/item/reagent_containers/food/snacks))
+ else if(target.is_drainable() || istype(target, /obj/item/reagent_containers/food/snacks))
if(!reagents.total_volume)
to_chat(user, "[src] is empty!")
return
diff --git a/code/modules/food_and_drinks/food/customizables.dm b/code/modules/food_and_drinks/food/customizables.dm
index 3351a67d39..f3460edcaa 100644
--- a/code/modules/food_and_drinks/food/customizables.dm
+++ b/code/modules/food_and_drinks/food/customizables.dm
@@ -291,7 +291,7 @@
desc = "A simple bowl, used for soups and salads."
icon = 'icons/obj/food/soupsalad.dmi'
icon_state = "bowl"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
materials = list(MAT_GLASS = 500)
w_class = WEIGHT_CLASS_NORMAL
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index 7f574e0313..08b09124d5 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -94,7 +94,7 @@
if(!do_mob(user, M))
return
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
M.visible_message("[user] forces [M] to eat [src].", \
"[user] forces [M] to eat [src].")
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index a336d77404..40eae1b570 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -29,7 +29,7 @@ God bless America.
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
var/obj/item/reagent_containers/food/snacks/deepfryholder/frying //What's being fried RIGHT NOW?
var/cook_time = 0
var/oil_use = 0.05 //How much cooking oil is used per tick
diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
index c2be28fb21..40f99b363a 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
@@ -15,7 +15,7 @@
var/portion = 10
var/selected_drink
var/list/stored_food = list()
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
var/obj/item/reagent_containers/mixer
/obj/machinery/food_cart/Initialize()
@@ -100,7 +100,7 @@
stored_food[sanitize(S.name)]++
else
stored_food[sanitize(S.name)] = 1
- else if(O.is_open_container())
+ else if(O.is_drainable())
return
else
. = ..()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
index 1b00de1842..f2f288fe7a 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
@@ -14,7 +14,7 @@
anchored = FALSE
use_power = NO_POWER_USE
layer = BELOW_OBJ_LAYER
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
max_integrity = 300
var/list/product_types = list()
var/dispense_flavour = ICECREAM_VANILLA
@@ -112,7 +112,7 @@
else
to_chat(user, "[O] already has ice cream in it.")
return 1
- else if(O.is_open_container())
+ else if(O.is_drainable())
return
else
return ..()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index dfa249c04d..52ee5ebd2b 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -81,7 +81,7 @@
src.icon_state = "mw"
src.broken = 0 // Fix it!
src.dirty = 0 // just to be sure
- src.container_type = OPENCONTAINER_1
+ src.container_type = OPENCONTAINER
return 0 //to use some fuel
else
to_chat(user, "It's broken!")
@@ -98,7 +98,7 @@
src.dirty = 0 // It's clean!
src.broken = 0 // just to be sure
src.icon_state = "mw"
- src.container_type = OPENCONTAINER_1
+ src.container_type = OPENCONTAINER
src.updateUsrDialog()
return 1 // Disables the after-attack so we don't spray the floor/user.
else
@@ -119,7 +119,7 @@
src.dirty = 0 // It's clean!
src.broken = 0 // just to be sure
src.icon_state = "mw"
- src.container_type = OPENCONTAINER_1
+ src.container_type = OPENCONTAINER
else if(src.dirty==100) // The microwave is all dirty so can't be used!
to_chat(user, "It's dirty!")
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index 3403253c07..c72f26a4e7 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -13,7 +13,7 @@ body {
background: #fff;
font-family: Verdana, sans-serif;
font-size: 9pt;
- line-height: 1.4;
+ line-height: 1.2;
overflow-x: hidden;
overflow-y: scroll;
word-wrap: break-word;
diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html
index 82a1ed4885..d40fd75f39 100644
--- a/code/modules/goonchat/browserassets/html/browserOutput.html
+++ b/code/modules/goonchat/browserassets/html/browserOutput.html
@@ -36,6 +36,8 @@
Decrease font size -
Increase font size +
+
Decrease line height -
+
Increase line height +
Toggle ping display
Highlight string
Save chat log
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js
index 43092846c2..4ca135bfd7 100644
--- a/code/modules/goonchat/browserassets/js/browserOutput.js
+++ b/code/modules/goonchat/browserassets/js/browserOutput.js
@@ -593,6 +593,7 @@ $(function() {
******************************************/
var savedConfig = {
'sfontSize': getCookie('fontsize'),
+ 'slineHeight': getCookie('lineheight'),
'spingDisabled': getCookie('pingdisabled'),
'shighlightTerms': getCookie('highlightterms'),
'shighlightColor': getCookie('highlightcolor'),
@@ -604,6 +605,10 @@ $(function() {
$messages.css('font-size', savedConfig.sfontSize);
internalOutput('
Loaded font size setting of: '+savedConfig.sfontSize+'', 'internal');
}
+ if (savedConfig.slineHeight) {
+ $("body").css('line-height', savedConfig.slineHeight);
+ internalOutput('
Loaded line height setting of: '+savedConfig.slineHeight+'', 'internal');
+ }
if (savedConfig.spingDisabled) {
if (savedConfig.spingDisabled == 'true') {
opts.pingDisabled = true;
@@ -843,6 +848,28 @@ $(function() {
internalOutput('
Font size set to '+fontSize+'', 'internal');
});
+ $('#decreaseLineHeight').click(function(e) {
+ var Heightline = parseFloat($("body").css('line-height'));
+ var Sizefont = parseFloat($("body").css('font-size'));
+ var lineheightvar = Heightline / Sizefont
+ lineheightvar -= 0.1;
+ lineheightvar = lineheightvar.toFixed(1)
+ $("body").css({'line-height': lineheightvar});
+ setCookie('lineheight', lineheightvar, 365);
+ internalOutput('
Line height set to '+lineheightvar+'', 'internal');
+ });
+
+ $('#increaseLineHeight').click(function(e) {
+ var Heightline = parseFloat($("body").css('line-height'));
+ var Sizefont = parseFloat($("body").css('font-size'));
+ var lineheightvar = Heightline / Sizefont
+ lineheightvar += 0.1;
+ lineheightvar = lineheightvar.toFixed(1)
+ $("body").css({'line-height': lineheightvar});
+ setCookie('lineheight', lineheightvar, 365);
+ internalOutput('
Line height set to '+lineheightvar+'', 'internal');
+ });
+
$('#togglePing').click(function(e) {
if (opts.pingDisabled) {
$('#ping').slideDown('fast');
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index 388a9d6893..85605fd2c4 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -387,9 +387,9 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
/datum/holiday/xmas
name = CHRISTMAS
- begin_day = 23
+ begin_day = 22
begin_month = DECEMBER
- end_day = 25
+ end_day = 27
/datum/holiday/xmas/greet()
return "Have a merry Christmas!"
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index 42a927f4e9..c72d9e5c28 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -24,12 +24,6 @@
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
volume = 100
- container_type = OPENCONTAINER_1
- slot_flags = SLOT_BELT
- throwforce = 0
- w_class = WEIGHT_CLASS_SMALL
- throw_speed = 3
- throw_range = 10
/obj/item/reagent_containers/spray/weedspray/Initialize()
. = ..()
@@ -48,12 +42,6 @@
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
volume = 100
- container_type = OPENCONTAINER_1
- slot_flags = SLOT_BELT
- throwforce = 0
- w_class = WEIGHT_CLASS_SMALL
- throw_speed = 3
- throw_range = 10
/obj/item/reagent_containers/spray/pestspray/Initialize()
. = ..()
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index d22ca703c2..c46fb92feb 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -712,8 +712,8 @@
else if(transfer_amount) // Droppers, cans, beakers, what have you.
visi_msg="[user] uses [reagent_source] on [target]"
irrigate = 1
- // Beakers, bottles, buckets, etc. Can't use is_open_container though.
- if(istype(reagent_source, /obj/item/reagent_containers/glass/))
+ // Beakers, bottles, buckets, etc.
+ if(reagent_source.is_drainable())
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation)
diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm
index 0941c033f6..2acce3d450 100644
--- a/code/modules/integrated_electronics/passive/power.dm
+++ b/code/modules/integrated_electronics/passive/power.dm
@@ -90,7 +90,7 @@
icon_state = "chemical_cell"
extended_desc = "This is effectively an internal beaker. It will consume and produce power from plasma, slime jelly, welding fuel, carbon,\
ethanol, nutriments and blood , in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
complexity = 4
inputs = list()
outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_REF)
diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm
index 78b1e9682e..33f92c3646 100644
--- a/code/modules/integrated_electronics/subtypes/reagents.dm
+++ b/code/modules/integrated_electronics/subtypes/reagents.dm
@@ -1,3 +1,5 @@
+#define IC_SMOKE_REAGENTS_MINIMUM_UNITS 10
+
/obj/item/integrated_circuit/reagent
category_text = "Reagent"
resistance_flags = UNACIDABLE | FIRE_PROOF
@@ -8,8 +10,6 @@
if(volume)
create_reagents(volume)
-
-
/obj/item/integrated_circuit/reagent/smoke
name = "smoke generator"
desc = "Unlike most electronics, creating smoke is completely intentional."
@@ -17,7 +17,7 @@
extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \
into the smoke clouds when activated. The reagents are consumed when smoke is made."
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
volume = 100
complexity = 20
@@ -44,6 +44,8 @@
push_data()
/obj/item/integrated_circuit/reagent/smoke/do_work()
+ if(!reagents || (reagents.total_volume < IC_SMOKE_REAGENTS_MINIMUM_UNITS))
+ return
var/location = get_turf(src)
var/datum/effect_system/smoke_spread/chem/S = new
S.attach(location)
@@ -54,11 +56,9 @@
notified = TRUE
S.start()
- if(reagents)
- reagents.clear_reagents()
+ reagents.clear_reagents()
activate_pin(2)
-
/obj/item/integrated_circuit/reagent/injector
name = "integrated hypo-injector"
desc = "This scary looking thing is able to pump liquids into whatever it's pointed at."
@@ -66,7 +66,7 @@
extended_desc = "This autoinjector can push reagents into another container or someone else outside of the machine. The target \
must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. Negative given amount makes injector suck out reagents."
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
volume = 30
complexity = 20
@@ -145,7 +145,7 @@
return
if(direction_mode == SYRINGE_INJECT)
- if(!reagents.total_volume || !AM.is_injectable() || AM.reagents.total_volume >= AM.reagents.maximum_volume)
+ if(!reagents.total_volume || !AM.is_injectable() || AM.reagents.holder_full())
activate_pin(3)
return
@@ -156,12 +156,8 @@
return
//Always log attemped injections for admins
- var/list/rinject = list()
- for(var/datum/reagent/R in reagents.reagent_list)
- rinject += R.name
- var/contained = english_list(rinject)
-
- add_logs(src, L, "attemped to inject", addition="which had [contained]") //TODO: proper logging (maybe last touched and assembled)
+ var/contained = reagents.log_list()
+ add_logs(src, L, "attemped to inject", addition="which had [contained]")
L.visible_message("
[acting_object] is trying to inject [L]!", \
"
[acting_object] is trying to inject you!")
busy = TRUE
@@ -169,6 +165,7 @@
var/fraction = min(transfer_amount/reagents.total_volume, 1)
reagents.reaction(L, INJECT, fraction)
reagents.trans_to(L, transfer_amount)
+ add_logs(src, L, "injected", addition="which had [contained]")
L.visible_message("
[acting_object] injects [L] with its needle!", \
"
[acting_object] injects you with its needle!")
else
@@ -263,8 +260,7 @@
activate_pin(2)
return
- // FALSE in those procs makes mobs invalid targets.
- if(!source.is_drawable(FALSE) || !target.is_injectable(FALSE))
+ if(!source.is_drainable() || !target.is_refillable())
return
source.reagents.trans_to(target, transfer_amount)
@@ -276,7 +272,7 @@
icon_state = "reagent_storage"
extended_desc = "This is effectively an internal beaker."
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
volume = 60
complexity = 4
@@ -398,8 +394,7 @@
if(!source.reagents || !target.reagents)
return
- // FALSE in those procs makes mobs invalid targets.
- if(!source.is_drawable(FALSE) || !target.is_injectable(FALSE))
+ if(!source.is_drainable() || !target.is_refillable())
return
if(target.reagents.maximum_volume - target.reagents.total_volume <= 0)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 4ecae3730d..4481de1e36 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -471,7 +471,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set hidden = TRUE
var/max_view = client.prefs.unlock_content ? GHOST_MAX_VIEW_RANGE_MEMBER : GHOST_MAX_VIEW_RANGE_DEFAULT
if(input)
- client.change_view(CLAMP(client.view + input, 7, max_view))
+ client.rescale_view(input, 7, max_view)
/mob/dead/observer/verb/boo()
set category = "Ghost"
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index 79bbee9db1..fe41c074c0 100644
--- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -90,10 +90,9 @@
id = "xeno"
say_mod = "hisses"
default_color = "00FF00"
- species_traits = list(MUTCOLORS,LIPS,DIGITIGRADE,PIERCEIMMUNE,SPECIES_ORGANIC)
+ species_traits = list(MUTCOLORS,LIPS,DIGITIGRADE,SPECIES_ORGANIC)
mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur","mam_body_markings")
default_features = list("xenotail"="xeno","xenohead"="standard","xenodorsal"="standard","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None","mam_body_markings" = "xeno")
- heatmod = 1.3
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 6ee1ed5229..fbc8e85eb4 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -343,8 +343,15 @@
return 1
return 0
+// Living mobs use can_inject() to make sure that the mob is not syringe-proof in general.
/mob/living/proc/can_inject()
- return 1
+ return TRUE
+
+/mob/living/is_injectable(allowmobs = TRUE)
+ return (allowmobs && reagents && can_inject())
+
+/mob/living/is_drawable(allowmobs = TRUE)
+ return (allowmobs && reagents && can_inject())
/mob/living/proc/get_organ_target()
var/mob/shooter = src
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index ce0571ca4e..5445941ed3 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/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index b1be1c3076..26e455106b 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -352,7 +352,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "k9"
- moduleselect_icon = "k9"
+ moduleselect_icon = "security"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -387,7 +387,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "medihound"
- moduleselect_icon = "medihound"
+ moduleselect_icon = "medical"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -409,7 +409,7 @@
/obj/item/clockwork/slab/cyborg/janitor,
/obj/item/clockwork/replica_fabricator/cyborg)
cyborg_base_icon = "scrubpup"
- moduleselect_icon = "scrubpup"
+ moduleselect_icon = "janitor"
hat_offset = INFINITY
clean_on_move = TRUE
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0e6ecf1672..8046daf55d 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 fa899aec0f..1105940f22 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
@@ -152,7 +152,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 9ffbff5619..a91db7f177 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -45,6 +45,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 1656a43505..b26d01d880 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/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index fd52d8f0ac..cde600186f 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -162,7 +162,7 @@
* Sleepypens
*/
/obj/item/pen/sleepy
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
/obj/item/pen/sleepy/attack(mob/living/M, mob/user)
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 22712e970d..15b76d2641 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/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/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index 71befb50f1..4e341fa2a4 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -17,6 +17,7 @@
var/delay = 0 //Delay for energy weapons
var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown.
var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the ammo is fired.
+ var/heavy_metal = TRUE
/obj/item/ammo_casing/New()
@@ -58,3 +59,47 @@
to_chat(user, "
You fail to collect anything!")
else
return ..()
+
+/obj/item/ammo_casing/throw_impact(atom/A)
+ if(heavy_metal)
+ bounce_away(FALSE, NONE)
+ . = ..()
+
+/obj/item/ammo_casing/proc/bounce_away(still_warm = FALSE, delay = 3)
+ SpinAnimation(10, 1)
+ update_icon()
+ var/turf/T = get_turf(src)
+ if(still_warm && T && (is_type_in_typecache(T, GLOB.bullet_bounce_away_sizzle)))
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/items/welder.ogg', 20, 1), delay)
+ else if(T && (!is_type_in_typecache(T, GLOB.bullet_bounce_away_blacklist)))
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/weapons/bulletremove.ogg', 60, 1), delay)
+
+GLOBAL_LIST_INIT(bullet_bounce_away_sizzle, typecacheof(list(
+ /turf/closed/indestructible/rock/snow,
+ /turf/closed/wall/ice,
+ /turf/closed/wall/mineral/snow,
+ /turf/open/floor/grass/snow,
+ /turf/open/floor/holofloor/snow,
+ /turf/open/floor/plating/asteroid/snow,
+ /turf/open/floor/plating/ice,
+ /turf/open/water)))
+
+GLOBAL_LIST_INIT(bullet_bounce_away_blacklist, typecacheof(list(
+ /turf/closed/indestructible/rock/snow,
+ /turf/closed/indestructible/splashscreen,
+ /turf/closed/wall/mineral/snow,
+ /turf/open/chasm,
+ /turf/open/floor/carpet,
+ /turf/open/floor/grass,
+ /turf/open/floor/holofloor/beach,
+ /turf/open/floor/holofloor/carpet,
+ /turf/open/floor/holofloor/grass,
+ /turf/open/floor/holofloor/hyperspace,
+ /turf/open/floor/holofloor/snow,
+ /turf/open/floor/plating/asteroid/snow,
+ /turf/open/floor/plating/beach,
+ /turf/open/indestructible/reebe_void,
+ /turf/open/lava,
+ /turf/open/space,
+ /turf/open/water,
+ /turf/template_noop)))
diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm
index d51ea36e15..edd28e72a8 100644
--- a/code/modules/projectiles/ammunition/ammo_casings.dm
+++ b/code/modules/projectiles/ammunition/ammo_casings.dm
@@ -284,9 +284,9 @@
icon_state = "cshell"
projectile_type = /obj/item/projectile/bullet/dart
-/obj/item/ammo_casing/shotgun/dart/New()
- ..()
- container_type |= OPENCONTAINER_1
+/obj/item/ammo_casing/shotgun/dart/Initialize()
+ . = ..()
+ container_type |= OPENCONTAINER
create_reagents(30)
reagents.set_reacting(TRUE)
@@ -302,4 +302,4 @@
reagents.add_reagent("spore", 6)
reagents.add_reagent("mutetoxin", 6) //;HELP OPS IN MAINT
reagents.add_reagent("coniine", 6)
- reagents.add_reagent("sodium_thiopental", 6)
\ No newline at end of file
+ reagents.add_reagent("sodium_thiopental", 6)
diff --git a/code/modules/projectiles/ammunition/caseless.dm b/code/modules/projectiles/ammunition/caseless.dm
index 7432f9f8e7..b3439c86b2 100644
--- a/code/modules/projectiles/ammunition/caseless.dm
+++ b/code/modules/projectiles/ammunition/caseless.dm
@@ -4,6 +4,7 @@
/obj/item/ammo_casing/caseless
desc = "A caseless bullet casing."
firing_effect_type = null
+ heavy_metal = FALSE
/obj/item/ammo_casing/caseless/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread)
if (..()) //successfully firing
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index dcd9d356ad..40c198ec4e 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -7,6 +7,7 @@
var/select_name = "energy"
fire_sound = 'sound/weapons/laser.ogg'
firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/energy
+ heavy_metal = FALSE
/obj/item/ammo_casing/energy/chameleon
projectile_type = /obj/item/projectile/energy/chameleon
diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm
index 11fd12da70..de103b399e 100644
--- a/code/modules/projectiles/ammunition/special.dm
+++ b/code/modules/projectiles/ammunition/special.dm
@@ -3,6 +3,7 @@
desc = "I didn't even know magic needed ammo..."
projectile_type = /obj/item/projectile/magic
firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/magic
+ heavy_metal = FALSE
/obj/item/ammo_casing/magic/change
projectile_type = /obj/item/projectile/magic/change
diff --git a/code/modules/projectiles/box_magazine.dm b/code/modules/projectiles/box_magazine.dm
index 0e6ab6c23f..bf941108ff 100644
--- a/code/modules/projectiles/box_magazine.dm
+++ b/code/modules/projectiles/box_magazine.dm
@@ -96,9 +96,10 @@
/obj/item/ammo_box/attack_self(mob/user)
var/obj/item/ammo_casing/A = get_round()
if(A)
- user.put_in_hands(A)
+ if(!user.put_in_hands(A))
+ A.bounce_away(FALSE, NONE)
+ playsound(src, 'sound/weapons/bulletinsert.ogg', 60, 1)
to_chat(user, "
You remove a round from \the [src]!")
- playsound(A, 'sound/weapons/bulletremove.ogg', 60, 1)
update_icon()
/obj/item/ammo_box/update_icon()
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index c4ba7a33b7..680c86ff5c 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -31,8 +31,7 @@
if(istype(AC)) //there's a chambered round
if(casing_ejector)
AC.forceMove(drop_location()) //Eject casing onto ground.
- AC.SpinAnimation(10, 1) //next gen special effects
- addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, AC, 'sound/weapons/bulletremove.ogg', 60, 1), 3)
+ AC.bounce_away(TRUE)
chambered = null
else if(empty_chamber)
chambered = null
@@ -125,8 +124,7 @@
to_chat(user, "
You pull the magazine out of \the [src].")
else if(chambered)
AC.forceMove(drop_location())
- AC.SpinAnimation(10, 1)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, AC, 'sound/weapons/bulletremove.ogg', 60, 1), 3)
+ AC.bounce_away()
chambered = null
to_chat(user, "
You unload the round from \the [src]'s chamber.")
playsound(src, "gun_slide_lock", 70, 1)
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index f642a94284..563b3d9ad5 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -40,9 +40,7 @@
CB = magazine.get_round(0)
if(CB)
CB.forceMove(drop_location())
- CB.SpinAnimation(10, 1)
- CB.update_icon()
- addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, CB, 'sound/weapons/bulletremove.ogg', 60, 1), 3)
+ CB.bounce_away(FALSE, NONE)
num_unloaded++
if (num_unloaded)
to_chat(user, "
You unload [num_unloaded] shell\s from [src].")
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index d3b1815d0b..e702013233 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -57,8 +57,7 @@
/obj/item/gun/ballistic/shotgun/proc/pump_unload(mob/M)
if(chambered)//We have a shell in the chamber
chambered.forceMove(drop_location())//Eject casing
- chambered.SpinAnimation(10, 1)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, chambered, 'sound/weapons/bulletremove.ogg', 60, 1), 3)
+ chambered.bounce_away()
chambered = null
/obj/item/gun/ballistic/shotgun/proc/pump_reload(mob/M)
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 06bda36c66..a4ae8cae13 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -121,7 +121,6 @@
item_state = "plasmacutter"
ammo_type = list(/obj/item/ammo_casing/energy/plasma)
flags_1 = CONDUCT_1
- container_type = OPENCONTAINER_1
attack_verb = list("attacked", "slashed", "cut", "sliced")
force = 12
sharpness = IS_SHARP
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index ef609696a2..94e8b465c1 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -59,6 +59,19 @@
if(my_atom && my_atom.reagents == src)
my_atom.reagents = null
+
+// Used in attack logs for reagents in pills and such
+/datum/reagents/proc/log_list()
+ if(!length(reagent_list))
+ return "no reagents"
+
+ var/list/data = list()
+ for(var/r in reagent_list) //no reagents will be left behind
+ var/datum/reagent/R = r
+ data += "[R.id] ([round(R.volume, 0.1)]u)"
+ //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
+ return english_list(data)
+
/datum/reagents/proc/remove_any(amount = 1)
var/list/cached_reagents = reagent_list
var/total_transfered = 0
@@ -228,8 +241,7 @@
var/list/cached_reagents = reagent_list
var/list/cached_addictions = addiction_list
if(C)
- chem_temp = C.bodytemperature
- handle_reactions()
+ expose_temperature(C.bodytemperature, 0.25)
var/need_mob_update = 0
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
@@ -731,6 +743,16 @@
out += "[taste_desc]"
return english_list(out, "something indescribable")
+
+
+/datum/reagents/proc/expose_temperature(var/temperature, var/coeff=0.02)
+ var/temp_delta = (temperature - chem_temp) * coeff
+ if(temp_delta > 0)
+ chem_temp = min(chem_temp + max(temp_delta, 1), temperature)
+ else
+ chem_temp = max(chem_temp + min(temp_delta, -1), temperature)
+ chem_temp = round(chem_temp)
+ handle_reactions()
///////////////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 51ddf549e0..ac8f3bc656 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -184,7 +184,7 @@
if(default_unfasten_wrench(user, I))
return
- if(istype(I, /obj/item/reagent_containers) && (I.container_type & OPENCONTAINER_1))
+ if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
var/obj/item/reagent_containers/B = I
. = 1 //no afterattack
if(beaker)
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 722ddbf15f..96dabf8aaa 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -64,7 +64,7 @@
if(default_deconstruction_crowbar(I))
return
- if(istype(I, /obj/item/reagent_containers) && (I.container_type & OPENCONTAINER_1))
+ if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
. = 1 //no afterattack
if(beaker)
to_chat(user, "
A container is already loaded into [src]!")
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 631a027d9a..d463def8af 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -88,7 +88,7 @@
if(default_unfasten_wrench(user, I))
return
- if(istype(I, /obj/item/reagent_containers) && (I.container_type & OPENCONTAINER_1))
+ if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
. = 1 // no afterattack
if(panel_open)
to_chat(user, "
You can't use the [src.name] while its panel is opened!")
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index f6b0f464fd..ef186d8a79 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -225,7 +225,7 @@
/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/reagent_containers) && (I.container_type & OPENCONTAINER_1))
+ if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
. = TRUE //no afterattack
if(stat & (NOPOWER|BROKEN))
return
diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
index c98024471b..48dd5c2dc0 100644
--- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
@@ -62,7 +62,7 @@
if(default_unfasten_wrench(user, I))
return
- if (istype(I, /obj/item/reagent_containers) && (I.container_type & OPENCONTAINER_1) )
+ if (istype(I, /obj/item/reagent_containers) && I.is_open_container())
if (!beaker)
if(!user.transferItemToLoc(I, src))
to_chat(user, "
[I] is stuck to your hand!")
diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
index 86205caba5..7941853a91 100644
--- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm
+++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
@@ -46,6 +46,8 @@
var/new_volume = REAGENTS_BASE_VOLUME
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
new_volume += REAGENTS_BASE_VOLUME * B.rating
+ if(!reagents)
+ create_reagents(new_volume)
reagents.maximum_volume = new_volume
if(new_volume < reagents.total_volume)
reagents.reaction(loc, TOUCH) // if someone manages to downgrade it without deconstructing
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index a3c0d2c034..a9f9145972 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -97,10 +97,10 @@
/datum/reagent/consumable/cooking_oil/reaction_obj(obj/O, reac_volume)
if(holder && holder.chem_temp >= fry_temperature)
- if(isitem(O))
+ if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder))
O.loc.visible_message("
[O] rapidly fries as it's splashed with hot oil! Somehow.")
- var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location())
- F.fry(O, volume)
+ var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location(), O)
+ F.fry(volume)
/datum/reagent/consumable/cooking_oil/reaction_mob(mob/living/M, method = TOUCH, reac_volume, show_message = 1, touch_protection = 0)
if(!istype(M))
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 8698c10b05..6fb21e847b 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -48,15 +48,6 @@
/obj/item/reagent_containers/afterattack(obj/target, mob/user , flag)
return
-/obj/item/reagent_containers/proc/reagentlist(obj/item/reagent_containers/snack) //Attack logs for regents in pills
- var/data
- if(snack.reagents.reagent_list && snack.reagents.reagent_list.len) //find a reagent list if there is and check if it has entries
- for (var/datum/reagent/R in snack.reagents.reagent_list) //no reagents will be left behind
- data += "[R.id]([R.volume] units); " //Using IDs because SOME chemicals(I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
- return data
- else
- return "No reagents"
-
/obj/item/reagent_containers/proc/canconsume(mob/eater, mob/user)
if(!iscarbon(eater))
return 0
@@ -80,8 +71,7 @@
..()
/obj/item/reagent_containers/fire_act(exposed_temperature, exposed_volume)
- reagents.chem_temp += 30
- reagents.handle_reactions()
+ reagents.expose_temperature(exposed_temperature)
..()
/obj/item/reagent_containers/throw_impact(atom/target)
@@ -127,7 +117,8 @@
reagents.clear_reagents()
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
- if(is_open_container())
- reagents.chem_temp = max(reagents.chem_temp, 1000)
- reagents.handle_reactions()
+ reagents.expose_temperature(1000)
..()
+
+/obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ reagents.expose_temperature(exposed_temperature)
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 28a07d5862..0a99d9da6e 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -173,7 +173,7 @@ Borg Shaker
if(!proximity)
return
- else if(target.is_open_container() && target.reagents)
+ else if(target.is_refillable())
var/datum/reagents/R = reagent_list[mode]
if(!R.total_volume)
to_chat(user, "
[src] is currently out of this ingredient! Please allow some time for the synthesizer to produce more.")
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 30aa67e91a..144db32a6c 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -6,7 +6,7 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(1, 2, 3, 4, 5)
volume = 5
- container_type = TRANSPARENT_1
+ container_type = TRANSPARENT
/obj/item/reagent_containers/dropper/afterattack(obj/target, mob/user , proximity)
if(!proximity)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index df2df7c171..06a242cca9 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -3,7 +3,7 @@
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50)
volume = 50
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = TRUE
resistance_flags = ACID_PROOF
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("
[user] feeds something to [M].", "
[user] feeds something to you.")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
else
to_chat(user, "
You swallow a gulp of [src].")
var/fraction = min(5/reagents.total_volume, 1)
@@ -56,32 +56,30 @@
if((!proximity) || !check_allowed_items(target,target_self=1))
return
- else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
-
- if(target.reagents && !target.reagents.total_volume)
- to_chat(user, "
[target] is empty and can't be refilled!")
- return
-
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "
[src] is full.")
- return
-
- var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
- to_chat(user, "
You fill [src] with [trans] unit\s of the contents of [target].")
-
- else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "
[src] is empty!")
return
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "
[target] is full.")
+ if(target.reagents.holder_full())
+ to_chat(user, "
[target] is full.")
return
-
var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "
You transfer [trans] unit\s of the solution to [target].")
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
+ to_chat(user, "
[target] is empty and can't be refilled!")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "
[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "
You fill [src] with [trans] unit\s of the contents of [target].")
+
else if(reagents.total_volume)
if(user.a_intent == INTENT_HARM)
user.visible_message("
[user] splashes the contents of [src] onto [target]!", \
@@ -91,15 +89,9 @@
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
var/hotness = I.is_hot()
- if(hotness)
- var/added_heat = (hotness / 100) //ishot returns a temperature
- if(reagents)
- if(reagents.chem_temp < hotness) //can't be heated to be hotter than the source
- reagents.chem_temp += added_heat
- to_chat(user, "
You heat [src] with [I].")
- reagents.handle_reactions()
- else
- to_chat(user, "
[src] is already hotter than [I]!")
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "
You heat [name] with [I]!")
if(istype(I, /obj/item/reagent_containers/food/snacks/egg)) //breaking eggs
var/obj/item/reagent_containers/food/snacks/egg/E = I
@@ -169,7 +161,6 @@
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact
name = "cryostasis beaker"
@@ -179,7 +170,6 @@
materials = list(MAT_METAL=3000)
volume = 50
amount_per_transfer_from_this = 10
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact/Initialize()
. = ..()
@@ -195,7 +185,6 @@
volume = 300
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/cryoxadone
list_reagents = list("cryoxadone" = 30)
@@ -238,7 +227,6 @@
amount_per_transfer_from_this = 20
possible_transfer_amounts = list(10,15,20,25,30,50,70)
volume = 70
- flags_1 = OPENCONTAINER_1
flags_inv = HIDEHAIR
slot_flags = SLOT_HEAD
resistance_flags = NONE
@@ -409,4 +397,4 @@
/obj/item/reagent_containers/glass/beaker/large/bromine
name = "bromine beaker"
- list_reagents = list("bromine" = 50)
\ No newline at end of file
+ list_reagents = list("bromine" = 50)
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index dff0869322..53e0c9bfb6 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -10,7 +10,7 @@
volume = 30
possible_transfer_amounts = list()
resistance_flags = ACID_PROOF
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
var/ignore_flags = 0
var/infinite = FALSE
@@ -88,7 +88,7 @@
amount_per_transfer_from_this = 10
volume = 10
ignore_flags = 1 //so you can medipen through hardsuits
- container_type = DRAWABLE_1
+ container_type = DRAWABLE
flags_1 = null
list_reagents = list("epinephrine" = 10)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 5a2e888210..4908a55911 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -46,7 +46,7 @@
"
[user] forces [M] to [apply_method] [src].")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
if(reagents.total_volume)
reagents.reaction(M, apply_type)
reagents.trans_to(M, reagents.total_volume)
@@ -57,10 +57,15 @@
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
if(!proximity)
return
- if(target.is_open_container() != 0 && target.reagents)
- if(!target.reagents.total_volume)
+ if(target.is_refillable())
+ if(target.is_drainable() && !target.reagents.total_volume)
to_chat(user, "
[target] is empty! There's nothing to dissolve [src] in.")
return
+
+ if(target.reagents.holder_full())
+ to_chat(user, "
[target] is full.")
+ return
+
to_chat(user, "
You dissolve [src] in [target].")
for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
to_chat(O, "
[user] slips something into [target]!")
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 789345ca77..2e34e39f8f 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -7,7 +7,7 @@
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
@@ -23,17 +23,17 @@
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
-/obj/item/reagent_containers/spray/afterattack(atom/A as mob|obj, mob/user)
+/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
return
- if(istype(A, /obj/structure/reagent_dispensers) && get_dist(src,A) <= 1) //this block copypasted from reagent_containers/glass, for lack of a better solution
- if(!A.reagents.total_volume && A.reagents)
- to_chat(user, "
\The [A] is empty.")
+ if((A.is_drainable() && !A.is_refillable()) && get_dist(src,A) <= 1)
+ if(!A.reagents.total_volume)
+ to_chat(user, "
[A] is empty.")
return
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "
\The [src] is full.")
+ if(reagents.holder_full())
+ to_chat(user, "
[src] is full.")
return
var/trans = A.reagents.trans_to(src, 50) //transfer 50u , using the spray's transfer amount would take too long to refill
@@ -41,7 +41,7 @@
return
if(reagents.total_volume < amount_per_transfer_from_this)
- to_chat(user, "
\The [src] is empty!")
+ to_chat(user, "
[src] is empty!")
return
spray(A)
@@ -123,6 +123,14 @@
current_range = spray_range
to_chat(user, "
You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""]. You'll now use [amount_per_transfer_from_this] units per use.")
+/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, params)
+ var/hotness = I.is_hot()
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "
You heat [name] with [I]!")
+ return ..()
+
+
/obj/item/reagent_containers/spray/verb/empty()
set name = "Empty Spray Bottle"
set category = "Object"
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index d60d415e9a..3f38be95c9 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -13,7 +13,7 @@
var/busy = FALSE // needed for delayed drawing of blood
var/proj_piercing = 0 //does it pierce through thick clothes when shot with syringe gun
materials = list(MAT_METAL=10, MAT_GLASS=20)
- container_type = TRANSPARENT_1
+ container_type = TRANSPARENT
/obj/item/reagent_containers/syringe/Initialize()
. = ..()
@@ -107,11 +107,8 @@
update_icon()
if(SYRINGE_INJECT)
- //Always log attemped injections for admins
- var/list/rinject = list()
- for(var/datum/reagent/R in reagents.reagent_list)
- rinject += R.name
- var/contained = english_list(rinject)
+ // Always log attemped injections for admins
+ var/contained = reagents.log_list()
add_logs(user, L, "attemped to inject", src, addition="which had [contained]")
if(!reagents.total_volume)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index ea80f4c508..f0c0ecfb68 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -5,7 +5,7 @@
icon_state = "water"
density = TRUE
anchored = FALSE
- container_type = DRAWABLE_1
+ container_type = DRAINABLE | AMOUNT_VISIBLE
pressure_resistance = 2*ONE_ATMOSPHERE
max_integrity = 300
var/tank_volume = 1000 //In units, how much the dispenser can hold
@@ -18,7 +18,7 @@
boom()
/obj/structure/reagent_dispensers/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/reagent_containers))
+ if(W.is_refillable())
return 0 //so we can refill them via their afterattack.
else
return ..()
@@ -28,14 +28,6 @@
reagents.add_reagent(reagent_id, tank_volume)
. = ..()
-/obj/structure/reagent_dispensers/examine(mob/user)
- ..()
- if(reagents.total_volume)
- to_chat(user, "
It has [reagents.total_volume] unit\s left.")
- else
- to_chat(user, "
It's empty.")
-
-
/obj/structure/reagent_dispensers/proc/boom()
visible_message("
\The [src] ruptures!")
chem_splash(loc, 5, list(reagents))
diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm
index a66fdf7e03..207b610a8c 100644
--- a/code/modules/research/circuitprinter.dm
+++ b/code/modules/research/circuitprinter.dm
@@ -8,12 +8,10 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
name = "circuit imprinter"
desc = "Manufactures circuit boards for the construction of machines."
icon_state = "circuit_imprinter"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
circuit = /obj/item/circuitboard/machine/circuit_imprinter
var/efficiency_coeff
- var/console_link = TRUE //can this link to a console?
- var/requires_console = TRUE
var/datum/component/material_container/materials //Store for hyper speed!
@@ -32,11 +30,11 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
)
/obj/machinery/rnd/circuit_imprinter/Initialize()
- var/datum/component/material_container/materials
materials = AddComponent(/datum/component/material_container, list(MAT_GLASS, MAT_GOLD, MAT_DIAMOND, MAT_METAL, MAT_BLUESPACE), 0,
FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
create_reagents(0)
+ RefreshParts()
return ..()
/obj/machinery/rnd/circuit_imprinter/RefreshParts()
@@ -119,11 +117,9 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
return TRUE
/obj/machinery/rnd/circuit_imprinter/proc/do_print(path, list/matlist, notify_admins)
- if(notify_admins)
- if(usr)
- usr.investigate_log("built [path] at a circuit imprinter.", INVESTIGATE_RESEARCH)
- var/turf/T = get_turf(usr)
- message_admins("[key_name(usr)][ADMIN_JMP(T)] has built [path] at a circuit imprinter at [COORD(usr)]")
+ if(notify_admins && usr)
+ investigate_log("[key_name(usr)] built [path] at a circuit imprinter.", INVESTIGATE_RESEARCH)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] has built [path] at a circuit imprinter.")
var/obj/item/I = new path(get_turf(src))
I.materials = matlist.Copy()
- SSblackbox.record_feedback("nested_tally", "circuit_printed", 1, list("[type]", "[path]"))
+ SSblackbox.record_feedback("nested tally", "circuit_printed", 1, list("[type]", "[path]"))
diff --git a/code/modules/research/departmental_circuit_imprinter.dm b/code/modules/research/departmental_circuit_imprinter.dm
index bd3414884f..06e7c531b8 100644
--- a/code/modules/research/departmental_circuit_imprinter.dm
+++ b/code/modules/research/departmental_circuit_imprinter.dm
@@ -2,12 +2,10 @@
name = "Department Circuit Imprinter"
desc = "A special circuit imprinter with a built in interface meant for departmental usage, with built in ExoSync recievers allowing it to print designs researched that match its ROM-encoded department type. Features a bluespace materials reciever for recieving materials without the hassle of running to mining!"
icon_state = "circuit_imprinter"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
circuit = /obj/item/circuitboard/machine/circuit_imprinter/department
- console_link = FALSE
requires_console = FALSE
- var/list/allowed_department_flags = DEPARTMENTAL_FLAG_ALL
var/list/datum/design/cached_designs
var/list/datum/design/matching_designs
var/department_tag = "Unidentified" //used for material distribution among other things.
@@ -145,8 +143,7 @@
/obj/machinery/rnd/circuit_imprinter/department/proc/ui_header()
var/list/l = list()
- l += "
Nanotrasen Department Circuit Imprinter: [department_tag]
[RDSCREEN_NOBREAK]"
- l += "
Connected Technology database: [host_research == SSresearch.science_tech? "Nanotrasen" : "Third Party"]"
+ l += "[host_research.organization] [department_tag] Department Circuit Imprinter"
l += "Security protocols: [emagged? "
Disabled" : "
Enabled"]"
l += "
Material Amount: [materials.total_amount] / [materials.max_amount]"
l += "
Chemical volume: [reagents.total_volume] / [reagents.maximum_volume]"
diff --git a/code/modules/research/departmental_lathe.dm b/code/modules/research/departmental_lathe.dm
index 2e534195d9..dc3c8ad66f 100644
--- a/code/modules/research/departmental_lathe.dm
+++ b/code/modules/research/departmental_lathe.dm
@@ -2,12 +2,10 @@
name = "department protolathe"
desc = "A special protolathe with a built in interface meant for departmental usage, with built in ExoSync recievers allowing it to print designs researched that match its ROM-encoded department type. Features a bluespace materials reciever for recieving materials without the hassle of running to mining!"
icon_state = "protolathe"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
circuit = /obj/item/circuitboard/machine/protolathe/department
- console_link = FALSE
requires_console = FALSE
- var/list/allowed_department_flags = DEPARTMENTAL_FLAG_ALL
var/list/datum/design/cached_designs
var/list/datum/design/matching_designs
var/department_tag = "Unidentified" //used for material distribution among other things.
@@ -188,8 +186,7 @@
/obj/machinery/rnd/protolathe/department/proc/ui_header()
var/list/l = list()
- l += "
Nanotrasen Department Lathe: [department_tag]
[RDSCREEN_NOBREAK]"
- l += "
Connected Technology database: [host_research == SSresearch.science_tech? "Nanotrasen" : "Third Party"]"
+ l += "[host_research.organization] [department_tag] Department Lathe"
l += "Security protocols: [emagged? "
Disabled" : "
Enabled"]"
l += "
Material Amount: [materials.total_amount] / [materials.max_amount]"
l += "
Chemical volume: [reagents.total_volume] / [reagents.maximum_volume]"
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index e16aadb7cd..0af1650d42 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -43,11 +43,49 @@ other types of metals and chemistry for reagents).
var/lathe_time_factor = 1 //How many times faster than normal is this to build on the protolathe
var/dangerous_construction = FALSE //notify and log for admin investigations if this is printed.
var/departmental_flags = ALL //bitflags for deplathes.
+ var/list/datum/techweb_node/unlocked_by = list()
+ var/icon_cache
/datum/design/Destroy()
CRASH("DESIGN DATUMS SHOULD NOT EVER BE DESTROYED AS THEY ARE ONLY MEANT TO BE IN A GLOBAL LIST AND REFERENCED FOR US.")
return ..()
+/datum/design/proc/icon_html(client/user)
+ if (!icon_cache)
+ // construct the icon and slap it into the resource cache
+ var/atom/item = build_path
+ if (!ispath(item, /atom))
+ // biogenerator outputs to beakers by default
+ if (build_type & BIOGENERATOR)
+ item = /obj/item/reagent_containers/glass/beaker/large
+ else
+ return // shouldn't happen, but just in case
+
+ // circuit boards become their resulting machines or computers
+ if (ispath(item, /obj/item/circuitboard))
+ var/obj/item/circuitboard/C = item
+ var/machine = initial(C.build_path)
+ if (machine)
+ item = machine
+ var/icon_file = initial(item.icon)
+ var/icon/I = icon(icon_file, initial(item.icon_state), SOUTH)
+
+ // computers (and snowflakes) get their screen and keyboard sprites
+ if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
+ var/obj/machinery/computer/C = item
+ var/screen = initial(C.icon_screen)
+ var/keyboard = initial(C.icon_keyboard)
+ if (screen)
+ I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
+ if (keyboard)
+ I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
+
+ // based on icon2html
+ icon_cache = "[generate_asset_name(I)].png"
+ register_asset(icon_cache, I)
+ send_asset(user, icon_cache, FALSE)
+ return "
]\")
"
+
////////////////////////////////////////
//Disks for transporting design datums//
////////////////////////////////////////
diff --git a/code/modules/research/designs/AI_module_designs.dm b/code/modules/research/designs/AI_module_designs.dm
index 13ddd2582f..eb92bb3737 100644
--- a/code/modules/research/designs/AI_module_designs.dm
+++ b/code/modules/research/designs/AI_module_designs.dm
@@ -20,8 +20,8 @@
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/board/onehuman_module
- name = "Module Design (OneCrew)"
- desc = "Allows for the construction of a OneCrew AI Module."
+ name = "Module Design (OneHuman)"
+ desc = "Allows for the construction of a OneHuman AI Module."
id = "onehuman_module"
materials = list(MAT_GLASS = 1000, MAT_DIAMOND = 100)
build_path = /obj/item/aiModule/zeroth/oneHuman
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index ff2ccc938f..8542660343 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -600,14 +600,6 @@
build_path = /obj/item/device/electropack
category = list("hacked", "Tools")
-/datum/design/shock_collar
- name = "Shock Collar"
- id = "shock_collar"
- build_type = AUTOLATHE
- materials = list(MAT_METAL = 5000, MAT_GLASS = 2000)
- build_path = /obj/item/device/electropack/shockcollar
- category = list("hacked", "Security")
-
/datum/design/large_welding_tool
name = "Industrial Welding Tool"
id = "large_welding_tool"
diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm
index e3caef247c..05acb20f0e 100644
--- a/code/modules/research/destructive_analyzer.dm
+++ b/code/modules/research/destructive_analyzer.dm
@@ -44,6 +44,8 @@ Note: Must be placed within 3 tiles of the R&D Console
to_chat(user, "
You add the [O.name] to the [src.name]!")
flick("d_analyzer_la", src)
addtimer(CALLBACK(src, .proc/finish_loading), 10)
+ if (linked_console)
+ linked_console.updateUsrDialog()
/obj/machinery/rnd/destructive_analyzer/proc/finish_loading()
update_icon()
@@ -93,30 +95,35 @@ Note: Must be placed within 3 tiles of the R&D Console
/obj/machinery/rnd/destructive_analyzer/proc/user_try_decon_id(id, mob/user)
if(!istype(loaded_item) || !istype(linked_console))
return FALSE
- if(id && !(id == RESEARCH_MATERIAL_RECLAMATION_ID))
+
+ if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID)
var/datum/techweb_node/TN = get_techweb_node_by_id(id)
if(!istype(TN))
return FALSE
- var/list/pos1 = techweb_item_boost_check(loaded_item)
- if(isnull(pos1[id]))
+ var/list/can_boost = techweb_item_boost_check(loaded_item)
+ if(isnull(can_boost[id]))
return FALSE
var/dpath = loaded_item.type
- if(isnull(TN.boost_item_paths[dpath]))
+ var/worth = TN.boost_item_paths[dpath]
+ if(isnull(worth))
return FALSE
- var/dboost = TN.boost_item_paths[dpath]
- var/choice = input("Are you sure you want to destroy [loaded_item.name] for a boost of [dboost? 0 : dboost] in node [TN.display_name]") in list("Proceed", "Cancel")
+ var/difference = min(worth, TN.research_cost) - linked_console.stored_research.boosted_nodes[TN.id]
+ if(worth && difference <= 0)
+ return FALSE
+ var/choice = input("Are you sure you want to destroy [loaded_item] to [!worth ? "reveal [TN.display_name]" : "boost [TN.display_name] by [difference] point\s"]?") in list("Proceed", "Cancel")
if(choice == "Cancel")
return FALSE
if(QDELETED(loaded_item) || QDELETED(linked_console) || !user.Adjacent(linked_console) || QDELETED(src))
return FALSE
- SSblackbox.record_feedback("nested_tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]"))
+ SSblackbox.record_feedback("nested tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]"))
if(destroy_item(loaded_item))
linked_console.stored_research.boost_with_path(SSresearch.techweb_nodes[TN.id], dpath)
+
else
var/point_value = techweb_item_point_check(loaded_item)
if(linked_console.stored_research.deconstructed_items[loaded_item.type])
point_value = 0
- var/choice = input("Are you sure you want to destroy [loaded_item.name] for [point_value? "[point_value] points" : "material reclaimation"]?") in list("Proceed", "Cancel")
+ var/choice = input("Are you sure you want to destroy [loaded_item] for [point_value ? "[point_value] research points" : "material reclamation"]?") in list("Proceed", "Cancel")
if(choice == "Cancel")
return FALSE
if(QDELETED(loaded_item) || QDELETED(linked_console) || !user.Adjacent(linked_console) || QDELETED(src))
@@ -133,4 +140,5 @@ Note: Must be placed within 3 tiles of the R&D Console
return FALSE
loaded_item.forceMove(get_turf(src))
loaded_item = null
+ update_icon()
return TRUE
diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm
index 521f1d7f29..1dc32e6dde 100644
--- a/code/modules/research/protolathe.dm
+++ b/code/modules/research/protolathe.dm
@@ -11,12 +11,10 @@ Note: Must be placed west/left of and R&D console to function.
name = "protolathe"
desc = "Converts raw materials into useful objects."
icon_state = "protolathe"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
circuit = /obj/item/circuitboard/machine/protolathe
var/efficiency_coeff
- var/console_link = TRUE //allow console link.
- var/requires_console = TRUE
var/list/categories = list(
"Power Designs",
"Medical Designs",
@@ -31,7 +29,7 @@ Note: Must be placed west/left of and R&D console to function.
"Computer Parts"
)
- var/datum/component/material_container/materials
+ var/datum/component/material_container/materials //Store for hyper speed!
/obj/machinery/rnd/protolathe/Initialize()
create_reagents(0)
@@ -39,6 +37,7 @@ Note: Must be placed west/left of and R&D console to function.
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), 0,
FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
+ RefreshParts()
return ..()
/obj/machinery/rnd/protolathe/RefreshParts()
@@ -75,6 +74,7 @@ Note: Must be placed west/left of and R&D console to function.
materials.retrieve_all()
..()
+
/obj/machinery/rnd/protolathe/disconnect_console()
linked_console.linked_lathe = null
..()
@@ -124,13 +124,11 @@ Note: Must be placed west/left of and R&D console to function.
return TRUE
/obj/machinery/rnd/protolathe/proc/do_print(path, amount, list/matlist, notify_admins)
- if(notify_admins)
- if(usr)
- usr.investigate_log("built [amount] of [path] at a protolathe.", INVESTIGATE_RESEARCH)
- var/turf/T = get_turf(usr)
- message_admins("[key_name(usr)][ADMIN_JMP(T)] has built [amount] of [path] at a protolathe at [COORD(usr)]")
+ if(notify_admins && usr)
+ investigate_log("[key_name(usr)] built [amount] of [path] at a protolathe.", INVESTIGATE_RESEARCH)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] has built [amount] of [path] at a protolathe")
for(var/i in 1 to amount)
var/obj/item/I = new path(get_turf(src))
if(!istype(I, /obj/item/stack/sheet) && !istype(I, /obj/item/ore/bluespace_crystal))
I.materials = matlist.Copy()
- SSblackbox.record_feedback("nested_tally", "item_printed", amount, list("[type]", "[path]"))
\ No newline at end of file
+ SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]"))
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 116d41d7f8..0b9453a62d 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -45,6 +45,7 @@ doesn't have toxins access.
var/disk_slot_selected
var/searchstring = ""
var/searchtype = ""
+ var/ui_mode = RDCONSOLE_UI_MODE_NORMAL
var/research_control = TRUE
@@ -150,11 +151,9 @@ doesn't have toxins access.
return FALSE
var/price = TN.get_price(stored_research)
if(stored_research.research_points >= price)
- investigate_log("[key_name_admin(user)] researched [id]([price]) on techweb id [stored_research.id].")
+ investigate_log("[key_name(user)] researched [id]([price]) on techweb id [stored_research.id].", INVESTIGATE_RESEARCH)
if(stored_research == SSresearch.science_tech)
- if(stored_research.researched_nodes.len < 30)
- SSblackbox.record_feedback("tally", "science_techweb_unlock_first_thirty", 1, "[id]")
- SSblackbox.record_feedback("tally", "science_techweb_unlock", 1, "[id]")
+ SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "price" = "[price]", "time" = "[SQLtime()]"))
if(stored_research.research_node(SSresearch.techweb_nodes[id]))
say("Sucessfully researched [TN.display_name].")
var/logname = "Unknown"
@@ -218,24 +217,27 @@ doesn't have toxins access.
/obj/machinery/computer/rdconsole/proc/ui_header()
var/list/l = list()
- l += "
Nanotrasen Research and Development
[RDSCREEN_NOBREAK]"
- l += "
Connected Technology database: [stored_research == SSresearch.science_tech? "Nanotrasen" : "Third Party"]"
- l += "Available Points: [stored_research.research_points]"
+ l += "[stored_research.organization] Research and Development Network"
+ l += "Available points: [round(stored_research.research_points)] (+[round(stored_research.last_bitcoins * 60)] / minute)"
l += "Security protocols: [emagged? "
Disabled" : "
Enabled"]"
- l += "Design Disk: [d_disk? "
Loaded" : "
Not Loaded"] | \
- Technology Disk: [t_disk? "
Loaded" : "
Not Loaded"]"
l += "
Main Menu |
Back [RDSCREEN_NOBREAK]"
+ l += "[ui_mode == 1? "Normal View" : "Normal View"] | [ui_mode == 2? "Expert View" : "Expert View"] | [ui_mode == 3? "List View" : "List View"]"
return l
/obj/machinery/computer/rdconsole/proc/ui_main_menu()
var/list/l = list()
if(research_control)
l += ""
return l
@@ -278,6 +280,8 @@ doesn't have toxins access.
var/datum/design/D = stored_research.researched_designs[v]
if(!(selected_category in D.category)|| !(D.build_type & PROTOLATHE))
continue
+ if(!(D.departmental_flags & linked_lathe.allowed_department_flags))
+ continue
var/temp_material
var/c = 50
var/t
@@ -328,6 +332,8 @@ doesn't have toxins access.
l += ui_protolathe_header()
var/coeff = linked_lathe.efficiency_coeff
for(var/datum/design/D in matching_designs)
+ if(!(D.departmental_flags & linked_lathe.allowed_department_flags))
+ continue
var/temp_material
var/c = 50
var/t
@@ -416,6 +422,8 @@ doesn't have toxins access.
var/datum/design/D = stored_research.researched_designs[v]
if(!(selected_category in D.category) || !(D.build_type & IMPRINTER))
continue
+ if(!(D.departmental_flags & linked_imprinter.allowed_department_flags))
+ continue
var/temp_materials
var/check_materials = TRUE
@@ -443,6 +451,8 @@ doesn't have toxins access.
var/coeff = linked_imprinter.efficiency_coeff
for(var/datum/design/D in matching_designs)
+ if(!(D.departmental_flags & linked_imprinter.allowed_department_flags))
+ continue
var/temp_materials
var/check_materials = TRUE
var/all_materials = D.materials + D.reagents_list
@@ -529,122 +539,214 @@ doesn't have toxins access.
RDSCREEN_UI_DECONSTRUCT_CHECK
var/list/l = list()
if(!linked_destroy.loaded_item)
- l += "No Item Loaded. Standing-by...
"
+ l += "No item loaded. Standing-by...
"
else
- l += "Deconstruction Menu
"
- l += "
Eject Item"
- l += "Name: [linked_destroy.loaded_item.name]"
- l += "Select a node to boost by deconstructing this item."
- l += "This item is able to boost:"
- var/list/listin = techweb_item_boost_check(linked_destroy.loaded_item)
- for(var/node_id in listin)
- var/datum/techweb_node/N = get_techweb_node_by_id(node_id)
- var/worth = listin[N.id]
- if(!stored_research.researched_nodes[N.id] && !stored_research.boosted_nodes[N.id])
- l += "
[N.display_name]: [worth] points"
- else
- l += "
[RDSCREEN_NOBREAK]"
+ l += "| [icon2html(linked_destroy.loaded_item, usr)] | [linked_destroy.loaded_item.name] Eject |
[RDSCREEN_NOBREAK]"
+ l += "Select a node to boost by deconstructing this item. This item can boost:"
+
+ var/anything = FALSE
+ var/list/boostable_nodes = techweb_item_boost_check(linked_destroy.loaded_item)
+ for(var/id in boostable_nodes)
+ anything = TRUE
+ var/worth = boostable_nodes[id]
+ var/datum/techweb_node/N = get_techweb_node_by_id(id)
+
+ l += "[RDSCREEN_NOBREAK]"
+ if (stored_research.researched_nodes[N.id]) // already researched
+ l += "
[N.display_name]"
+ l += "This node has already been researched."
+ else if (worth == 0) // reveal only
+ if (stored_research.hidden_nodes[N.id])
+ l += "
[N.display_name]"
+ l += "This node will be revealed."
+ else
+ l += "
[N.display_name]"
+ l += "This node has already been revealed."
+ else // boost by the difference
+ var/difference = min(worth, N.research_cost) - stored_research.boosted_nodes[N.id]
+ if (difference > 0)
+ l += "
[N.display_name]"
+ l += "This node will be boosted by [difference] points."
+ else
+ l += "
[N.display_name]"
+ l += "This node has already been boosted."
+ l += "
[RDSCREEN_NOBREAK]"
+
+ // point deconstruction and material reclamation use the same ID to prevent accidentally missing the points
var/point_value = techweb_item_point_check(linked_destroy.loaded_item)
- if(point_value && isnull(stored_research.deconstructed_items[linked_destroy.loaded_item.type]))
- l += "Generic Point Deconstruction - [point_value] points"
- l += "Material Reclaimation Deconstruction"
+ if(point_value)
+ anything = TRUE
+ l += "[RDSCREEN_NOBREAK]"
+ if (stored_research.deconstructed_items[linked_destroy.loaded_item.type])
+ l += "
Point Deconstruction"
+ l += "This item's [point_value] point\s have already been claimed."
+ else
+ l += "
Point Deconstruction"
+ l += "This item is worth [point_value] point\s!"
+ l += "
[RDSCREEN_NOBREAK]"
+
+ var/list/materials = linked_destroy.loaded_item.materials
+ if (materials.len)
+ l += "Material Reclamation"
+ for (var/M in materials)
+ l += "* [CallMaterialName(M)] x [materials[M]]"
+ l += "
[RDSCREEN_NOBREAK]"
+ anything = TRUE
+
+ if (!anything)
+ l += "Nothing!"
+
l += " "
return l
-/obj/machinery/computer/rdconsole/proc/ui_techweb() //Legacy code.
+/obj/machinery/computer/rdconsole/proc/ui_techweb()
var/list/l = list()
- var/list/avail = list() //This could probably be optimized a bit later.
- var/list/unavail = list()
- var/list/res = list()
- for(var/v in stored_research.researched_nodes)
- res += stored_research.researched_nodes[v]
- for(var/v in stored_research.available_nodes)
- if(stored_research.researched_nodes[v])
- continue
- avail += stored_research.available_nodes[v]
- for(var/v in stored_research.visible_nodes)
- if(stored_research.available_nodes[v])
- continue
- unavail += stored_research.visible_nodes[v]
- l += "Technology Nodes:
[RDSCREEN_NOBREAK]"
- l += "Available for Research:
"
- for(var/datum/techweb_node/N in avail)
- var/not_unlocked = (stored_research.available_nodes[N.id] && !stored_research.researched_nodes[N.id])
- var/has_points = (stored_research.research_points >= N.get_price(stored_research))
- var/research_href = not_unlocked? (has_points? "
Research" : "
Not Enough Points") : null
- l += "
[N.display_name][research_href]"
- l += "
Locked Nodes:
"
- for(var/datum/techweb_node/N in unavail)
- l += "
[N.display_name]"
- l += "
Researched Nodes:
"
- for(var/datum/techweb_node/N in res)
- l += "
[N.display_name]"
+ if(ui_mode != RDCONSOLE_UI_MODE_LIST)
+ var/list/columns = list()
+ var/max_tier = 0
+ for (var/node_ in stored_research.tiers)
+ var/datum/techweb_node/node = node_
+ var/tier = stored_research.tiers[node]
+ LAZYINITLIST(columns["[tier]"]) // String hackery to make the numbers associative
+ columns["[tier]"] += ui_techweb_single_node(node, minimal=(tier != 1))
+ max_tier = max(max_tier, tier)
+
+ l += "
| Researched | Available | Future |
|---|
[RDSCREEN_NOBREAK]"
+ for(var/tier in 0 to max_tier)
+ l += "| [RDSCREEN_NOBREAK]"
+ l += columns["[tier]"]
+ l += " | [RDSCREEN_NOBREAK]"
+ l += "
[RDSCREEN_NOBREAK]"
+ else
+ var/list/avail = list() //This could probably be optimized a bit later.
+ var/list/unavail = list()
+ var/list/res = list()
+ for(var/v in stored_research.researched_nodes)
+ res += stored_research.researched_nodes[v]
+ for(var/v in stored_research.available_nodes)
+ if(stored_research.researched_nodes[v])
+ continue
+ avail += stored_research.available_nodes[v]
+ for(var/v in stored_research.visible_nodes)
+ if(stored_research.available_nodes[v])
+ continue
+ unavail += stored_research.visible_nodes[v]
+ l += "
Technology Nodes:
[RDSCREEN_NOBREAK]"
+ l += "
Available for Research:
"
+ for(var/datum/techweb_node/N in avail)
+ var/not_unlocked = (stored_research.available_nodes[N.id] && !stored_research.researched_nodes[N.id])
+ var/has_points = (stored_research.research_points >= N.get_price(stored_research))
+ var/research_href = not_unlocked? (has_points? "
Research" : "
Not Enough Points") : null
+ l += "
[N.display_name][research_href]"
+ l += "
Locked Nodes:
"
+ for(var/datum/techweb_node/N in unavail)
+ l += "
[N.display_name]"
+ l += "
Researched Nodes:
"
+ for(var/datum/techweb_node/N in res)
+ l += "
[N.display_name]"
+ l += "
[RDSCREEN_NOBREAK]"
+ return l
+
+/obj/machinery/computer/rdconsole/proc/machine_icon(atom/item)
+ return icon2html(initial(item.icon), usr, initial(item.icon_state), SOUTH)
+
+/obj/machinery/computer/rdconsole/proc/ui_techweb_single_node(datum/techweb_node/node, selflink=TRUE, minimal=FALSE)
+ var/list/l = list()
+ if (stored_research.hidden_nodes[node.id])
+ return l
+ var/price = node.get_price(stored_research)
+ var/display_name = node.display_name
+ if (selflink)
+ display_name = "
[display_name]"
+ l += "
[display_name] [RDSCREEN_NOBREAK]"
+ if(minimal)
+ l += "
[node.description]"
+ else
+ if(stored_research.researched_nodes[node.id])
+ l += "
Researched"
+ else if(stored_research.available_nodes[node.id])
+ if(stored_research.research_points >= price)
+ l += "
[price]"
+ else
+ l += "
[price]" // gray - too expensive
+ else
+ l += "
[price]" // red - missing prereqs
+ if(ui_mode == RDCONSOLE_UI_MODE_NORMAL)
+ l += "[node.description]"
+ for(var/i in node.designs)
+ var/datum/design/D = node.designs[i]
+ l += "
[D.icon_html(usr)][RDSCREEN_NOBREAK]"
l += "
[RDSCREEN_NOBREAK]"
return l
-/obj/machinery/computer/rdconsole/proc/ui_techweb_nodeview() //Legacy code
+/obj/machinery/computer/rdconsole/proc/ui_techweb_nodeview()
RDSCREEN_UI_SNODE_CHECK
var/list/l = list()
if(stored_research.hidden_nodes[selected_node.id])
l += "
ERROR: RESEARCH NODE UNKNOWN.
"
- l += "
[selected_node.display_name]
"
- l += "Description: [selected_node.description]"
- l += "Status: [stored_research.researched_nodes[selected_node.id]? "Researched" : "Locked"]"
- l += "Point Cost: [selected_node.get_price(stored_research)]. [RDSCREEN_NOBREAK]"
- if(stored_research.researched_nodes[selected_node.id])
- l += "
Already Researched
[RDSCREEN_NOBREAK]"
- else if(stored_research.available_nodes[selected_node.id])
- if(stored_research.research_points >= selected_node.get_price(stored_research))
- l += "
[RDSCREEN_NOBREAK]"
- else
- l += "
Not Enough Points
[RDSCREEN_NOBREAK]"
- else if(stored_research.visible_nodes[selected_node.id])
- l += "
Prerequisites not met!
[RDSCREEN_NOBREAK]"
- else
- l += "
ERROR
[RDSCREEN_NOBREAK]"
- l += "
Designs:
[RDSCREEN_NOBREAK]"
- for(var/i in selected_node.designs)
- var/datum/design/D = selected_node.designs[i]
- l += "
[D.name]"
- l += "
Prerequisites:
[RDSCREEN_NOBREAK]"
- for(var/i in selected_node.prerequisites)
- var/datum/techweb_node/prereq = selected_node.prerequisites[i]
- var/sc = stored_research.researched_nodes[prereq.id]
- var/begin
- var/end
- if(sc)
- begin = "
"
- end = ""
- else
- begin = "
"
- end = ""
- l += "
[begin][prereq.display_name][end]"
- l += "
Unlocks:
[RDSCREEN_NOBREAK]"
- for(var/i in selected_node.unlocks)
- var/datum/techweb_node/unlock = selected_node.unlocks[i]
- l += "
[unlock.display_name]"
+ return
- l += "
[RDSCREEN_NOBREAK]"
+ l += "
[RDSCREEN_NOBREAK]"
+ if (length(selected_node.prerequisites))
+ l += "| Requires | [RDSCREEN_NOBREAK]"
+ l += "Current Node | [RDSCREEN_NOBREAK]"
+ if (length(selected_node.unlocks))
+ l += "Unlocks | [RDSCREEN_NOBREAK]"
+
+ l += "
[RDSCREEN_NOBREAK]"
+ if (length(selected_node.prerequisites))
+ l += "| [RDSCREEN_NOBREAK]"
+ for (var/i in selected_node.prerequisites)
+ l += ui_techweb_single_node(selected_node.prerequisites[i])
+ l += " | [RDSCREEN_NOBREAK]"
+ l += "[RDSCREEN_NOBREAK]"
+ l += ui_techweb_single_node(selected_node, selflink=FALSE)
+ l += " | [RDSCREEN_NOBREAK]"
+ if (length(selected_node.unlocks))
+ l += "[RDSCREEN_NOBREAK]"
+ for (var/i in selected_node.unlocks)
+ l += ui_techweb_single_node(selected_node.unlocks[i])
+ l += " | [RDSCREEN_NOBREAK]"
+
+ l += "
[RDSCREEN_NOBREAK]"
return l
/obj/machinery/computer/rdconsole/proc/ui_techweb_designview() //Legacy code
RDSCREEN_UI_SDESIGN_CHECK
var/list/l = list()
var/datum/design/D = selected_design
- l += "
Name: [D.name]"
+ l += "
| [D.icon_html(usr)] | [D.name] |
[RDSCREEN_NOBREAK]"
if(D.build_type)
- l += "Lathe Types:"
- if(D.build_type & IMPRINTER) l += "Circuit Imprinter"
- if(D.build_type & PROTOLATHE) l += "Protolathe"
- if(D.build_type & AUTOLATHE) l += "Autolathe"
- if(D.build_type & MECHFAB) l += "Exosuit Fabricator"
- if(D.build_type & BIOGENERATOR) l += "Biogenerator"
- if(D.build_type & LIMBGROWER) l += "Limbgrower"
- if(D.build_type & SMELTER) l += "Smelter"
- l += "Required Materials:"
+ var/lathes = list()
+ if(D.build_type & IMPRINTER)
+ lathes += "
[machine_icon(/obj/machinery/rnd/circuit_imprinter)][RDSCREEN_NOBREAK]"
+ if (linked_imprinter && D.id in stored_research.researched_designs)
+ l += "
Imprint"
+ if(D.build_type & PROTOLATHE)
+ lathes += "
[machine_icon(/obj/machinery/rnd/protolathe)][RDSCREEN_NOBREAK]"
+ if (linked_lathe && D.id in stored_research.researched_designs)
+ l += "
Construct"
+ if(D.build_type & AUTOLATHE)
+ lathes += "
[machine_icon(/obj/machinery/autolathe)][RDSCREEN_NOBREAK]"
+ if(D.build_type & MECHFAB)
+ lathes += "
[machine_icon(/obj/machinery/mecha_part_fabricator)][RDSCREEN_NOBREAK]"
+ if(D.build_type & BIOGENERATOR)
+ lathes += "
[machine_icon(/obj/machinery/biogenerator)][RDSCREEN_NOBREAK]"
+ if(D.build_type & LIMBGROWER)
+ lathes += "
[machine_icon(/obj/machinery/limbgrower)][RDSCREEN_NOBREAK]"
+ if(D.build_type & SMELTER)
+ lathes += "
[machine_icon(/obj/machinery/mineral/processing_unit)][RDSCREEN_NOBREAK]"
+ l += "Construction types:"
+ l += lathes
+ l += ""
+ l += "Required materials:"
var/all_mats = D.materials + D.reagents_list
for(var/M in all_mats)
l += "* [CallMaterialName(M)] x [all_mats[M]]"
+ l += "Unlocked by:"
+ for (var/node in D.unlocked_by)
+ l += ui_techweb_single_node(node)
l += "[RDSCREEN_NOBREAK]
"
return l
@@ -710,6 +812,8 @@ doesn't have toxins access.
if(ls["switch_screen"])
back = screen
screen = text2num(ls["switch_screen"])
+ if(ls["ui_mode"])
+ ui_mode = text2num(ls["ui_mode"])
if(ls["lock_console"])
if(allowed(usr))
lock_console(usr)
@@ -862,7 +966,8 @@ doesn't have toxins access.
/obj/machinery/computer/rdconsole/interact(mob/user)
user.set_machine(src)
- var/datum/browser/popup = new(user, "rndconsole", name, 460, 550)
+ var/datum/browser/popup = new(user, "rndconsole", name, 900, 600)
+ popup.add_stylesheet("techwebs", 'html/browser/techwebs.css')
popup.set_content(generate_ui())
popup.open()
diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm
index ad75ddf07b..eea79f77e6 100644
--- a/code/modules/research/rdmachines.dm
+++ b/code/modules/research/rdmachines.dm
@@ -1,5 +1,4 @@
-
//All devices that link into the R&D console fall into thise type for easy identification and some shared procs.
@@ -11,10 +10,13 @@
use_power = IDLE_POWER_USE
var/busy = FALSE
var/hacked = FALSE
+ var/console_link = TRUE //allow console link.
+ var/requires_console = TRUE
var/disabled = FALSE
var/shocked = FALSE
var/obj/machinery/computer/rdconsole/linked_console
var/obj/item/loaded_item = null //the item loaded inside the machine (currently only used by experimentor and destructive analyzer)
+ var/allowed_department_flags = ALL
/obj/machinery/rnd/proc/reset_busy()
busy = FALSE
@@ -59,7 +61,7 @@
return
if(default_deconstruction_crowbar(O))
return
- if(is_open_container() && O.is_open_container())
+ if(is_refillable() && O.is_drainable())
return FALSE //inserting reagents into the machine
if(Insert_Item(O, user))
return TRUE
@@ -78,28 +80,26 @@
/obj/machinery/rnd/proc/is_insertion_ready(mob/user)
if(panel_open)
to_chat(user, "
You can't load [src] while it's opened!")
- return
- if (disabled)
- return
- if (!linked_console) // Try to auto-connect to new RnD consoles nearby.
- if(!linked_console)
- to_chat(user, "
[src] must be linked to an R&D console first!")
- return
- if (busy)
+ return FALSE
+ if(disabled)
+ return FALSE
+ if(requires_console && !linked_console)
+ to_chat(user, "
[src] must be linked to an R&D console first!")
+ return FALSE
+ if(busy)
to_chat(user, "
[src] is busy right now.")
- return
+ return FALSE
if(stat & BROKEN)
to_chat(user, "
[src] is broken.")
- return
+ return FALSE
if(stat & NOPOWER)
to_chat(user, "
[src] has no power.")
- return
+ return FALSE
if(loaded_item)
to_chat(user, "
[src] is already loaded.")
- return
+ return FALSE
return TRUE
-
//we eject the loaded item when deconstructing the machine
/obj/machinery/rnd/on_deconstruction()
if(loaded_item)
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index af1dc853d8..0e2e788b8f 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -82,7 +82,6 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi
//Rating 1
-
/obj/item/stock_parts/capacitor
name = "capacitor"
desc = "A basic capacitor used in the construction of a variety of devices."
diff --git a/code/modules/research/techweb/__techweb_helpers.dm b/code/modules/research/techweb/__techweb_helpers.dm
index adfa5c78d0..af4fe7480b 100644
--- a/code/modules/research/techweb/__techweb_helpers.dm
+++ b/code/modules/research/techweb/__techweb_helpers.dm
@@ -130,6 +130,9 @@
CHECK_TICK
/proc/calculate_techweb_nodes()
+ for(var/design_id in SSresearch.techweb_designs)
+ var/datum/design/D = SSresearch.techweb_designs[design_id]
+ D.unlocked_by.Cut()
for(var/node_id in SSresearch.techweb_nodes)
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
node.prerequisites = list()
@@ -138,7 +141,9 @@
for(var/i in node.prereq_ids)
node.prerequisites[i] = SSresearch.techweb_nodes[i]
for(var/i in node.design_ids)
- node.designs[i] = SSresearch.techweb_designs[i]
+ var/datum/design/D = SSresearch.techweb_designs[i]
+ node.designs[i] = D
+ D.unlocked_by += node
if(node.hidden)
SSresearch.techweb_nodes_hidden[node.id] = node
CHECK_TICK
diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm
index 74ace7e4c2..d59dea55d3 100644
--- a/code/modules/research/techweb/_techweb.dm
+++ b/code/modules/research/techweb/_techweb.dm
@@ -17,6 +17,9 @@
var/id = "generic"
var/list/research_logs = list() //IC logs.
var/max_bomb_value = 0
+ var/organization = "Third-Party" //Organization name, used for display.
+ var/last_bitcoins = 0 //Current per-second production, used for display only.
+ var/list/tiers = list() //Assoc list, datum = number, 1 is available, 2 is all reqs are 1, so on
/datum/techweb/New()
for(var/i in SSresearch.techweb_nodes_starting)
@@ -28,6 +31,7 @@
/datum/techweb/admin
research_points = INFINITY //KEKKLES.
id = "ADMIN"
+ organization = "CentCom"
/datum/techweb/admin/New() //All unlocked.
. = ..()
@@ -38,6 +42,7 @@
/datum/techweb/science //Global science techweb for RND consoles.
id = "SCIENCE"
+ organization = "Nanotrasen"
/datum/techweb/Destroy()
researched_nodes = null
@@ -148,15 +153,31 @@
recalculate_nodes(TRUE) //Fully rebuild the tree.
/datum/techweb/proc/boost_with_path(datum/techweb_node/N, itempath)
- if(!istype(N)||!ispath(itempath))
+ if(!istype(N) || !ispath(itempath))
return FALSE
- var/boost = N.boost_item_paths[itempath]
- if(!boosted_nodes[N])
- boosted_nodes[N] = boost
- if(N.autounlock_by_boost)
- hidden_nodes -= N.id
+ boosted_nodes[N] = max(boosted_nodes[N], N.boost_item_paths[itempath])
+ if(N.autounlock_by_boost)
+ hidden_nodes -= N.id
return TRUE
+/datum/techweb/proc/update_tiers(datum/techweb_node/base)
+ var/list/current = list(base)
+ while (current.len)
+ var/list/next = list()
+ for (var/node_ in current)
+ var/datum/techweb_node/node = node_
+ var/tier = 0
+ if (!researched_nodes[node.id]) // researched is tier 0
+ for (var/id in node.prereq_ids)
+ var/prereq_tier = tiers[node.prerequisites[id]]
+ tier = max(tier, prereq_tier + 1)
+
+ if (tier != tiers[node])
+ tiers[node] = tier
+ for (var/id in node.unlocks)
+ next += node.unlocks[id]
+ current = next
+
/datum/techweb/proc/update_node_status(datum/techweb_node/node, autoupdate_consoles = TRUE)
var/researched = FALSE
var/available = FALSE
@@ -185,6 +206,7 @@
else
if(visible)
visible_nodes[node.id] = node
+ update_tiers(node)
if(autoupdate_consoles)
for(var/v in consoles_accessing)
var/obj/machinery/computer/rdconsole/V = v
diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm
index 75faf07bf1..3ec6c4cf9d 100644
--- a/code/modules/research/techweb/_techweb_node.dm
+++ b/code/modules/research/techweb/_techweb_node.dm
@@ -23,8 +23,6 @@
actual_cost = research_cost
/datum/techweb_node/proc/get_price(datum/techweb/host)
- if(!host)
- return actual_cost
- var/discount = boost_item_paths[host.boosted_nodes[src]]
- actual_cost = research_cost - discount
+ if(host)
+ actual_cost = research_cost - host.boosted_nodes[src]
return actual_cost
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 96b252854b..ba43a1c24b 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -1,6 +1,6 @@
//Current rate: 132500 research points in 90 minutes
-//Current cargo price: 250000 points for fullmaxed R&D.
+//Current cargo price: 280000 points for fullmaxed R&D.
//Base Node
/datum/techweb_node/base
@@ -9,7 +9,7 @@
display_name = "Basic Research Technology"
description = "NT default research technologies."
design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani",
- "destructive_analyzer", "protolathe", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
+ "destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
"space_heater") //Default research tech, prevents bricking
/////////////////////////Biotech/////////////////////////
@@ -18,7 +18,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("mass_spectrometer", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "pandemic")
+ design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "pandemic")
research_cost = 2500
export_price = 10000
@@ -27,7 +27,16 @@
display_name = "Advanced Biotechnology"
description = "Advanced Biotechnology"
prereq_ids = list("biotech")
- design_ids = list("piercesyringe", "adv_mass_spectrometer", "plasmarefiller", "limbgrower")
+ design_ids = list("piercesyringe", "plasmarefiller", "limbgrower")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/bio_process
+ id = "bio_process"
+ display_name = "Biological Processing"
+ description = "From slimes to kitchens."
+ prereq_ids = list("biotech")
+ design_ids = list("smartfridge", "gibber", "deepfryer", "monkey_recycler", "processor", "gibber", "microwave")
research_cost = 2500
export_price = 10000
@@ -52,8 +61,8 @@
/////////////////////////engineering tech/////////////////////////
/datum/techweb_node/engineering
id = "engineering"
- description = "Modern Engineering Technology."
display_name = "Industrial Engineering"
+ description = "A refresher course on modern engineering technology."
prereq_ids = list("base")
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "emitter", "high_cell", "adv_matter_bin",
"atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "weldingmask", "mesons", "thermomachine", "tesla_coil", "grounding_rod", "apc_control")
@@ -62,13 +71,31 @@
/datum/techweb_node/adv_engi
id = "adv_engi"
- description = "Advanced Engineering research"
display_name = "Advanced Engineering"
+ description = "Pushing the boundaries of physics, one chainsaw-fist at a time."
prereq_ids = list("engineering", "emp_basic")
design_ids = list("engine_goggles", "diagnostic_hud", "magboots")
research_cost = 2500
export_price = 10000
+/datum/techweb_node/high_efficiency
+ id = "high_efficiency"
+ display_name = "High Efficiency Parts"
+ description = "Finely-tooled manufacturing techniques allowing for picometer-perfect precision levels."
+ prereq_ids = list("engineering", "datatheory")
+ design_ids = list("pico_mani", "super_matter_bin")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/adv_power
+ id = "adv_power"
+ display_name = "Advanced Power Manipulation"
+ description = "How to get more zap."
+ prereq_ids = list("engineering")
+ design_ids = list("smes", "super_cell", "hyper_cell", "super_capacitor", "superpacman", "mrspacman", "power_turbine", "power_turbine_console", "power_compressor")
+ research_cost = 2500
+ export_price = 10000
+
/////////////////////////Bluespace tech/////////////////////////
/datum/techweb_node/bluespace_basic //Bluespace-memery
id = "bluespace_basic"
@@ -89,6 +116,26 @@
research_cost = 2500
export_price = 10000
+/datum/techweb_node/practical_bluespace
+ id = "practical_bluespace"
+ display_name = "Applied Bluespace Research"
+ description = "Using bluespace to make things faster and better."
+ prereq_ids = list("bluespace_basic", "engineering")
+ design_ids = list("bs_rped","minerbag_holding", "telesci_gps", "bluespacebeaker", "bluespacesyringe", "bluespacebodybag", "phasic_scanning")
+ research_cost = 2500
+ export_price = 10000
+
+
+/datum/techweb_node/bluespace_power
+ id = "bluespace_power"
+ display_name = "Bluespace Power Technology"
+ description = "Even more powerful.. power!"
+ prereq_ids = list("adv_power", "adv_bluespace")
+ design_ids = list("bluespace_cell", "quadratic_capacitor")
+ research_cost = 2500
+ export_price = 10000
+
+
/////////////////////////plasma tech/////////////////////////
/datum/techweb_node/basic_plasma
id = "basic_plasma"
@@ -127,112 +174,6 @@
research_cost = 2500
export_price = 10000
-/////////////////////////EMP tech/////////////////////////
-/datum/techweb_node/emp_basic //EMP tech for some reason
- id = "emp_basic"
- display_name = "Electromagnetic Theory"
- description = "Study into usage of frequencies in the electromagnetic spectrum."
- prereq_ids = list("base")
- design_ids = list("holosign", "inducer", "tray_goggles", "holopad")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/emp_adv
- id = "emp_adv"
- display_name = "Advanced Electromagnetic Theory"
- prereq_ids = list("emp_basic")
- design_ids = list("ultra_micro_laser")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/emp_super
- id = "emp_super"
- display_name = "Quantum Electromagnetic Technology" //bs
- description = "Even better electromagnetic technology"
- prereq_ids = list("emp_adv")
- design_ids = list("quadultra_micro_laser")
- research_cost = 2500
- export_price = 10000
-
-/////////////////////////Clown tech/////////////////////////
-/datum/techweb_node/clown
- id = "clown"
- display_name = "Clown Technology"
- description = "Honk?!"
- prereq_ids = list("base")
- design_ids = list("air_horn", "honker_main", "honker_peri", "honker_targ", "honk_chassis", "honk_head", "honk_torso", "honk_left_arm", "honk_right_arm",
- "honk_left_leg", "honk_right_leg", "mech_banana_mortar", "mech_mousetrap_mortar", "mech_honker", "mech_punching_face", "implant_trombone")
- research_cost = 2500
- export_price = 10000
-
-////////////////////////Computer tech////////////////////////
-/datum/techweb_node/comptech
- id = "comptech"
- display_name = "Computer Consoles"
- description = "Computers and how they work."
- prereq_ids = list("datatheory")
- design_ids = list("cargo", "cargorequest", "stockexchange", "libraryconsole", "aifixer", "mining", "crewconsole", "comconsole", "idcardconsole", "operating", "seccamera")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/computer_hardware_basic //Modular computers are shitty and nearly useless so until someone makes them actually useful this can be easy to get.
- id = "computer_hardware_basic"
- display_name = "Computer Hardware"
- description = "How computer hardware are made."
- prereq_ids = list("comptech")
- research_cost = 2500
- export_price = 10000
- design_ids = list("hdd_basic", "hdd_advanced", "hdd_super", "hdd_cluster", "ssd_small", "ssd_micro", "netcard_basic", "netcard_advanced", "netcard_wired",
- "portadrive_basic", "portadrive_advanced", "portadrive_super", "cardslot", "aislot", "miniprinter", "APClink", "bat_control", "bat_normal", "bat_advanced",
- "bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small")
-
-/datum/techweb_node/computer_board_gaming
- id = "computer_board_gaming"
- display_name = "Arcade Games"
- description = "For the slackers on the station."
- prereq_ids = list("comptech")
- design_ids = list("arcade_battle", "arcade_orion", "slotmachine")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/comp_recordkeeping
- id = "comp_recordkeeping"
- display_name = "Computerized Recordkeeping"
- description = "Organized record databases and how they're used."
- prereq_ids = list("comptech")
- design_ids = list("secdata", "med_data", "prisonmanage", "vendor", "automated_announcement")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/telecomms
- id = "telecomms"
- display_name = "Telecommunications Technology"
- description = "Subspace transmission technology for near-instant communications devices."
- prereq_ids = list("comptech", "bluespace_basic")
- research_cost = 2500
- export_price = 10000
- design_ids = list("s-receiver", "s-bus", "s-broadcaster", "s-processor", "s-hub", "s-server", "s-relay", "comm_monitor", "comm_server",
- "s-ansible", "s-filter", "s-amplifier", "ntnet_relay", "s-treatment", "s-analyzer", "s-crystal", "s-transmitter")
-
-/datum/techweb_node/integrated_HUDs
- id = "integrated_HUDs"
- display_name = "Integrated HUDs"
- description = "The usefulness of computerized records, projected straight onto your eyepiece!"
- prereq_ids = list("comp_recordkeeping", "emp_basic")
- design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/NVGtech
- id = "NVGtech"
- display_name = "Night Vision Technology"
- description = "Allows seeing in the dark without actual light!"
- prereq_ids = list("integrated_HUDs", "adv_engi", "emp_adv")
- design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "nvgmesons")
- research_cost = 2500
- export_price = 10000
-
-////////////////////////AI & Cyborg tech////////////////////////
/datum/techweb_node/neural_programming
id = "neural_programming"
display_name = "Neural Programming"
@@ -281,7 +222,7 @@
/datum/techweb_node/cyborg_upg_med
id = "cyborg_upg_med"
display_name = "Cyborg Upgrades: Medical"
- description = "Medical upgrades for cyborgs"
+ description = "Medical upgrades for cyborgs."
prereq_ids = list("adv_biotech", "cyborg")
design_ids = list("borg_upgrade_defibrillator", "borg_upgrade_piercinghypospray", "borg_upgrade_highstrengthsynthesiser", "borg_upgrade_expandedsynthesiser")
research_cost = 2500
@@ -291,7 +232,7 @@
id = "cyborg_upg_combat"
display_name = "Cyborg Upgrades: Combat"
description = "Military grade upgrades for cyborgs."
- prereq_ids = list("adv_robotics", "adv_engi")
+ prereq_ids = list("adv_robotics", "adv_engi" , "weaponry")
design_ids = list("borg_upgrade_vtec", "borg_upgrade_disablercooler")
research_cost = 2500
export_price = 10000
@@ -307,6 +248,112 @@
research_cost = 2500
export_price = 10000
+/////////////////////////EMP tech/////////////////////////
+/datum/techweb_node/emp_basic //EMP tech for some reason
+ id = "emp_basic"
+ display_name = "Electromagnetic Theory"
+ description = "Study into usage of frequencies in the electromagnetic spectrum."
+ prereq_ids = list("base")
+ design_ids = list("holosign", "inducer", "tray_goggles", "holopad")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/emp_adv
+ id = "emp_adv"
+ display_name = "Advanced Electromagnetic Theory"
+ description = "Determining whether reversing the polarity will actually help in a given situation."
+ prereq_ids = list("emp_basic")
+ design_ids = list("ultra_micro_laser")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/emp_super
+ id = "emp_super"
+ display_name = "Quantum Electromagnetic Technology" //bs
+ description = "Even better electromagnetic technology."
+ prereq_ids = list("emp_adv")
+ design_ids = list("quadultra_micro_laser")
+ research_cost = 2500
+ export_price = 10000
+
+/////////////////////////Clown tech/////////////////////////
+/datum/techweb_node/clown
+ id = "clown"
+ display_name = "Clown Technology"
+ description = "Honk?!"
+ prereq_ids = list("base")
+ design_ids = list("air_horn", "honker_main", "honker_peri", "honker_targ", "honk_chassis", "honk_head", "honk_torso", "honk_left_arm", "honk_right_arm",
+ "honk_left_leg", "honk_right_leg", "mech_banana_mortar", "mech_mousetrap_mortar", "mech_honker", "mech_punching_face", "implant_trombone")
+ research_cost = 2500
+ export_price = 10000
+
+////////////////////////Computer tech////////////////////////
+/datum/techweb_node/comptech
+ id = "comptech"
+ display_name = "Computer Consoles"
+ description = "Computers and how they work."
+ prereq_ids = list("datatheory")
+ design_ids = list("cargo", "cargorequest", "stockexchange", "libraryconsole", "aifixer", "mining", "crewconsole", "comconsole", "idcardconsole", "operating", "seccamera")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/computer_hardware_basic //Modular computers are shitty and nearly useless so until someone makes them actually useful this can be easy to get.
+ id = "computer_hardware_basic"
+ display_name = "Computer Hardware"
+ description = "How computer hardware are made."
+ prereq_ids = list("comptech")
+ research_cost = 2500
+ export_price = 10000
+ design_ids = list("hdd_basic", "hdd_advanced", "hdd_super", "hdd_cluster", "ssd_small", "ssd_micro", "netcard_basic", "netcard_advanced", "netcard_wired",
+ "portadrive_basic", "portadrive_advanced", "portadrive_super", "cardslot", "aislot", "miniprinter", "APClink", "bat_control", "bat_normal", "bat_advanced",
+ "bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small")
+
+/datum/techweb_node/computer_board_gaming
+ id = "computer_board_gaming"
+ display_name = "Arcade Games"
+ description = "For the slackers on the station."
+ prereq_ids = list("comptech")
+ design_ids = list("arcade_battle", "arcade_orion", "slotmachine")
+ research_cost = 1000
+ export_price = 10000
+
+/datum/techweb_node/comp_recordkeeping
+ id = "comp_recordkeeping"
+ display_name = "Computerized Recordkeeping"
+ description = "Organized record databases and how they're used."
+ prereq_ids = list("comptech")
+ design_ids = list("secdata", "med_data", "prisonmanage", "vendor", "automated_announcement")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/telecomms
+ id = "telecomms"
+ display_name = "Telecommunications Technology"
+ description = "Subspace transmission technology for near-instant communications devices."
+ prereq_ids = list("comptech", "bluespace_basic")
+ research_cost = 2500
+ export_price = 10000
+ design_ids = list("s-receiver", "s-bus", "s-broadcaster", "s-processor", "s-hub", "s-server", "s-relay", "comm_monitor", "comm_server",
+ "s-ansible", "s-filter", "s-amplifier", "ntnet_relay", "s-treatment", "s-analyzer", "s-crystal", "s-transmitter")
+
+/datum/techweb_node/integrated_HUDs
+ id = "integrated_HUDs"
+ display_name = "Integrated HUDs"
+ description = "The usefulness of computerized records, projected straight onto your eyepiece!"
+ prereq_ids = list("comp_recordkeeping", "emp_basic")
+ design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles")
+ research_cost = 2500
+ export_price = 10000
+
+/datum/techweb_node/NVGtech
+ id = "NVGtech"
+ display_name = "Night Vision Technology"
+ description = "Allows seeing in the dark without actual light!"
+ prereq_ids = list("integrated_HUDs", "adv_engi", "emp_adv")
+ design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "nvgmesons")
+ research_cost = 2500
+ export_price = 10000
+
////////////////////////Medical////////////////////////
/datum/techweb_node/cloning
id = "cloning"
@@ -323,7 +370,7 @@
description = "Smart freezing of objects to preserve them!"
prereq_ids = list("adv_engi", "emp_basic", "biotech")
design_ids = list("splitbeaker", "noreactsyringe", "cryotube", "cryo_Grenade")
- research_cost = 2500
+ research_cost = 2000
export_price = 10000
/datum/techweb_node/subdermal_implants
@@ -357,7 +404,7 @@
id = "adv_cyber_implants"
display_name = "Advanced Cybernetic Implants"
description = "Upgraded and more powerful cybernetic implants."
- prereq_ids = list("neural_programming", "cyber_implants")
+ prereq_ids = list("neural_programming", "cyber_implants","integrated_HUDs")
design_ids = list("ci-toolset", "ci-surgery", "ci-reviver")
research_cost = 2500
export_price = 10000
@@ -366,40 +413,11 @@
id = "combat_cyber_implants"
display_name = "Combat Cybernetic Implants"
description = "Military grade combat implants to improve performance."
- prereq_ids = list("adv_cyber_implants") //Needs way more reqs.
+ prereq_ids = list("adv_cyber_implants","weaponry","NVGtech","high_efficiency")
design_ids = list("ci-xray", "ci-thermals", "ci-antidrop", "ci-antistun", "ci-thrusters")
research_cost = 2500
export_price = 10000
-////////////////////////generic biotech////////////////////////
-/datum/techweb_node/bio_process
- id = "bio_process"
- display_name = "Biological Processing"
- description = "From slimes to kitchens."
- prereq_ids = list("biotech")
- design_ids = list("smartfridge", "gibber", "deepfryer", "monkey_recycler", "processor", "gibber", "microwave")
- research_cost = 2500
- export_price = 10000
-
-////////////////////////generic engineering////////////////////////
-/datum/techweb_node/high_efficiency
- id = "high_efficiency"
- display_name = "High Efficiency Parts"
- description = "High Efficiency Parts"
- prereq_ids = list("engineering", "datatheory")
- design_ids = list("pico_mani", "super_matter_bin")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/adv_power
- id = "adv_power"
- display_name = "Advanced Power Manipulation"
- description = "How to get more zap."
- prereq_ids = list("engineering")
- design_ids = list("smes", "super_cell", "hyper_cell", "super_capacitor", "superpacman", "mrspacman", "power_turbine", "power_turbine_console", "power_compressor")
- research_cost = 2500
- export_price = 10000
-
////////////////////////Tools////////////////////////
/datum/techweb_node/basic_mining
id = "basic_mining"
@@ -419,15 +437,6 @@
research_cost = 2500
export_price = 10000
-/datum/techweb_node/practical_bluespace
- id = "practical_bluespace"
- display_name = "Applied Bluespace Research"
- description = "Using bluespace to make things faster and better."
- prereq_ids = list("bluespace_basic", "engineering")
- design_ids = list("bs_rped","minerbag_holding", "telesci_gps", "bluespacebeaker", "bluespacesyringe", "bluespacebodybag", "phasic_scanning")
- research_cost = 2500
- export_price = 10000
-
/datum/techweb_node/janitor
id = "janitor"
display_name = "Advanced Sanitation Technology"
@@ -455,22 +464,13 @@
research_cost = 2500
export_price = 10000
-/datum/techweb_node/exp_equipment
- id = "exp_equipment"
+/datum/techweb_node/exp_flight
+ id = "exp_flight"
display_name = "Experimental Flight Equipment"
description = "Highly advanced construction tools."
design_ids = list("flightshoes", "flightpack", "flightsuit")
- prereq_ids = list("adv_engi")
- research_cost = 2500
- export_price = 10000
-
-/datum/techweb_node/bluespace_power
- id = "bluespace_power"
- display_name = "Bluespace Power Technology"
- description = "Even more powerful.. power!"
- prereq_ids = list("adv_power", "adv_bluespace")
- design_ids = list("bluespace_cell", "quadratic_capacitor")
- research_cost = 2500
+ prereq_ids = list("adv_engi","integrated_HUDs", "adv_power" , "high_efficiency")
+ research_cost = 5000
export_price = 10000
/////////////////////////weaponry tech/////////////////////////
@@ -496,7 +496,7 @@
id = "electronic_weapons"
display_name = "Electric Weapons"
description = "Weapons using electric technology"
- prereq_ids = list("weaponry", "adv_power")
+ prereq_ids = list("weaponry", "adv_power" , "emp_basic")
design_ids = list("stunrevolver", "stunshell", "tele_shield")
research_cost = 2500
export_price = 10000
@@ -506,7 +506,7 @@
display_name = "Radioactive Weaponry"
description = "Weapons using radioactive technology."
prereq_ids = list("adv_engi", "adv_weaponry")
- design_ids = list("nuclear_gun", "decloner")
+ design_ids = list("nuclear_gun")
research_cost = 2500
export_price = 10000
@@ -586,8 +586,8 @@
/datum/techweb_node/adv_mecha
id = "adv_mecha"
- display_name = "Mechanical Exosuits"
- description = "Mechanized exosuits that are several magnitudes stronger and more powerful than the average human."
+ display_name = "Advanced Exosuits"
+ description = "For when you just aren't Gundam enough."
prereq_ids = list("adv_robotics", "mecha")
design_ids = list("mech_repair_droid")
research_cost = 2500
@@ -627,7 +627,7 @@
id = "mecha_phazon"
display_name = "EXOSUIT: Phazon"
description = "Phazon exosuit designs"
- prereq_ids = list("adv_mecha", "weaponry")
+ prereq_ids = list("adv_mecha", "weaponry" , "adv_bluespace")
design_ids = list("phazon_chassis", "phazon_torso", "phazon_head", "phazon_left_arm", "phazon_right_arm", "phazon_left_leg", "phazon_right_leg", "phazon_main",
"phazon_peri", "phazon_targ", "phazon_armor")
research_cost = 2500
@@ -637,7 +637,7 @@
id = "mech_tools"
display_name = "Basic Exosuit Equipment"
description = "Various tools fit for basic mech units"
- prereq_ids = list("mecha", "engineering")
+ prereq_ids = list("mecha")
design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer")
research_cost = 2500
export_price = 10000
@@ -646,7 +646,7 @@
id = "adv_mecha_tools"
display_name = "Advanced Exosuit Equipment"
description = "Tools for high level mech suits"
- prereq_ids = list("adv_mecha", "mech_tools", "adv_engi")
+ prereq_ids = list("adv_mecha", "mech_tools")
design_ids = list("mech_rcd")
research_cost = 2500
export_price = 10000
@@ -662,9 +662,9 @@
/datum/techweb_node/mech_modules
id = "adv_mecha_modules"
- display_name = "Basic Exosuit Modules"
+ display_name = "Simple Exosuit Modules"
description = "An advanced piece of mech weaponry"
- prereq_ids = list("adv_mecha", "adv_power")
+ prereq_ids = list("adv_mecha", "bluespace_power")
design_ids = list("mech_energy_relay", "mech_ccw_armor", "mech_proj_armor", "mech_generator_nuclear")
research_cost = 2500
export_price = 10000
@@ -779,7 +779,7 @@
/datum/techweb_node/mech_lmg
id = "mech_lmg"
- display_name = "Exosuit Weapon (PBT \"Pacifier\" Mounted Taser)"
+ display_name = "Exosuit Weapon (\"Ultra AC 2\" LMG)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("adv_mecha", "adv_weaponry", "ballistic_weapons")
design_ids = list("mech_lmg")
@@ -800,12 +800,12 @@
id = "alientech"
display_name = "Alien Technology"
description = "Things used by the greys."
- prereq_ids = list("base")
+ prereq_ids = list("biotech","engineering")
boost_item_paths = list(/obj/item/gun/energy/alien = 0, /obj/item/scalpel/alien = 0, /obj/item/hemostat/alien = 0, /obj/item/retractor/alien = 0, /obj/item/circular_saw/alien = 0,
/obj/item/cautery/alien = 0, /obj/item/surgicaldrill/alien = 0, /obj/item/screwdriver/abductor = 0, /obj/item/wrench/abductor = 0, /obj/item/crowbar/abductor = 0, /obj/item/device/multitool/abductor = 0,
/obj/item/weldingtool/abductor = 0, /obj/item/wirecutters/abductor = 0, /obj/item/circuitboard/machine/abductor = 0, /obj/item/abductor_baton = 0, /obj/item/device/abductor = 0)
- research_cost = 2500
- export_price = 10000
+ research_cost = 5000
+ export_price = 20000
hidden = TRUE
design_ids = list("alienalloy")
@@ -813,13 +813,13 @@
id = "alien_bio"
display_name = "Alien Biological Tools"
description = "Advanced biological tools."
- prereq_ids = list("alientech", "biotech")
+ prereq_ids = list("alientech", "adv_biotech")
design_ids = list("alien_scalpel", "alien_hemostat", "alien_retractor", "alien_saw", "alien_drill", "alien_cautery")
boost_item_paths = list(/obj/item/gun/energy/alien = 0, /obj/item/scalpel/alien = 0, /obj/item/hemostat/alien = 0, /obj/item/retractor/alien = 0, /obj/item/circular_saw/alien = 0,
/obj/item/cautery/alien = 0, /obj/item/surgicaldrill/alien = 0, /obj/item/screwdriver/abductor = 0, /obj/item/wrench/abductor = 0, /obj/item/crowbar/abductor = 0, /obj/item/device/multitool/abductor = 0,
/obj/item/weldingtool/abductor = 0, /obj/item/wirecutters/abductor = 0, /obj/item/circuitboard/machine/abductor = 0, /obj/item/abductor_baton = 0, /obj/item/device/abductor = 0)
research_cost = 2500
- export_price = 10000
+ export_price = 20000
hidden = TRUE
/datum/techweb_node/alien_engi
@@ -831,9 +831,38 @@
/obj/item/weldingtool/abductor = 0, /obj/item/wirecutters/abductor = 0, /obj/item/circuitboard/machine/abductor = 0, /obj/item/abductor_baton = 0, /obj/item/device/abductor = 0)
design_ids = list("alien_wrench", "alien_wirecutters", "alien_screwdriver", "alien_crowbar", "alien_welder", "alien_multitool")
research_cost = 2500
+ export_price = 20000
+ hidden = TRUE
+
+/datum/techweb_node/syndicate_basic
+ id = "syndicate_basic"
+ display_name = "Illegal Technology"
+ description = "Dangerous research used to create dangerous objects."
+ prereq_ids = list("adv_engi", "adv_weaponry", "explosive_weapons")
+ design_ids = list("decloner", "borg_syndicate_module", "suppressor", "largecrossbow")
+ research_cost = 10000
export_price = 10000
hidden = TRUE
+/datum/techweb_node/syndicate_basic/New() //Crappy way of making syndicate gear decon supported until there's another way.
+ . = ..()
+ boost_item_paths = list()
+ for(var/cat in GLOB.uplink_items)
+ var/list/l = cat
+ for(var/i in l)
+ var/datum/uplink_item/UI = i
+ boost_item_paths[UI.item] = 0 //allows deconning to unlock.
+
+//HELPERS
+/proc/total_techweb_exports()
+ var/list/datum/techweb_node/processing = list()
+ for(var/i in subtypesof(/datum/techweb_node))
+ processing += new i
+ . = 0
+ for(var/i in processing)
+ var/datum/techweb_node/TN = i
+ . += TN.export_price
+
/proc/total_techweb_points()
var/list/datum/techweb_node/processing = list()
for(var/i in subtypesof(/datum/techweb_node))
@@ -842,19 +871,3 @@
for(var/i in processing)
var/datum/techweb_node/TN = i
. += TN.research_cost
-
-/*
-/datum/design/borg_syndicate_module
- name = "Cyborg Upgrade (Illegal Modules)"
- id = "borg_syndicate_module"
- construction_time = 120
-
-/datum/design/suppressor
- name = "Universal Suppressor"
- id = "suppressor"
-
-/datum/design/largecrossbow
- name = "Energy Crossbow"
- id = "largecrossbow"
- build_path = /obj/item/gun/energy/kinetic_accelerator/crossbow/large
-*/
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 93fd8dda37..8e2ce4b7a0 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -11,7 +11,7 @@
throwforce = 0
throw_speed = 3
throw_range = 6
- container_type = INJECTABLE_1
+ container_type = INJECTABLE | DRAWABLE
grind_results = list()
var/Uses = 1 // uses before it goes inert
var/qdel_timer = null // deletion timer, for delayed reactions
@@ -472,7 +472,7 @@
desc = "A golem's head."
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
flags_1 = ABSTRACT_1 | NODROP_1
-
+
/obj/item/stack/tile/bluespace
name = "bluespace floor tile"
singular_name = "floor tile"
diff --git a/code/modules/spells/spell_types/rightandwrong.dm b/code/modules/spells/spell_types/rightandwrong.dm
index b992871004..7ab3121a3a 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 98ec01f641..88377455c6 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/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index e23e7ff7d3..a90923e58f 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -61,7 +61,7 @@
/obj/item/organ/cyberimp/arm/emag_act()
return 0
-/obj/item/organ/cyberimp/arm/gun/emp_act(severity)
+/obj/item/organ/cyberimp/arm/emp_act(severity)
if(prob(15/severity) && owner)
to_chat(owner, "
[src] is hit by EMP!")
// give the owner an idea about why his implant is glitching
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index d28adebe4b..ebff0fdbeb 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1096,16 +1096,9 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
/datum/uplink_item/device_tools/codespeak_manual
name = "Codespeak Manual"
- desc = "Syndicate agents can be trained to use a series of codewords to convey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. One use."
- item = /obj/item/codespeak_manual
- cost = 2
- exclude_modes = list(/datum/game_mode/nuclear)
-
-/datum/uplink_item/device_tools/codespeak_manual_deluxe
- name = "Deluxe Codespeak Manual"
- desc = "Syndicate agents can be trained to use a series of codewords to convey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. This is the deluxe edition, which has unlimited uses."
- cost = 8
- include_modes = list(/datum/game_mode/nuclear)
+ desc = "Syndicate agents can be trained to use a series of codewords to convey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. This is the deluxe edition, which has unlimited used."
+ item = /obj/item/codespeak_manual/unlimited
+ cost = 3
// Implants
/datum/uplink_item/implants
diff --git a/html/browser/roundend.css b/html/browser/roundend.css
new file mode 100644
index 0000000000..82235f1273
--- /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/html/browser/techwebs.css b/html/browser/techwebs.css
new file mode 100644
index 0000000000..889196cc28
--- /dev/null
+++ b/html/browser/techwebs.css
@@ -0,0 +1,20 @@
+[data-tooltip] {
+ position: relative;
+}
+
+[data-tooltip]:hover::before {
+ position: absolute;
+ z-index: 1;
+ top: 100%;
+ padding: 0 4px;
+ margin-top: 1px;
+ border: 1px solid #40628a;
+ background: black;
+ color: white;
+ content: attr(data-tooltip);
+ min-width: 160px;
+}
+
+.technode {
+ width: 256px;
+}
diff --git a/html/changelog.css b/html/changelog.css
index 031c1e42c0..2bfa3fa495 100644
--- a/html/changelog.css
+++ b/html/changelog.css
@@ -1,41 +1,41 @@
-.top{font-family:Tahoma,sans-serif;font-size:12px;}
-h2{font-family:Tahoma,sans-serif;}
-a img {border:none;}
-.bgimages16 li {
- padding:2px 10px 2px 30px;
- background-position:6px center;
- background-repeat:no-repeat;
- border:1px solid #ddd;
- border-left:4px solid #999;
- margin-bottom:2px;
-}
-.bugfix {background-image:url(bug-minus.png)}
-.wip {background-image:url(hard-hat-exclamation.png)}
-.tweak {background-image:url(wrench-screwdriver.png)}
-.soundadd {background-image:url(music-plus.png)}
-.sounddel {background-image:url(music-minus.png)}
-.rscdel {background-image:url(cross-circle.png)}
-.rscadd {background-image:url(tick-circle.png)}
-.imageadd {background-image:url(image-plus.png)}
-.imagedel {background-image:url(image-minus.png)}
-.spellcheck {background-image:url(spell-check.png)}
-.experiment {background-image:url(burn-exclamation.png)}
-.refactor {background-image:url(burn-exclamation.png)}
-.code_imp {background-image:url(coding.png)}
-.config {background-image:url(chrome_wrench.png)}
-.admin {background-image:url(ban.png)}
-.server {background-image:url(hard-hat-exclamation.png)}
-.balance {background-image:url(scales.png)}
-.sansserif {font-family:Tahoma,sans-serif;font-size:12px;}
-.commit {margin-bottom:20px;font-size:100%;font-weight:normal;}
-.changes {list-style:none;margin:5px 0;padding:0 0 0 25px;font-size:0.8em;}
-.date {margin:10px 0;color:blue;border-bottom:2px solid #00f;width:60%;padding:2px 0;font-size:1em;font-weight:bold;}
-.author {padding-left:10px;margin:0;font-weight:bold;font-size:0.9em;}
-.drop {cursor:pointer;border:1px solid #999;display:inline;font-size:0.9em;padding:1px 20px 1px 5px;line-height:16px;}
-.hidden {display:none;}
-.indrop {margin:2px 0 0 0;clear:both;background:#fff;border:1px solid #ddd;padding:5px 10px;}
-.indrop p {margin:0;font-size:0.8em;line-height:16px;margin:1px 0;}
-.indrop img {margin-right:5px;vertical-align:middle;}
-.closed {background:url(chevron-expand.png) right center no-repeat;}
-.open {background:url(chevron.png) right center no-repeat;}
-.lic {font-size:9px;}
\ No newline at end of file
+.top{font-family:Tahoma,sans-serif;font-size:12px;}
+h2{font-family:Tahoma,sans-serif;}
+a img {border:none;}
+.bgimages16 li {
+ padding:2px 10px 2px 30px;
+ background-position:6px center;
+ background-repeat:no-repeat;
+ border:1px solid #ddd;
+ border-left:4px solid #999;
+ margin-bottom:2px;
+}
+.bugfix {background-image:url(bug-minus.png)}
+.wip {background-image:url(hard-hat-exclamation.png)}
+.tweak {background-image:url(wrench-screwdriver.png)}
+.soundadd {background-image:url(music-plus.png)}
+.sounddel {background-image:url(music-minus.png)}
+.rscdel {background-image:url(cross-circle.png)}
+.rscadd {background-image:url(tick-circle.png)}
+.imageadd {background-image:url(image-plus.png)}
+.imagedel {background-image:url(image-minus.png)}
+.spellcheck {background-image:url(spell-check.png)}
+.experiment {background-image:url(burn-exclamation.png)}
+.refactor {background-image:url(burn-exclamation.png)}
+.code_imp {background-image:url(coding.png)}
+.config {background-image:url(chrome-wrench.png)}
+.admin {background-image:url(ban.png)}
+.server {background-image:url(hard-hat-exclamation.png)}
+.balance {background-image:url(scales.png)}
+.sansserif {font-family:Tahoma,sans-serif;font-size:12px;}
+.commit {margin-bottom:20px;font-size:100%;font-weight:normal;}
+.changes {list-style:none;margin:5px 0;padding:0 0 0 25px;font-size:0.8em;}
+.date {margin:10px 0;color:blue;border-bottom:2px solid #00f;width:60%;padding:2px 0;font-size:1em;font-weight:bold;}
+.author {padding-left:10px;margin:0;font-weight:bold;font-size:0.9em;}
+.drop {cursor:pointer;border:1px solid #999;display:inline;font-size:0.9em;padding:1px 20px 1px 5px;line-height:16px;}
+.hidden {display:none;}
+.indrop {margin:2px 0 0 0;clear:both;background:#fff;border:1px solid #ddd;padding:5px 10px;}
+.indrop p {margin:0;font-size:0.8em;line-height:16px;margin:1px 0;}
+.indrop img {margin-right:5px;vertical-align:middle;}
+.closed {background:url(chevron-expand.png) right center no-repeat;}
+.open {background:url(chevron.png) right center no-repeat;}
+.lic {font-size:9px;}
diff --git a/html/changelogs/AutoChangeLog-pr-3639.yml b/html/changelogs/AutoChangeLog-pr-3639.yml
deleted file mode 100644
index 3625dfce90..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3639.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "Antags are able to greentext again"
diff --git a/html/changelogs/AutoChangeLog-pr-3731.yml b/html/changelogs/AutoChangeLog-pr-3731.yml
deleted file mode 100644
index 9486c7e793..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3731.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - bugfix: "Singularity objects no longer become contaminated by radiation."
- - admin: "Removed the radiation message admin spam and moved it to an investigation log."
diff --git a/html/changelogs/AutoChangeLog-pr-3747.yml b/html/changelogs/AutoChangeLog-pr-3747.yml
deleted file mode 100644
index 46ad021439..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3747.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - tweak: "\"Tail removal\" and \"tail attachment\" surgeries are merged with \"organ manipulation\"."
diff --git a/html/changelogs/AutoChangeLog-pr-3818.yml b/html/changelogs/AutoChangeLog-pr-3818.yml
deleted file mode 100644
index 1be3ec57f4..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3818.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Swindly"
-delete-after: True
-changes:
- - bugfix: "You can now cancel a cavity implant during the implanting/removing step by using drapes while holding the appropriate tool in your inactive hand. Cyborgs can cancel the surgery by using drapes alone."
diff --git a/html/changelogs/AutoChangeLog-pr-3858.yml b/html/changelogs/AutoChangeLog-pr-3858.yml
deleted file mode 100644
index 2243f683c0..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3858.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "deathride58 & TGstation contributors"
-delete-after: True
-changes:
- - bugfix: "Fixed various area issues in Boxstation. The theatre no longer has an air alarm for space, and Security no longer has a line of walls with broken lighting."
- - tweak: "Added more lights to Boxstation's security"
- - rscadd: "(Upstream) Added a new white ship to Deltastation"
- - tweak: "(Upstream) Replaced the reinforced glass in Atmos' gas tanks with reinforced plasma glass"
- - tweak: "(Upstream) Atmos can no longer burn itself down via the waste loop outlet"
diff --git a/html/changelogs/AutoChangeLog-pr-3864.yml b/html/changelogs/AutoChangeLog-pr-3864.yml
deleted file mode 100644
index 2ff6cc010e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3864.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - tweak: "Cooldown on the Ripley's mining drills has been halved."
- - tweak: "The frequency of the Ripley's ore pulse has been doubled."
diff --git a/html/changelogs/AutoChangeLog-pr-3871.yml b/html/changelogs/AutoChangeLog-pr-3871.yml
deleted file mode 100644
index 910a5893eb..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3871.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Bluespace shelter walls no longer smooth with non-shelter walls and windows."
diff --git a/html/changelogs/AutoChangeLog-pr-3879.yml b/html/changelogs/AutoChangeLog-pr-3879.yml
deleted file mode 100644
index 440ea3e616..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3879.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "as334"
-delete-after: True
-changes:
- - rscadd: "Pluoxium can now be formed by irradiating tiles with CO2 in the air."
- - rscadd: "Rad collectors now steadily form Tritium at a slow pace."
- - balance: "Nerfs fusion by making it slower, and produce radioactivity."
- - balance: "Noblium formation now requires significantly more energy input."
- - balance: "Tanks now melt if their temperature is above 1 Million Kelvin."
diff --git a/html/changelogs/AutoChangeLog-pr-3881.yml b/html/changelogs/AutoChangeLog-pr-3881.yml
deleted file mode 100644
index da5bf113eb..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3881.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Mark9013100"
-delete-after: True
-changes:
- - tweak: "Charcoal bottles have been renamed, and have been given a more informative description."
diff --git a/html/changelogs/AutoChangeLog-pr-3884.yml b/html/changelogs/AutoChangeLog-pr-3884.yml
deleted file mode 100644
index cccc830fa8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3884.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "You can no longer delete girders, lattices, or catwalks with the RPD"
- - bugfix: "Fixes runtimes that occur when clicking girders, lattices, catwalks, or disposal pipes with the RPD in paint mode"
diff --git a/html/changelogs/AutoChangeLog-pr-3886.yml b/html/changelogs/AutoChangeLog-pr-3886.yml
deleted file mode 100644
index df6baaf9e8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3886.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Clockwork slabs no longer refer to components"
diff --git a/html/changelogs/AutoChangeLog-pr-3887.yml b/html/changelogs/AutoChangeLog-pr-3887.yml
deleted file mode 100644
index 6abe71ce5d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3887.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DaxDupont"
-delete-after: True
-changes:
- - bugfix: "Medbots can inject from one tile away again."
diff --git a/html/changelogs/AutoChangeLog-pr-3889.yml b/html/changelogs/AutoChangeLog-pr-3889.yml
deleted file mode 100644
index 0dbe1a4a54..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3889.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "The detective and heads of staff are no longer attacked by portable turrets."
diff --git a/html/changelogs/AutoChangeLog-pr-3892.yml b/html/changelogs/AutoChangeLog-pr-3892.yml
deleted file mode 100644
index d56a3291ca..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3892.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - bugfix: "Fixes ruin cable spawning and probably some other bugs"
diff --git a/html/changelogs/AutoChangeLog-pr-3900.yml b/html/changelogs/AutoChangeLog-pr-3900.yml
deleted file mode 100644
index aea022be12..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3900.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Qbopper and JJRcop"
-delete-after: True
-changes:
- - tweak: "The default internet sound volume was changed from 100 to 25. Stop complaining in OOC about your ears!"
diff --git a/html/changelogs/AutoChangeLog-pr-3901.yml b/html/changelogs/AutoChangeLog-pr-3901.yml
deleted file mode 100644
index ac91a766d7..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3901.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "nicn"
-delete-after: True
-changes:
- - balance: "Damage from low pressure has been doubled."
diff --git a/html/changelogs/AutoChangeLog-pr-3908.yml b/html/changelogs/AutoChangeLog-pr-3908.yml
deleted file mode 100644
index bd69080a7d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3908.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Posters may no longer be placed on diagonal wall corners."
diff --git a/html/changelogs/AutoChangeLog-pr-3912.yml b/html/changelogs/AutoChangeLog-pr-3912.yml
deleted file mode 100644
index 85cf3a8454..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3912.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - rscadd: "Deep fryers now have sound."
- - tweak: "Deep fryers now use cooking oil, a specialized reagent that becomes highly damaging at high temperatures. You can get it from grinding soybeans and meat."
- - tweak: "Deep fryers now become more efficient with higher-level micro lasers, using less oil and frying faster."
- - tweak: "Deep fryers now slowly use oil as it fries objects, instead of all at once."
- - bugfix: "You can now correctly refill deep fryers with syringes and pills."
- - rscadd: "Microwaves have new sounds!"
diff --git a/html/changelogs/AutoChangeLog-pr-3913.yml b/html/changelogs/AutoChangeLog-pr-3913.yml
deleted file mode 100644
index c2a59fe367..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3913.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Cobby"
-delete-after: True
-changes:
- - rscadd: "The Xray now only hits the first mob it comes into contact with instead of being outright removed from the game."
diff --git a/html/changelogs/AutoChangeLog-pr-3916.yml b/html/changelogs/AutoChangeLog-pr-3916.yml
deleted file mode 100644
index e61e4d044c..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3916.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Frozenguy5"
-delete-after: True
-changes:
- - bugfix: "Broken cable cuffs no longer has an invisible sprite."
diff --git a/html/changelogs/AutoChangeLog-pr-3919.yml b/html/changelogs/AutoChangeLog-pr-3919.yml
deleted file mode 100644
index ab0e21a5d3..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3919.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Floyd / Qustinnus"
-delete-after: True
-changes:
- - soundadd: "Reebe now has ambience sounds"
diff --git a/html/changelogs/AutoChangeLog-pr-3920.yml b/html/changelogs/AutoChangeLog-pr-3920.yml
deleted file mode 100644
index 8111335f02..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3920.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "LetterJay"
-delete-after: True
-changes:
- - bugfix: "Flavor text can be examined again"
diff --git a/html/changelogs/AutoChangeLog-pr-3951.yml b/html/changelogs/AutoChangeLog-pr-3951.yml
deleted file mode 100644
index 6dcac4a2d3..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3951.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "SpiderPsycho"
-delete-after: True
-changes:
- - rscadd: "Added insects without fuzz"
- - rscdel: "Removed fuzz"
- - tweak: "changed the name of the fuzzless sprites to insects so the character creation can call them properly."
diff --git a/html/changelogs/AutoChangeLog-pr-3959.yml b/html/changelogs/AutoChangeLog-pr-3959.yml
deleted file mode 100644
index f89f2489dd..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3959.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "disable_warning wasn't getting checked and the chat was being spammed"
diff --git a/html/changelogs/AutoChangeLog-pr-3960.yml b/html/changelogs/AutoChangeLog-pr-3960.yml
deleted file mode 100644
index dd9ab1e232..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3960.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "cell chargers weren't animating properly"
diff --git a/html/changelogs/AutoChangeLog-pr-3961.yml b/html/changelogs/AutoChangeLog-pr-3961.yml
deleted file mode 100644
index 52f66a3b46..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3961.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ike709"
-delete-after: True
-changes:
- - imageadd: "Added new vent and scrubber sprites by Partheo."
diff --git a/html/changelogs/AutoChangeLog-pr-3964.yml b/html/changelogs/AutoChangeLog-pr-3964.yml
deleted file mode 100644
index 6061524af8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3964.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "Atmos scrubbers (vent and portable) can now filter any and all gases."
diff --git a/html/changelogs/AutoChangeLog-pr-3966.yml b/html/changelogs/AutoChangeLog-pr-3966.yml
deleted file mode 100644
index 40cdd5ec13..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3966.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - bugfix: "Sped up saycode to remove free lag from highpop"
diff --git a/html/changelogs/AutoChangeLog-pr-3967.yml b/html/changelogs/AutoChangeLog-pr-3967.yml
deleted file mode 100644
index 28378bcc30..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3967.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DaxDupont"
-delete-after: True
-changes:
- - tweak: "CentCom has issued a firmware updated for the operating computers. It is no longer needed to manually refresh the procedure and patient status."
diff --git a/html/changelogs/AutoChangeLog-pr-3968.yml b/html/changelogs/AutoChangeLog-pr-3968.yml
deleted file mode 100644
index 3430a1e8cb..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3968.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "JJRcop"
-delete-after: True
-changes:
- - bugfix: "Fixes changeling eggs not putting the changeling in control if the brainslug is destroyed before hatching."
diff --git a/html/changelogs/AutoChangeLog-pr-3969.yml b/html/changelogs/AutoChangeLog-pr-3969.yml
deleted file mode 100644
index 7f53c200d6..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3969.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "HUDs from mechs and helmets no longer conflict with HUD glasses and no longer inappropriately remove implanted HUDs."
diff --git a/html/changelogs/AutoChangeLog-pr-3975.yml b/html/changelogs/AutoChangeLog-pr-3975.yml
deleted file mode 100644
index 450706db1f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3975.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DaxDupont"
-delete-after: True
-changes:
- - bugfix: "Proximity sensors no longer beep when unarmed."
diff --git a/html/changelogs/AutoChangeLog-pr-3976.yml b/html/changelogs/AutoChangeLog-pr-3976.yml
deleted file mode 100644
index b3d144e1de..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3976.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Iamgoofball"
-delete-after: True
-changes:
- - spellcheck: "fixed grammar on output circuits"
diff --git a/html/changelogs/AutoChangeLog-pr-3977.yml b/html/changelogs/AutoChangeLog-pr-3977.yml
deleted file mode 100644
index a4916a713e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3977.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Iamgoofball"
-delete-after: True
-changes:
- - spellcheck: "fixes grammar on list circuits"
diff --git a/html/changelogs/AutoChangeLog-pr-3978.yml b/html/changelogs/AutoChangeLog-pr-3978.yml
deleted file mode 100644
index 0840869b16..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3978.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Iamgoofball"
-delete-after: True
-changes:
- - spellcheck: "fixes grammar on logic gate descriptions"
diff --git a/html/changelogs/AutoChangeLog-pr-3979.yml b/html/changelogs/AutoChangeLog-pr-3979.yml
deleted file mode 100644
index e9a21ef984..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3979.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Iamgoofball"
-delete-after: True
-changes:
- - bugfix: "fixes grammar on trig circuits"
diff --git a/html/changelogs/AutoChangeLog-pr-3980.yml b/html/changelogs/AutoChangeLog-pr-3980.yml
deleted file mode 100644
index 09e3ebe5ef..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3980.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "MMMiracles"
-delete-after: True
-changes:
- - balance: "Power regen on the regular tesla relay has been reduced to 50, from 150."
diff --git a/html/changelogs/AutoChangeLog-pr-3981.yml b/html/changelogs/AutoChangeLog-pr-3981.yml
deleted file mode 100644
index 0670048ed3..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3981.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "nicbn"
-delete-after: True
-changes:
- - soundadd: "Now rolling beds and office chairs have a sound!"
diff --git a/html/changelogs/AutoChangeLog-pr-3983.yml b/html/changelogs/AutoChangeLog-pr-3983.yml
deleted file mode 100644
index 0e3a681757..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3983.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "oranges"
-delete-after: True
-changes:
- - rscdel: "Removed the shocker circuit"
diff --git a/html/changelogs/AutoChangeLog-pr-3988.yml b/html/changelogs/AutoChangeLog-pr-3988.yml
deleted file mode 100644
index 743551eaaa..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3988.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DaxDupont"
-delete-after: True
-changes:
- - bugfix: "Plant trays will now properly process fluorine and adjust toxins and water contents."
diff --git a/html/changelogs/AutoChangeLog-pr-3992.yml b/html/changelogs/AutoChangeLog-pr-3992.yml
deleted file mode 100644
index b60be8068c..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3992.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "JJRcop"
-delete-after: True
-changes:
- - tweak: "The silicon airlock menu looks a little more like it used to."
diff --git a/html/changelogs/AutoChangeLog-pr-3993.yml b/html/changelogs/AutoChangeLog-pr-3993.yml
deleted file mode 100644
index 14c4d31514..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3993.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "purple bartender suit and apron added to clothesmates!"
- - rscadd: "long hair 3 added, check it out. both have sprites from okand!"
diff --git a/html/changelogs/AutoChangeLog-pr-3994.yml b/html/changelogs/AutoChangeLog-pr-3994.yml
deleted file mode 100644
index 2ff513ddf5..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3994.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "The RPD has a shiny new UI!"
- - rscadd: "The RPD can now paint pipes as it lays them, for quicker piping projects."
diff --git a/html/changelogs/AutoChangeLog-pr-3995.yml b/html/changelogs/AutoChangeLog-pr-3995.yml
deleted file mode 100644
index 77d6c658da..0000000000
--- a/html/changelogs/AutoChangeLog-pr-3995.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-author: "ShizCalev (Upstream), WJohnston (Upstream), Okand37 (Upstream), deathride58"
-delete-after: True
-changes:
- - tweak: "(Upstream) The computers on all maps have have been updated for the latest directional sprite changes. Please report any computers facing in strange directions to your nearest mapper."
- - rscadd: "(Upstream) Updated the Test Map debugging verb to report more issues regarding APCs.
-DELTASTATION"
- - bugfix: "(Upstream) Reverted Okand37's morgue changes which broke power in the area."
- - bugfix: "(Upstream) Corrected wrong area on the Southern airlock leading into electrical maintenance.
-ALL STATIONS"
- - bugfix: "(Upstream) Corrected numerous duplicate APCs in areas which led to power issues."
- - rscdel: "(Upstream) Removes stationary docking ports for syndicate infiltrator ships on all maps. Use the docking navigator computer instead! This gives the white ship and syndicate infiltrator more room to navigate and place custom locations that are otherwise occupied by fixed shuttle landing zones that are rarely used."
- - rscadd: "(Upstream, Deltastation) Tweaked Atmospherics"
- - bugfix: "(Upstream, Deltastation) Fixed the Incinerator air injector"
- - rscadd: "(Upstream, Deltastation) Tweaked Engineering"
- - rscadd: "(Upstream, Deltastation) Added logs to the Chaplain's closet for gimmicks (bonfires)"
- - rscadd: "(Upstream, Deltastation) Tweaked Security"
- - bugfix: "(Upstream, Deltastation) Fixed medical morgue maintenance not providing radiation shielding and exterior chemistry windoor"
- - rscadd: "(Upstream, Deltastation) Bar now has a door from the backroom to the theatre stage"
- - rscadd: "(Upstream, Deltastation) Tweaked Locker Room/Dormitories"
- - bugfix: "The armory no longer has a deep frying oil vat in place of dragnets."
diff --git a/html/changelogs/AutoChangeLog-pr-4000.yml b/html/changelogs/AutoChangeLog-pr-4000.yml
deleted file mode 100644
index bfd91f572d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4000.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - imageadd: "The Nanotrasen logo on modular computers has been fixed, rejoice!"
diff --git a/html/changelogs/AutoChangeLog-pr-4001.yml b/html/changelogs/AutoChangeLog-pr-4001.yml
deleted file mode 100644
index 578f211e20..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4001.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Pizza box stacking works again."
diff --git a/html/changelogs/AutoChangeLog-pr-4005.yml b/html/changelogs/AutoChangeLog-pr-4005.yml
deleted file mode 100644
index cf136090a6..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4005.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "now lists should work properly"
diff --git a/html/changelogs/AutoChangeLog-pr-4008.yml b/html/changelogs/AutoChangeLog-pr-4008.yml
deleted file mode 100644
index 6d6b7d53b8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4008.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "zennerx"
-delete-after: True
-changes:
- - bugfix: "fixed a bug that made you try and scream while unconscious due to a fire"
diff --git a/html/changelogs/AutoChangeLog-pr-4010.yml b/html/changelogs/AutoChangeLog-pr-4010.yml
deleted file mode 100644
index b413fb1671..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4010.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Kor"
-delete-after: True
-changes:
- - bugfix: "Blobbernauts will no longer spawn if a player is not selected to control it, preventing AI blobbernauts from running off the blob and to their deaths."
diff --git a/html/changelogs/AutoChangeLog-pr-4012.yml b/html/changelogs/AutoChangeLog-pr-4012.yml
deleted file mode 100644
index 18b4c3dfd2..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4012.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Toriate"
-delete-after: True
-changes:
- - tweak: "Mag Pistol and Mag Rifle no longer spawn with magazines when built in protolathe"
- - balance: "Nerf guns no longer max out science in five seconds flat"
- - bugfix: "Nerf gun magazines no longer give infinite metal and glass"
diff --git a/html/changelogs/AutoChangeLog-pr-4013.yml b/html/changelogs/AutoChangeLog-pr-4013.yml
deleted file mode 100644
index 0507fafc72..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4013.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Fix some permanent-on and permanent-off bugs caused by the HUD stacking change."
diff --git a/html/changelogs/AutoChangeLog-pr-4014.yml b/html/changelogs/AutoChangeLog-pr-4014.yml
deleted file mode 100644
index 1a1698767d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4014.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "Skylar Lineman, your local R&D moonlighter"
-delete-after: True
-changes:
- - rscadd: "Research has been completely overhauled into the techweb system! No more levels, the station now unlocks research \"nodes\" with research points passively generated when there is atleast one research server properly cooled, powered, and online."
- - rscadd: "R&D lab has been replaced by the departmental lathe system on the three major maps. Each department gets a lathe and possibly a circuit imprinter that only have designs assigned by that department."
- - rscadd: "The ore redemption machine has been moved into cargo bay on maps with decentralized research to prevent the hallways from becoming a free for all. Honk!"
- - balance: "You shouldn't expect balance as this is the initial merge. Please put all feedback and concerns on the forum so we can revise the system over the days, weeks, and months, to make this enjoyable for everyone. Heavily wanted are ideas of how to add more ways of generating points."
- - balance: "You can get techweb points by setting off bombs with an active science doppler array listening. The bombs have to have a theoretical radius far above maxcap to make a difference. You can only go up, not down, in radius, so you can't get 6 times the points with 6 TTVs. The algorithm is exponentially/logarithmically scaled to prevent \"world destroyer\" bombs from instantly finishing research."
diff --git a/html/changelogs/AutoChangeLog-pr-4022.yml b/html/changelogs/AutoChangeLog-pr-4022.yml
deleted file mode 100644
index 295229de2b..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4022.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Chairs, PA parts, infrared emitters, and doppler arrays will now rotate clockwise."
diff --git a/html/changelogs/AutoChangeLog-pr-4026.yml b/html/changelogs/AutoChangeLog-pr-4026.yml
deleted file mode 100644
index 3424fdd501..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4026.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - bugfix: "Using a chameleon projector will now dismount you from any vehicles you are riding, in order to prevent wacky space glitches and being sent to a realm outside space and time."
diff --git a/html/changelogs/AutoChangeLog-pr-4027.yml b/html/changelogs/AutoChangeLog-pr-4027.yml
deleted file mode 100644
index 925f8d5256..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4027.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ike709"
-delete-after: True
-changes:
- - bugfix: "Fixed some computers facing the wrong direction."
diff --git a/html/changelogs/AutoChangeLog-pr-4028.yml b/html/changelogs/AutoChangeLog-pr-4028.yml
deleted file mode 100644
index 1af9360833..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4028.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Code by Pyko, Ported by Frozenguy5"
-delete-after: True
-changes:
- - rscadd: "Rat Kebabs and Double Rat Kebabs have been added!"
diff --git a/html/changelogs/AutoChangeLog-pr-4030.yml b/html/changelogs/AutoChangeLog-pr-4030.yml
deleted file mode 100644
index ca630fbfd8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4030.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "zennerx"
-delete-after: True
-changes:
- - tweak: "Skateboard crashes now give slight brain damage!"
- - rscadd: "Using a helmet prevents brain damage from the skateboard!"
diff --git a/html/changelogs/AutoChangeLog-pr-4031.yml b/html/changelogs/AutoChangeLog-pr-4031.yml
deleted file mode 100644
index 4907986852..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4031.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - code_imp: "Ladders have been refactored and should be far less buggy."
- - bugfix: "Jacob's ladder actually works again."
diff --git a/html/changelogs/AutoChangeLog-pr-4032.yml b/html/changelogs/AutoChangeLog-pr-4032.yml
deleted file mode 100644
index 4969c5bcaf..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4032.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "PubbyStation - Unpowered air injectors in various locations have been fixed."
diff --git a/html/changelogs/AutoChangeLog-pr-4033.yml b/html/changelogs/AutoChangeLog-pr-4033.yml
deleted file mode 100644
index effc283b83..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4033.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "MetaStation - Air injector leading out of the incinerator has been fixed"
- - bugfix: "MetaStation - Corrected a couple maintenance airlocks being powered by the wrong areas."
diff --git a/html/changelogs/AutoChangeLog-pr-4034.yml b/html/changelogs/AutoChangeLog-pr-4034.yml
deleted file mode 100644
index eff19f0cfa..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4034.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Throwing drinking glasses and cartons will now consistently cause them to break!"
diff --git a/html/changelogs/AutoChangeLog-pr-4036.yml b/html/changelogs/AutoChangeLog-pr-4036.yml
deleted file mode 100644
index 820c726cea..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4036.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Computers will no longer rotate incorrectly when being deconstructed."
- - bugfix: "You can now rotate computer frames during construction."
diff --git a/html/changelogs/AutoChangeLog-pr-4038.yml b/html/changelogs/AutoChangeLog-pr-4038.yml
deleted file mode 100644
index 9500855d83..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4038.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "WJohnston"
-delete-after: True
-changes:
- - bugfix: "Green banded default airlocks now have extended click area like all other airlocks."
diff --git a/html/changelogs/AutoChangeLog-pr-4043.yml b/html/changelogs/AutoChangeLog-pr-4043.yml
deleted file mode 100644
index b867396350..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4043.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Francinum"
-delete-after: True
-changes:
- - tweak: "The shuttle build plate is now better sized for all stations."
diff --git a/html/changelogs/AutoChangeLog-pr-4049.yml b/html/changelogs/AutoChangeLog-pr-4049.yml
deleted file mode 100644
index f2d883ca0d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4049.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "WJohnston"
-delete-after: True
-changes:
- - imageadd: "A bunch of new turf decals for mappers to play with, coming in yellow, white, and red varieties!"
diff --git a/html/changelogs/AutoChangeLog-pr-4050.yml b/html/changelogs/AutoChangeLog-pr-4050.yml
deleted file mode 100644
index 85d49a56fe..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4050.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Computers will no longer delete themselves when being built, whoops!"
diff --git a/html/changelogs/AutoChangeLog-pr-4051.yml b/html/changelogs/AutoChangeLog-pr-4051.yml
deleted file mode 100644
index ee3ed953c1..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4051.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - refactor: "Old integrated circuit save file format is ditched in favor of JSON. Readability, both of save files and save code, is improved greatly."
- - tweak: "Integrated circuit panels now open with screwdriver instead of crowbar, to match every single other thing on this server."
- - tweak: "Integrated circuit printer now stores up to 25 metal sheets."
- - bugfix: "Fixed integrated circuit rechargers not recharging guns properly and not updating icons."
- - bugfix: "Fixed multiple bugs in integrated circuits UIs, improved overall usability."
diff --git a/html/changelogs/AutoChangeLog-pr-4052.yml b/html/changelogs/AutoChangeLog-pr-4052.yml
deleted file mode 100644
index ad7e91b332..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4052.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Humans missing legs or are legcuffed will no longer move slower in areas without gravity."
diff --git a/html/changelogs/AutoChangeLog-pr-4053.yml b/html/changelogs/AutoChangeLog-pr-4053.yml
deleted file mode 100644
index 9f749a63a5..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4053.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Toriate"
-delete-after: True
-changes:
- - rscadd: "Added recolourable clothes"
- - tweak: "jumpsuits in mixed wardrobe replaced with recolourable clothes"
- - imageadd: "greyscaled clothing sprites for colourable clothes"
diff --git a/html/changelogs/AutoChangeLog-pr-4055.yml b/html/changelogs/AutoChangeLog-pr-4055.yml
deleted file mode 100644
index 618a46b39c..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4055.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "The structures external to stations are now properly lit. Make sure you bring a flashlight."
diff --git a/html/changelogs/AutoChangeLog-pr-4059.yml b/html/changelogs/AutoChangeLog-pr-4059.yml
deleted file mode 100644
index 1742cf5805..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4059.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "psykzz"
-delete-after: True
-changes:
- - rscadd: "Added TGUI for Turbine computer"
diff --git a/html/changelogs/AutoChangeLog-pr-4060.yml b/html/changelogs/AutoChangeLog-pr-4060.yml
deleted file mode 100644
index 7846d861f4..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4060.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Y0SH1 M4S73R"
-delete-after: True
-changes:
- - spellcheck: "The R&D Server's name is now improper."
- - spellcheck: "The R&D Server now has an explanation of what it does."
diff --git a/html/changelogs/AutoChangeLog-pr-4064.yml b/html/changelogs/AutoChangeLog-pr-4064.yml
deleted file mode 100644
index 90f52d39aa..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4064.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "jammer312"
-delete-after: True
-changes:
- - bugfix: "fixed conjuration spells forgetting about conjured items"
diff --git a/html/changelogs/AutoChangeLog-pr-4066.yml b/html/changelogs/AutoChangeLog-pr-4066.yml
deleted file mode 100644
index 6858021004..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4066.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - code_imp: "Chasm code has been refactored to be more sane."
- - bugfix: "Building lattices over chasms no longer sometimes deletes the chasm."
diff --git a/html/changelogs/AutoChangeLog-pr-4067.yml b/html/changelogs/AutoChangeLog-pr-4067.yml
deleted file mode 100644
index 103a03d08a..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4067.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Space cats will no longer have a smashed helmet when they lay down."
diff --git a/html/changelogs/AutoChangeLog-pr-4069.yml b/html/changelogs/AutoChangeLog-pr-4069.yml
deleted file mode 100644
index c6832bbbf7..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4069.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - admin: "\"ahelp\" chat command can now accept a ticket number as opposed to a ckey"
diff --git a/html/changelogs/AutoChangeLog-pr-4072.yml b/html/changelogs/AutoChangeLog-pr-4072.yml
deleted file mode 100644
index 88296b7a45..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4072.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - code_imp: "Added round id to the status world topic"
diff --git a/html/changelogs/AutoChangeLog-pr-4075.yml b/html/changelogs/AutoChangeLog-pr-4075.yml
deleted file mode 100644
index d627c00d1f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4075.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "GupGup"
-delete-after: True
-changes:
- - bugfix: "Fixes hostile mobs attacking surrounding tiles when trying to attack someone"
diff --git a/html/changelogs/AutoChangeLog-pr-4076.yml b/html/changelogs/AutoChangeLog-pr-4076.yml
deleted file mode 100644
index b40f213dd3..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4076.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - rscadd: "Added two new symptoms: one allows viruses to still work while dead, and allows infection of undead species, and one allows infection of inorganic species (such as plasmapeople or golems)."
diff --git a/html/changelogs/AutoChangeLog-pr-4077.yml b/html/changelogs/AutoChangeLog-pr-4077.yml
deleted file mode 100644
index 56e6ca4c9e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4077.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Aliens in soft-crit will now use the correct sprite."
diff --git a/html/changelogs/AutoChangeLog-pr-4080.yml b/html/changelogs/AutoChangeLog-pr-4080.yml
deleted file mode 100644
index d10288ec03..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4080.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "MrStonedOne and Jordie"
-delete-after: True
-changes:
- - server: "As a late note, serverops be advise that mysql is no longer supported. existing mysql databases will need to be converted to mariadb"
diff --git a/html/changelogs/AutoChangeLog-pr-4084.yml b/html/changelogs/AutoChangeLog-pr-4084.yml
deleted file mode 100644
index ddd147e1e0..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4084.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "The vault in boxstation now has power again."
- - bugfix: "The gravity generator in boxstation now has power again."
- - bugfix: "Various broken decals in boxstation have been fixed."
- - bugfix: "The clown and mime offices no longer have APCs pointing to the wrong areas."
- - rscadd: "Boxstation's secure cell has been readded to security."
diff --git a/html/changelogs/AutoChangeLog-pr-4095.yml b/html/changelogs/AutoChangeLog-pr-4095.yml
deleted file mode 100644
index dd5036cb59..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4095.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - rscdel: "Removed \"console screen\" stock part. Just use glass sheets instead."
diff --git a/html/changelogs/AutoChangeLog-pr-4099.yml b/html/changelogs/AutoChangeLog-pr-4099.yml
deleted file mode 100644
index ac5424fd57..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4099.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - bugfix: "Custom shuttle dockers can no longer place docking regions inside other custom docker regions."
diff --git a/html/changelogs/AutoChangeLog-pr-4100.yml b/html/changelogs/AutoChangeLog-pr-4100.yml
deleted file mode 100644
index e8abc00b9e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4100.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Fix water misters being inappropriately glued to hands in some cases."
diff --git a/html/changelogs/AutoChangeLog-pr-4105.yml b/html/changelogs/AutoChangeLog-pr-4105.yml
deleted file mode 100644
index 1ce922ad64..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4105.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "More Robust Than You"
-delete-after: True
-changes:
- - tweak: "Spessmen are now smart enough to realize you don't need to turn around to pull cigarette butts"
diff --git a/html/changelogs/AutoChangeLog-pr-4106.yml b/html/changelogs/AutoChangeLog-pr-4106.yml
deleted file mode 100644
index 326d296e90..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4106.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Some misplaced decals in the Hotel brig have been corrected."
diff --git a/html/changelogs/AutoChangeLog-pr-4110.yml b/html/changelogs/AutoChangeLog-pr-4110.yml
deleted file mode 100644
index cd94f6dae7..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4110.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CosmicScientist"
-delete-after: True
-changes:
- - bugfix: "bolas are back in tablecrafting!"
diff --git a/html/changelogs/AutoChangeLog-pr-4111.yml b/html/changelogs/AutoChangeLog-pr-4111.yml
deleted file mode 100644
index 1019538b17..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4111.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - bugfix: "Fixes thermite burning hotter than the boiling point of stone"
diff --git a/html/changelogs/AutoChangeLog-pr-4112.yml b/html/changelogs/AutoChangeLog-pr-4112.yml
deleted file mode 100644
index 12412931b6..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4112.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "AIs and cyborgs can interact with unscrewed airlocks and APCs."
diff --git a/html/changelogs/AutoChangeLog-pr-4116.yml b/html/changelogs/AutoChangeLog-pr-4116.yml
deleted file mode 100644
index 877ad76460..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4116.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Dorsisdwarf"
-delete-after: True
-changes:
- - tweak: "Catpeople are now distracted instead of debilitated"
- - rscadd: "Normal cats now go for laser pointers"
diff --git a/html/changelogs/AutoChangeLog-pr-4117.yml b/html/changelogs/AutoChangeLog-pr-4117.yml
deleted file mode 100644
index bb2c70bccc..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4117.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "You can no longer buckle people to roller beds from inside of a locker."
diff --git a/html/changelogs/AutoChangeLog-pr-4121.yml b/html/changelogs/AutoChangeLog-pr-4121.yml
deleted file mode 100644
index a226595420..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4121.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "zennerx"
-delete-after: True
-changes:
- - bugfix: "Zombies don't reanimate with no head!"
diff --git a/html/changelogs/AutoChangeLog-pr-4124.yml b/html/changelogs/AutoChangeLog-pr-4124.yml
deleted file mode 100644
index e568f3e9df..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4124.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "WJohnston"
-delete-after: True
-changes:
- - bugfix: "Fixed a case where items would sometimes be placed underneath racks."
diff --git a/html/changelogs/AutoChangeLog-pr-4125.yml b/html/changelogs/AutoChangeLog-pr-4125.yml
deleted file mode 100644
index a8f5bdbe86..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4125.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - bugfix: "Hopefully fixed mesons granting the ability to hear people through walls."
diff --git a/html/changelogs/AutoChangeLog-pr-4126.yml b/html/changelogs/AutoChangeLog-pr-4126.yml
deleted file mode 100644
index 42689125e8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4126.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Cryo cells can now be properly rotated with a wrench."
diff --git a/html/changelogs/AutoChangeLog-pr-4127.yml b/html/changelogs/AutoChangeLog-pr-4127.yml
deleted file mode 100644
index b9f6abc58d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4127.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "More Robust Than You"
-delete-after: True
-changes:
- - bugfix: "Fixed cult leaders being de-culted upon election if they had a mindshield implant"
diff --git a/html/changelogs/AutoChangeLog-pr-4129.yml b/html/changelogs/AutoChangeLog-pr-4129.yml
deleted file mode 100644
index 16d3765876..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4129.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - rscadd: "You can now make a new tasty traditional treat: butterdogs. Watch out, they're slippery."
diff --git a/html/changelogs/AutoChangeLog-pr-4133.yml b/html/changelogs/AutoChangeLog-pr-4133.yml
deleted file mode 100644
index 2b50fbd4ea..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4133.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - balance: "Viruses' healing symptoms have been reworked!"
- - rscdel: "All existing healing symptoms have been removed in favour of new ones."
- - rscdel: "Weight Even and Weight Gain have been removed, so hunger can be used for balancing in symptoms."
- - rscadd: "Starlight Condensation heals toxin damage if you're in space using starlight as a catalyst. Being up to two tiles away also works, as long as you can still see it, but slower."
- - rscadd: "Toxolysis (level 7) rapidly cleanses all chemicals from the body, with no exception."
- - rscadd: "Cellular Molding heals brute damage depending on your body temperature: the higher the temperature, the faster the healing. Requires above-average temperature to activate, and the speed heavily increases while on fire."
- - rscadd: "Regenerative Coma (level 8) causes the virus to send you into a deep coma when you are heavily damaged (>70 brute+burn damage). While you are unconscious, either from the virus or from other sources, the virus will heal both brute and burn damage fairly quickly. Sleeping also works, but at reduced speed."
- - rscadd: "Tissue Hydration heals burn damage if you are wet (negative fire stacks) or if you have water in your bloodstream."
- - rscadd: "Plasma Fixation (level 8) stabilizes temperature and heals burns while plasma is in your body or while standing in a plasma cloud. Does not protect from the poisoning effects of plasma."
- - rscadd: "Radioactive Resonance gives a mild constant brute and burn healing while irradiated. The healing becomes more intense if you reach higher levels of radiation, but is still less than the alternatives."
- - rscadd: "Metabolic Boost (level 7) doubles the rate at which you process chemicals, good and bad, but also increases hunger tenfold."
diff --git a/html/changelogs/AutoChangeLog-pr-4136.yml b/html/changelogs/AutoChangeLog-pr-4136.yml
deleted file mode 100644
index 0737b28919..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4136.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - rscadd: "New integrated circuit components: list constructors/deconstructors. Useful for building lists and taking them apart."
- - bugfix: "Fixed multiple bugs in integrated circuits UIs, improved overall usability."
diff --git a/html/changelogs/AutoChangeLog-pr-4143.yml b/html/changelogs/AutoChangeLog-pr-4143.yml
deleted file mode 100644
index dc1f281cec..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4143.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - code_imp: "rejiggered botcode a little bit"
diff --git a/html/changelogs/AutoChangeLog-pr-4144.yml b/html/changelogs/AutoChangeLog-pr-4144.yml
deleted file mode 100644
index bcefc8437a..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4144.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "You can make many different types of office and comfy chairs with metal"
- - tweak: "Stack menus use /datum/browser"
diff --git a/html/changelogs/AutoChangeLog-pr-4145.yml b/html/changelogs/AutoChangeLog-pr-4145.yml
deleted file mode 100644
index c7b269b20f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4145.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "improvedname"
-delete-after: True
-changes:
- - tweak: "toolbelts can now carry geiger counters"
diff --git a/html/changelogs/AutoChangeLog-pr-4149.yml b/html/changelogs/AutoChangeLog-pr-4149.yml
deleted file mode 100644
index 909fc3e1b9..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4149.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "JJRcop"
-delete-after: True
-changes:
- - admin: "Fixed the Make space ninja verb."
diff --git a/html/changelogs/AutoChangeLog-pr-4150.yml b/html/changelogs/AutoChangeLog-pr-4150.yml
deleted file mode 100644
index 943af018e5..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4150.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - rscdel: "Mass-spectrometers are removed. Would anyone notice if not for this changelog entry?"
diff --git a/html/changelogs/AutoChangeLog-pr-4152.yml b/html/changelogs/AutoChangeLog-pr-4152.yml
deleted file mode 100644
index df1b1cd09f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4152.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ACCount"
-delete-after: True
-changes:
- - rscdel: "\"Machine prototype\" is removed from the game."
diff --git a/html/changelogs/AutoChangeLog-pr-4155.yml b/html/changelogs/AutoChangeLog-pr-4155.yml
deleted file mode 100644
index 0f762fae2e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4155.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "AI and observer diagnostic huds will now show the astar path of all bots, and Pai bots will be given a visible path to follow when called by the AI."
diff --git a/html/changelogs/AutoChangeLog-pr-4162.yml b/html/changelogs/AutoChangeLog-pr-4162.yml
deleted file mode 100644
index be4968592e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4162.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - tweak: "The sloth no longer suspiciously moves fast when gliding between tiles."
- - balance: "The sloth's movespeed when inhabited by a player has been lowered from once every 1/5 of a second to once every second."
diff --git a/html/changelogs/AutoChangeLog-pr-4170.yml b/html/changelogs/AutoChangeLog-pr-4170.yml
deleted file mode 100644
index f54be6c190..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4170.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ninjanomnom"
-delete-after: True
-changes:
- - tweak: "Reduced the max volume of sm by 1/5th and made the upper bounds only play mid delamination."
diff --git a/html/changelogs/AutoChangeLog-pr-4171.yml b/html/changelogs/AutoChangeLog-pr-4171.yml
deleted file mode 100644
index 612f5ad379..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4171.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "psykzz"
-delete-after: True
-changes:
- - bugfix: "Fixing the broken turbine computer"
diff --git a/html/changelogs/AutoChangeLog-pr-4172.yml b/html/changelogs/AutoChangeLog-pr-4172.yml
deleted file mode 100644
index a2dac53175..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4172.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - tweak: "Damage examinations now include a \"moderate\" classification. Before minor was <30 and severe was anything 30 or above. Now minor is <25, moderate is 25 to <50, and severe is 50+."
diff --git a/html/changelogs/AutoChangeLog-pr-4175.yml b/html/changelogs/AutoChangeLog-pr-4175.yml
deleted file mode 100644
index 1eed117c43..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4175.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - imageadd: "Construct shells have a new animated sprite"
diff --git a/html/changelogs/AutoChangeLog-pr-4176.yml b/html/changelogs/AutoChangeLog-pr-4176.yml
deleted file mode 100644
index 76ccbf0925..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4176.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "Toriate"
-delete-after: True
-changes:
- - rscadd: "Added Lavaknights, a new ghost role of cat people in knight armor."
- - rscadd: "Added Hypereutactic blades, NEBs on steroids."
- - tweak: "Made NEBs alt click to recolor
-wip: Added lavaknight spawners. Someone else needs to add it in to a map or ruin properly."
- - imageadd: "added sprites for hypereutactic blades"
diff --git a/html/changelogs/AutoChangeLog-pr-4177.yml b/html/changelogs/AutoChangeLog-pr-4177.yml
deleted file mode 100644
index f6e65ed068..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4177.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - balance: "Clockwork magicks will now prevent Bags of Holding from being combined on Reebe."
diff --git a/html/changelogs/AutoChangeLog-pr-4180.yml b/html/changelogs/AutoChangeLog-pr-4180.yml
deleted file mode 100644
index fb6248b653..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4180.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - bugfix: "Flashes will now burn out AFTER flashing when they fail instead of being a ticking time bomb that waits to screw you over on your next attempt."
diff --git a/html/changelogs/AutoChangeLog-pr-4182.yml b/html/changelogs/AutoChangeLog-pr-4182.yml
deleted file mode 100644
index 6d0c949e11..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4182.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Frozenguy5"
-delete-after: True
-changes:
- - tweak: "The Particle Accelerator's wires can no longer be EMP'd"
diff --git a/html/changelogs/AutoChangeLog-pr-4184.yml b/html/changelogs/AutoChangeLog-pr-4184.yml
deleted file mode 100644
index f97a70a206..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4184.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CosmicScientist"
-delete-after: True
-changes:
- - rscadd: "You can make plushies kiss one another!"
diff --git a/html/changelogs/AutoChangeLog-pr-4186.yml b/html/changelogs/AutoChangeLog-pr-4186.yml
deleted file mode 100644
index 86951d81f1..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4186.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - code_imp: "Cleans up some loc assignments"
diff --git a/html/changelogs/AutoChangeLog-pr-4191.yml b/html/changelogs/AutoChangeLog-pr-4191.yml
deleted file mode 100644
index 5904f70b86..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4191.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "BeeSting12"
-delete-after: True
-changes:
- - spellcheck: "Occupand ---> Occupant on opened cryogenic pods."
- - spellcheck: "Cyrogenic ---> Cryogenic on opened cryogenic pods."
diff --git a/html/changelogs/AutoChangeLog-pr-4196.yml b/html/changelogs/AutoChangeLog-pr-4196.yml
deleted file mode 100644
index 49ab9fdbd9..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4196.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "zennerx"
-delete-after: True
-changes:
- - spellcheck: "fixed some typos in the weapon firing mechanism description"
diff --git a/html/changelogs/AutoChangeLog-pr-4198.yml b/html/changelogs/AutoChangeLog-pr-4198.yml
deleted file mode 100644
index 93e2f2212a..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4198.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - rscadd: "Light fixtures now turn an ominous, dim red color when they lose power, and draw from an internal power cell to maintain it until either the cell dies (usually after 10 minutes) or power is restored."
- - rscadd: "You can override emergency light functionality from an APC. You can also click on individual lights as a cyborg or AI to override them individually. Traitor AIs also have a new ability that disables emergency lights across the entire station."
diff --git a/html/changelogs/AutoChangeLog-pr-4200.yml b/html/changelogs/AutoChangeLog-pr-4200.yml
deleted file mode 100644
index a2321590c7..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4200.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "You can now lay (buckle!) yourself to a bed to avoid being burnt to a crisp during \"the floor is lava\" event."
diff --git a/html/changelogs/AutoChangeLog-pr-4201.yml b/html/changelogs/AutoChangeLog-pr-4201.yml
deleted file mode 100644
index 127a8b26ed..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4201.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - tweak: "Igniting plasma statues no longer ignores ignition temperature and only creates as much plasma as was used in its creation."
diff --git a/html/changelogs/AutoChangeLog-pr-4207.yml b/html/changelogs/AutoChangeLog-pr-4207.yml
deleted file mode 100644
index 692dca99ed..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4207.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - bugfix: "You now need fuel in your welder to repair mechs."
diff --git a/html/changelogs/AutoChangeLog-pr-4209.yml b/html/changelogs/AutoChangeLog-pr-4209.yml
deleted file mode 100644
index ee1613d170..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4209.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "You can now record and replay holopad messages using holodisks."
- - rscadd: "Holodisks are printable in autolathes."
diff --git a/html/changelogs/AutoChangeLog-pr-4215.yml b/html/changelogs/AutoChangeLog-pr-4215.yml
deleted file mode 100644
index 6e4fe16805..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4215.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dax Dupont"
-delete-after: True
-changes:
- - rscadd: "Nanotrasen is happy to announce the pinnacle in plasma research! The Disco Inferno shuttle design is the result of decades of plasma research. Burn, baby, burn!"
diff --git a/html/changelogs/AutoChangeLog-pr-4216.yml b/html/changelogs/AutoChangeLog-pr-4216.yml
deleted file mode 100644
index 8b39d4aa94..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4216.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - tweak: "Stethoscopes now inform the user if the target can be defibrillated; the user will hear a \"faint, fluttery pulse.\""
diff --git a/html/changelogs/AutoChangeLog-pr-4218.yml b/html/changelogs/AutoChangeLog-pr-4218.yml
deleted file mode 100644
index 334c16e021..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4218.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - spellcheck: "Energy values are now measured in joules. What was previously 1 unit is now 1 kJ."
diff --git a/html/changelogs/AutoChangeLog-pr-4220.yml b/html/changelogs/AutoChangeLog-pr-4220.yml
deleted file mode 100644
index 7287bee043..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4220.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - sounddel: "Reduced the volume of showers"
diff --git a/html/changelogs/AutoChangeLog-pr-4234.yml b/html/changelogs/AutoChangeLog-pr-4234.yml
deleted file mode 100644
index 3310bdb750..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4234.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Syndicate uplink implants now work again."
diff --git a/html/changelogs/AutoChangeLog-pr-4235.yml b/html/changelogs/AutoChangeLog-pr-4235.yml
deleted file mode 100644
index 35197c0edf..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4235.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - rscdel: "Reverted changes in 3d sound system that tripled the distance that sound would carry."
diff --git a/html/changelogs/AutoChangeLog-pr-4240.yml b/html/changelogs/AutoChangeLog-pr-4240.yml
deleted file mode 100644
index bb77fc8cd8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4240.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "coiax"
-delete-after: True
-changes:
- - rscadd: "Quiet areas of libraries on station have now been equipped with a
-vending machine containing suitable recreational activities."
diff --git a/html/changelogs/AutoChangeLog-pr-4241.yml b/html/changelogs/AutoChangeLog-pr-4241.yml
deleted file mode 100644
index 77a17bb5b1..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4241.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "coiax"
-delete-after: True
-changes:
- - rscadd: "The drone dispenser on Metastation has been moved to the
-maintenance by Robotics."
diff --git a/html/changelogs/AutoChangeLog-pr-4243.yml b/html/changelogs/AutoChangeLog-pr-4243.yml
deleted file mode 100644
index 4971528f94..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4243.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Revenant Defile ability"
-delete-after: True
-changes:
- - bugfix: "Revenant's Defile now removes salt piles"
diff --git a/html/changelogs/AutoChangeLog-pr-4244.yml b/html/changelogs/AutoChangeLog-pr-4244.yml
deleted file mode 100644
index d1081a8801..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4244.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dax Dupont & Alek2ander"
-delete-after: True
-changes:
- - tweak: "Binary chat messages been made more visible."
diff --git a/html/changelogs/AutoChangeLog-pr-4246.yml b/html/changelogs/AutoChangeLog-pr-4246.yml
deleted file mode 100644
index 555f050d39..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4246.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - rscadd: "Brain damage has been completely reworked!
-remove: Brain damage now no longer simply makes you dumb. Although most of its effects have been shifted into a brain trauma."
- - rscadd: "Every time you take brain damage, there's a chance you'll suffer a brain trauma. There are many variations of brain traumas, split in mild, severe, and special."
- - rscadd: "Mild brain traumas are the easiest to get, can be lightly to moderately annoying, and can be cured with mannitol and time."
- - rscadd: "Severe brain traumas are much rarer and require extensive brain damage before you have a chance to get them; they are usually very debilitating. Unlike mild traumas, they require surgery to cure. A new surgery procedure has been added for this, the aptly named Brain Surgery. It can also heal minor traumas."
- - rscadd: "Special brain traumas are rarely gained in place of Severe traumas: they are either complex or beneficial.
-However, they are also even easier to cure than mild traumas, which means that keeping these will usually mean keeping a mild trauma along with it."
- - rscadd: "Mobs can only naturally have one mild trauma and one severe or special trauma."
- - balance: "Brain damage will now kill and ruin the brain if it goes above 200. If it somehow goes above 400, the brain will melt and be destroyed completely."
- - balance: "Many brain-damaging effects have been given a damage cap, making them non-lethal."
- - rscdel: "The Unintelligible mutation has been removed and made into a brain trauma."
- - rscdel: "Brain damage no longer makes using machines a living hell."
- - rscadd: "Abductors give minor traumas to people they experiment on."
diff --git a/html/changelogs/AutoChangeLog-pr-4250.yml b/html/changelogs/AutoChangeLog-pr-4250.yml
deleted file mode 100644
index 7539b323a8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4250.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - rscadd: "Added the Eminence role to clockcult! Players can elect themselves or ghosts as the Eminence from the eminence spire structure on Reebe."
- - rscadd: "The Eminence is incorporeal and invisible, and directs the entire cult. Anything they say is heard over the Hierophant network, and they can issue commands by middle-clicking themselves or different turfs."
- - rscadd: "The Eminence also has a single-use mass recall that warps all servants to the Ark chamber."
- - rscadd: "Added traps, triggers, and brass filaments to link them. They can all be constructed from brass sheets, and do different things and trigger in different ways. Current traps include the brass skewer and steam vent, and triggers include the pressure sensor, lever, and repeater."
- - rscadd: "The Eminence can activate trap triggers by clicking on them!"
- - rscadd: "Servants can deconstruct traps instantly with a wrench."
- - rscdel: "Mending Mantra has been removed."
- - tweak: "Clockwork scriptures have been recolored and sorted based on their functions; yellow scriptures are for construction, red for offense, blue for defense, and purple for niche."
- - balance: "Servants now spawn with a PDA and black shoes to make disguise more feasible."
- - balance: "The Eminence can superheat up to 20 clockwork walls at a time. Superheated walls are immune to hulk and mech punches, but can still be broken conventionally."
- - balance: "Clockwork walls are slightly faster to build before the Ark activates, taking an extra second less."
- - bugfix: "Poly no longer continually undergoes binary fission when Ratvar is in range."
- - code_imp: "The global records alert for servants will no longer display info that doesn't affect them since the rework."
diff --git a/html/changelogs/AutoChangeLog-pr-4254.yml b/html/changelogs/AutoChangeLog-pr-4254.yml
deleted file mode 100644
index cdfa4c7c0b..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4254.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - bugfix: "Games vending machines can now properly be rebuilt."
- - bugfix: "Games vending machines can now be refilled via supply crates."
- - rscadd: "Games Supply Crates have been added to the cargo console."
diff --git a/html/changelogs/AutoChangeLog-pr-4259.yml b/html/changelogs/AutoChangeLog-pr-4259.yml
deleted file mode 100644
index 7536cfa7a6..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4259.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "Action buttons now remember positions where you locked."
- - tweak: "Now locking action buttons prevents them from being reset."
diff --git a/html/changelogs/AutoChangeLog-pr-4260.yml b/html/changelogs/AutoChangeLog-pr-4260.yml
deleted file mode 100644
index 1880edb973..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4260.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - rscadd: "You can now make pet carriers from the autolathe, to carry around chef meat and other small animals without having to drag them. The HoP, captain, and CMO also start with carriers in their lockers for their pets."
diff --git a/html/changelogs/AutoChangeLog-pr-4261.yml b/html/changelogs/AutoChangeLog-pr-4261.yml
deleted file mode 100644
index d7b0bcebf5..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4261.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Fox McCloud"
-delete-after: True
-changes:
- - tweak: "Slime blueprints can now make an area compatible with Xenobio consoles, regardless of the name of the new area"
diff --git a/html/changelogs/AutoChangeLog-pr-4264.yml b/html/changelogs/AutoChangeLog-pr-4264.yml
deleted file mode 100644
index 3a3b5c1f42..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4264.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "You now can get a medal for wasting hours talking to the secret debug tile."
- - bugfix: "Fixed runtime for the tile when poly's speech file doesn't exist."
diff --git a/html/changelogs/AutoChangeLog-pr-4266.yml b/html/changelogs/AutoChangeLog-pr-4266.yml
deleted file mode 100644
index e66348d5b4..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4266.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Fixed the camera failure, race swap, cursed items, and imposter wizard random events"
- - tweak: "The cursed items event no longer nullspaces items"
diff --git a/html/changelogs/AutoChangeLog-pr-4267.yml b/html/changelogs/AutoChangeLog-pr-4267.yml
deleted file mode 100644
index 97e3a17b9a..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4267.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "MrDoomBringer"
-delete-after: True
-changes:
- - imageadd: "All stations have been outfitted with brand new Smoke Machines! They have nicer sprites now!"
diff --git a/html/changelogs/AutoChangeLog-pr-4270.yml b/html/changelogs/AutoChangeLog-pr-4270.yml
deleted file mode 100644
index 06c99c93ee..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4270.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - config: "The default view range can now be defined in the config. The default is 15x15, which is simplified to 7 by BYOND. For reference, Goonstation's widescreen range is 21x15. Do note that changing this value will affect the title screen. The title screen images and the title screen area on the Centcom z-level will have to be updated if the default view range is changed."
diff --git a/html/changelogs/AutoChangeLog-pr-4272.yml b/html/changelogs/AutoChangeLog-pr-4272.yml
deleted file mode 100644
index 8bedafab45..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4272.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "coiax"
-delete-after: True
-changes:
- - rscadd: "The drone dispenser on Box Station has been moved from the Testing
-Lab to the Morgue/Robotics maintenance tunnel."
diff --git a/html/changelogs/AutoChangeLog-pr-4274.yml b/html/changelogs/AutoChangeLog-pr-4274.yml
deleted file mode 100644
index b1915f089b..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4274.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dax Dupont"
-delete-after: True
-changes:
- - bugfix: "Fixed observer chat flavor of silicon chat."
diff --git a/html/changelogs/AutoChangeLog-pr-4279.yml b/html/changelogs/AutoChangeLog-pr-4279.yml
deleted file mode 100644
index cddc887068..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4279.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dax Dupont"
-delete-after: True
-changes:
- - bugfix: "Grilles now no longer revert to a pre-broken icon state when you hit them after they broke."
diff --git a/html/changelogs/AutoChangeLog-pr-4283.yml b/html/changelogs/AutoChangeLog-pr-4283.yml
deleted file mode 100644
index a96b866609..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4283.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - tweak: "The pAI software interface is now accessible via an action button."
diff --git a/html/changelogs/AutoChangeLog-pr-4286.yml b/html/changelogs/AutoChangeLog-pr-4286.yml
deleted file mode 100644
index 83ede8f21d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4286.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "External airlocks of the mining base and gulag are now cycle-linked."
diff --git a/html/changelogs/AutoChangeLog-pr-4287.yml b/html/changelogs/AutoChangeLog-pr-4287.yml
deleted file mode 100644
index 55bbeb05c2..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4287.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - tweak: "Instead of activating randomly on speech, Godwoken Syndrome randomly grants inspiration, causing the next message to be a Voice of God."
diff --git a/html/changelogs/AutoChangeLog-pr-4289.yml b/html/changelogs/AutoChangeLog-pr-4289.yml
deleted file mode 100644
index d0da6e0f58..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4289.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "Nanotrasen would like to remind crewmembers and especially medical personnel to stand clear of cadeavers before applying a defibrillator shock. (You get shocked if you're pulling/grabbing someone being defibbed.)"
- - tweak: "defib shock/charge sounds upped from 50% to 75%."
diff --git a/html/changelogs/AutoChangeLog-pr-4290.yml b/html/changelogs/AutoChangeLog-pr-4290.yml
deleted file mode 100644
index a7a034433f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4290.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Swindly"
-delete-after: True
-changes:
- - rscadd: "You can kill yourself with a few more items."
diff --git a/html/changelogs/AutoChangeLog-pr-4292.yml b/html/changelogs/AutoChangeLog-pr-4292.yml
deleted file mode 100644
index 14dda4b668..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4292.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - tweak: "Flickering lights will now actually flicker and not go between emergency lights and normal lighting."
diff --git a/html/changelogs/AutoChangeLog-pr-4296.yml b/html/changelogs/AutoChangeLog-pr-4296.yml
deleted file mode 100644
index 1e87a3fdaf..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4296.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - bugfix: "Emergency lights no longer stay on forever in some cases."
diff --git a/html/changelogs/AutoChangeLog-pr-4305.yml b/html/changelogs/AutoChangeLog-pr-4305.yml
deleted file mode 100644
index d6ae57f28d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4305.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "The MULEbots that the station starts with now show their ID numbers."
diff --git a/html/changelogs/AutoChangeLog-pr-4306.yml b/html/changelogs/AutoChangeLog-pr-4306.yml
deleted file mode 100644
index 0a6361f11d..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4306.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Improvedname"
-delete-after: True
-changes:
- - tweak: "cats now drop their ears and tail when butchered."
diff --git a/html/changelogs/AutoChangeLog-pr-4308.yml b/html/changelogs/AutoChangeLog-pr-4308.yml
deleted file mode 100644
index 5f277e0e53..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4308.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Booze-o-mats have beer"
diff --git a/html/changelogs/AutoChangeLog-pr-4312.yml b/html/changelogs/AutoChangeLog-pr-4312.yml
deleted file mode 100644
index 8c05f5d79e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4312.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - bugfix: "Modes not in rotation have had their \"false report\" weights for the Command Report standardized"
diff --git a/html/changelogs/AutoChangeLog-pr-4313.yml b/html/changelogs/AutoChangeLog-pr-4313.yml
deleted file mode 100644
index a1124c765a..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4313.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - tweak: "The white ship navigation computer now takes 10 seconds to designate a landing spot, and users can no longer see the syndicate shuttle or its custom landing location. If the white ship landing location would intersect the syndicate shuttle or its landing location, it will fail after the 10 seconds have elapsed."
diff --git a/html/changelogs/AutoChangeLog-pr-4314.yml b/html/changelogs/AutoChangeLog-pr-4314.yml
deleted file mode 100644
index e471271981..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4314.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "flightsuits should no longer disappear when you take them off involuntarily"
- - bugfix: "beam rifles actually fire striaght now"
- - bugfix: "click catchers now actually work"
- - bugfix: "you no longer see space in areas you normally can't see, instead of black. in reality you can still see space but it's faint enough that you can't tell so I'll say I fixed it."
diff --git a/html/changelogs/AutoChangeLog-pr-4315.yml b/html/changelogs/AutoChangeLog-pr-4315.yml
deleted file mode 100644
index a021f0ccc4..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4315.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "Added MANY new types of airlock assembly that can be built with metal. Use metal in hand to see the new airlock assembly recipes."
- - rscadd: "Added new airlock types to the RCD and airlock painter"
- - rscadd: "Vault door assemblies can be built with 8 plasteel, high security assemblies with 6 plasteel"
- - rscadd: "Glass mineral airlocks are finally constructible. Use glass and mineral sheets on an airlock assembly in any order to make them."
- - tweak: "Glass and mineral sheets are now able to be welded out of door assemblies rather than having to deconstruct the whole thing"
- - rscdel: "Airlock painter no longer works on airlock assemblies (still works on airlocks)"
- - bugfix: "Titanium airlocks no longer have any missing overlays"
diff --git a/html/changelogs/AutoChangeLog-pr-4319.yml b/html/changelogs/AutoChangeLog-pr-4319.yml
deleted file mode 100644
index 851d5f12bc..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4319.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Frozenguy5"
-delete-after: True
-changes:
- - balance: "Some hardsuits have had their melee, fire and rad armor ratings tweaked."
diff --git a/html/changelogs/AutoChangeLog-pr-4331.yml b/html/changelogs/AutoChangeLog-pr-4331.yml
deleted file mode 100644
index 04532aa4a8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4331.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Swindly"
-delete-after: True
-changes:
- - bugfix: "Swarmers can no longer deconstruct objects with living things in them."
diff --git a/html/changelogs/AutoChangeLog-pr-4338.yml b/html/changelogs/AutoChangeLog-pr-4338.yml
deleted file mode 100644
index da4fde1e23..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4338.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "You can now print telecomms equipment again."
diff --git a/html/changelogs/AutoChangeLog-pr-4339.yml b/html/changelogs/AutoChangeLog-pr-4339.yml
deleted file mode 100644
index bf7c49d3e8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4339.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - rscadd: "The blood cult revive rune will now replace the souls of braindead or inactive cultists/constructs when properly invoked. These \"revivals\" will not count toward the revive limit."
- - rscadd: "The clock cult healing rune will now replace the souls of braindead or inactive cultists/constructs when left atop the rune. These \"revivals\" will not drain the rune's energy."
diff --git a/html/changelogs/AutoChangeLog-pr-4340.yml b/html/changelogs/AutoChangeLog-pr-4340.yml
deleted file mode 100644
index 6992dc2fd8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4340.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "fixes mobs not metabolizing their reagents"
diff --git a/html/changelogs/AutoChangeLog-pr-4341.yml b/html/changelogs/AutoChangeLog-pr-4341.yml
deleted file mode 100644
index e276d3bcb8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4341.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Mark9013100"
-delete-after: True
-changes:
- - rscadd: "Medical Wardrobes now contain an additional standard and EMT labcoat."
diff --git a/html/changelogs/AutoChangeLog-pr-4344.yml b/html/changelogs/AutoChangeLog-pr-4344.yml
deleted file mode 100644
index a020f7882f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4344.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "Donator items use the proper sprites when worn again."
diff --git a/html/changelogs/AutoChangeLog-pr-4346.yml b/html/changelogs/AutoChangeLog-pr-4346.yml
deleted file mode 100644
index d03954b91f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4346.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "The standard-issue PDAs are now holographic again."
diff --git a/html/changelogs/AutoChangeLog-pr-4349.yml b/html/changelogs/AutoChangeLog-pr-4349.yml
deleted file mode 100644
index 3f1bb91439..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4349.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Nonstandard power cells found in MULEbots, cyborgs, and elsewhere now have the correct description."
diff --git a/html/changelogs/AutoChangeLog-pr-4350.yml b/html/changelogs/AutoChangeLog-pr-4350.yml
deleted file mode 100644
index 2116fa9fd5..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4350.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - bugfix: "Genetics will no longer have a random block completely disappear each round"
diff --git a/html/changelogs/AutoChangeLog-pr-4351.yml b/html/changelogs/AutoChangeLog-pr-4351.yml
deleted file mode 100644
index bc5cabdb55..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4351.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - bugfix: "glass shards and bananium floors no longer make a sound when \"walked\" over by a camera or a ghost"
diff --git a/html/changelogs/AutoChangeLog-pr-4353.yml b/html/changelogs/AutoChangeLog-pr-4353.yml
deleted file mode 100644
index 6fcf3e2ebe..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4353.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "deathride58"
-delete-after: True
-changes:
- - rscadd: "All maps now have departmental lathes as they're supposed to."
- - rscadd: "Pubbystation and Omegastation now have kinkmates! This does not add them back to the rotation, though. Tell Jay to re-enable Pubby and Omega in the server's config."
- - rscadd: "Omegastation's dorms now have bolt buttons."
- - bugfix: "The table in the back of Boxstation's maint bar gambling area will no longer throw people around."
diff --git a/html/changelogs/AutoChangeLog-pr-4354.yml b/html/changelogs/AutoChangeLog-pr-4354.yml
deleted file mode 100644
index e9aa1f0f2b..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4354.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - code_imp: "Tidied up some loc assignments"
diff --git a/html/changelogs/AutoChangeLog-pr-4359.yml b/html/changelogs/AutoChangeLog-pr-4359.yml
deleted file mode 100644
index 6679e4b920..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4359.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - server: "Added new admin flag, AUTOLOGIN, to control if admins start with admin powers. this defaults to on, and can be removed with -AUTOLOGIN"
- - admin: "Admins with +PERMISSION may now deadmin or readmin other admins via the permission panel."
diff --git a/html/changelogs/AutoChangeLog-pr-4361.yml b/html/changelogs/AutoChangeLog-pr-4361.yml
deleted file mode 100644
index 140a9a4fe3..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4361.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Shuttles now place hyperspace ripples where they are about to land again."
diff --git a/html/changelogs/AutoChangeLog-pr-4363.yml b/html/changelogs/AutoChangeLog-pr-4363.yml
deleted file mode 100644
index fda81eb42b..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4363.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "JStheguy"
-delete-after: True
-changes:
- - rscadd: "Added 10 new assembly designs to the integrated circuit printer, the difference from current designs is purely aesthetics."
- - imageadd: "Added the icons for said new assembly designs to electronic_setups.dmi, changed the current electronic mechanism and electronic machine sprites."
diff --git a/html/changelogs/AutoChangeLog-pr-4365.yml b/html/changelogs/AutoChangeLog-pr-4365.yml
deleted file mode 100644
index 165bb4d0df..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4365.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Epoc"
-delete-after: True
-changes:
- - bugfix: "Adds Cybernetic Lungs to the Cyber Organs research node"
diff --git a/html/changelogs/AutoChangeLog-pr-4372.yml b/html/changelogs/AutoChangeLog-pr-4372.yml
deleted file mode 100644
index 7c1aa4b97c..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4372.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "ShizCalev"
-delete-after: True
-changes:
- - soundadd: "Revamped gun dry-firing sounds."
- - tweak: "Everyone around you will now hear when your gun goes click. You don't want to hear click when you want to hear bang!"
diff --git a/html/changelogs/AutoChangeLog-pr-4375.yml b/html/changelogs/AutoChangeLog-pr-4375.yml
deleted file mode 100644
index 2cf7f4c721..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4375.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - code_imp: "fixes the remaining loc assignments"
diff --git a/html/changelogs/AutoChangeLog-pr-4377.yml b/html/changelogs/AutoChangeLog-pr-4377.yml
deleted file mode 100644
index 5234e24f49..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4377.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - rscadd: "Grinding runed metal and brass now produces iron/blood and iron/teslium, respectively."
- - balance: "As part of some code-side improvements, the amount of reagents you get from grinding some objects might be slightly different."
- - bugfix: "Some grinding recipes that didn't work, like dead mice and glowsticks, now do."
- - bugfix: "All-In-One grinders now correctly grind up everything, instead of one thing at a time."
diff --git a/html/changelogs/AutoChangeLog-pr-4378.yml b/html/changelogs/AutoChangeLog-pr-4378.yml
deleted file mode 100644
index 22ea638655..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4378.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - imageadd: "Closet sprites changed."
diff --git a/html/changelogs/AutoChangeLog-pr-4382.yml b/html/changelogs/AutoChangeLog-pr-4382.yml
deleted file mode 100644
index 64568eb274..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4382.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - config: "Added \"$include\" directives to config files. These are recursive. Only config.txt will be default loaded if they are specified inside it"
diff --git a/html/changelogs/AutoChangeLog-pr-4383.yml b/html/changelogs/AutoChangeLog-pr-4383.yml
deleted file mode 100644
index cf9c743a03..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4383.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Naksu"
-delete-after: True
-changes:
- - code_imp: "Preliminary work on tracking cliented living mobs across Z-levels to facilitate mob AI changes later"
diff --git a/html/changelogs/AutoChangeLog-pr-4384.yml b/html/changelogs/AutoChangeLog-pr-4384.yml
deleted file mode 100644
index d7f2f90350..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4384.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "EtheoBoxxman"
-delete-after: True
-changes:
- - rscdel: "Removed chasm that spawns on killing ash walker tendril"
diff --git a/html/changelogs/AutoChangeLog-pr-4389.yml b/html/changelogs/AutoChangeLog-pr-4389.yml
deleted file mode 100644
index 36f17b95de..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4389.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Toriate"
-delete-after: True
-changes:
- - tweak: "NEBs now consistently alt click to recolor"
diff --git a/html/changelogs/AutoChangeLog-pr-4390.yml b/html/changelogs/AutoChangeLog-pr-4390.yml
deleted file mode 100644
index 89d3683a34..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4390.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "AverageJoe82"
-delete-after: True
-changes:
- - rscadd: "drones now have night vision"
- - rscdel: "drones no longer have lights"
diff --git a/html/changelogs/AutoChangeLog-pr-4394.yml b/html/changelogs/AutoChangeLog-pr-4394.yml
deleted file mode 100644
index 68d57a2d11..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4394.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "The shuttle will no longer be autocalled if the round has already ended."
diff --git a/html/changelogs/AutoChangeLog-pr-4416.yml b/html/changelogs/AutoChangeLog-pr-4416.yml
deleted file mode 100644
index 543fe52edd..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4416.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Robustin"
-delete-after: True
-changes:
- - bugfix: "The wizard event \"race swap\" should now stick to \"safer\" species."
diff --git a/html/changelogs/AutoChangeLog-pr-4417.yml b/html/changelogs/AutoChangeLog-pr-4417.yml
deleted file mode 100644
index 46b7019353..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4417.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xhuis"
-delete-after: True
-changes:
- - bugfix: "Clockcult power alerts will no longer show outside of the clockcult gamemode (they could be triggered by scarabs.)"
diff --git a/html/changelogs/AutoChangeLog-pr-4420.yml b/html/changelogs/AutoChangeLog-pr-4420.yml
deleted file mode 100644
index 305d701c7f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4420.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - rscadd: "A few new traumas have been added."
- - balance: "Thresholds to get brain traumas have been lowered, as they currently pretty much only trigger if you intentionally chug impedrezene."
- - tweak: "Melee head hits deal minor brain damage. Crits still do a significant amount."
- - tweak: "Nuke Op implants no longer trigger on deathgasp. (They still explode on death)"
- - tweak: "You'll now receive messages when crossing certain brain damage thresholds."
- - tweak: "Split Personalities are instructed not to suicide while in control."
- - tweak: "Godwoken Syndrome now randomly sends Voice of God commands, instead of being controllable."
diff --git a/html/changelogs/AutoChangeLog-pr-4437.yml b/html/changelogs/AutoChangeLog-pr-4437.yml
deleted file mode 100644
index 9b11b0912e..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4437.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "nicbn"
-delete-after: True
-changes:
- - bugfix: "Now the chem smoke machine uses stock parts for volume and range."
diff --git a/html/changelogs/AutoChangeLog-pr-4442.yml b/html/changelogs/AutoChangeLog-pr-4442.yml
deleted file mode 100644
index e480e91419..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4442.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - rscadd: "Abductors can now see if people already have glands! Never worry about abducting the same guy twice again."
- - rscadd: "Added the Mind Interface Device to the abductor shop for 2 Credits. Only scientists can use it."
- - rscadd: "The MID has two modes: Transmit and Control."
- - rscadd: "Transmit will allow you to send a message anytime, anywhere to the mind of a target of your choice, regardless of language barriers. The message will be anonymous, but abductor-like."
- - rscadd: "Control allows you to give a temporary directive to a target with an implanted gland, that they MUST follow. Duration and amount of uses varies by gland type. When a gland is spent, it will no longer respond to Control signals. The target forgets ever receiving the objective when the duration ends."
diff --git a/html/changelogs/AutoChangeLog-pr-4445.yml b/html/changelogs/AutoChangeLog-pr-4445.yml
deleted file mode 100644
index 6dd7a7e486..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4445.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - bugfix: "Fixed captain's PDA showing unusable Toggle Remote Door menu option"
diff --git a/html/changelogs/AutoChangeLog-pr-4453.yml b/html/changelogs/AutoChangeLog-pr-4453.yml
deleted file mode 100644
index 24bce9c510..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4453.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "coiax"
-delete-after: True
-changes:
- - rscadd: "A changeling will learn all languages from anyone they absorb."
diff --git a/html/changelogs/AutoChangeLog-pr-4458.yml b/html/changelogs/AutoChangeLog-pr-4458.yml
deleted file mode 100644
index 4e51890691..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4458.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - tweak: "The Disease Outbreak event now can generate random advanced viruses, with more symptoms and higher level as round time goes on."
diff --git a/html/changelogs/AutoChangeLog-pr-4464.yml b/html/changelogs/AutoChangeLog-pr-4464.yml
deleted file mode 100644
index 17f7d8fc07..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4464.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CitadelStationBot"
-delete-after: True
-changes:
- - rscadd: "You can enforce no smoking zones with a disarm aimed at the smokers mouth."
diff --git a/html/changelogs/AutoChangeLog-pr-4467.yml b/html/changelogs/AutoChangeLog-pr-4467.yml
deleted file mode 100644
index ae009bf26f..0000000000
--- a/html/changelogs/AutoChangeLog-pr-4467.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "improvedname"
-delete-after: True
-changes:
- - bugfix: "Corrects 357. speedloader in the autolathe"
diff --git a/html/changelogs/AutoChangeLog-pr-4491.yml b/html/changelogs/AutoChangeLog-pr-4491.yml
new file mode 100644
index 0000000000..3076537362
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4491.yml
@@ -0,0 +1,4 @@
+author: "Kor"
+delete-after: True
+changes:
+ - rscadd: "During Christmas you will be able to click on the tree in the Chapel to receive one present per round. That present can contain any item in the game."
diff --git a/html/changelogs/AutoChangeLog-pr-4504.yml b/html/changelogs/AutoChangeLog-pr-4504.yml
new file mode 100644
index 0000000000..7da90cb88b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4504.yml
@@ -0,0 +1,4 @@
+author: "Naksu"
+delete-after: True
+changes:
+ - bugfix: "frying oil actually works"
diff --git a/icons/obj/flora/pinetrees.dmi b/icons/obj/flora/pinetrees.dmi
index e7fa58cb1a..a68e0388b0 100644
Binary files a/icons/obj/flora/pinetrees.dmi and b/icons/obj/flora/pinetrees.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index e7d7919ad7..aadf2bf1b8 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -108,6 +108,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"
@@ -345,9 +346,9 @@
#include "code\datums\components\caltrop.dm"
#include "code\datums\components\chasm.dm"
#include "code\datums\components\decal.dm"
-#include "code\datums\components\knockoff.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm"
+#include "code\datums\components\knockoff.dm"
#include "code\datums\components\material_container.dm"
#include "code\datums\components\ntnet_interface.dm"
#include "code\datums\components\paintable.dm"
@@ -491,6 +492,7 @@
#include "code\game\gamemodes\antag_hud.dm"
#include "code\game\gamemodes\antag_spawner.dm"
#include "code\game\gamemodes\antag_spawner_cit.dm"
+#include "code\game\gamemodes\antag_team.dm"
#include "code\game\gamemodes\cit_objectives.dm"
#include "code\game\gamemodes\events.dm"
#include "code\game\gamemodes\game_mode.dm"
@@ -1307,6 +1309,7 @@
#include "code\modules\client\client_defines.dm"
#include "code\modules\client\client_procs.dm"
#include "code\modules\client\message.dm"
+#include "code\modules\client\player_details.dm"
#include "code\modules\client\preferences.dm"
#include "code\modules\client\preferences_savefile.dm"
#include "code\modules\client\preferences_toggles.dm"
diff --git a/tools/Runtime Condenser/Main.cpp b/tools/Runtime Condenser/Main.cpp
index 732318269b..3f8678992b 100644
--- a/tools/Runtime Condenser/Main.cpp
+++ b/tools/Runtime Condenser/Main.cpp
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
/* Runtime Condenser by Nodrak
* Cleaned up and refactored by MrStonedOne
* This will sum up identical runtimes into one, giving a total of how many times it occured. The first occurance
@@ -387,3 +388,421 @@ int main() {
return 0;
}
+=======
+/* Runtime Condenser by Nodrak
+ * Cleaned up and refactored by MrStonedOne
+ * This will sum up identical runtimes into one, giving a total of how many times it occured. The first occurance
+ * of the runtime will log the source, usr and src, the rest will just add to the total. Infinite loops will
+ * also be caught and displayed (if any) above the list of runtimes.
+ *
+ * How to use:
+ * 1) Copy and paste your list of runtimes from Dream Daemon into input.exe
+ * 2) Run RuntimeCondenser.exe
+ * 3) Open output.txt for a condensed report of the runtimes
+ *
+ * How to compile:
+ * Requires visual c++ compiler 2012 or any linux compiler with c++11 support.
+ * Windows:
+ * Normal: cl.exe /EHsc /Ox /Qpar Main.cpp
+ * Debug: cl.exe /EHsc /Zi Main.cpp
+ * Linux:
+ * Normal: g++ -O3 -std=c++11 Main.cpp -o rc
+ * Debug: g++ -g -Og -std=c++11 Main.cpp -o rc
+ * Any Compile errors most likely indicate lack of c++11 support. Google how to upgrade or nag coderbus for help..
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define PROGRESS_FPS 10
+#define PROGRESS_BAR_INNER_WIDTH 50
+#define LINEBUFFER (32*1024) //32KiB
+
+using namespace std;
+
+struct runtime {
+ string text;
+ string proc;
+ string source;
+ string usr;
+ string src;
+ string loc;
+ unsigned int count;
+};
+struct harddel {
+ string type;
+ unsigned int count;
+};
+//What we use to read input
+string * lastLine = new string();
+string * currentLine = new string();
+string * nextLine = new string();
+
+//Stores lines we want to keep to print out
+unordered_map storedRuntime;
+unordered_map storedInfiniteLoop;
+unordered_map storedHardDel;
+
+//Stat tracking stuff for output
+unsigned int totalRuntimes = 0;
+unsigned int totalInfiniteLoops = 0;
+unsigned int totalHardDels = 0;
+
+
+bool endofbuffer = false;
+//like substr, but returns an empty string if the string is smaller then start, rather then an exception.
+inline string safe_substr(string * S, size_t start = 0, size_t end = string::npos) {
+ if (start > S->length())
+ start = S->length();
+ return S->substr(start, end);
+}
+//getline() is slow as fucking balls. this is quicker because we prefill a buffer rather then read 1 byte at a time searching for newlines, lowering on i/o calls and overhead. (110MB/s vs 40MB/s on a 1.8GB file pre-filled into the disk cache)
+//if i wanted to make it even faster, I'd use a reading thread, a new line searching thread, another thread or four for searching for runtimes in the list to see if they are unique, and finally the main thread for displaying the progress bar. but fuck that noise.
+inline string * readline(FILE * f) {
+ static char buf[LINEBUFFER];
+ static size_t pos = 0;
+ static size_t size = 0;
+
+ for (size_t i = pos; i < LINEBUFFER; i++) {
+ char c = buf[i];
+ if (i >= size && (pos || i < LINEBUFFER-1)) {
+ if (feof(f) || ferror(f))
+ break;
+ if (size && pos) { //move current stuff to start of buffer
+ size -= pos;
+ i -= pos;
+ memmove(buf, &buf[pos], size);
+ }
+ //fill remaining buffer
+ size += fread(&buf[i], 1, LINEBUFFER-size-1, f);
+ pos = 0;
+ c = buf[i];
+ }
+ if (c == '\n') {
+ //trim off any newlines from the start
+ while (i > pos && (buf[pos] == '\r' || buf[pos] == '\n'))
+ pos++;
+ string * s = new string(&buf[pos], i-pos);
+ pos = i+1;
+ return s;
+ }
+
+ }
+ string * s = new string(&buf[pos], size-pos);
+ pos = 0;
+ size = 0;
+ endofbuffer = true;
+ return s;
+}
+
+inline void forward_progress(FILE * inputFile) {
+ delete(lastLine);
+ lastLine = currentLine;
+ currentLine = nextLine;
+ nextLine = readline(inputFile);
+ //strip out any timestamps.
+ if (nextLine->length() >= 10) {
+ if ((*nextLine)[0] == '[' && (*nextLine)[3] == ':' && (*nextLine)[6] == ':' && (*nextLine)[9] == ']')
+ nextLine->erase(0, 10);
+ }
+}
+//deallocates to, copys from to to.
+inline void string_send(string * &from, string * &to) {
+ delete(to);
+ to = new string(*from);
+}
+inline void printprogressbar(unsigned short progress /*as percent*/) {
+ double const modifer = 100.0L/(double)PROGRESS_BAR_INNER_WIDTH;
+ size_t bars = (double)progress/modifer;
+ cerr << "\r[" << string(bars, '=') << ((progress < 100) ? ">" : "") << string(PROGRESS_BAR_INNER_WIDTH-(bars+((progress < 100) ? 1 : 0)), ' ') << "] " << progress << "%";
+ cerr.flush();
+}
+
+bool readFromFile(bool isstdin) {
+ //Open file to read
+ FILE * inputFile = stdin;
+ if (!isstdin)
+ inputFile = fopen("Input.txt", "r");
+
+ if (ferror(inputFile))
+ return false;
+ long long fileLength = 0;
+ clock_t nextupdate = 0;
+ if (!isstdin) {
+ fseek(inputFile, 0, SEEK_END);
+ fileLength = ftell(inputFile);
+ fseek(inputFile, 0, SEEK_SET);
+ nextupdate = clock();
+ }
+
+ if (feof(inputFile))
+ return false; //empty file
+ do {
+ //Update our lines
+ forward_progress(inputFile);
+ //progress bar
+
+ if (!isstdin && clock() >= nextupdate) {
+ int dProgress = (int)(((long double)ftell(inputFile) / (long double)fileLength) * 100.0L);
+ printprogressbar(dProgress);
+ nextupdate = clock() + (CLOCKS_PER_SEC/PROGRESS_FPS);
+ }
+ //Found a runtime!
+ if (safe_substr(currentLine, 0, 14) == "runtime error:") {
+ if (currentLine->length() <= 17) { //empty runtime, check next line.
+ //runtime is on the line before this one. (byond bug)
+ if (nextLine->length() < 2) {
+ string_send(lastLine, nextLine);
+ }
+ forward_progress(inputFile);
+ string * tmp = new string("runtime error: " + *currentLine);
+ string_send(tmp, currentLine);
+ delete(tmp);
+ }
+ //we assign this to the right container in a moment.
+ unordered_map * storage_container;
+
+ //runtime is actually an infinite loop
+ if (safe_substr(currentLine, 15, 23) == "Infinite loop suspected" || safe_substr(currentLine, 15, 31) == "Maximum recursion level reached") {
+ //use our infinite loop container.
+ storage_container = &storedInfiniteLoop;
+ totalInfiniteLoops++;
+ // skip the line about world.loop_checks
+ forward_progress(inputFile);
+ string_send(lastLine, currentLine);
+ } else {
+ //use the runtime container
+ storage_container = &storedRuntime;
+ totalRuntimes++;
+ }
+
+ string key = *currentLine;
+ bool procfound = false; //so other things don't have to bother checking for this again.
+ if (safe_substr(nextLine, 0, 10) == "proc name:") {
+ key += *nextLine;
+ procfound = true;
+ }
+
+ //(get the address of a runtime from (a pointer to a container of runtimes)) to then store in a pointer to a runtime.
+ //(and who said pointers were hard.)
+ runtime* R = &((*storage_container)[key]);
+
+ //new
+ if (R->text != *currentLine) {
+ R->text = *currentLine;
+ if (procfound) {
+ R->proc = *nextLine;
+ forward_progress(inputFile);
+ }
+ R->count = 1;
+
+ //search for source file info
+ if (safe_substr(nextLine, 2, 12) == "source file:") {
+ R->source = *nextLine;
+ //skip again
+ forward_progress(inputFile);
+ }
+ //If we find this, we have new stuff to store
+ if (safe_substr(nextLine, 2, 4) == "usr:") {
+ forward_progress(inputFile);
+ forward_progress(inputFile);
+ //Store more info
+ R->usr = *lastLine;
+ R->src = *currentLine;
+ if (safe_substr(nextLine, 2, 8) == "src.loc:") {
+ R->loc = *nextLine;
+ forward_progress(inputFile);
+ }
+ }
+
+ } else { //existed already
+ R->count++;
+ if (procfound)
+ forward_progress(inputFile);
+ }
+
+ } else if (safe_substr(currentLine, 0, 7) == "Path : ") {
+ string deltype = safe_substr(currentLine, 7);
+ if (deltype.substr(deltype.size()-1,1) == " ") //some times they have a single trailing space.
+ deltype = deltype.substr(0, deltype.size()-1);
+
+ unsigned int failures = strtoul(safe_substr(nextLine, 11).c_str(), NULL, 10);
+ if (failures <= 0)
+ continue;
+
+ totalHardDels += failures;
+ harddel* D = &storedHardDel[deltype];
+ if (D->type != deltype) {
+ D->type = deltype;
+ D->count = failures;
+ } else {
+ D->count += failures;
+ }
+ }
+ } while (!feof(inputFile) || !endofbuffer); //Until end of file
+ if (!isstdin)
+ printprogressbar(100);
+ cerr << endl;
+ return true;
+}
+
+bool runtimeComp(const runtime &a, const runtime &b) {
+ return a.count > b.count;
+}
+
+bool hardDelComp(const harddel &a, const harddel &b) {
+ return a.count > b.count;
+}
+
+bool writeToFile(bool usestdio) {
+ //Open and clear the file
+ ostream * output = &cout;
+ ofstream * outputFile;
+ if (!usestdio)
+ output = outputFile = new ofstream("Output.txt", ios::trunc);
+
+
+ if(usestdio || outputFile->is_open()) {
+ *output << "Note: The source file, src and usr are all from the FIRST of the identical runtimes. Everything else is cropped.\n\n";
+ if(storedInfiniteLoop.size() > 0)
+ *output << "Total unique infinite loops: " << storedInfiniteLoop.size() << endl;
+
+ if(totalInfiniteLoops > 0)
+ *output << "Total infinite loops: " << totalInfiniteLoops << endl << endl;
+
+ *output << "Total unique runtimes: " << storedRuntime.size() << endl;
+ *output << "Total runtimes: " << totalRuntimes << endl << endl;
+ if(storedHardDel.size() > 0)
+ *output << "Total unique hard deletions: " << storedHardDel.size() << endl;
+
+ if(totalHardDels > 0)
+ *output << "Total hard deletions: " << totalHardDels << endl << endl;
+
+
+ //If we have infinite loops, display them first.
+ if(storedInfiniteLoop.size() > 0) {
+ vector infiniteLoops;
+ infiniteLoops.reserve(storedInfiniteLoop.size());
+ for (unordered_map::iterator it=storedInfiniteLoop.begin(); it != storedInfiniteLoop.end(); it++)
+ infiniteLoops.push_back(it->second);
+ storedInfiniteLoop.clear();
+ sort(infiniteLoops.begin(), infiniteLoops.end(), runtimeComp);
+ *output << "** Infinite loops **";
+ for (int i=0; i < infiniteLoops.size(); i++) {
+ runtime* R = &infiniteLoops[i];
+ *output << endl << endl << "The following infinite loop has occurred " << R->count << " time(s).\n";
+ *output << R->text << endl;
+ if(R->proc.length())
+ *output << R->proc << endl;
+ if(R->source.length())
+ *output << R->source << endl;
+ if(R->usr.length())
+ *output << R->usr << endl;
+ if(R->src.length())
+ *output << R->src << endl;
+ if(R->loc.length())
+ *output << R->loc << endl;
+ }
+ *output << endl << endl; //For spacing
+ }
+
+
+ //Do runtimes next
+ *output << "** Runtimes **";
+ vector runtimes;
+ runtimes.reserve(storedRuntime.size());
+ for (unordered_map::iterator it=storedRuntime.begin(); it != storedRuntime.end(); it++)
+ runtimes.push_back(it->second);
+ storedRuntime.clear();
+ sort(runtimes.begin(), runtimes.end(), runtimeComp);
+ for (int i=0; i < runtimes.size(); i++) {
+ runtime* R = &runtimes[i];
+ *output << endl << endl << "The following runtime has occurred " << R->count << " time(s).\n";
+ *output << R->text << endl;
+ if(R->proc.length())
+ *output << R->proc << endl;
+ if(R->source.length())
+ *output << R->source << endl;
+ if(R->usr.length())
+ *output << R->usr << endl;
+ if(R->src.length())
+ *output << R->src << endl;
+ if(R->loc.length())
+ *output << R->loc << endl;
+ }
+ *output << endl << endl; //For spacing
+
+ //and finally, hard deletes
+ if(totalHardDels > 0) {
+ *output << endl << "** Hard deletions **";
+ vector hardDels;
+ hardDels.reserve(storedHardDel.size());
+ for (unordered_map::iterator it=storedHardDel.begin(); it != storedHardDel.end(); it++)
+ hardDels.push_back(it->second);
+ storedHardDel.clear();
+ sort(hardDels.begin(), hardDels.end(), hardDelComp);
+ for(int i=0; i < hardDels.size(); i++) {
+ harddel* D = &hardDels[i];
+ *output << endl << D->type << " - " << D->count << " time(s).\n";
+ }
+ }
+ if (!usestdio) {
+ outputFile->close();
+ delete outputFile;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+int main(int argc, const char * argv[]) {
+ ios_base::sync_with_stdio(false);
+ ios::sync_with_stdio(false);
+ bool usestdio = false;
+ if (argc >= 2 && !strcmp(argv[1], "-s"))
+ usestdio = true;
+
+ char exit; //Used to stop the program from immediately exiting
+ cerr << "Reading input.\n";
+ if(readFromFile(usestdio)) {
+ cerr << "Input read successfully!\n";
+ } else {
+ cerr << "Input failed to open, shutting down.\n";
+ if (!usestdio) {
+ cerr << "\nEnter any letter to quit.\n";
+ exit = cin.get();
+ }
+ return 1;
+ }
+
+
+ cerr << "Writing output.\n";
+ if(writeToFile(usestdio)) {
+ cerr << "Output was successful!\n";
+ if (!usestdio) {
+ cerr << "\nEnter any letter to quit.\n";
+ exit = cin.get();
+ }
+ return 0;
+ } else {
+ cerr << "The output file could not be opened, shutting down.\n";
+ if (!usestdio) {
+ cerr << "\nEnter any letter to quit.\n";
+ exit = cin.get();
+ }
+ return 1;
+ }
+
+ return 0;
+}
+>>>>>>> dbccf52... Merge pull request #33702 from MrStonedOne/rc-the-unix-way
diff --git a/tools/Runtime Condenser/RuntimeCondenser.exe b/tools/Runtime Condenser/RuntimeCondenser.exe
index e53102f219..642efd09f0 100644
Binary files a/tools/Runtime Condenser/RuntimeCondenser.exe and b/tools/Runtime Condenser/RuntimeCondenser.exe differ