"
+ 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/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 74c565da52..68ab173ecd 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -60,7 +60,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!second)
return "0 seconds"
if(second >= 60)
- minute = round_down(second/60)
+ minute = FLOOR(second/60, 1)
second = round(second - (minute*60), 0.1)
second_rounded = TRUE
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
@@ -91,7 +91,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!minute)
return "[second]"
if(minute >= 60)
- hour = round_down(minute/60,1)
+ hour = FLOOR(minute/60, 1)
minute = (minute - (hour*60))
if(minute) //alot simpler from here since you don't have to worry about fractions
if(minute != 1)
@@ -114,7 +114,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!hour)
return "[minute][second]"
if(hour >= 24)
- day = round_down(hour/24,1)
+ day = FLOOR(hour/24, 1)
hour = (hour - (day*24))
if(hour)
if(hour != 1)
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index bae773b27e..2ebe24b85b 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -117,7 +117,7 @@
//Converts an angle (degrees) into an ss13 direction
/proc/angle2dir(degree)
- degree = SimplifyDegrees(degree)
+ degree = SIMPLIFY_DEGREES(degree)
switch(degree)
if(0 to 22.5) //north requires two angle ranges
return NORTH
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 9ec23fa966..1fd60c2bd4 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -147,10 +147,10 @@ Turf and target are separate in case you want to teleport some distance from a t
var/line[] = list(locate(px,py,M.z))
var/dx=N.x-px //x distance
var/dy=N.y-py
- var/dxabs=abs(dx)//Absolute value of x distance
- var/dyabs=abs(dy)
- var/sdx=sign(dx) //Sign of x distance (+ or -)
- var/sdy=sign(dy)
+ var/dxabs = abs(dx)//Absolute value of x distance
+ var/dyabs = abs(dy)
+ var/sdx = SIGN(dx) //Sign of x distance (+ or -)
+ var/sdy = SIGN(dy)
var/x=dxabs>>1 //Counters for steps taken, setting to distance/2
var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast.
var/j //Generic integer for counting
@@ -953,8 +953,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tY = tY[1]
tX = splittext(tX[1], ":")
tX = tX[1]
- tX = Clamp(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
- tY = Clamp(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
+ tX = CLAMP(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
+ tY = CLAMP(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/screen_loc2turf(text, turf/origin)
@@ -966,8 +966,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tX = splittext(tZ[2], "-")
tX = text2num(tX[2])
tZ = origin.z
- tX = Clamp(origin.x + 7 - tX, 1, world.maxx)
- tY = Clamp(origin.y + 7 - tY, 1, world.maxy)
+ tX = CLAMP(origin.x + 7 - tX, 1, world.maxx)
+ tY = CLAMP(origin.y + 7 - tY, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/IsValidSrc(datum/D)
@@ -1272,7 +1272,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
. = 0
var/i = DS2TICKS(initial_delay)
do
- . += Ceiling(i*DELTA_CALC)
+ . += CEILING(i*DELTA_CALC, 1)
sleep(i*world.tick_lag*DELTA_CALC)
i *= 2
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
@@ -1508,9 +1508,34 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "\[[url_encode(thing.tag)]\]"
return "\ref[input]"
+// Makes a call in the context of a different usr
+// Use sparingly
+/world/proc/PushUsr(mob/M, datum/callback/CB)
+ var/temp = usr
+ usr = M
+ . = CB.Invoke()
+ usr = temp
+
//Returns a list of all servants of Ratvar and observers.
/proc/servants_and_ghosts()
. = list()
for(var/V in GLOB.player_list)
if(is_servant_of_ratvar(V) || isobserver(V))
. += V
+
+//datum may be null, but it does need to be a typed var
+#define NAMEOF(datum, X) (list(##datum.##X, #X)[2])
+
+#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
+//dupe code because dm can't handle 3 level deep macros
+#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
+
+/proc/___callbackvarset(list_or_datum, var_name, var_value)
+ if(length(list_or_datum))
+ list_or_datum[var_name] = var_value
+ return
+ var/datum/D = list_or_datum
+ if(IsAdminAdvancedProcCall())
+ D.vv_edit_var(var_name, var_value) //same result generally, unless badmemes
+ else
+ D.vars[var_name] = var_value
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/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
index ff38107bfb..e3d1af79ed 100755
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -60,8 +60,6 @@
var/pref = C.prefs.parallax
if (isnull(pref))
pref = PARALLAX_HIGH
- if (C.byond_version < 511)
- pref = PARALLAX_DISABLE
switch(C.prefs.parallax)
if (PARALLAX_INSANE)
C.parallax_throttle = FALSE
@@ -257,8 +255,8 @@
view = world.view
var/list/viewscales = getviewsize(view)
- var/countx = Ceiling((viewscales[1]/2)/(480/world.icon_size))+1
- var/county = Ceiling((viewscales[2]/2)/(480/world.icon_size))+1
+ var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
+ var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 1)+1
var/list/new_overlays = new
for(var/x in -countx to countx)
for(var/y in -county to county)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index f1ec409520..769cdb2244 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -1,277 +1,277 @@
-/obj/screen/robot
- icon = 'icons/mob/screen_cyborg.dmi'
-
-/obj/screen/robot/module
- name = "cyborg module"
- icon_state = "nomod"
-
-/obj/screen/robot/Click()
- if(isobserver(usr))
- return 1
-
-/obj/screen/robot/module/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- if(R.module.type != /obj/item/robot_module)
- R.hud_used.toggle_show_robot_modules()
- return 1
- R.pick_module()
-
-/obj/screen/robot/module1
- name = "module1"
- icon_state = "inv1"
-
-/obj/screen/robot/module1/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(1)
-
-/obj/screen/robot/module2
- name = "module2"
- icon_state = "inv2"
-
-/obj/screen/robot/module2/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(2)
-
-/obj/screen/robot/module3
- name = "module3"
- icon_state = "inv3"
-
-/obj/screen/robot/module3/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(3)
-
-/obj/screen/robot/radio
- name = "radio"
- icon_state = "radio"
-
-/obj/screen/robot/radio/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.radio.interact(R)
-
-/obj/screen/robot/store
- name = "store"
- icon_state = "store"
-
-/obj/screen/robot/store/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.uneq_active()
-
-/obj/screen/robot/lamp
- name = "headlamp"
- icon_state = "lamp0"
-
-/obj/screen/robot/lamp/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.control_headlamp()
-
-/obj/screen/robot/thrusters
- name = "ion thrusters"
- icon_state = "ionpulse0"
-
-/obj/screen/robot/thrusters/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_ionpulse()
-
-/datum/hud/robot
- ui_style_icon = 'icons/mob/screen_cyborg.dmi'
-
-/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
- ..()
- var/mob/living/silicon/robot/mymobR = mymob
- var/obj/screen/using
-
- using = new/obj/screen/language_menu
- using.screen_loc = ui_borg_language_menu
- static_inventory += using
-
-//Radio
- using = new /obj/screen/robot/radio()
- using.screen_loc = ui_borg_radio
- static_inventory += using
-
-//Module select
- using = new /obj/screen/robot/module1()
- using.screen_loc = ui_inv1
- static_inventory += using
- mymobR.inv1 = using
-
- using = new /obj/screen/robot/module2()
- using.screen_loc = ui_inv2
- static_inventory += using
- mymobR.inv2 = using
-
- using = new /obj/screen/robot/module3()
- using.screen_loc = ui_inv3
- static_inventory += using
- mymobR.inv3 = using
-
-//End of module select
-
-//Photography stuff
- using = new /obj/screen/ai/image_take()
- using.screen_loc = ui_borg_camera
- static_inventory += using
-
- using = new /obj/screen/ai/image_view()
- using.screen_loc = ui_borg_album
- static_inventory += using
-
-//Sec/Med HUDs
- using = new /obj/screen/ai/sensors()
- using.screen_loc = ui_borg_sensor
- static_inventory += using
-
-//Headlamp control
- using = new /obj/screen/robot/lamp()
- using.screen_loc = ui_borg_lamp
- static_inventory += using
- mymobR.lamp_button = using
-
-//Thrusters
- using = new /obj/screen/robot/thrusters()
- using.screen_loc = ui_borg_thrusters
- static_inventory += using
- mymobR.thruster_button = using
-
-//Intent
- action_intent = new /obj/screen/act_intent/robot()
- action_intent.icon_state = mymob.a_intent
- static_inventory += action_intent
-
-//Health
- healths = new /obj/screen/healths/robot()
- infodisplay += healths
-
-//Installed Module
- mymobR.hands = new /obj/screen/robot/module()
- mymobR.hands.screen_loc = ui_borg_module
- static_inventory += mymobR.hands
-
-//Store
- module_store_icon = new /obj/screen/robot/store()
- module_store_icon.screen_loc = ui_borg_store
-
- pull_icon = new /obj/screen/pull()
- pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
- pull_icon.update_icon(mymob)
- pull_icon.screen_loc = ui_borg_pull
- hotkeybuttons += pull_icon
-
-
- zone_select = new /obj/screen/zone_sel/robot()
- zone_select.update_icon(mymob)
- static_inventory += zone_select
-
-
-/datum/hud/proc/toggle_show_robot_modules()
- if(!iscyborg(mymob))
- return
-
- var/mob/living/silicon/robot/R = mymob
-
- R.shown_robot_modules = !R.shown_robot_modules
- update_robot_modules_display()
-
-/datum/hud/proc/update_robot_modules_display(mob/viewer)
- if(!iscyborg(mymob))
- return
-
- var/mob/living/silicon/robot/R = mymob
-
- var/mob/screenmob = viewer || R
-
- if(!R.module)
- return
-
- if(!R.client)
- return
-
- if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
- //Modules display is shown
- screenmob.client.screen += module_store_icon //"store" icon
-
- if(!R.module.modules)
- to_chat(usr, "
Selected module has no modules to select")
- return
-
- if(!R.robot_modules_background)
- return
-
- var/display_rows = Ceiling(length(R.module.get_inactive_modules()) / 8)
- R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
- screenmob.client.screen += R.robot_modules_background
-
- var/x = -4 //Start at CENTER-4,SOUTH+1
- var/y = 1
-
- for(var/atom/movable/A in R.module.get_inactive_modules())
- //Module is not currently active
- screenmob.client.screen += A
- if(x < 0)
- A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
- else
- A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
- A.layer = ABOVE_HUD_LAYER
- A.plane = ABOVE_HUD_PLANE
-
- x++
- if(x == 4)
- x = -4
- y++
-
- else
- //Modules display is hidden
- screenmob.client.screen -= module_store_icon //"store" icon
-
- for(var/atom/A in R.module.get_inactive_modules())
- //Module is not currently active
- screenmob.client.screen -= A
- R.shown_robot_modules = 0
- screenmob.client.screen -= R.robot_modules_background
-
-/mob/living/silicon/robot/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/robot(src)
-
-
-/datum/hud/robot/persistent_inventory_update(mob/viewer)
- if(!mymob)
- return
- var/mob/living/silicon/robot/R = mymob
-
- var/mob/screenmob = viewer || R
-
- if(screenmob.hud_used)
- if(screenmob.hud_used.hud_shown)
- for(var/i in 1 to R.held_items.len)
- var/obj/item/I = R.held_items[i]
- if(I)
- switch(i)
- if(1)
- I.screen_loc = ui_inv1
- if(2)
- I.screen_loc = ui_inv2
- if(3)
- I.screen_loc = ui_inv3
- else
- return
- screenmob.client.screen += I
- else
- for(var/obj/item/I in R.held_items)
- screenmob.client.screen -= I
+/obj/screen/robot
+ icon = 'icons/mob/screen_cyborg.dmi'
+
+/obj/screen/robot/module
+ name = "cyborg module"
+ icon_state = "nomod"
+
+/obj/screen/robot/Click()
+ if(isobserver(usr))
+ return 1
+
+/obj/screen/robot/module/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ if(R.module.type != /obj/item/robot_module)
+ R.hud_used.toggle_show_robot_modules()
+ return 1
+ R.pick_module()
+
+/obj/screen/robot/module1
+ name = "module1"
+ icon_state = "inv1"
+
+/obj/screen/robot/module1/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(1)
+
+/obj/screen/robot/module2
+ name = "module2"
+ icon_state = "inv2"
+
+/obj/screen/robot/module2/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(2)
+
+/obj/screen/robot/module3
+ name = "module3"
+ icon_state = "inv3"
+
+/obj/screen/robot/module3/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(3)
+
+/obj/screen/robot/radio
+ name = "radio"
+ icon_state = "radio"
+
+/obj/screen/robot/radio/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.radio.interact(R)
+
+/obj/screen/robot/store
+ name = "store"
+ icon_state = "store"
+
+/obj/screen/robot/store/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.uneq_active()
+
+/obj/screen/robot/lamp
+ name = "headlamp"
+ icon_state = "lamp0"
+
+/obj/screen/robot/lamp/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.control_headlamp()
+
+/obj/screen/robot/thrusters
+ name = "ion thrusters"
+ icon_state = "ionpulse0"
+
+/obj/screen/robot/thrusters/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_ionpulse()
+
+/datum/hud/robot
+ ui_style_icon = 'icons/mob/screen_cyborg.dmi'
+
+/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
+ ..()
+ var/mob/living/silicon/robot/mymobR = mymob
+ var/obj/screen/using
+
+ using = new/obj/screen/language_menu
+ using.screen_loc = ui_borg_language_menu
+ static_inventory += using
+
+//Radio
+ using = new /obj/screen/robot/radio()
+ using.screen_loc = ui_borg_radio
+ static_inventory += using
+
+//Module select
+ using = new /obj/screen/robot/module1()
+ using.screen_loc = ui_inv1
+ static_inventory += using
+ mymobR.inv1 = using
+
+ using = new /obj/screen/robot/module2()
+ using.screen_loc = ui_inv2
+ static_inventory += using
+ mymobR.inv2 = using
+
+ using = new /obj/screen/robot/module3()
+ using.screen_loc = ui_inv3
+ static_inventory += using
+ mymobR.inv3 = using
+
+//End of module select
+
+//Photography stuff
+ using = new /obj/screen/ai/image_take()
+ using.screen_loc = ui_borg_camera
+ static_inventory += using
+
+ using = new /obj/screen/ai/image_view()
+ using.screen_loc = ui_borg_album
+ static_inventory += using
+
+//Sec/Med HUDs
+ using = new /obj/screen/ai/sensors()
+ using.screen_loc = ui_borg_sensor
+ static_inventory += using
+
+//Headlamp control
+ using = new /obj/screen/robot/lamp()
+ using.screen_loc = ui_borg_lamp
+ static_inventory += using
+ mymobR.lamp_button = using
+
+//Thrusters
+ using = new /obj/screen/robot/thrusters()
+ using.screen_loc = ui_borg_thrusters
+ static_inventory += using
+ mymobR.thruster_button = using
+
+//Intent
+ action_intent = new /obj/screen/act_intent/robot()
+ action_intent.icon_state = mymob.a_intent
+ static_inventory += action_intent
+
+//Health
+ healths = new /obj/screen/healths/robot()
+ infodisplay += healths
+
+//Installed Module
+ mymobR.hands = new /obj/screen/robot/module()
+ mymobR.hands.screen_loc = ui_borg_module
+ static_inventory += mymobR.hands
+
+//Store
+ module_store_icon = new /obj/screen/robot/store()
+ module_store_icon.screen_loc = ui_borg_store
+
+ pull_icon = new /obj/screen/pull()
+ pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
+ pull_icon.update_icon(mymob)
+ pull_icon.screen_loc = ui_borg_pull
+ hotkeybuttons += pull_icon
+
+
+ zone_select = new /obj/screen/zone_sel/robot()
+ zone_select.update_icon(mymob)
+ static_inventory += zone_select
+
+
+/datum/hud/proc/toggle_show_robot_modules()
+ if(!iscyborg(mymob))
+ return
+
+ var/mob/living/silicon/robot/R = mymob
+
+ R.shown_robot_modules = !R.shown_robot_modules
+ update_robot_modules_display()
+
+/datum/hud/proc/update_robot_modules_display(mob/viewer)
+ if(!iscyborg(mymob))
+ return
+
+ var/mob/living/silicon/robot/R = mymob
+
+ var/mob/screenmob = viewer || R
+
+ if(!R.module)
+ return
+
+ if(!R.client)
+ return
+
+ if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
+ //Modules display is shown
+ screenmob.client.screen += module_store_icon //"store" icon
+
+ if(!R.module.modules)
+ to_chat(usr, "
Selected module has no modules to select")
+ return
+
+ if(!R.robot_modules_background)
+ return
+
+ var/display_rows = CEILING(length(R.module.get_inactive_modules()) / 8, 1)
+ R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
+ screenmob.client.screen += R.robot_modules_background
+
+ var/x = -4 //Start at CENTER-4,SOUTH+1
+ var/y = 1
+
+ for(var/atom/movable/A in R.module.get_inactive_modules())
+ //Module is not currently active
+ screenmob.client.screen += A
+ if(x < 0)
+ A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
+ else
+ A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
+ A.layer = ABOVE_HUD_LAYER
+ A.plane = ABOVE_HUD_PLANE
+
+ x++
+ if(x == 4)
+ x = -4
+ y++
+
+ else
+ //Modules display is hidden
+ screenmob.client.screen -= module_store_icon //"store" icon
+
+ for(var/atom/A in R.module.get_inactive_modules())
+ //Module is not currently active
+ screenmob.client.screen -= A
+ R.shown_robot_modules = 0
+ screenmob.client.screen -= R.robot_modules_background
+
+/mob/living/silicon/robot/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud/robot(src)
+
+
+/datum/hud/robot/persistent_inventory_update(mob/viewer)
+ if(!mymob)
+ return
+ var/mob/living/silicon/robot/R = mymob
+
+ var/mob/screenmob = viewer || R
+
+ if(screenmob.hud_used)
+ if(screenmob.hud_used.hud_shown)
+ for(var/i in 1 to R.held_items.len)
+ var/obj/item/I = R.held_items[i]
+ if(I)
+ switch(i)
+ if(1)
+ I.screen_loc = ui_inv1
+ if(2)
+ I.screen_loc = ui_inv2
+ if(3)
+ I.screen_loc = ui_inv3
+ else
+ return
+ screenmob.client.screen += I
+ else
+ for(var/obj/item/I in R.held_items)
+ screenmob.client.screen -= I
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 859c957a43..2dddce8542 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -58,6 +58,8 @@
SendSignal(COMSIG_ITEM_ATTACK, M, user)
if(flags_1 & NOBLUDGEON_1)
return
+ if(user.disabilities & PACIFISM)
+ return
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
else if(hitsound)
@@ -119,9 +121,9 @@
/obj/item/proc/get_clamped_volume()
if(w_class)
if(force)
- return Clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
+ return CLAMP((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
else
- return Clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
+ return CLAMP(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
var/message_verb = "attacked"
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 02cdfe7c13..d52a7f6fdc 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -63,6 +63,7 @@
/atom/proc/attack_animal(mob/user)
return
+
/mob/living/RestrainedClickOn(atom/A)
return
diff --git a/code/citadel/cit_arousal.dm b/code/citadel/cit_arousal.dm
index 0c03ffb399..077824fe9e 100644
--- a/code/citadel/cit_arousal.dm
+++ b/code/citadel/cit_arousal.dm
@@ -62,14 +62,14 @@
/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
- arousalloss = Clamp(arousalloss + amount, min_arousal, max_arousal)
+ arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
- arousalloss = Clamp(amount, min_arousal, max_arousal)
+ arousalloss = CLAMP(amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm
index 92dcb9baf0..d2db743d91 100644
--- a/code/controllers/configuration/config_entry.dm
+++ b/code/controllers/configuration/config_entry.dm
@@ -9,7 +9,7 @@
var/value
var/default //read-only, just set value directly
- var/resident_file //the file which this belongs to, must be set
+ var/resident_file //the file which this was loaded from, if any
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
var/protection = NONE
@@ -18,8 +18,6 @@
var/dupes_allowed = FALSE
/datum/config_entry/New()
- if(!resident_file)
- CRASH("Config entry [type] has no resident_file set")
if(type == abstract_type)
CRASH("Abstract config entry [type] instatiated!")
name = lowertext(type2top(type))
@@ -110,7 +108,7 @@
/datum/config_entry/number/ValidateAndSet(str_val)
var/temp = text2num(trim(str_val))
if(!isnull(temp))
- value = Clamp(integer ? round(temp) : temp, min_val, max_val)
+ value = CLAMP(integer ? round(temp) : temp, min_val, max_val)
if(value != temp && !var_edited)
log_config("Changing [name] from [temp] to [value]!")
return TRUE
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index e9c0aa71b8..e5e999f003 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -20,10 +20,13 @@ GLOBAL_PROTECT(config_dir)
/datum/controller/configuration/New()
config = src
- var/list/config_files = InitEntries()
+ InitEntries()
LoadModes()
- for(var/I in config_files)
- LoadEntries(I)
+ 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")
+ LoadEntries("comms.txt")
loadmaplist(CONFIG_MAPS_FILE)
/datum/controller/configuration/Destroy()
@@ -42,8 +45,6 @@ GLOBAL_PROTECT(config_dir)
var/list/_entries_by_type = list()
entries_by_type = _entries_by_type
- . = list()
-
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
var/datum/config_entry/E = I
if(initial(E.abstract_type) == I)
@@ -57,24 +58,30 @@ GLOBAL_PROTECT(config_dir)
continue
_entries[esname] = E
_entries_by_type[I] = E
- .[E.resident_file] = TRUE
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
entries -= CE.name
entries_by_type -= CE.type
-/datum/controller/configuration/proc/LoadEntries(filename)
+/datum/controller/configuration/proc/LoadEntries(filename, list/stack = list())
+ var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename
+ if(filename_to_test in stack)
+ log_config("Warning: Config recursion detected ([english_list(stack)]), breaking!")
+ return
+ stack = stack + filename_to_test
+
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
var/list/_entries = entries
for(var/L in lines)
if(!L)
continue
-
- if(copytext(L, 1, 2) == "#")
+
+ var/firstchar = copytext(L, 1, 2)
+ if(firstchar == "#")
continue
- var/lockthis = copytext(L, 1, 2) == "@"
+ var/lockthis = firstchar == "@"
if(lockthis)
L = copytext(L, 2)
@@ -90,15 +97,25 @@ 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)
+ log_config("Warning: Invalid $include directive: [value]")
+ else
+ LoadEntries(value, stack)
+ continue
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
continue
-
- if(filename != E.resident_file)
- log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
- continue
if(lockthis)
E.protection |= CONFIG_ENTRY_LOCKED
@@ -107,10 +124,14 @@ GLOBAL_PROTECT(config_dir)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else if(E.modified && !E.dupes_allowed)
- log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
+ log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.")
+
+ E.resident_file = filename
if(validated)
E.modified = TRUE
+
+ ++.
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
diff --git a/code/controllers/configuration/entries/comms.dm b/code/controllers/configuration/entries/comms.dm
index bf099f6cb6..56cec985f1 100644
--- a/code/controllers/configuration/entries/comms.dm
+++ b/code/controllers/configuration/entries/comms.dm
@@ -1,22 +1,20 @@
-#define CURRENT_RESIDENT_FILE "comms.txt"
-
-CONFIG_DEF(string/comms_key)
+/datum/config_entry/string/comms_key
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
-CONFIG_DEF(string/cross_server_address)
+/datum/config_entry/keyed_string_list/cross_server
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/cross_server_address/ValidateAndSet(str_val)
return str_val != "byond:\\address:port" && ..()
-CONFIG_DEF(string/cross_comms_name)
+/datum/config_entry/string/cross_comms_name
GLOBAL_VAR_INIT(medals_enabled, TRUE) //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
-CONFIG_DEF(string/medal_hub_address)
+/datum/config_entry/string/medal_hub_address
-CONFIG_DEF(string/medal_hub_password)
- protection = CONFIG_ENTRY_HIDDEN
\ No newline at end of file
+/datum/config_entry/string/medal_hub_password
+ protection = CONFIG_ENTRY_HIDDEN
diff --git a/code/controllers/configuration/entries/config.dm b/code/controllers/configuration/entries/config.dm
deleted file mode 100644
index 37081c15dd..0000000000
--- a/code/controllers/configuration/entries/config.dm
+++ /dev/null
@@ -1,390 +0,0 @@
-#define CURRENT_RESIDENT_FILE "config.txt"
-
-CONFIG_DEF(flag/autoadmin) // if autoadmin is enabled
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/autoadmin_rank) // the rank for autoadmins
- value = "Game Master"
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/servername) // server name (the name of the game window)
-
-CONFIG_DEF(string/serversqlname) // short form server name used for the DB
-
-CONFIG_DEF(string/stationname) // station name (the name of the station in-game)
-
-CONFIG_DEF(number/lobby_countdown) // In between round countdown.
- value = 120
- min_val = 0
-
-CONFIG_DEF(number/round_end_countdown) // Post round murder death kill countdown
- value = 25
- min_val = 0
-
-CONFIG_DEF(flag/hub) // if the game appears on the hub or not
-
-CONFIG_DEF(flag/log_ooc) // log OOC channel
-
-CONFIG_DEF(flag/log_access) // log login/logout
-
-CONFIG_DEF(flag/log_say) // log client say
-
-CONFIG_DEF(flag/log_admin) // log admin actions
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/log_prayer) // log prayers
-
-CONFIG_DEF(flag/log_law) // log lawchanges
-
-CONFIG_DEF(flag/log_game) // log game events
-
-CONFIG_DEF(flag/log_vote) // log voting
-
-CONFIG_DEF(flag/log_whisper) // log client whisper
-
-CONFIG_DEF(flag/log_attack) // log attack messages
-
-CONFIG_DEF(flag/log_emote) // log emotes
-
-CONFIG_DEF(flag/log_adminchat) // log admin chat messages
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/log_pda) // log pda messages
-
-CONFIG_DEF(flag/log_twitter) // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
-
-CONFIG_DEF(flag/log_world_topic) // log all world.Topic() calls
-
-CONFIG_DEF(flag/log_manifest) // log crew manifest to seperate file
-
-CONFIG_DEF(flag/allow_admin_ooccolor) // Allows admins with relevant permissions to have their own ooc colour
-
-CONFIG_DEF(flag/allow_vote_restart) // allow votes to restart
-
-CONFIG_DEF(flag/allow_vote_mode) // allow votes to change mode
-
-CONFIG_DEF(number/vote_delay) // minimum time between voting sessions (deciseconds, 10 minute default)
- value = 6000
- min_val = 0
-
-CONFIG_DEF(number/vote_period) // length of voting period (deciseconds, default 1 minute)
- value = 600
- min_val = 0
-
-CONFIG_DEF(flag/default_no_vote) // vote does not default to nochange/norestart
-
-CONFIG_DEF(flag/no_dead_vote) // dead people can't vote
-
-CONFIG_DEF(flag/allow_metadata) // Metadata is supported.
-
-CONFIG_DEF(flag/popup_admin_pm) // adminPMs to non-admins show in a pop-up 'reply' window when set
-
-CONFIG_DEF(number/fps)
- value = 20
- min_val = 1
- max_val = 100 //byond will start crapping out at 50, so this is just ridic
- var/sync_validate = FALSE
-
-/datum/config_entry/number/fps/ValidateAndSet(str_val)
- . = ..()
- if(.)
- sync_validate = TRUE
- var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
- if(!TL.sync_validate)
- TL.ValidateAndSet(10 / value)
- sync_validate = FALSE
-
-CONFIG_DEF(number/ticklag)
- integer = FALSE
- var/sync_validate = FALSE
-
-/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
- var/datum/config_entry/CE = /datum/config_entry/number/fps
- value = 10 / initial(CE.value)
- ..()
-
-/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
- . = text2num(str_val) > 0 && ..()
- if(.)
- sync_validate = TRUE
- var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
- if(!FPS.sync_validate)
- FPS.ValidateAndSet(10 / value)
- sync_validate = FALSE
-
-CONFIG_DEF(flag/allow_holidays)
-
-CONFIG_DEF(number/tick_limit_mc_init) //SSinitialization throttling
- value = TICK_LIMIT_MC_INIT_DEFAULT
- min_val = 0 //oranges warned us
- integer = FALSE
-
-CONFIG_DEF(flag/admin_legacy_system) //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/hostedby)
-
-CONFIG_DEF(flag/norespawn)
-
-CONFIG_DEF(flag/guest_jobban)
-
-CONFIG_DEF(flag/usewhitelist)
-
-CONFIG_DEF(flag/ban_legacy_system) //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/use_age_restriction_for_jobs) //Do jobs use account age restrictions? --requires database
-
-CONFIG_DEF(flag/use_account_age_for_jobs) //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
-
-CONFIG_DEF(flag/use_exp_tracking)
-
-CONFIG_DEF(flag/use_exp_restrictions_heads)
-
-CONFIG_DEF(number/use_exp_restrictions_heads_hours)
- value = 0
- min_val = 0
-
-CONFIG_DEF(flag/use_exp_restrictions_heads_department)
-
-CONFIG_DEF(flag/use_exp_restrictions_other)
-
-CONFIG_DEF(flag/use_exp_restrictions_admin_bypass)
-
-CONFIG_DEF(string/server)
-
-CONFIG_DEF(string/banappeals)
-
-CONFIG_DEF(string/wikiurl)
- value = "http://www.tgstation13.org/wiki"
-
-CONFIG_DEF(string/forumurl)
- value = "http://tgstation13.org/phpBB/index.php"
-
-CONFIG_DEF(string/rulesurl)
- value = "http://www.tgstation13.org/wiki/Rules"
-
-CONFIG_DEF(string/githuburl)
- value = "https://www.github.com/tgstation/-tg-station"
-
-CONFIG_DEF(number/githubrepoid)
- value = null
- min_val = 0
-
-CONFIG_DEF(flag/guest_ban)
-
-CONFIG_DEF(number/id_console_jobslot_delay)
- value = 30
- min_val = 0
-
-CONFIG_DEF(number/inactivity_period) //time in ds until a player is considered inactive)
- value = 3000
- min_val = 0
-
-/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
- . = ..()
- if(.)
- value *= 10 //documented as seconds in config.txt
-
-CONFIG_DEF(number/afk_period) //time in ds until a player is considered inactive)
- value = 3000
- min_val = 0
-
-/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
- . = ..()
- if(.)
- value *= 10 //documented as seconds in config.txt
-
-CONFIG_DEF(flag/kick_inactive) //force disconnect for inactive players
-
-CONFIG_DEF(flag/load_jobs_from_txt)
-
-CONFIG_DEF(flag/forbid_singulo_possession)
-
-CONFIG_DEF(flag/automute_on) //enables automuting/spam prevention
-
-CONFIG_DEF(string/panic_server_name)
-
-/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
- return str_val != "\[Put the name here\]" && ..()
-
-CONFIG_DEF(string/panic_server_address) //Reconnect a player this linked server if this server isn't accepting new players
-
-/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
- return str_val != "byond://address:port" && ..()
-
-CONFIG_DEF(string/invoke_youtubedl)
- protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-
-CONFIG_DEF(flag/show_irc_name)
-
-CONFIG_DEF(flag/see_own_notes) //Can players see their own admin notes (read-only)?
-
-CONFIG_DEF(number/note_fresh_days)
- value = null
- min_val = 0
- integer = FALSE
-
-CONFIG_DEF(number/note_stale_days)
- value = null
- min_val = 0
- integer = FALSE
-
-CONFIG_DEF(flag/maprotation)
-
-CONFIG_DEF(number/maprotatechancedelta)
- value = 0.75
- min_val = 0
- max_val = 1
- integer = FALSE
-
-CONFIG_DEF(number/soft_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/hard_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/extreme_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(string/soft_popcap_message)
- value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
-
-CONFIG_DEF(string/hard_popcap_message)
- value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
-
-CONFIG_DEF(string/extreme_popcap_message)
- value = "The server is currently serving a high number of users, find alternative servers."
-
-CONFIG_DEF(flag/panic_bunker) // prevents people the server hasn't seen before from connecting
-
-CONFIG_DEF(number/notify_new_player_age) // how long do we notify admins of a new player
- min_val = -1
-
-CONFIG_DEF(number/notify_new_player_account_age) // how long do we notify admins of a new byond account
- min_val = 0
-
-CONFIG_DEF(flag/irc_first_connection_alert) // do we notify the irc channel when somebody is connecting for the first time?
-
-CONFIG_DEF(flag/check_randomizer)
-
-CONFIG_DEF(string/ipintel_email)
-
-/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
- return str_val != "ch@nge.me" && ..()
-
-CONFIG_DEF(number/ipintel_rating_bad)
- value = 1
- integer = FALSE
- min_val = 0
- max_val = 1
-
-CONFIG_DEF(number/ipintel_save_good)
- value = 12
- min_val = 0
-
-CONFIG_DEF(number/ipintel_save_bad)
- value = 1
- min_val = 0
-
-CONFIG_DEF(string/ipintel_domain)
- value = "check.getipintel.net"
-
-CONFIG_DEF(flag/aggressive_changelog)
-
-CONFIG_DEF(flag/autoconvert_notes) //if all connecting player's notes should attempt to be converted to the database
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/allow_webclient)
-
-CONFIG_DEF(flag/webclient_only_byond_members)
-
-CONFIG_DEF(flag/announce_admin_logout)
-
-CONFIG_DEF(flag/announce_admin_login)
-
-CONFIG_DEF(flag/allow_map_voting)
-
-CONFIG_DEF(flag/generate_minimaps)
-
-CONFIG_DEF(number/client_warn_version)
- value = null
- min_val = 500
- max_val = DM_VERSION - 1
-
-CONFIG_DEF(string/client_warn_message)
- value = "Your version of byond may have issues or be blocked from accessing this server in the future."
-
-CONFIG_DEF(flag/client_warn_popup)
-
-CONFIG_DEF(number/client_error_version)
- value = null
- min_val = 500
- max_val = DM_VERSION - 1
-
-CONFIG_DEF(string/client_error_message)
- value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
-
-CONFIG_DEF(number/minute_topic_limit)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/second_topic_limit)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/error_cooldown) // The "cooldown" time for each occurrence of a unique error)
- value = 600
- min_val = 0
-
-CONFIG_DEF(number/error_limit) // How many occurrences before the next will silence them
- value = 50
-
-CONFIG_DEF(number/error_silence_time) // How long a unique error will be silenced for
- value = 6000
-
-CONFIG_DEF(number/error_msg_delay) // How long to wait between messaging admins about occurrences of a unique error
- value = 50
-
-CONFIG_DEF(flag/irc_announce_new_game)
-
-CONFIG_DEF(flag/debug_admin_hrefs)
-
-CONFIG_DEF(number/mc_tick_rate/base_mc_tick_rate)
- integer = FALSE
- value = 1
-
-CONFIG_DEF(number/mc_tick_rate/high_pop_mc_tick_rate)
- integer = FALSE
- value = 1.1
-
-CONFIG_DEF(number/mc_tick_rate/high_pop_mc_mode_amount)
- value = 65
-
-CONFIG_DEF(number/mc_tick_rate/disable_high_pop_mc_mode_amount)
- value = 60
-
-CONFIG_TWEAK(number/mc_tick_rate)
- abstract_type = /datum/config_entry/number/mc_tick_rate
-
-CONFIG_TWEAK(number/mc_tick_rate/ValidateAndSet(str_val))
- . = ..()
- if (.)
- Master.UpdateTickRate()
-
-CONFIG_DEF(flag/resume_after_initializations)
-
-CONFIG_TWEAK(flag/resume_after_initializations/ValidateAndSet(str_val))
- . = ..()
- if(. && Master.current_runlevel)
- world.sleep_offline = !value
-
-CONFIG_DEF(number/rounds_until_hard_restart)
- value = -1
- min_val = 0
-
-CONFIG_DEF(string/default_view)
- value = "15x15"
diff --git a/code/controllers/configuration/entries/dbconfig.dm b/code/controllers/configuration/entries/dbconfig.dm
index c46880686a..1ac4d85419 100644
--- a/code/controllers/configuration/entries/dbconfig.dm
+++ b/code/controllers/configuration/entries/dbconfig.dm
@@ -1,28 +1,26 @@
-#define CURRENT_RESIDENT_FILE "dbconfig.txt"
-
-CONFIG_DEF(flag/sql_enabled) // for sql switching
+/datum/config_entry/flag/sql_enabled // for sql switching
protection = CONFIG_ENTRY_LOCKED
-CONFIG_DEF(string/address)
+/datum/config_entry/string/address
value = "localhost"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(number/port)
+/datum/config_entry/number/port
value = 3306
min_val = 0
max_val = 65535
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_database)
+/datum/config_entry/string/feedback_database
value = "test"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_login)
+/datum/config_entry/string/feedback_login
value = "root"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_password)
+/datum/config_entry/string/feedback_password
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_tableprefix)
+/datum/config_entry/string/feedback_tableprefix
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index b04d7845f5..2d96e3c64b 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -1,253 +1,255 @@
-#define CURRENT_RESIDENT_FILE "game_options.txt"
+/datum/config_entry/number_list/repeated_mode_adjust
-CONFIG_DEF(number_list/repeated_mode_adjust)
-
-CONFIG_DEF(keyed_number_list/probability)
+/datum/config_entry/keyed_number_list/probability
/datum/config_entry/keyed_number_list/probability/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_number_list/max_pop)
+/datum/config_entry/keyed_number_list/max_pop
/datum/config_entry/keyed_number_list/max_pop/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_number_list/min_pop)
+/datum/config_entry/keyed_number_list/min_pop
/datum/config_entry/keyed_number_list/min_pop/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_flag_list/continuous) // which roundtypes continue if all antagonists die
+/datum/config_entry/keyed_flag_list/continuous // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_flag_list/midround_antag) // which roundtypes use the midround antagonist system
+/datum/config_entry/keyed_flag_list/midround_antag // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_string_list/policy)
+/datum/config_entry/keyed_string_list/policy
-CONFIG_DEF(number/damage_multiplier)
+/datum/config_entry/number/damage_multiplier
value = 1
integer = FALSE
-CONFIG_DEF(number/minimal_access_threshold) //If the number of players is larger than this threshold, minimal access will be turned on.
+/datum/config_entry/number/minimal_access_threshold //If the number of players is larger than this threshold, minimal access will be turned on.
min_val = 0
-CONFIG_DEF(flag/jobs_have_minimal_access) //determines whether jobs use minimal access or expanded access.
+/datum/config_entry/flag/jobs_have_minimal_access //determines whether jobs use minimal access or expanded access.
-CONFIG_DEF(flag/assistants_have_maint_access)
+/datum/config_entry/flag/assistants_have_maint_access
-CONFIG_DEF(flag/security_has_maint_access)
+/datum/config_entry/flag/security_has_maint_access
-CONFIG_DEF(flag/everyone_has_maint_access)
+/datum/config_entry/flag/everyone_has_maint_access
-CONFIG_DEF(flag/sec_start_brig) //makes sec start in brig instead of dept sec posts
+/datum/config_entry/flag/sec_start_brig //makes sec start in brig instead of dept sec posts
-CONFIG_DEF(flag/force_random_names)
+/datum/config_entry/flag/force_random_names
-CONFIG_DEF(flag/humans_need_surnames)
+/datum/config_entry/flag/humans_need_surnames
-CONFIG_DEF(flag/allow_ai) // allow ai job
+/datum/config_entry/flag/allow_ai // allow ai job
-CONFIG_DEF(flag/disable_secborg) // disallow secborg module to be chosen.
+/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
-CONFIG_DEF(flag/disable_peaceborg)
+/datum/config_entry/flag/disable_peaceborg
-CONFIG_DEF(number/traitor_scaling_coeff) //how much does the amount of players get divided by to determine traitors
+/datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors
value = 6
min_val = 1
-CONFIG_DEF(number/brother_scaling_coeff) //how many players per brother team
+/datum/config_entry/number/brother_scaling_coeff //how many players per brother team
value = 25
min_val = 1
-CONFIG_DEF(number/changeling_scaling_coeff) //how much does the amount of players get divided by to determine changelings
+/datum/config_entry/number/changeling_scaling_coeff //how much does the amount of players get divided by to determine changelings
value = 6
min_val = 1
-CONFIG_DEF(number/security_scaling_coeff) //how much does the amount of players get divided by to determine open security officer positions
+/datum/config_entry/number/security_scaling_coeff //how much does the amount of players get divided by to determine open security officer positions
value = 8
min_val = 1
-CONFIG_DEF(number/abductor_scaling_coeff) //how many players per abductor team
+/datum/config_entry/number/abductor_scaling_coeff //how many players per abductor team
value = 15
min_val = 1
-CONFIG_DEF(number/traitor_objectives_amount)
+/datum/config_entry/number/traitor_objectives_amount
value = 2
min_val = 0
-CONFIG_DEF(number/brother_objectives_amount)
+/datum/config_entry/number/brother_objectives_amount
value = 2
min_val = 0
-CONFIG_DEF(flag/reactionary_explosions) //If we use reactionary explosions, explosions that react to walls and doors
+/datum/config_entry/flag/reactionary_explosions //If we use reactionary explosions, explosions that react to walls and doors
-CONFIG_DEF(flag/protect_roles_from_antagonist) //If security and such can be traitor/cult/other
+/datum/config_entry/flag/protect_roles_from_antagonist //If security and such can be traitor/cult/other
-CONFIG_DEF(flag/protect_assistant_from_antagonist) //If assistants can be traitor/cult/other
+/datum/config_entry/flag/protect_assistant_from_antagonist //If assistants can be traitor/cult/other
-CONFIG_DEF(flag/enforce_human_authority) //If non-human species are barred from joining as a head of staff
+/datum/config_entry/flag/enforce_human_authority //If non-human species are barred from joining as a head of staff
-CONFIG_DEF(flag/allow_latejoin_antagonists) // If late-joining players can be traitor/changeling
+/datum/config_entry/flag/allow_latejoin_antagonists // If late-joining players can be traitor/changeling
-CONFIG_DEF(number/midround_antag_time_check) // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
+/datum/config_entry/number/midround_antag_time_check // How late (in minutes you want the midround antag system to stay on, setting this to 0 will disable the system)
value = 60
min_val = 0
-CONFIG_DEF(number/midround_antag_life_check) // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
+/datum/config_entry/number/midround_antag_life_check // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
value = 0.7
integer = FALSE
min_val = 0
max_val = 1
-CONFIG_DEF(number/shuttle_refuel_delay)
+/datum/config_entry/number/shuttle_refuel_delay
value = 12000
min_val = 0
-CONFIG_DEF(flag/show_game_type_odds) //if set this allows players to see the odds of each roundtype on the get revision screen
+/datum/config_entry/flag/show_game_type_odds //if set this allows players to see the odds of each roundtype on the get revision screen
-CONFIG_DEF(keyed_flag_list/roundstart_races) //races you can play as from the get go.
+/datum/config_entry/keyed_flag_list/roundstart_races //races you can play as from the get go.
-CONFIG_DEF(flag/join_with_mutant_humans) //players can pick mutant bodyparts for humans before joining the game
+/datum/config_entry/flag/join_with_mutant_humans //players can pick mutant bodyparts for humans before joining the game
-CONFIG_DEF(flag/no_summon_guns) //No
+/datum/config_entry/flag/no_summon_guns //No
-CONFIG_DEF(flag/no_summon_magic) //Fun
+/datum/config_entry/flag/no_summon_magic //Fun
-CONFIG_DEF(flag/no_summon_events) //Allowed
+/datum/config_entry/flag/no_summon_events //Allowed
-CONFIG_DEF(flag/no_intercept_report) //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
+/datum/config_entry/flag/no_intercept_report //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
-CONFIG_DEF(number/arrivals_shuttle_dock_window) //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
+/datum/config_entry/number/arrivals_shuttle_dock_window //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
value = 55
min_val = 30
-CONFIG_DEF(flag/arrivals_shuttle_require_undocked) //Require the arrivals shuttle to be undocked before latejoiners can join
+/datum/config_entry/flag/arrivals_shuttle_require_undocked //Require the arrivals shuttle to be undocked before latejoiners can join
-CONFIG_DEF(flag/arrivals_shuttle_require_safe_latejoin) //Require the arrivals shuttle to be operational in order for latejoiners to join
+/datum/config_entry/flag/arrivals_shuttle_require_safe_latejoin //Require the arrivals shuttle to be operational in order for latejoiners to join
-CONFIG_DEF(string/alert_green)
+/datum/config_entry/string/alert_green
value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
-CONFIG_DEF(string/alert_blue_upto)
+/datum/config_entry/string/alert_blue_upto
value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
-CONFIG_DEF(string/alert_blue_downto)
+/datum/config_entry/string/alert_blue_downto
value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
-CONFIG_DEF(string/alert_red_upto)
+/datum/config_entry/string/alert_red_upto
value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
-CONFIG_DEF(string/alert_red_downto)
+/datum/config_entry/string/alert_red_downto
value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
-CONFIG_DEF(string/alert_delta)
+/datum/config_entry/string/alert_delta
value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
-CONFIG_DEF(flag/revival_pod_plants)
+/datum/config_entry/flag/revival_pod_plants
-CONFIG_DEF(flag/revival_cloning)
+/datum/config_entry/flag/revival_cloning
-CONFIG_DEF(number/revival_brain_life)
+/datum/config_entry/number/revival_brain_life
value = -1
min_val = -1
-CONFIG_DEF(flag/rename_cyborg)
+/datum/config_entry/flag/rename_cyborg
-CONFIG_DEF(flag/ooc_during_round)
+/datum/config_entry/flag/ooc_during_round
-CONFIG_DEF(flag/emojis)
+/datum/config_entry/flag/emojis
-CONFIG_DEF(number/run_delay) //Used for modifying movement speed for mobs.
+/datum/config_entry/number/run_delay //Used for modifying movement speed for mobs.
var/static/value_cache = 0
-CONFIG_TWEAK(number/run_delay/ValidateAndSet())
+/datum/config_entry/number/run_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
-CONFIG_DEF(number/walk_delay)
+/datum/config_entry/number/walk_delay
var/static/value_cache = 0
-CONFIG_TWEAK(number/walk_delay/ValidateAndSet())
+/datum/config_entry/number/walk_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
-CONFIG_DEF(number/human_delay) //Mob specific modifiers. NOTE: These will affect different mob types in different ways
-CONFIG_DEF(number/robot_delay)
-CONFIG_DEF(number/monkey_delay)
-CONFIG_DEF(number/alien_delay)
-CONFIG_DEF(number/slime_delay)
-CONFIG_DEF(number/animal_delay)
+/datum/config_entry/number/human_delay //Mob specific modifiers. NOTE: These will affect different mob types in different ways
+/datum/config_entry/number/robot_delay
+/datum/config_entry/number/monkey_delay
+/datum/config_entry/number/alien_delay
+/datum/config_entry/number/slime_delay
+/datum/config_entry/number/animal_delay
-CONFIG_DEF(number/gateway_delay) //How long the gateway takes before it activates. Default is half an hour.
+/datum/config_entry/number/gateway_delay //How long the gateway takes before it activates. Default is half an hour.
value = 18000
min_val = 0
-CONFIG_DEF(flag/ghost_interaction)
+/datum/config_entry/flag/ghost_interaction
-CONFIG_DEF(flag/silent_ai)
-CONFIG_DEF(flag/silent_borg)
+/datum/config_entry/flag/silent_ai
+/datum/config_entry/flag/silent_borg
-CONFIG_DEF(flag/sandbox_autoclose) // close the sandbox panel after spawning an item, potentially reducing griff
+/datum/config_entry/flag/sandbox_autoclose // close the sandbox panel after spawning an item, potentially reducing griff
-CONFIG_DEF(number/default_laws) //Controls what laws the AI spawns with.
+/datum/config_entry/number/default_laws //Controls what laws the AI spawns with.
value = 0
min_val = 0
max_val = 3
-CONFIG_DEF(number/silicon_max_law_amount)
+/datum/config_entry/number/silicon_max_law_amount
value = 12
min_val = 0
-CONFIG_DEF(keyed_flag_list/random_laws)
+/datum/config_entry/keyed_flag_list/random_laws
-CONFIG_DEF(keyed_number_list/law_weight)
+/datum/config_entry/keyed_number_list/law_weight
splitter = ","
-CONFIG_DEF(number/assistant_cap)
+/datum/config_entry/number/assistant_cap
value = -1
min_val = -1
-CONFIG_DEF(flag/starlight)
-CONFIG_DEF(flag/grey_assistants)
+/datum/config_entry/flag/starlight
+/datum/config_entry/flag/grey_assistants
-CONFIG_DEF(number/lavaland_budget)
+/datum/config_entry/number/lavaland_budget
value = 60
min_val = 0
-CONFIG_DEF(number/space_budget)
+/datum/config_entry/number/space_budget
value = 16
min_val = 0
-CONFIG_DEF(flag/allow_random_events) // Enables random events mid-round when set
+/datum/config_entry/flag/allow_random_events // Enables random events mid-round when set
-CONFIG_DEF(number/events_min_time_mul) // Multipliers for random events minimal starting time and minimal players amounts
+/datum/config_entry/number/events_min_time_mul // Multipliers for random events minimal starting time and minimal players amounts
value = 1
min_val = 0
integer = FALSE
-CONFIG_DEF(number/events_min_players_mul)
+/datum/config_entry/number/events_min_players_mul
value = 1
min_val = 0
integer = FALSE
-CONFIG_DEF(number/mice_roundstart)
+/datum/config_entry/number/mice_roundstart
value = 10
min_val = 0
-CONFIG_DEF(number/bombcap)
+/datum/config_entry/number/bombcap
value = 14
min_val = 4
-CONFIG_DEF(flag/allow_crew_objectives)
-CONFIG_DEF(flag/allow_miscreants)
-CONFIG_DEF(flag/allow_extended_miscreants)
+//Cit changes - Adds config options for crew objectives and miscreants
+/datum/config_entry/flag/allow_crew_objectives
+
+/datum/config_entry/flag/allow_miscreants
+
+/datum/config_entry/flag/allow_extended_miscreants
+//End of Cit changes
/datum/config_entry/number/bombcap/ValidateAndSet(str_val)
. = ..()
@@ -258,9 +260,9 @@ CONFIG_DEF(flag/allow_extended_miscreants)
GLOB.MAX_EX_FLASH_RANGE = value
GLOB.MAX_EX_FLAME_RANGE = value
-CONFIG_DEF(number/emergency_shuttle_autocall_threshold)
+/datum/config_entry/number/emergency_shuttle_autocall_threshold
min_val = 0
max_val = 1
integer = FALSE
-CONFIG_DEF(flag/ic_printing)
+/datum/config_entry/flag/ic_printing
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
new file mode 100644
index 0000000000..637e65c46f
--- /dev/null
+++ b/code/controllers/configuration/entries/general.dm
@@ -0,0 +1,388 @@
+/datum/config_entry/flag/autoadmin // if autoadmin is enabled
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/autoadmin_rank // the rank for autoadmins
+ value = "Game Master"
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/servername // server name (the name of the game window)
+
+/datum/config_entry/string/serversqlname // short form server name used for the DB
+
+/datum/config_entry/string/stationname // station name (the name of the station in-game)
+
+/datum/config_entry/number/lobby_countdown // In between round countdown.
+ value = 120
+ min_val = 0
+
+/datum/config_entry/number/round_end_countdown // Post round murder death kill countdown
+ value = 25
+ min_val = 0
+
+/datum/config_entry/flag/hub // if the game appears on the hub or not
+
+/datum/config_entry/flag/log_ooc // log OOC channel
+
+/datum/config_entry/flag/log_access // log login/logout
+
+/datum/config_entry/flag/log_say // log client say
+
+/datum/config_entry/flag/log_admin // log admin actions
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/log_prayer // log prayers
+
+/datum/config_entry/flag/log_law // log lawchanges
+
+/datum/config_entry/flag/log_game // log game events
+
+/datum/config_entry/flag/log_vote // log voting
+
+/datum/config_entry/flag/log_whisper // log client whisper
+
+/datum/config_entry/flag/log_attack // log attack messages
+
+/datum/config_entry/flag/log_emote // log emotes
+
+/datum/config_entry/flag/log_adminchat // log admin chat messages
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/log_pda // log pda messages
+
+/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
+
+/datum/config_entry/flag/log_world_topic // log all world.Topic() calls
+
+/datum/config_entry/flag/log_manifest // log crew manifest to seperate file
+
+/datum/config_entry/flag/allow_admin_ooccolor // Allows admins with relevant permissions to have their own ooc colour
+
+/datum/config_entry/flag/allow_vote_restart // allow votes to restart
+
+/datum/config_entry/flag/allow_vote_mode // allow votes to change mode
+
+/datum/config_entry/number/vote_delay // minimum time between voting sessions (deciseconds, 10 minute default)
+ value = 6000
+ min_val = 0
+
+/datum/config_entry/number/vote_period // length of voting period (deciseconds, default 1 minute)
+ value = 600
+ min_val = 0
+
+/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
+
+/datum/config_entry/flag/no_dead_vote // dead people can't vote
+
+/datum/config_entry/flag/allow_metadata // Metadata is supported.
+
+/datum/config_entry/flag/popup_admin_pm // adminPMs to non-admins show in a pop-up 'reply' window when set
+
+/datum/config_entry/number/fps
+ value = 20
+ min_val = 1
+ max_val = 100 //byond will start crapping out at 50, so this is just ridic
+ var/sync_validate = FALSE
+
+/datum/config_entry/number/fps/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ sync_validate = TRUE
+ var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
+ if(!TL.sync_validate)
+ TL.ValidateAndSet(10 / value)
+ sync_validate = FALSE
+
+/datum/config_entry/number/ticklag
+ integer = FALSE
+ var/sync_validate = FALSE
+
+/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
+ var/datum/config_entry/CE = /datum/config_entry/number/fps
+ value = 10 / initial(CE.value)
+ ..()
+
+/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
+ . = text2num(str_val) > 0 && ..()
+ if(.)
+ sync_validate = TRUE
+ var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
+ if(!FPS.sync_validate)
+ FPS.ValidateAndSet(10 / value)
+ sync_validate = FALSE
+
+/datum/config_entry/flag/allow_holidays
+
+/datum/config_entry/number/tick_limit_mc_init //SSinitialization throttling
+ value = TICK_LIMIT_MC_INIT_DEFAULT
+ min_val = 0 //oranges warned us
+ integer = FALSE
+
+/datum/config_entry/flag/admin_legacy_system //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/hostedby
+
+/datum/config_entry/flag/norespawn
+
+/datum/config_entry/flag/guest_jobban
+
+/datum/config_entry/flag/usewhitelist
+
+/datum/config_entry/flag/ban_legacy_system //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/use_age_restriction_for_jobs //Do jobs use account age restrictions? --requires database
+
+/datum/config_entry/flag/use_account_age_for_jobs //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
+
+/datum/config_entry/flag/use_exp_tracking
+
+/datum/config_entry/flag/use_exp_restrictions_heads
+
+/datum/config_entry/number/use_exp_restrictions_heads_hours
+ value = 0
+ min_val = 0
+
+/datum/config_entry/flag/use_exp_restrictions_heads_department
+
+/datum/config_entry/flag/use_exp_restrictions_other
+
+/datum/config_entry/flag/use_exp_restrictions_admin_bypass
+
+/datum/config_entry/string/server
+
+/datum/config_entry/string/banappeals
+
+/datum/config_entry/string/wikiurl
+ value = "http://www.tgstation13.org/wiki"
+
+/datum/config_entry/string/forumurl
+ value = "http://tgstation13.org/phpBB/index.php"
+
+/datum/config_entry/string/rulesurl
+ value = "http://www.tgstation13.org/wiki/Rules"
+
+/datum/config_entry/string/githuburl
+ value = "https://www.github.com/tgstation/-tg-station"
+
+/datum/config_entry/number/githubrepoid
+ value = null
+ min_val = 0
+
+/datum/config_entry/flag/guest_ban
+
+/datum/config_entry/number/id_console_jobslot_delay
+ value = 30
+ min_val = 0
+
+/datum/config_entry/number/inactivity_period //time in ds until a player is considered inactive
+ value = 3000
+ min_val = 0
+
+/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ value *= 10 //documented as seconds in config.txt
+
+/datum/config_entry/number/afk_period //time in ds until a player is considered inactive
+ value = 3000
+ min_val = 0
+
+/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ value *= 10 //documented as seconds in config.txt
+
+/datum/config_entry/flag/kick_inactive //force disconnect for inactive players
+
+/datum/config_entry/flag/load_jobs_from_txt
+
+/datum/config_entry/flag/forbid_singulo_possession
+
+/datum/config_entry/flag/automute_on //enables automuting/spam prevention
+
+/datum/config_entry/string/panic_server_name
+
+/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
+ return str_val != "\[Put the name here\]" && ..()
+
+/datum/config_entry/string/panic_server_address //Reconnect a player this linked server if this server isn't accepting new players
+
+/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
+ return str_val != "byond://address:port" && ..()
+
+/datum/config_entry/string/invoke_youtubedl
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
+
+/datum/config_entry/flag/show_irc_name
+
+/datum/config_entry/flag/see_own_notes //Can players see their own admin notes
+
+/datum/config_entry/number/note_fresh_days
+ value = null
+ min_val = 0
+ integer = FALSE
+
+/datum/config_entry/number/note_stale_days
+ value = null
+ min_val = 0
+ integer = FALSE
+
+/datum/config_entry/flag/maprotation
+
+/datum/config_entry/number/maprotatechancedelta
+ value = 0.75
+ min_val = 0
+ max_val = 1
+ integer = FALSE
+
+/datum/config_entry/number/soft_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/hard_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/extreme_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/string/soft_popcap_message
+ value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
+
+/datum/config_entry/string/hard_popcap_message
+ value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
+
+/datum/config_entry/string/extreme_popcap_message
+ value = "The server is currently serving a high number of users, find alternative servers."
+
+/datum/config_entry/flag/panic_bunker // prevents people the server hasn't seen before from connecting
+
+/datum/config_entry/number/notify_new_player_age // how long do we notify admins of a new player
+ min_val = -1
+
+/datum/config_entry/number/notify_new_player_account_age // how long do we notify admins of a new byond account
+ min_val = 0
+
+/datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time?
+
+/datum/config_entry/flag/check_randomizer
+
+/datum/config_entry/string/ipintel_email
+
+/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
+ return str_val != "ch@nge.me" && ..()
+
+/datum/config_entry/number/ipintel_rating_bad
+ value = 1
+ integer = FALSE
+ min_val = 0
+ max_val = 1
+
+/datum/config_entry/number/ipintel_save_good
+ value = 12
+ min_val = 0
+
+/datum/config_entry/number/ipintel_save_bad
+ value = 1
+ min_val = 0
+
+/datum/config_entry/string/ipintel_domain
+ value = "check.getipintel.net"
+
+/datum/config_entry/flag/aggressive_changelog
+
+/datum/config_entry/flag/autoconvert_notes //if all connecting player's notes should attempt to be converted to the database
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/allow_webclient
+
+/datum/config_entry/flag/webclient_only_byond_members
+
+/datum/config_entry/flag/announce_admin_logout
+
+/datum/config_entry/flag/announce_admin_login
+
+/datum/config_entry/flag/allow_map_voting
+
+/datum/config_entry/flag/generate_minimaps
+
+/datum/config_entry/number/client_warn_version
+ value = null
+ min_val = 500
+ max_val = DM_VERSION - 1
+
+/datum/config_entry/string/client_warn_message
+ value = "Your version of byond may have issues or be blocked from accessing this server in the future."
+
+/datum/config_entry/flag/client_warn_popup
+
+/datum/config_entry/number/client_error_version
+ value = null
+ min_val = 500
+ max_val = DM_VERSION - 1
+
+/datum/config_entry/string/client_error_message
+ value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
+
+/datum/config_entry/number/minute_topic_limit
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/second_topic_limit
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
+ value = 600
+ min_val = 0
+
+/datum/config_entry/number/error_limit // How many occurrences before the next will silence them
+ value = 50
+
+/datum/config_entry/number/error_silence_time // How long a unique error will be silenced for
+ value = 6000
+
+/datum/config_entry/number/error_msg_delay // How long to wait between messaging admins about occurrences of a unique error
+ value = 50
+
+/datum/config_entry/flag/irc_announce_new_game
+
+/datum/config_entry/flag/debug_admin_hrefs
+
+/datum/config_entry/number/mc_tick_rate/base_mc_tick_rate
+ integer = FALSE
+ value = 1
+
+/datum/config_entry/number/mc_tick_rate/high_pop_mc_tick_rate
+ integer = FALSE
+ value = 1.1
+
+/datum/config_entry/number/mc_tick_rate/high_pop_mc_mode_amount
+ value = 65
+
+/datum/config_entry/number/mc_tick_rate/disable_high_pop_mc_mode_amount
+ value = 60
+
+/datum/config_entry/number/mc_tick_rate
+ abstract_type = /datum/config_entry/number/mc_tick_rate
+
+/datum/config_entry/number/mc_tick_rate/ValidateAndSet(str_val)
+ . = ..()
+ if (.)
+ Master.UpdateTickRate()
+
+/datum/config_entry/flag/resume_after_initializations
+
+/datum/config_entry/flag/resume_after_initializations/ValidateAndSet(str_val)
+ . = ..()
+ if(. && Master.current_runlevel)
+ world.sleep_offline = !value
+
+/datum/config_entry/number/rounds_until_hard_restart
+ value = -1
+ min_val = 0
+
+/datum/config_entry/string/default_view
+ value = "15x15"
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 568257e10f..b9950da7b9 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -301,7 +301,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
continue
//Byond resumed us late. assume it might have to do the same next tick
- if (last_run + Ceiling(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time)
+ if (last_run + CEILING(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time)
sleep_delta += 1
sleep_delta = MC_AVERAGE_FAST(sleep_delta, 1) //decay sleep_delta
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/throwing.dm b/code/controllers/subsystem/throwing.dm
index 97d84a0d3b..ec21f3bab2 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -80,7 +80,7 @@ SUBSYSTEM_DEF(throwing)
last_move = world.time
//calculate how many tiles to move, making up for any missed ticks.
- var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
+ var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1)
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
finalize()
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/action.dm b/code/datums/action.dm
index f941a00a54..ede0fa75a2 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -344,6 +344,19 @@
/datum/action/item_action/change
name = "Change"
+/datum/action/item_action/nano_picket_sign
+ name = "Retext Nano Picket Sign"
+ var/obj/item/picket_sign/S
+
+/datum/action/item_action/nano_picket_sign/New(Target)
+ ..()
+ if(istype(Target, /obj/item/picket_sign))
+ S = Target
+
+/datum/action/item_action/nano_picket_sign/Trigger()
+ if(istype(S))
+ S.retext(owner)
+
/datum/action/item_action/adjust
/datum/action/item_action/adjust/New(Target)
diff --git a/code/datums/actions/beam_rifle.dm b/code/datums/actions/beam_rifle.dm
new file mode 100644
index 0000000000..783b93fbdb
--- /dev/null
+++ b/code/datums/actions/beam_rifle.dm
@@ -0,0 +1,12 @@
+
+/datum/action/item_action/zoom_speed_action
+ name = "Toggle Zooming Speed"
+ icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon_state = "projectile"
+ background_icon_state = "bg_tech"
+
+/datum/action/item_action/zoom_lock_action
+ name = "Switch Zoom Mode"
+ icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "zoom_mode"
+ background_icon_state = "bg_tech"
diff --git a/code/datums/actions/flightsuit.dm b/code/datums/actions/flightsuit.dm
index 3e78fa5332..cf249fed31 100644
--- a/code/datums/actions/flightsuit.dm
+++ b/code/datums/actions/flightsuit.dm
@@ -1,5 +1,3 @@
-
-
/datum/action/item_action/flightsuit
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
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..031e08738f 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
@@ -223,7 +223,7 @@
if(verbose)
to_chat(user, "
[target] is not compatible with our biology.")
return
- if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
+ if((target.has_disability(NOCLONE)) || (target.has_disability(NOCLONE)))
if(verbose)
to_chat(user, "
DNA of [target] is ruined beyond usability!")
return
@@ -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/monkey.dm b/code/datums/antagonists/monkey.dm
new file mode 100644
index 0000000000..8d7462b567
--- /dev/null
+++ b/code/datums/antagonists/monkey.dm
@@ -0,0 +1,170 @@
+#define MONKEYS_ESCAPED 1
+#define MONKEYS_LIVED 2
+#define MONKEYS_DIED 3
+#define DISEASE_LIVED 4
+
+/datum/antagonist/monkey
+ name = "Monkey"
+ job_rank = ROLE_MONKEY
+ roundend_category = "monkeys"
+ var/datum/objective_team/monkey/monkey_team
+
+/datum/antagonist/monkey/on_gain()
+ . = ..()
+ SSticker.mode.ape_infectees += owner
+ owner.special_role = "Infected Monkey"
+
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever
+ if(!owner.current.HasDisease(D))
+ D.affected_mob = owner
+ owner.current.viruses += D
+ else
+ QDEL_NULL(D)
+
+/datum/antagonist/monkey/greet()
+ to_chat(owner, "
You are a monkey now!")
+ to_chat(owner, "
Bite humans to infect them, follow the orders of the monkey leaders, and help fellow monkeys!")
+ to_chat(owner, "
Ensure at least one infected monkey escapes on the Emergency Shuttle!")
+ to_chat(owner, "
As an intelligent monkey, you know how to use technology and how to ventcrawl while wearing things.")
+ to_chat(owner, "
You can use :k to talk to fellow monkeys!")
+ SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
+
+/datum/antagonist/monkey/on_removal()
+ . = ..()
+ owner.special_role = null
+ SSticker.mode.ape_infectees -= owner
+
+ var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
+ if(D)
+ D.cure()
+
+/datum/antagonist/monkey/create_team(datum/objective_team/monkey/new_team)
+ if(!new_team)
+ for(var/datum/antagonist/monkey/N in get_antagonists(/datum/antagonist/monkey, TRUE))
+ if(N.monkey_team)
+ monkey_team = N.monkey_team
+ return
+ monkey_team = new /datum/objective_team/monkey
+ monkey_team.update_objectives()
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ monkey_team = new_team
+
+/datum/antagonist/monkey/proc/forge_objectives()
+ if(monkey_team)
+ owner.objectives |= monkey_team.objectives
+
+/datum/antagonist/monkey/leader
+ name = "Monkey Leader"
+
+/datum/antagonist/monkey/leader/on_gain()
+ . = ..()
+ var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
+ if(D)
+ D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
+ var/obj/item/organ/heart/freedom/F = new
+ F.Insert(owner.current, drop_if_replaced = FALSE)
+ SSticker.mode.ape_leaders += owner
+ owner.special_role = "Monkey Leader"
+
+/datum/antagonist/monkey/leader/on_removal()
+ . = ..()
+ SSticker.mode.ape_leaders -= owner
+ var/obj/item/organ/heart/H = new
+ H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart
+
+/datum/antagonist/monkey/leader/greet()
+ to_chat(owner, "
You are the Jungle Fever patient zero!!")
+ to_chat(owner, "
You have been planted onto this station by the Animal Rights Consortium.")
+ to_chat(owner, "
Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.")
+ to_chat(owner, "
While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.")
+ to_chat(owner, "
Your mission will be deemed a success if any of the live infected monkeys reach CentCom.")
+ to_chat(owner, "
As an initial infectee, you will be considered a 'leader' by your fellow monkeys.")
+ to_chat(owner, "
You can use :k to talk to fellow monkeys!")
+ SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
+
+/datum/objective/monkey
+ explanation_text = "Ensure that infected monkeys escape on the emergency shuttle!"
+ martyr_compatible = TRUE
+ var/monkeys_to_win = 1
+ var/escaped_monkeys = 0
+
+/datum/objective/monkey/check_completion()
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
+ for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
+ if (M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
+ escaped_monkeys++
+ if(escaped_monkeys >= monkeys_to_win)
+ return TRUE
+ return FALSE
+
+/datum/objective_team/monkey
+ name = "Monkeys"
+
+/datum/objective_team/monkey/proc/update_objectives()
+ objectives = list()
+ var/datum/objective/monkey/O = new /datum/objective/monkey()
+ O.team = src
+ objectives += O
+ return
+
+/datum/objective_team/monkey/proc/infected_monkeys_alive()
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
+ for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
+ if(M.HasDisease(D))
+ return TRUE
+ return FALSE
+
+/datum/objective_team/monkey/proc/infected_monkeys_escaped()
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
+ for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
+ if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
+ return TRUE
+ return FALSE
+
+/datum/objective_team/monkey/proc/infected_humans_escaped()
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
+ for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
+ if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
+ return TRUE
+ return FALSE
+
+/datum/objective_team/monkey/proc/infected_humans_alive()
+ var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
+ for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
+ if(M.HasDisease(D))
+ return TRUE
+ return FALSE
+
+/datum/objective_team/monkey/proc/get_result()
+ if(infected_monkeys_escaped())
+ return MONKEYS_ESCAPED
+ if(infected_monkeys_alive())
+ return MONKEYS_LIVED
+ if(infected_humans_alive() || infected_humans_escaped())
+ return DISEASE_LIVED
+ return MONKEYS_DIED
+
+/datum/objective_team/monkey/roundend_report()
+ var/list/parts = list()
+ switch(get_result())
+ if(MONKEYS_ESCAPED)
+ parts += "
Monkey Major Victory!"
+ parts += "
Central Command and [station_name()] were taken over by the monkeys! Ook ook!"
+ if(MONKEYS_LIVED)
+ parts += "
Monkey Minor Victory!"
+ parts += "
[station_name()] was taken over by the monkeys! Ook ook!"
+ if(DISEASE_LIVED)
+ parts += "
Monkey Minor Defeat!"
+ parts += "
All the monkeys died, but the disease lives on! The future is uncertain."
+ if(MONKEYS_DIED)
+ parts += "
Monkey Major Defeat!"
+ parts += "
All the monkeys died, and Jungle Fever was wiped out!"
+ if(LAZYLEN(SSticker.mode.ape_leaders))
+ parts += ""
+ parts += printplayerlist(SSticker.mode.ape_leaders)
+ if(LAZYLEN(SSticker.mode.ape_infectees))
+ parts += ""
+ parts += printplayerlist(SSticker.mode.ape_infectees)
+ return "
[parts.Join("
")]
"
\ No newline at end of file
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
new file mode 100644
index 0000000000..8b7fc7826f
--- /dev/null
+++ b/code/datums/antagonists/nukeop.dm
@@ -0,0 +1,322 @@
+#define NUKE_RESULT_FLUKE 0
+#define NUKE_RESULT_NUKE_WIN 1
+#define NUKE_RESULT_CREW_WIN 2
+#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
+#define NUKE_RESULT_DISK_LOST 4
+#define NUKE_RESULT_DISK_STOLEN 5
+#define NUKE_RESULT_NOSURVIVORS 6
+#define NUKE_RESULT_WRONG_STATION 7
+#define NUKE_RESULT_WRONG_STATION_DEAD 8
+
+/datum/antagonist/nukeop
+ name = "Nuclear Operative"
+ roundend_category = "syndicate operatives" //just in case
+ job_rank = ROLE_OPERATIVE
+ 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
+
+/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
+ var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
+ opshud.join_hud(M)
+ set_antag_hud(M, "synd")
+
+/datum/antagonist/nukeop/proc/update_synd_icons_removed(mob/living/M)
+ var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
+ opshud.leave_hud(M)
+ set_antag_hud(M, null)
+
+/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_synd_icons_added(M)
+
+/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_synd_icons_removed(M)
+
+/datum/antagonist/nukeop/proc/equip_op()
+ 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)
+ return TRUE
+
+/datum/antagonist/nukeop/greet()
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
+ to_chat(owner, "
You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!")
+ owner.announce_objectives()
+ return
+
+/datum/antagonist/nukeop/on_gain()
+ give_alias()
+ forge_objectives()
+ . = ..()
+ equip_op()
+ memorize_code()
+ if(send_to_spawnpoint)
+ move_to_spawnpoint()
+
+/datum/antagonist/nukeop/get_team()
+ return nuke_team
+
+/datum/antagonist/nukeop/proc/assign_nuke()
+ if(nuke_team && !nuke_team.tracked_nuke)
+ nuke_team.memorized_code = random_nukecode()
+ var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
+ if(nuke)
+ nuke_team.tracked_nuke = nuke
+ if(nuke.r_code == "ADMIN")
+ nuke.r_code = nuke_team.memorized_code
+ else //Already set by admins/something else?
+ nuke_team.memorized_code = nuke.r_code
+ else
+ stack_trace("Syndicate nuke not found during nuke team creation.")
+ nuke_team.memorized_code = null
+
+/datum/antagonist/nukeop/proc/give_alias()
+ if(nuke_team && nuke_team.syndicate_name)
+ var/number = 1
+ number = nuke_team.members.Find(owner)
+ owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
+
+/datum/antagonist/nukeop/proc/memorize_code()
+ if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
+ owner.store_memory("
[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]", 0, 0)
+ to_chat(owner, "The nuclear authorization code is:
[nuke_team.memorized_code]")
+ else
+ to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
+
+/datum/antagonist/nukeop/proc/forge_objectives()
+ if(nuke_team)
+ owner.objectives |= nuke_team.objectives
+
+/datum/antagonist/nukeop/proc/move_to_spawnpoint()
+ var/team_number = 1
+ if(nuke_team)
+ team_number = nuke_team.members.Find(owner)
+ owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
+
+/datum/antagonist/nukeop/leader/move_to_spawnpoint()
+ owner.current.forceMove(pick(GLOB.nukeop_leader_start))
+
+/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/team/nuclear
+ nuke_team.update_objectives()
+ assign_nuke() //This is bit ugly
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ nuke_team = new_team
+
+/datum/antagonist/nukeop/leader
+ name = "Nuclear Operative Leader"
+ nukeop_outfit = /datum/outfit/syndicate/leader
+ always_new_team = TRUE
+ var/title
+
+/datum/antagonist/nukeop/leader/memorize_code()
+ ..()
+ if(nuke_team && nuke_team.memorized_code)
+ var/obj/item/paper/P = new
+ P.info = "The nuclear authorization code is:
[nuke_team.memorized_code]"
+ P.name = "nuclear bomb code"
+ var/mob/living/carbon/human/H = owner.current
+ if(!istype(H))
+ P.forceMove(get_turf(H))
+ else
+ H.put_in_hands(P, TRUE)
+ H.update_icons()
+
+/datum/antagonist/nukeop/leader/give_alias()
+ title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
+ if(nuke_team && nuke_team.syndicate_name)
+ owner.current.real_name = "[nuke_team.syndicate_name] [title]"
+ else
+ owner.current.real_name = "Syndicate [title]"
+
+/datum/antagonist/nukeop/leader/greet()
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
+ to_chat(owner, "
You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.")
+ to_chat(owner, "
If you feel you are not up to this task, give your ID to another operative.")
+ to_chat(owner, "
In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.")
+ owner.announce_objectives()
+ addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1)
+
+
+/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
+ if(!nuke_team)
+ return
+ nuke_team.rename_team(ask_name())
+
+/datum/team/nuclear/proc/rename_team(new_name)
+ syndicate_name = new_name
+ name = "[syndicate_name] Team"
+ for(var/I in members)
+ var/datum/mind/synd_mind = I
+ var/mob/living/carbon/human/H = synd_mind.current
+ if(!istype(H))
+ continue
+ var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
+ H.fully_replace_character_name(H.real_name,chosen_name)
+
+/datum/antagonist/nukeop/leader/proc/ask_name()
+ var/randomname = pick(GLOB.last_names)
+ var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
+ if (!newname)
+ newname = randomname
+ else
+ newname = reject_bad_name(newname)
+ if(!newname)
+ newname = randomname
+
+ return capitalize(newname)
+
+/datum/antagonist/nukeop/lone
+ name = "Lone Operative"
+ always_new_team = TRUE
+ send_to_spawnpoint = FALSE //Handled by event
+ nukeop_outfit = /datum/outfit/syndicate/full
+
+/datum/antagonist/nukeop/lone/assign_nuke()
+ if(nuke_team && !nuke_team.tracked_nuke)
+ nuke_team.memorized_code = random_nukecode()
+ var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
+ if(nuke)
+ nuke_team.tracked_nuke = nuke
+ if(nuke.r_code == "ADMIN")
+ nuke.r_code = nuke_team.memorized_code
+ else //Already set by admins/something else?
+ nuke_team.memorized_code = nuke.r_code
+ else
+ stack_trace("Station self destruct ot found during lone op team creation.")
+ nuke_team.memorized_code = null
+
+/datum/team/nuclear
+ var/syndicate_name
+ var/obj/machinery/nuclearbomb/tracked_nuke
+ var/core_objective = /datum/objective/nuclear
+ var/memorized_code
+
+/datum/team/nuclear/New()
+ ..()
+ syndicate_name = syndicate_name()
+
+/datum/team/nuclear/proc/update_objectives()
+ if(core_objective)
+ var/datum/objective/O = new core_objective
+ O.team = src
+ objectives += O
+
+/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/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/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/team/nuclear/proc/get_result()
+ var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
+ var/disk_rescued = disk_rescued()
+ var/syndies_didnt_escape = !syndies_escaped()
+ var/station_was_nuked = SSticker.mode.station_was_nuked
+ var/nuke_off_station = SSticker.mode.nuke_off_station
+
+ if(nuke_off_station == NUKE_SYNDICATE_BASE)
+ return NUKE_RESULT_FLUKE
+ else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
+ return NUKE_RESULT_NUKE_WIN
+ else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
+ return NUKE_RESULT_NOSURVIVORS
+ else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
+ return NUKE_RESULT_WRONG_STATION
+ else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
+ return NUKE_RESULT_WRONG_STATION_DEAD
+ else if ((disk_rescued || evacuation) && operatives_dead())
+ return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
+ else if (disk_rescued)
+ return NUKE_RESULT_CREW_WIN
+ else if (!disk_rescued && operatives_dead())
+ return NUKE_RESULT_DISK_LOST
+ else if (!disk_rescued && evacuation)
+ return NUKE_RESULT_DISK_STOLEN
+ else
+ return //Undefined result
+
+/datum/team/nuclear/roundend_report()
+ var/list/parts = list()
+ parts += ""
+
+ switch(get_result())
+ if(NUKE_RESULT_FLUKE)
+ 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)
+ parts += "
Syndicate Major Victory!"
+ parts += "
[syndicate_name] operatives have destroyed [station_name()]!"
+ if(NUKE_RESULT_NOSURVIVORS)
+ 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)
+ 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)
+ 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)
+ parts += "
Crew Major Victory!"
+ parts += "
The Research Staff has saved the disk and killed the [syndicate_name] Operatives"
+ if(NUKE_RESULT_CREW_WIN)
+ parts += "
Crew Major Victory"
+ parts += "
The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!"
+ if(NUKE_RESULT_DISK_LOST)
+ 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)
+ 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
+ parts += "
Neutral Victory"
+ parts += "
Mission aborted!"
+
+ var/text = "
"
+ var/purchases = ""
+ var/TC_uses = 0
+ for(var/I in members)
+ var/datum/mind/syndicate = I
+ for(var/U in GLOB.uplinks)
+ var/datum/component/uplink/H = U
+ if(H.owner == syndicate.key)
+ 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")]"
+
+ 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/beam.dm b/code/datums/beam.dm
index c1a75c8b7e..dc68de933a 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -128,11 +128,11 @@
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
- a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
+ a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
- a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
+ a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
X.y += a
Pixel_y %= 32
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
new file mode 100644
index 0000000000..ea01a87506
--- /dev/null
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -0,0 +1,157 @@
+/datum/brain_trauma/special/imaginary_friend
+ name = "Imaginary Friend"
+ desc = "Patient can see and hear an imaginary person."
+ scan_desc = "partial schizophrenia"
+ gain_text = "
You feel in good company, for some reason."
+ lose_text = "
You feel lonely again."
+ var/mob/camera/imaginary_friend/friend
+ var/friend_initialized = FALSE
+
+/datum/brain_trauma/special/imaginary_friend/on_gain()
+ ..()
+ make_friend()
+ get_ghost()
+
+/datum/brain_trauma/special/imaginary_friend/on_life()
+ if(get_dist(owner, friend) > 9)
+ friend.yank()
+ if(!friend)
+ qdel(src)
+ return
+ if(!friend.client && friend_initialized)
+ addtimer(CALLBACK(src, .proc/reroll_friend), 600)
+
+/datum/brain_trauma/special/imaginary_friend/on_lose()
+ ..()
+ QDEL_NULL(friend)
+
+//If the friend goes afk, make a brand new friend. Plenty of fish in the sea of imagination.
+/datum/brain_trauma/special/imaginary_friend/proc/reroll_friend()
+ if(friend.client) //reconnected
+ return
+ friend_initialized = FALSE
+ QDEL_NULL(friend)
+ make_friend()
+ get_ghost()
+
+/datum/brain_trauma/special/imaginary_friend/proc/make_friend()
+ friend = new(get_turf(src), src)
+
+/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
+ set waitfor = FALSE
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend)
+ if(LAZYLEN(candidates))
+ var/client/C = pick(candidates)
+ friend.key = C.key
+ friend_initialized = TRUE
+ else
+ qdel(src)
+
+/mob/camera/imaginary_friend
+ name = "imaginary friend"
+ real_name = "imaginary friend"
+ move_on_shuttle = TRUE
+ desc = "A wonderful yet fake friend."
+ see_in_dark = 0
+ lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
+ sight = NONE
+ see_invisible = SEE_INVISIBLE_LIVING
+ var/icon/human_image
+ var/image/current_image
+ var/mob/living/carbon/owner
+ var/datum/brain_trauma/special/imaginary_friend/trauma
+
+/mob/camera/imaginary_friend/Login()
+ ..()
+ to_chat(src, "
You are the imaginary friend of [owner]!")
+ to_chat(src, "
You are absolutely loyal to your friend, no matter what.")
+ to_chat(src, "
You cannot directly influence the world around you, but you can see what [owner] cannot.")
+
+/mob/camera/imaginary_friend/Initialize(mapload, _trauma)
+ . = ..()
+ var/gender = pick(MALE, FEMALE)
+ real_name = random_unique_name(gender)
+ name = real_name
+ trauma = _trauma
+ owner = trauma.owner
+ human_image = get_flat_human_icon(null, pick(SSjob.occupations))
+ Show()
+
+/mob/camera/imaginary_friend/proc/Show()
+ if(!client) //nobody home
+ return
+
+ //Remove old image from owner and friend
+ if(owner.client)
+ owner.client.images.Remove(current_image)
+
+ client.images.Remove(current_image)
+
+ //Generate image from the static icon and the current dir
+ current_image = image(human_image, src, , MOB_LAYER, dir=src.dir)
+ current_image.override = TRUE
+ current_image.name = name
+
+ //Add new image to owner and friend
+ if(owner.client)
+ owner.client.images |= current_image
+
+ client.images |= current_image
+
+/mob/camera/imaginary_friend/Destroy()
+ if(owner.client)
+ owner.client.images.Remove(human_image)
+ if(client)
+ client.images.Remove(human_image)
+ return ..()
+
+/mob/camera/imaginary_friend/proc/yank()
+ if(!client) //don't bother if the friend is braindead
+ return
+ forceMove(get_turf(owner))
+ Show()
+
+/mob/camera/imaginary_friend/say(message)
+ if (!message)
+ return
+
+ if (src.client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+ if (src.client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ friend_talk(message)
+
+/mob/camera/imaginary_friend/proc/friend_talk(message)
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ if(!message)
+ return
+
+ log_talk(src,"[key_name(src)] : [message]",LOGSAY)
+
+ var/rendered = "
[name] [say_quote(message)]"
+ var/dead_rendered = "
[name] (Imaginary friend of [owner]) [say_quote(message)]"
+
+ to_chat(owner, "[rendered]")
+ to_chat(src, "[rendered]")
+
+ for(var/mob/M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, owner)
+ to_chat(M, "[link] [dead_rendered]")
+
+/mob/camera/imaginary_friend/emote(act,m_type=1,message = null)
+ return
+
+/mob/camera/imaginary_friend/forceMove(atom/destination)
+ dir = get_dir(get_turf(src), destination)
+ loc = destination
+ if(get_dist(src, owner) > 9)
+ yank()
+ return
+ Show()
+
+/mob/camera/imaginary_friend/movement_delay()
+ return 2
diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm
index 6bfa149aa7..d5ccc71ef9 100644
--- a/code/datums/brain_damage/mild.dm
+++ b/code/datums/brain_damage/mild.dm
@@ -42,7 +42,7 @@
lose_text = "
You feel smart again."
/datum/brain_trauma/mild/dumbness/on_gain()
- owner.disabilities |= DUMB
+ owner.add_disability(DUMB, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/mild/dumbness/on_life()
@@ -54,7 +54,7 @@
..()
/datum/brain_trauma/mild/dumbness/on_lose()
- owner.disabilities &= ~DUMB
+ owner.remove_disability(DUMB, TRAUMA_DISABILITY)
owner.derpspeech = 0
..()
@@ -107,6 +107,26 @@
..()
+/datum/brain_trauma/mild/healthy
+ name = "Anosognosia"
+ desc = "Patient always feels healthy, regardless of their condition."
+ scan_desc = "self-awareness deficit"
+ gain_text = "
You feel great!"
+ lose_text = "
You no longer feel perfectly healthy."
+
+/datum/brain_trauma/mild/healthy/on_gain()
+ owner.set_screwyhud(SCREWYHUD_HEALTHY)
+ ..()
+
+/datum/brain_trauma/mild/healthy/on_life()
+ owner.set_screwyhud(SCREWYHUD_HEALTHY) //just in case of hallucinations
+ owner.adjustStaminaLoss(-5) //no pain, no fatigue
+ ..()
+
+/datum/brain_trauma/mild/healthy/on_lose()
+ owner.set_screwyhud(SCREWYHUD_NONE)
+ ..()
+
/datum/brain_trauma/mild/muscle_weakness
name = "Muscle Weakness"
desc = "Patient experiences occasional bouts of muscle weakness."
@@ -133,3 +153,62 @@
to_chat(owner, "
You feel a sudden weakness in your muscles!")
owner.adjustStaminaLoss(50)
..()
+
+/datum/brain_trauma/mild/muscle_spasms
+ name = "Muscle Spasms"
+ desc = "Patient has occasional muscle spasms, causing them to move unintentionally."
+ scan_desc = "nervous fits"
+ gain_text = "
Your muscles feel oddly faint."
+ lose_text = "
You feel in control of your muscles again."
+
+/datum/brain_trauma/mild/muscle_spasms/on_life()
+ if(prob(7))
+ switch(rand(1,5))
+ if(1)
+ if(owner.canmove && !isspaceturf(owner.loc))
+ to_chat(owner, "
Your leg spasms!")
+ step(owner, pick(GLOB.cardinals))
+ if(2)
+ if(owner.incapacitated())
+ return
+ var/obj/item/I = owner.get_active_held_item()
+ if(I)
+ to_chat(owner, "
Your fingers spasm!")
+ log_attack("[key_name(owner)] used [I] due to a Muscle Spasm.")
+ I.attack_self(owner)
+ if(3)
+ var/prev_intent = owner.a_intent
+ owner.a_intent = INTENT_HARM
+
+ var/range = 1
+ if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
+ range = 7
+
+ var/list/mob/living/targets = list()
+ for(var/mob/M in oview(owner, range))
+ if(isliving(M))
+ targets += M
+ if(LAZYLEN(targets))
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] attacked someone due to a Muscle Spasm.") //the following attack will log itself
+ owner.ClickOn(pick(targets))
+ owner.a_intent = prev_intent
+ if(4)
+ var/prev_intent = owner.a_intent
+ owner.a_intent = INTENT_HARM
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] attacked himself to a Muscle Spasm.")
+ owner.ClickOn(owner)
+ owner.a_intent = prev_intent
+ if(5)
+ if(owner.incapacitated())
+ return
+ var/obj/item/I = owner.get_active_held_item()
+ var/list/turf/targets = list()
+ for(var/turf/T in oview(owner, 3))
+ targets += T
+ if(LAZYLEN(targets) && I)
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] threw [I] due to a Muscle Spasm.")
+ owner.throw_item(pick(targets))
+ ..()
\ No newline at end of file
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index 08cee65085..a138073040 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -7,22 +7,39 @@
/datum/brain_trauma/severe/mute
name = "Mutism"
desc = "Patient is completely unable to speak."
- scan_desc = "extensive damage to the brain's language center"
+ scan_desc = "extensive damage to the brain's speech center"
gain_text = "
You forget how to speak!"
lose_text = "
You suddenly remember how to speak."
/datum/brain_trauma/severe/mute/on_gain()
- owner.disabilities |= MUTE
- ..()
-
-//no fiddling with genetics to get out of this one
-/datum/brain_trauma/severe/mute/on_life()
- if(!(owner.disabilities & MUTE))
- on_gain()
+ owner.add_disability(MUTE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/mute/on_lose()
- owner.disabilities &= ~MUTE
+ owner.remove_disability(MUTE, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/aphasia
+ name = "Aphasia"
+ desc = "Patient is unable to speak or understand any language."
+ scan_desc = "extensive damage to the brain's language center"
+ gain_text = "
You have trouble forming words in your head..."
+ lose_text = "
You suddenly remember how languages work."
+ var/datum/language_holder/prev_language
+ var/datum/language_holder/mob_language
+
+/datum/brain_trauma/severe/aphasia/on_gain()
+ mob_language = owner.get_language_holder()
+ prev_language = mob_language.copy()
+ mob_language.remove_all_languages()
+ mob_language.grant_language(/datum/language/aphasia)
+ ..()
+
+/datum/brain_trauma/severe/aphasia/on_lose()
+ mob_language.remove_language(/datum/language/aphasia)
+ mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
+ QDEL_NULL(prev_language)
+ mob_language = null
..()
/datum/brain_trauma/severe/blindness
@@ -33,17 +50,11 @@
lose_text = "
Your vision returns."
/datum/brain_trauma/severe/blindness/on_gain()
- owner.become_blind()
- ..()
-
-//no fiddling with genetics to get out of this one
-/datum/brain_trauma/severe/blindness/on_life()
- if(!(owner.disabilities & BLIND))
- on_gain()
+ owner.become_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/blindness/on_lose()
- owner.cure_blind()
+ owner.cure_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/paralysis
@@ -109,7 +120,7 @@
stress -= 4
/datum/brain_trauma/severe/monophobia/proc/check_alone()
- if(owner.disabilities & BLIND)
+ if(owner.has_disability(BLIND))
return TRUE
for(var/mob/M in oview(owner, 7))
if(!isliving(M)) //ghosts ain't people
@@ -171,9 +182,39 @@
lose_text = "
You feel in control of your hands again."
/datum/brain_trauma/severe/discoordination/on_gain()
- owner.disabilities |= MONKEYLIKE
+ owner.add_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/discoordination/on_lose()
- owner.disabilities &= ~MONKEYLIKE
+ owner.remove_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
+
+/datum/brain_trauma/severe/pacifism
+ name = "Traumatic Non-Violence"
+ desc = "Patient is extremely unwilling to harm others in violent ways."
+ scan_desc = "pacific syndrome"
+ gain_text = "
You feel oddly peaceful."
+ lose_text = "
You no longer feel compelled to not harm."
+
+/datum/brain_trauma/severe/pacifism/on_gain()
+ owner.add_disability(PACIFISM, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/pacifism/on_lose()
+ owner.remove_disability(PACIFISM, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/pacifism
+ name = "Traumatic Non-Violence"
+ desc = "Patient is extremely unwilling to harm others in violent ways."
+ scan_desc = "pacific syndrome"
+ gain_text = "
You feel oddly peaceful."
+ lose_text = "
You no longer feel compelled to not harm."
+
+/datum/brain_trauma/severe/pacifism/on_gain()
+ owner.disabilities |= PACIFISM
+ ..()
+
+/datum/brain_trauma/severe/pacifism/on_lose()
+ owner.disabilities &= ~PACIFISM
+ ..()
\ No newline at end of file
diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm
index ddb8f8e6e6..db0ca60801 100644
--- a/code/datums/brain_damage/special.dm
+++ b/code/datums/brain_damage/special.dm
@@ -9,25 +9,35 @@
scan_desc = "god delusion"
gain_text = "
You feel a higher power inside your mind..."
lose_text = "
The divine presence leaves your head, no longer interested."
- var/next_speech = 0
- var/inspiration = FALSE
/datum/brain_trauma/special/godwoken/on_life()
..()
- if(!inspiration && world.time > next_speech && prob(4))
- to_chat(owner, "
[pick("You feel inspired!","You feel power course through you...","You feel something within you itching to speak...")]")
- inspiration = TRUE
+ if(prob(4))
+ if(prob(33) && (owner.IsStun() || owner.IsKnockdown() || owner.IsUnconscious()))
+ speak("unstun", TRUE)
+ else if(prob(60) && owner.health <= HEALTH_THRESHOLD_CRIT)
+ speak("heal", TRUE)
+ else if(prob(30) && owner.a_intent == INTENT_HARM)
+ speak("aggressive")
+ else
+ speak("neutral", prob(25))
-/datum/brain_trauma/special/godwoken/on_say(message)
- if(world.time > next_speech && inspiration)
- playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5)
- var/cooldown = voice_of_god(message, owner, list("colossus","yell"), 2)
- cooldown *= 0.33
- next_speech = world.time + cooldown
- inspiration = FALSE
- return ""
- else
- return message
+/datum/brain_trauma/special/godwoken/proc/speak(type, include_owner = FALSE)
+ var/message
+ switch(type)
+ if("unstun")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_unstun")
+ if("heal")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_heal")
+ if("neutral")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
+ if("aggressive")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_aggressive")
+ else
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
+
+ playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5)
+ voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE)
/datum/brain_trauma/special/bluespace_prophet
name = "Bluespace Prophecy"
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index c726b2ecb5..deed1c8406 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -23,7 +23,7 @@
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", null, null, null, 75, stranger_backseat)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
stranger_backseat.key = C.key
@@ -136,6 +136,7 @@
/mob/living/split_personality/Login()
..()
to_chat(src, "
As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.")
+ to_chat(src, "
Do not commit suicide or put the body in a deadly position. Behave like you care about it as much as the owner.")
/mob/living/split_personality/say(message)
to_chat(src, "
You cannot speak, your other self is controlling your body!")
diff --git a/code/datums/callback.dm b/code/datums/callback.dm
index 88d9427301..5566137189 100644
--- a/code/datums/callback.dm
+++ b/code/datums/callback.dm
@@ -48,6 +48,7 @@
var/datum/object = GLOBAL_PROC
var/delegate
var/list/arguments
+ var/datum/weakref/user
/datum/callback/New(thingtocall, proctocall, ...)
if (thingtocall)
@@ -55,6 +56,8 @@
delegate = proctocall
if (length(args) > 2)
arguments = args.Copy(3)
+ if(usr)
+ user = WEAKREF(usr)
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
@@ -70,8 +73,16 @@
call(thingtocall, proctocall)(arglist(calling_arguments))
/datum/callback/proc/Invoke(...)
+ if(!usr)
+ var/datum/weakref/W = user
+ if(W)
+ var/mob/M = W.resolve()
+ if(M)
+ return world.PushUsr(M, src)
+
if (!object)
return
+
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
@@ -87,8 +98,17 @@
//copy and pasted because fuck proc overhead
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
+
+ if(!usr)
+ var/datum/weakref/W = user
+ if(W)
+ var/mob/M = W.resolve()
+ if(M)
+ return world.PushUsr(M, src)
+
if (!object)
return
+
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
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/archaeology.dm b/code/datums/components/archaeology.dm
index 6fb2b67051..30bf107ad0 100644
--- a/code/datums/components/archaeology.dm
+++ b/code/datums/components/archaeology.dm
@@ -6,7 +6,7 @@
var/datum/callback/callback
/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list(), datum/callback/_callback)
- prob2drop = Clamp(_prob2drop, 0, 100)
+ prob2drop = CLAMP(_prob2drop, 0, 100)
archdrops = _archdrops
callback = _callback
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
diff --git a/code/datums/components/cleaning.dm b/code/datums/components/cleaning.dm
new file mode 100644
index 0000000000..5d9d5992e2
--- /dev/null
+++ b/code/datums/components/cleaning.dm
@@ -0,0 +1,40 @@
+/datum/component/cleaning
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+
+/datum/component/cleaning/Initialize()
+ if(!ismovableatom(parent))
+ . = COMPONENT_INCOMPATIBLE
+ CRASH("[type] added to a [parent.type]")
+ RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
+
+/datum/component/cleaning/proc/Clean()
+ var/atom/movable/AM = parent
+ var/turf/tile = AM.loc
+ if(!isturf(tile))
+ return
+
+ tile.clean_blood()
+ for(var/A in tile)
+ if(is_cleanable(A))
+ qdel(A)
+ else if(istype(A, /obj/item))
+ var/obj/item/cleaned_item = A
+ cleaned_item.clean_blood()
+ else if(ishuman(A))
+ var/mob/living/carbon/human/cleaned_human = A
+ if(cleaned_human.lying)
+ if(cleaned_human.head)
+ cleaned_human.head.clean_blood()
+ cleaned_human.update_inv_head()
+ if(cleaned_human.wear_suit)
+ cleaned_human.wear_suit.clean_blood()
+ cleaned_human.update_inv_wear_suit()
+ else if(cleaned_human.w_uniform)
+ cleaned_human.w_uniform.clean_blood()
+ cleaned_human.update_inv_w_uniform()
+ if(cleaned_human.shoes)
+ cleaned_human.shoes.clean_blood()
+ cleaned_human.update_inv_shoes()
+ cleaned_human.clean_blood()
+ cleaned_human.wash_cream()
+ to_chat(cleaned_human, "
[AM] cleans your face!")
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index a28213b0b5..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 = SimplifyDegrees(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/jousting.dm b/code/datums/components/jousting.dm
new file mode 100644
index 0000000000..68621e60ec
--- /dev/null
+++ b/code/datums/components/jousting.dm
@@ -0,0 +1,81 @@
+/datum/component/jousting
+ var/current_direction = NONE
+ var/max_tile_charge = 5
+ var/min_tile_charge = 2 //tiles before this code gets into effect.
+ var/current_tile_charge = 0
+ var/movement_reset_tolerance = 2 //deciseconds
+ var/unmounted_damage_boost_per_tile = 0
+ var/unmounted_knockdown_chance_per_tile = 0
+ var/unmounted_knockdown_time = 0
+ var/mounted_damage_boost_per_tile = 2
+ var/mounted_knockdown_chance_per_tile = 20
+ var/mounted_knockdown_time = 20
+ var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
+ var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
+ var/mob/current_holder
+ var/datum/component/redirect/listener
+ var/current_timerid
+
+/datum/component/jousting/Initialize()
+ if(!isitem(parent))
+ . = COMPONENT_INCOMPATIBLE
+ stack_trace("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
+ RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
+ RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
+ RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
+
+/datum/component/jousting/Destroy()
+ QDEL_NULL(listener)
+ return ..()
+
+/datum/component/jousting/proc/on_equip(mob/user, slot)
+ QDEL_NULL(listener)
+ current_holder = user
+ listener = new(user, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/mob_move))
+
+/datum/component/jousting/proc/on_drop(mob/user)
+ QDEL_NULL(listener)
+ current_holder = null
+ current_direction = NONE
+ current_tile_charge = 0
+
+/datum/component/jousting/proc/on_attack(mob/living/target, mob/user)
+ if(user != current_holder)
+ return
+ var/current = current_tile_charge
+ var/obj/item/I = parent
+ var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
+ if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
+ return
+ var/turf/target_turf = get_step(user, current_direction)
+ if(target in range(1, target_turf))
+ var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
+ var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
+ var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
+ var/sharp = I.is_sharp()
+ var/msg
+ if(damage)
+ msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
+ target.apply_damage(damage, BRUTE, user.zone_selected, 0)
+ if(prob(knockdown_chance))
+ msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
+ if(target_buckled)
+ target.buckled.unbuckle_mob(target)
+ target.Knockdown(knockdown_time)
+ if(length(msg))
+ user.visible_message("
[msg]!")
+
+/datum/component/jousting/proc/mob_move(newloc, dir)
+ if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
+ return
+ if(dir != current_direction)
+ current_tile_charge = 0
+ current_direction = dir
+ if(current_tile_charge < max_tile_charge)
+ current_tile_charge++
+ if(current_timerid)
+ deltimer(current_timerid)
+ current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
+
+/datum/component/jousting/proc/reset_charge()
+ current_tile_charge = 0
diff --git a/code/datums/components/knockoff.dm b/code/datums/components/knockoff.dm
new file mode 100644
index 0000000000..35d1e5423e
--- /dev/null
+++ b/code/datums/components/knockoff.dm
@@ -0,0 +1,53 @@
+//Items with these will have a chance to get knocked off when disarming
+/datum/component/knockoff
+ var/knockoff_chance = 100 //Chance to knockoff
+ var/list/target_zones //Aiming for these zones will cause the knockoff, null means all zones allowed
+ var/list/slots_knockoffable //Can be only knocked off from these slots, null means all slots allowed
+ var/datum/component/redirect/disarm_redirect
+
+/datum/component/knockoff/Initialize(knockoff_chance,zone_override,slots_knockoffable)
+ if(!isitem(parent))
+ . = COMPONENT_INCOMPATIBLE
+ CRASH("Knockoff component misuse")
+ RegisterSignal(COMSIG_ITEM_EQUIPPED,.proc/OnEquipped)
+ RegisterSignal(COMSIG_ITEM_DROPPED,.proc/OnDropped)
+
+ src.knockoff_chance = knockoff_chance
+
+ if(zone_override)
+ target_zones = zone_override
+
+ if(slots_knockoffable)
+ src.slots_knockoffable = slots_knockoffable
+
+/datum/component/knockoff/proc/Knockoff(mob/living/attacker,zone)
+ var/obj/item/I = parent
+ var/mob/living/carbon/human/wearer = I.loc
+ if(!istype(wearer))
+ return
+ if(target_zones && !(zone in target_zones))
+ return
+ if(!prob(knockoff_chance))
+ return
+ if(!wearer.dropItemToGround(I))
+ return
+
+ wearer.visible_message("
[attacker] knocks off [wearer]'s [I.name]!","
[attacker] knocks off your [I.name]!")
+
+/datum/component/knockoff/proc/OnEquipped(mob/living/carbon/human/H,slot)
+ if(!istype(H))
+ return
+ if(slots_knockoffable && !(slot in slots_knockoffable))
+ if(disarm_redirect)
+ QDEL_NULL(disarm_redirect)
+ return
+ if(!disarm_redirect)
+ disarm_redirect = H.AddComponent(/datum/component/redirect,list(COMSIG_HUMAN_DISARM_HIT),CALLBACK(src,.proc/Knockoff))
+
+/datum/component/knockoff/proc/OnDropped(mob/living/M)
+ if(disarm_redirect)
+ QDEL_NULL(disarm_redirect)
+
+/datum/component/knockoff/Destroy()
+ QDEL_NULL(disarm_redirect)
+ . = ..()
\ No newline at end of file
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/dash_weapon.dm b/code/datums/dash_weapon.dm
index 1637655d18..03badb2069 100644
--- a/code/datums/dash_weapon.dm
+++ b/code/datums/dash_weapon.dm
@@ -43,7 +43,7 @@
addtimer(CALLBACK(src, .proc/charge), charge_rate)
/datum/action/innate/dash/proc/charge()
- current_charges = Clamp(current_charges + 1, 0, max_charges)
+ current_charges = CLAMP(current_charges + 1, 0, max_charges)
holder.update_action_buttons_icon()
if(recharge_sound)
playsound(dashing_item, recharge_sound, 50, 1)
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 0c1058a287..60f90d61ad 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -185,10 +185,10 @@
if(properties["stealth"] >= 2)
visibility_flags = HIDDEN_SCANNER
- SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
+ SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
- permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
- cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
+ permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
+ cure_chance = 15 - CLAMP(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
@@ -243,7 +243,7 @@
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure()
if(properties && properties.len)
- var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
+ var/res = CLAMP(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
cures = list(advance_cures[res])
// Get the cure name from the cure_id
diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm
index 104a4c00c2..4f208b826b 100644
--- a/code/datums/diseases/advance/symptoms/heal.dm
+++ b/code/datums/diseases/advance/symptoms/heal.dm
@@ -1,10 +1,10 @@
/datum/symptom/heal
name = "Basic Healing (does nothing)" //warning for adminspawn viruses
desc = "You should not be seeing this."
- stealth = 1
- resistance = -4
- stage_speed = -4
- transmittable = -4
+ stealth = 0
+ resistance = 0
+ stage_speed = 0
+ transmittable = 0
level = 0 //not obtainable
base_message_chance = 20 //here used for the overlays
symptom_delay_min = 1
@@ -22,7 +22,6 @@
/datum/symptom/heal/Activate(datum/disease/advance/A)
if(!..())
return
- //100% chance to activate for slow but consistent healing
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
@@ -45,20 +44,20 @@
return TRUE
-/datum/symptom/heal/toxin
+/datum/symptom/heal/starlight
name = "Starlight Condensation"
- desc = "The virus reacts to direct starlight, producing regenerative chemicals that can cure toxin damage."
- stealth = 1
- resistance = -3
- stage_speed = -3
- transmittable = -3
+ desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
+ stealth = -1
+ resistance = -2
+ stage_speed = 0
+ transmittable = 1
level = 6
passive_message = "
You miss the feeling of starlight on your skin."
var/nearspace_penalty = 0.3
threshold_desc = "
Stage Speed 6: Increases healing speed.
\
Transmission 6: Removes penalty for only being close to space."
-/datum/symptom/heal/toxin/Start(datum/disease/advance/A)
+/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmission"] >= 6)
@@ -66,7 +65,7 @@
if(A.properties["stage_rate"] >= 6)
power = 2
-/datum/symptom/heal/toxin/CanHeal(datum/disease/advance/A)
+/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(istype(get_turf(M), /turf/open/space))
return power
@@ -75,15 +74,25 @@
if(istype(T, /turf/open/space))
return power * nearspace_penalty
-/datum/symptom/heal/toxin/Heal(mob/living/M, datum/disease/advance/A, actual_power)
+/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(M.getToxLoss() && prob(5))
- to_chat(M, "
Your skin tingles as the starlight purges toxins from your bloodstream.")
- M.adjustToxLoss(-heal_amt)
+ to_chat(M, "
Your skin tingles as the starlight seems to heal you.")
+
+ M.adjustToxLoss(-(4 * heal_amt)) //most effective on toxins
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+
+ if(!parts.len)
+ return
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
+ M.update_damage_overlays()
return 1
-/datum/symptom/heal/toxin/passive_message_condition(mob/living/M)
- if(M.getToxLoss())
+/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
return TRUE
return FALSE
@@ -91,7 +100,7 @@
name = "Toxolysis"
stealth = 0
resistance = -2
- stage_speed = -2
+ stage_speed = 2
transmittable = -2
level = 7
var/food_conversion = FALSE
@@ -153,58 +162,50 @@
to_chat(C, "
You feel an odd gurgle in your stomach, as if it was working much faster than normal.")
return 1
-/datum/symptom/heal/brute
- name = "Cellular Molding"
- desc = "The virus is able to shift cells around when in conditions of high heat, repairing existing physical damage."
- stealth = 1
- resistance = -3
- stage_speed = -3
- transmittable = -3
+/datum/symptom/heal/darkness
+ name = "Nocturnal Regeneration"
+ desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
+ stealth = 2
+ resistance = -1
+ stage_speed = -2
+ transmittable = -1
level = 6
- passive_message = "
You feel the flesh pulsing under your skin for a moment, but it's too cold to move."
+ passive_message = "
You feel tingling on your skin as light passes over it."
threshold_desc = "
Stage Speed 8: Doubles healing speed."
-/datum/symptom/heal/brute/Start(datum/disease/advance/A)
+/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
power = 2
-/datum/symptom/heal/brute/CanHeal(datum/disease/advance/A)
+/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
- switch(M.bodytemperature)
- if(0 to 340)
- return FALSE
- if(340 to BODYTEMP_HEAT_DAMAGE_LIMIT)
- . = 0.3 * power
- if(BODYTEMP_HEAT_DAMAGE_LIMIT to 400)
- . = 0.75 * power
- if(400 to 460)
- . = power
- else
- . = 1.5 * power
+ var/light_amount = 0
+ if(isturf(M.loc)) //else, there's considered to be no light
+ var/turf/T = M.loc
+ light_amount = min(1,T.get_lumcount()) - 0.5
+ if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
+ return power
- if(M.on_fire)
- . *= 2
-
-/datum/symptom/heal/brute/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
- var/list/parts = M.get_damaged_bodyparts(1,0) //brute only
+ var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
- to_chat(M, "
You feel your flesh moving beneath your heated skin, mending your wounds.")
+ to_chat(M, "
The darkness soothes and mends your wounds.")
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, 0))
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
M.update_damage_overlays()
return 1
-/datum/symptom/heal/brute/passive_message_condition(mob/living/M)
- if(M.getBruteLoss())
+/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
@@ -212,8 +213,8 @@
name = "Regenerative Coma"
desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
stealth = 0
- resistance = 0
- stage_speed = -2
+ resistance = 2
+ stage_speed = -3
transmittable = -2
level = 8
passive_message = "
The pain from your wounds makes you feel oddly sleepy..."
@@ -283,20 +284,20 @@
return TRUE
return FALSE
-/datum/symptom/heal/burn
+/datum/symptom/heal/water
name = "Tissue Hydration"
- desc = "The virus uses excess water inside and outside the body to repair burned tisue cells."
- stealth = 1
- resistance = -3
- stage_speed = -3
- transmittable = -3
+ desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
+ stealth = 0
+ resistance = -1
+ stage_speed = 0
+ transmittable = 1
level = 6
- passive_message = "
Your burned skin feels oddly dry..."
+ passive_message = "
Your skin feels oddly dry..."
var/absorption_coeff = 1
threshold_desc = "
Resistance 5: Water is consumed at a much slower rate.
\
Stage Speed 7: Increases healing speed."
-/datum/symptom/heal/burn/Start(datum/disease/advance/A)
+/datum/symptom/heal/water/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
@@ -304,7 +305,7 @@
if(A.properties["stealth"] >= 2)
absorption_coeff = 0.25
-/datum/symptom/heal/burn/CanHeal(datum/disease/advance/A)
+/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
. = 0
var/mob/living/M = A.affected_mob
if(M.fire_stacks < 0)
@@ -317,33 +318,33 @@
M.reagents.remove_reagent("water", 0.5 * absorption_coeff)
. += power * 0.5
-/datum/symptom/heal/burn/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
- var/list/parts = M.get_damaged_bodyparts(0,1) //burn only
+ var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
if(!parts.len)
return
if(prob(5))
- to_chat(M, "
You feel yourself absorbing the water around you to soothe your burned skin.")
+ to_chat(M, "
You feel yourself absorbing the water around you to soothe your damaged skin.")
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(0, heal_amt/parts.len))
+ if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
M.update_damage_overlays()
return 1
-/datum/symptom/heal/burn/passive_message_condition(mob/living/M)
- if(M.getFireLoss())
+/datum/symptom/heal/water/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/plasma
name = "Plasma Fixation"
- desc = "The virus draws plasma from the atmosphere and from inside the body to stabilize body temperature and heal burns."
+ desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
stealth = 0
- resistance = 0
+ resistance = 3
stage_speed = -2
transmittable = -2
level = 8
@@ -379,8 +380,6 @@
/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
- var/list/parts = M.get_damaged_bodyparts(0,1) //burn only
-
if(prob(5))
to_chat(M, "
You feel yourself absorbing plasma inside and around you...")
@@ -393,24 +392,25 @@
if(prob(5))
to_chat(M, "
You feel warmer.")
+ M.adjustToxLoss(-heal_amt)
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
- to_chat(M, "
The pain from your burns fades rapidly.")
-
+ to_chat(M, "
The pain from your wounds fades rapidly.")
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(0, heal_amt/parts.len))
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
-
/datum/symptom/heal/radiation
name = "Radioactive Resonance"
desc = "The virus uses radiation to fix damage through dna mutations."
stealth = -1
resistance = -2
- stage_speed = 0
+ stage_speed = 2
transmittable = -3
level = 6
symptom_delay_min = 1
@@ -450,6 +450,8 @@
if(cellular_damage)
M.adjustCloneLoss(-heal_amt * 0.5)
+ M.adjustToxLoss(-(2 * heal_amt))
+
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm
index 728dfa01d0..39d853a758 100644
--- a/code/datums/diseases/advance/symptoms/vision.dm
+++ b/code/datums/diseases/advance/symptoms/vision.dm
@@ -58,11 +58,12 @@ Bonus
M.blur_eyes(20)
M.adjust_eye_damage(5)
if(eyes.eye_damage >= 10)
- M.become_nearsighted()
+ M.become_nearsighted(EYE_DAMAGE)
if(prob(eyes.eye_damage - 10 + 1))
if(!remove_eyes)
- if(M.become_blind())
+ if(!M.has_disability(BLIND))
to_chat(M, "
You go blind!")
+ M.become_blind(EYE_DAMAGE)
else
M.visible_message("
[M]'s eyes fall off their sockets!", "
Your eyes fall off their sockets!")
eyes.Remove(M)
@@ -111,16 +112,16 @@ Bonus
return
switch(A.stage)
if(4, 5) //basically oculine
- if(M.disabilities & BLIND)
+ if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "
Your vision slowly returns...")
- M.cure_blind()
- M.cure_nearsighted()
+ M.cure_blind(EYE_DAMAGE)
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
- else if(M.disabilities & NEARSIGHT)
+ else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "
The blackness in your peripheral vision fades.")
- M.cure_nearsighted()
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm
index 71e4064676..6d77acd3ae 100644
--- a/code/datums/diseases/gbs.dm
+++ b/code/datums/diseases/gbs.dm
@@ -1,6 +1,6 @@
/datum/disease/gbs
name = "GBS"
- max_stages = 5
+ max_stages = 4
spread_text = "On contact"
spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
@@ -16,25 +16,15 @@
..()
switch(stage)
if(2)
- if(prob(45))
- affected_mob.adjustToxLoss(5)
- affected_mob.updatehealth()
- if(prob(1))
- affected_mob.emote("sneeze")
- if(3)
if(prob(5))
affected_mob.emote("cough")
- else if(prob(5))
+ if(3)
+ if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
- to_chat(affected_mob, "
You're starting to feel very weak...")
+ to_chat(affected_mob, "
Your body hurts all over!")
if(4)
- if(prob(10))
- affected_mob.emote("cough")
- affected_mob.adjustToxLoss(5)
- affected_mob.updatehealth()
- if(5)
- to_chat(affected_mob, "
Your body feels as if it's trying to rip itself open...")
+ to_chat(affected_mob, "
Your body feels as if it's trying to rip itself apart!")
if(prob(50))
affected_mob.gib()
else
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 60622f61cb..30bb3d1898 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -88,9 +88,12 @@
stage5 = list("
You feel like monkeying around.")
/datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob)
- if(!ismonkey(affected_mob))
- SSticker.mode.add_monkey(affected_mob.mind)
- affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
+ if(affected_mob.mind && !is_monkey(affected_mob))
+ add_monkey(affected_mob.mind)
+ if(ishuman(affected_mob))
+ var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
+ M.ventcrawler = VENTCRAWLER_ALWAYS
+
/datum/disease/transformation/jungle_fever/stage_act()
..()
@@ -107,7 +110,7 @@
affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."))
/datum/disease/transformation/jungle_fever/cure()
- SSticker.mode.remove_monkey(affected_mob.mind)
+ remove_monkey(affected_mob.mind)
..()
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 2e5bd580bf..b452eff382 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -16,8 +16,9 @@
var/emote_type = EMOTE_VISIBLE //Whether the emote is visible or audible
var/restraint_check = FALSE //Checks if the mob is restrained before performing the emote
var/muzzle_ignore = FALSE //Will only work if the emote is EMOTE_AUDIBLE
- var/list/mob_type_allowed_typecache //Types that are allowed to use that emote
+ var/list/mob_type_allowed_typecache = list(/mob) //Types that are allowed to use that emote
var/list/mob_type_blacklist_typecache //Types that are NOT allowed to use that emote
+ var/list/mob_type_ignore_stat_typecache
var/stat_allowed = CONSCIOUS
var/static/list/emote_list = list()
@@ -26,6 +27,7 @@
emote_list[key_third_person] = src
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
+ mob_type_ignore_stat_typecache = typecacheof(mob_type_ignore_stat_typecache)
/datum/emote/proc/run_emote(mob/user, params, type_override)
. = TRUE
@@ -37,9 +39,10 @@
msg = replace_pronoun(user, msg)
- var/mob/living/L = user
- for(var/obj/item/implant/I in L.implants)
- I.trigger(key, L)
+ if(isliving(user))
+ var/mob/living/L = user
+ for(var/obj/item/implant/I in L.implants)
+ I.trigger(key, L)
if(!msg)
return
@@ -97,7 +100,7 @@
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
- if(status_check)
+ if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
if(user.stat > stat_allowed || (user.status_flags & FAKEDEATH))
to_chat(user, "
You cannot [key] while unconscious.")
return FALSE
diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm
index b71c560193..73b76a9155 100644
--- a/code/datums/explosion.dm
+++ b/code/datums/explosion.dm
@@ -121,7 +121,7 @@ GLOBAL_LIST_EMPTY(explosions)
M.playsound_local(epicenter, null, 100, 1, frequency, falloff = 5, S = explosion_sound)
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
- var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
+ var/far_volume = CLAMP(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
EX_PREPROCESS_CHECK_TICK
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index ec39bcec67..c4ccc4c1fb 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -45,6 +45,8 @@
set name = "Show Server Revision"
set desc = "Check the current server code revision"
+ if(GLOB.round_id)
+ to_chat(src, "
Round ID: [GLOB.round_id]")
if(GLOB.revdata.originmastercommit)
to_chat(src, "
Server revision compiled on: [GLOB.revdata.date]")
var/prefix = ""
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index 5c78a0c321..82497adf45 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -101,7 +101,7 @@
"
[A] slams your chest! You can't breathe!")
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
if(D.losebreath <= 10)
- D.losebreath = Clamp(D.losebreath + 5, 0, 10)
+ D.losebreath = CLAMP(D.losebreath + 5, 0, 10)
D.adjustOxyLoss(10)
add_logs(A, D, "quickchoked")
return 1
@@ -112,7 +112,7 @@
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
if(D.silent <= 10)
- D.silent = Clamp(D.silent + 10, 0, 10)
+ D.silent = CLAMP(D.silent + 10, 0, 10)
add_logs(A, D, "neck chopped")
return 1
diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm
index 0d6a85359d..28f8e9502c 100644
--- a/code/datums/martial/psychotic_brawl.dm
+++ b/code/datums/martial/psychotic_brawl.dm
@@ -44,11 +44,9 @@
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
D.apply_damage(rand(5,10), BRUTE, "head")
A.apply_damage(rand(5,10), BRUTE, "head")
- if(!istype(A.head,/obj/item/clothing/head/helmet/) && !istype(A.head,/obj/item/clothing/head/hardhat))
- A.adjustBrainLoss(5)
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
D.adjustBrainLoss(5)
- A.Stun(rand(5,30))
+ A.Stun(rand(10,45))
D.Stun(rand(5,30))
if(5,6)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index f3a1f53dd2..0a4309e708 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -197,7 +197,7 @@
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
- if((CLUMSY in user.disabilities) && prob(50))
+ if((user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "
You club yourself over the head with [src].")
user.Knockdown(60)
if(ishuman(user))
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index c0ab1dc015..f7f3ef8825 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,13 +201,12 @@
remove_antag_datum(ANTAG_DATUM_BROTHER)
SSticker.mode.update_brother_icons_removed(src)
+
/datum/mind/proc/remove_nukeop()
- if(src in SSticker.mode.syndicates)
- SSticker.mode.syndicates -= src
- SSticker.mode.update_synd_icons_removed(src)
- special_role = null
- remove_objectives()
- remove_antag_equip()
+ var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ if(nuke)
+ remove_antag_datum(nuke.type)
+ special_role = null
/datum/mind/proc/remove_wizard()
remove_antag_datum(/datum/antagonist/wizard)
@@ -223,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()
@@ -329,14 +321,19 @@
SSticker.mode.add_cultist(src)
else if(is_revolutionary(creator))
- var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev)
+ var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
converter.add_revolutionary(src,FALSE)
else if(is_servant_of_ratvar(creator))
add_servant_of_ratvar(current)
else if(is_nuclear_operative(creator))
- make_Nuke(null, null, 0, FALSE)
+ var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ var/datum/antagonist/nukeop/N = new(src)
+ N.send_to_spawnpoint = FALSE
+ N.nukeop_outfit = null
+ add_antag_datum(N,converter.nuke_team)
+
enslaved_to = creator
@@ -464,20 +461,27 @@
text = uppertext(text)
text = "
[text]: "
if (ishuman(current))
- text += "
healthy |
infected |
HUMAN | other"
+ if(is_monkey_leader(src))
+ text += "
healthy |
infected LEADER |
human | other"
+ else
+ text += "
healthy |
infected |
leader |
HUMAN | other"
else if(ismonkey(current))
var/found = FALSE
for(var/datum/disease/transformation/jungle_fever/JF in current.viruses)
found = TRUE
break
- if(found)
- text += "
healthy |
INFECTED |
human | other"
+ var/isLeader = is_monkey_leader(src)
+
+ if(isLeader)
+ text += "
healthy |
infected LEADER |
human | other"
+ else if(found)
+ text += "
healthy |
INFECTED |
leader |
human | other"
else
- text += "
HEALTHY |
infected |
human | other"
+ text += "
HEALTHY |
infected |
leader |
human | other"
else
- text += "healthy | infected | human |
OTHER"
+ text += "healthy | infected | leader | human |
OTHER"
if(current && current.client && (ROLE_MONKEY in current.client.prefs.be_special))
text += " | Enabled in Prefs"
@@ -493,7 +497,8 @@
if (SSticker.mode.config_tag=="nuclear")
text = uppertext(text)
text = "
[text]: "
- if (src in SSticker.mode.syndicates)
+ var/datum/antagonist/nukeop/N = has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ if(N)
text += "
OPERATIVE |
nanotrasen"
text += "
To shuttle,
undress,
dress up."
var/code
@@ -713,7 +718,7 @@
out += sections[i]+"
"
- if(((src in SSticker.mode.traitors) || (src in SSticker.mode.syndicates)) && ishuman(current))
+ if(((src in SSticker.mode.traitors) || is_nuclear_operative(current)) && ishuman(current))
text = "Uplink:
give"
var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
@@ -769,17 +774,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)
@@ -901,11 +933,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]")
@@ -914,6 +950,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]")
@@ -996,11 +1037,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"])
@@ -1071,36 +1114,14 @@
message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
log_admin("[key_name(usr)] has de-nuke op'ed [current].")
if("nuclear")
- if(!(src in SSticker.mode.syndicates))
- SSticker.mode.syndicates += src
- SSticker.mode.update_synd_icons_added(src)
- if (SSticker.mode.syndicates.len==1)
- SSticker.mode.prepare_syndicate_leader(src)
- else
- current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
+ if(!has_antag_datum(/datum/antagonist/nukeop,TRUE))
+ add_antag_datum(/datum/antagonist/nukeop)
special_role = "Syndicate"
assigned_role = "Syndicate"
- to_chat(current, "
You are a [syndicate_name()] agent!")
- SSticker.mode.forge_syndicate_objectives(src)
- SSticker.mode.greet_syndicate(src)
message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
log_admin("[key_name(usr)] has nuke op'ed [current].")
if("lair")
current.forceMove(pick(GLOB.nukeop_start))
- if("dressup")
- var/mob/living/carbon/human/H = current
- qdel(H.belt)
- qdel(H.back)
- qdel(H.ears)
- qdel(H.gloves)
- qdel(H.head)
- qdel(H.shoes)
- qdel(H.wear_id)
- qdel(H.wear_suit)
- qdel(H.w_uniform)
-
- if (!SSticker.mode.equip_syndicate(current))
- to_chat(usr, "
Equipping a syndicate failed!")
if("tellcode")
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
@@ -1241,11 +1262,17 @@
else if (istype(M) && length(M.viruses))
for(var/thing in M.viruses)
var/datum/disease/D = thing
- D.cure(0)
+ D.cure(FALSE)
+ if("leader")
+ if(check_rights(R_ADMIN, 0))
+ add_monkey_leader(src)
+ log_admin("[key_name(usr)] made [key_name(current)] a monkey leader!")
+ message_admins("[key_name_admin(usr)] made [key_name_admin(current)] a monkey leader!")
if("infected")
- if (check_rights(R_ADMIN, 0))
+ if(check_rights(R_ADMIN, 0))
var/mob/living/carbon/human/H = current
var/mob/living/carbon/monkey/M = current
+ add_monkey(src)
if (istype(H))
log_admin("[key_name(usr)] attempting to monkeyize and infect [key_name(current)]")
message_admins("
[key_name_admin(usr)] attempting to monkeyize and infect [key_name_admin(current)]")
@@ -1263,6 +1290,7 @@
for(var/datum/disease/transformation/jungle_fever/JF in M.viruses)
JF.cure(0)
stoplag() //because deleting of virus is doing throught spawn(0) //What
+ remove_monkey(src)
log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
message_admins("
[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]")
H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
@@ -1348,50 +1376,6 @@
T.should_specialise = TRUE
add_antag_datum(T)
-
-/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
- if(!(src in SSticker.mode.syndicates))
- SSticker.mode.syndicates += src
- SSticker.mode.update_synd_icons_added(src)
- assigned_role = "Syndicate"
- special_role = "Syndicate"
- SSticker.mode.forge_syndicate_objectives(src)
- SSticker.mode.greet_syndicate(src)
- current.faction |= "syndicate"
-
- if(spawnloc)
- current.forceMove(spawnloc)
-
- if(ishuman(current))
- var/mob/living/carbon/human/H = current
- qdel(H.belt)
- qdel(H.back)
- qdel(H.ears)
- qdel(H.gloves)
- qdel(H.head)
- qdel(H.shoes)
- qdel(H.wear_id)
- qdel(H.wear_suit)
- qdel(H.w_uniform)
-
- SSticker.mode.equip_syndicate(current, telecrystals)
-
- if (nuke_code)
- store_memory("
Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
- to_chat(current, "The nuclear authorization code is:
[nuke_code]")
- else
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
- if(nuke)
- store_memory("
Syndicate Nuclear Bomb Code: [nuke.r_code]", 0, 0)
- to_chat(current, "The nuclear authorization code is:
nuke.r_code")
- else
- to_chat(current, "You were not provided with a nuclear code. Trying asking your team leader or contacting syndicate command.")
-
- if (leader)
- SSticker.mode.prepare_syndicate_leader(src,nuke_code)
- else
- current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
-
/datum/mind/proc/make_Changling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(!C)
@@ -1407,16 +1391,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/datums/mutations.dm b/code/datums/mutations.dm
index 170c0a2a7f..a171cf91da 100644
--- a/code/datums/mutations.dm
+++ b/code/datums/mutations.dm
@@ -8,7 +8,6 @@ GLOBAL_LIST_EMPTY(mutations_list)
GLOB.mutations_list[name] = src
/datum/mutation/human
-
var/dna_block
var/quality
var/get_chance = 100
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 23b91add58..015004eef6 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -85,12 +85,12 @@
/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= CLUMSY
+ owner.add_disability(CLUMSY, GENETIC_MUTATION)
/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~CLUMSY
+ owner.remove_disability(CLUMSY, GENETIC_MUTATION)
//Tourettes causes you to randomly stand in place and shout.
@@ -124,12 +124,12 @@
/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= DEAF
+ owner.add_disability(DEAF, GENETIC_MUTATION)
/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~DEAF
+ owner.remove_disability(DEAF, GENETIC_MUTATION)
//Monified turns you into a monkey.
diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm
index dee26166dd..60f5d75c5e 100644
--- a/code/datums/mutations/sight.dm
+++ b/code/datums/mutations/sight.dm
@@ -7,12 +7,12 @@
/datum/mutation/human/nearsight/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.become_nearsighted()
+ owner.become_nearsighted(GENETIC_MUTATION)
/datum/mutation/human/nearsight/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.cure_nearsighted()
+ owner.cure_nearsighted(GENETIC_MUTATION)
//Blind makes you blind. Who knew?
@@ -24,12 +24,12 @@
/datum/mutation/human/blind/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.become_blind()
+ owner.become_blind(GENETIC_MUTATION)
/datum/mutation/human/blind/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.cure_blind()
+ owner.cure_blind(GENETIC_MUTATION)
//X-Ray Vision lets you see through walls.
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index 3b4b38bbcc..dc1333024a 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -30,12 +30,12 @@
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= MUTE
+ owner.add_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~MUTE
+ owner.remove_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/smile
diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm
new file mode 100644
index 0000000000..635ae0bbec
--- /dev/null
+++ b/code/datums/position_point_vector.dm
@@ -0,0 +1,239 @@
+//Designed for things that need precision trajectories like projectiles.
+//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
+
+#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
+#define RETURN_PRECISE_POINT(A) new /datum/point(A)
+
+/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
+ var/x = 0
+ var/y = 0
+ var/z = 0
+ var/pixel_x = 0
+ var/pixel_y = 0
+
+/datum/position/proc/valid()
+ return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
+
+/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
+ if(istype(_x, /datum/point))
+ var/datum/point/P = _x
+ var/turf/T = P.return_turf()
+ _x = T.x
+ _y = T.y
+ _z = T.z
+ _pixel_x = P.return_px()
+ _pixel_y = P.return_py()
+ else if(isatom(_x))
+ var/atom/A = _x
+ _x = A.x
+ _y = A.y
+ _z = A.z
+ _pixel_x = A.pixel_x
+ _pixel_y = A.pixel_y
+ x = _x
+ y = _y
+ z = _z
+ pixel_x = _pixel_x
+ pixel_y = _pixel_y
+
+/datum/position/proc/return_turf()
+ return locate(x, y, z)
+
+/datum/position/proc/return_px()
+ return pixel_x
+
+/datum/position/proc/return_py()
+ return pixel_y
+
+/datum/position/proc/return_point()
+ return new /datum/point(src)
+
+/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
+ var/datum/point/P = new
+ P.x = round(a.x + (b.x - a.x) / 2, 1)
+ P.y = round(a.y + (b.y - a.y) / 2, 1)
+ P.z = a.z
+ return P
+
+/proc/pixel_length_between_points(datum/point/a, datum/point/b)
+ return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
+
+/proc/angle_between_points(datum/point/a, datum/point/b)
+ return ATAN2((b.y - a.y), (b.x - a.x))
+
+/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
+ var/x = 0
+ var/y = 0
+ var/z = 0
+
+/datum/point/proc/valid()
+ return x && y && z
+
+/datum/point/proc/copy_to(datum/point/p = new)
+ p.x = x
+ p.y = y
+ p.z = z
+ return p
+
+/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
+ if(istype(_x, /datum/position))
+ var/datum/position/P = _x
+ _x = P.x
+ _y = P.y
+ _z = P.z
+ _pixel_x = P.pixel_x
+ _pixel_y = P.pixel_y
+ else if(istype(_x, /atom))
+ var/atom/A = _x
+ _x = A.x
+ _y = A.y
+ _z = A.z
+ _pixel_x = A.pixel_x
+ _pixel_y = A.pixel_y
+ initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
+
+/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
+ if(!isnull(tile_x))
+ x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x
+ if(!isnull(tile_y))
+ y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
+ if(!isnull(tile_z))
+ z = tile_z
+
+/datum/point/proc/return_turf()
+ return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
+
+/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
+ return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
+
+/datum/point/proc/return_position()
+ return new /datum/position(src)
+
+/datum/point/proc/return_px()
+ return MODULUS(x, world.icon_size) - 16
+
+/datum/point/proc/return_py()
+ return MODULUS(y, world.icon_size) - 16
+
+/datum/point/proc/mapcheck()
+ . = FALSE
+ var/maxx = world.icon_size * world.maxx
+ var/maxy = world.icon_size * world.maxy
+ var/move_zx = 0
+ var/move_zy = 0
+ if(x < 0)
+ x += maxx
+ move_zx -= 1
+ if(y < 0)
+ y += maxy
+ move_zy -= 1
+ if(x > maxx)
+ x -= maxx
+ move_zx += 1
+ if(y > maxy)
+ y -= maxy
+ move_zy += 1
+ var/datum/space_level/S = GLOB.z_levels_list["[z]"]
+ if(move_zx != 0)
+ var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
+ z = L.z_value
+ . = TRUE
+ if(move_zy != 0)
+ var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
+ z = L.z_value
+ . = TRUE
+
+/datum/point/vector
+ var/speed = 32 //pixels per iteration
+ var/iteration = 0
+ var/angle = 0
+ var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
+ var/mpy = 0
+ var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
+ var/starting_y = 0
+ var/starting_z = 0
+
+/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
+ ..()
+ initialize_trajectory(_speed, _angle)
+
+/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
+ . = ..()
+ starting_x = x
+ starting_y = y
+ starting_z = z
+
+/datum/point/vector/copy_to(datum/point/vector/v = new)
+ ..(v)
+ v.speed = speed
+ v.iteration = iteration
+ v.angle = angle
+ v.mpx = mpx
+ v.mpy = mpy
+ v.starting_x = starting_x
+ v.starting_y = starting_y
+ v.starting_z = starting_z
+ return v
+
+/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
+ if(!isnull(pixel_speed))
+ speed = pixel_speed
+ set_angle(new_angle)
+
+/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
+ if(isnull(angle))
+ return
+ angle = new_angle
+ update_offsets()
+
+/datum/point/vector/proc/update_offsets()
+ mpx = sin(angle) * speed
+ mpy = cos(angle) * speed
+
+/datum/point/vector/proc/set_speed(new_speed)
+ if(isnull(new_speed) || speed == new_speed)
+ return
+ speed = new_speed
+ update_offsets()
+
+/datum/point/vector/proc/increment(multiplier = 1)
+ iteration++
+ x += mpx * 1
+ y += mpy * 1
+ if(mapcheck())
+ on_z_change()
+
+/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
+ var/datum/point/vector/v = copy_to()
+ if(force_simulate)
+ for(var/i in 1 to amount)
+ v.increment(multiplier)
+ else
+ v.increment(multiplier * amount)
+ return v
+
+/datum/point/vector/proc/on_z_change()
+ return
+
+/datum/point/vector/processed //pixel_speed is per decisecond.
+ var/last_process = 0
+ var/last_move = 0
+ var/paused = FALSE
+
+/datum/point/vector/processed/Destroy()
+ STOP_PROCESSING(SSprojectiles, src)
+
+/datum/point/vector/processed/proc/start()
+ last_process = world.time
+ last_move = world.time
+ START_PROCESSING(SSprojectiles, src)
+
+/datum/point/vector/processed/process()
+ if(paused)
+ last_move += world.time - last_process
+ last_process = world.time
+ return
+ var/needed_time = world.time - last_move
+ last_process = world.time
+ last_move = world.time
+ increment(needed_time)
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index f9883cfe50..3599c60f89 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -38,7 +38,7 @@
if (user.client)
user.client.images += bar
- progress = Clamp(progress, 0, goal)
+ progress = CLAMP(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if (!shown)
user.client.images += bar
diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm
index f065ccfeab..68d8ebc31f 100644
--- a/code/datums/radiation_wave.dm
+++ b/code/datums/radiation_wave.dm
@@ -34,7 +34,7 @@
var/strength
if(steps>1)
- strength = InverseSquareLaw(intensity, max(range_modifier*steps, 1), 1)
+ strength = INVERSE_SQUARE(intensity, max(range_modifier*steps, 1), 1)
else
strength = intensity
@@ -42,7 +42,7 @@
qdel(src)
return
- radiate(atoms, Floor(strength))
+ radiate(atoms, FLOOR(strength, 1))
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm
index e372d5c0b2..176c762e9c 100644
--- a/code/datums/saymode.dm
+++ b/code/datums/saymode.dm
@@ -33,7 +33,7 @@
if(LINGHIVE_LING)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/msg = "
[changeling.changelingID]: [message]"
- log_talk(src,"[changeling.changelingID]/[user.key] : [message]",LOGSAY)
+ log_talk(user,"[changeling.changelingID]/[user.key] : [message]",LOGSAY)
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
@@ -110,3 +110,25 @@
AI.holopad_talk(message, language)
return FALSE
return TRUE
+
+/datum/saymode/monkey
+ key = "k"
+ mode = MODE_MONKEY
+
+/datum/saymode/monkey/handle_message(mob/living/user, message, datum/language/language)
+ var/datum/mind = user.mind
+ if(!mind)
+ return TRUE
+ if(is_monkey_leader(mind) || (ismonkey(user) && is_monkey(mind)))
+ log_talk(user, "(MONKEY) [user]/[user.key]: [message]",LOGSAY)
+ if(prob(75) && ismonkey(user))
+ user.visible_message("
\The [user] chimpers.")
+ var/msg = "
\[[is_monkey_leader(mind) ? "Monkey Leader" : "Monkey"]\] [user]: [message]"
+ for(var/_M in GLOB.mob_list)
+ var/mob/M = _M
+ if(M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, user)
+ to_chat(M, "[link] [msg]")
+ if((is_monkey_leader(M.mind) || ismonkey(M)) && (M.mind in SSticker.mode.ape_infectees))
+ to_chat(M, msg)
+ return FALSE
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index 20d218f767..ec4b81acbe 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -60,8 +60,8 @@
if(istype(L)) //this is probably more safety than actually needed
var/vanguard = L.stun_absorption["vanguard"]
desc = initial(desc)
- desc += "
[Floor(vanguard["stuns_absorbed"] * 0.1)] seconds of stuns held back.\
- [GLOB.ratvar_awakens ? "":"
[Floor(min(vanguard["stuns_absorbed"] * 0.025, 20))] seconds of stun will affect you."]"
+ desc += "
[FLOOR(vanguard["stuns_absorbed"] * 0.1, 1)] seconds of stuns held back.\
+ [GLOB.ratvar_awakens ? "":"
[FLOOR(min(vanguard["stuns_absorbed"] * 0.025, 20), 1)] seconds of stun will affect you."]"
..()
/datum/status_effect/vanguard_shield/Destroy()
@@ -87,7 +87,7 @@
var/vanguard = owner.stun_absorption["vanguard"]
var/stuns_blocked = 0
if(vanguard)
- stuns_blocked = Floor(min(vanguard["stuns_absorbed"] * 0.25, 400))
+ stuns_blocked = FLOOR(min(vanguard["stuns_absorbed"] * 0.25, 400), 1)
vanguard["end_time"] = 0 //so it doesn't absorb the stuns we're about to apply
if(owner.stat != DEAD)
var/message_to_owner = "
You feel your Vanguard quietly fade..."
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 2ea1469481..cc64cc2eb8 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -230,7 +230,7 @@
if(prob(severity * 0.15))
to_chat(owner, "
\"[text2ratvar(pick(mania_messages))]\"")
owner.playsound_local(get_turf(motor), hum, severity, 1)
- owner.adjust_drugginess(Clamp(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
+ owner.adjust_drugginess(CLAMP(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
if(owner.hallucination < 50)
owner.hallucination = min(owner.hallucination + max(severity * 0.075, 1), 50) //7.5% of severity per second, minimum 1
if(owner.dizziness < 50)
@@ -310,7 +310,7 @@
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
bleed_overlay.pixel_x = -owner.pixel_x
- bleed_overlay.pixel_y = Floor(icon_height * 0.25)
+ bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
bleed_underlay.pixel_x = -owner.pixel_x
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm
index 901a8610a6..712b3425e0 100644
--- a/code/game/alternate_appearance.dm
+++ b/code/game/alternate_appearance.dm
@@ -78,6 +78,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
QDEL_NULL(ghost_appearance)
/datum/atom_hud/alternate_appearance/basic/add_to_hud(atom/A)
+ LAZYINITLIST(A.hud_list)
A.hud_list[appearance_key] = theImage
. = ..()
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/atoms_movable.dm b/code/game/atoms_movable.dm
index 121ac00f1d..08568660fd 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -132,44 +132,12 @@
if (orbiting)
orbiting.Check()
- if(flags_1 & CLEAN_ON_MOVE_1)
- clean_on_move()
-
var/datum/proximity_monitor/proximity_monitor = src.proximity_monitor
if(proximity_monitor)
proximity_monitor.HandleMove()
return 1
-/atom/movable/proc/clean_on_move()
- var/turf/tile = loc
- if(isturf(tile))
- tile.clean_blood()
- for(var/A in tile)
- if(is_cleanable(A))
- qdel(A)
- else if(istype(A, /obj/item))
- var/obj/item/cleaned_item = A
- cleaned_item.clean_blood()
- else if(ishuman(A))
- var/mob/living/carbon/human/cleaned_human = A
- if(cleaned_human.lying)
- if(cleaned_human.head)
- cleaned_human.head.clean_blood()
- cleaned_human.update_inv_head()
- if(cleaned_human.wear_suit)
- cleaned_human.wear_suit.clean_blood()
- cleaned_human.update_inv_wear_suit()
- else if(cleaned_human.w_uniform)
- cleaned_human.w_uniform.clean_blood()
- cleaned_human.update_inv_w_uniform()
- if(cleaned_human.shoes)
- cleaned_human.shoes.clean_blood()
- cleaned_human.update_inv_shoes()
- cleaned_human.clean_blood()
- cleaned_human.wash_cream()
- to_chat(cleaned_human, "
[src] cleans your face!")
-
/atom/movable/Destroy(force)
var/inform_admins = (flags_2 & INFORM_ADMINS_ON_RELOCATE_2)
var/stationloving = (flags_2 & STATIONLOVING_2)
@@ -516,7 +484,7 @@
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]"
- .["Get"] = "?_src=holder;[HrefToken()];admingetmovable=[REF(src)]"
+ .["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]"
/atom/movable/proc/ex_check(ex_id)
if(!ex_id)
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index 3358052c7f..d8ba1f5fa1 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -4,7 +4,7 @@
w_class = WEIGHT_CLASS_TINY
var/used = 0
-/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
+/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
return
/obj/item/antag_spawner/proc/equip_antag(mob/target)
@@ -67,18 +67,16 @@
else
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
-/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, school,datum/mind/user)
+/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
new /obj/effect/particle_effect/smoke(T)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
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 = school
+ app.school = kind
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
if(master_wizard)
@@ -107,7 +105,7 @@
if(used)
to_chat(user, "
[src] is out of power!")
return FALSE
- if(!(user.mind in SSticker.mode.syndicates))
+ if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
to_chat(user, "
AUTHENTICATION FAILURE. ACCESS DENIED.")
return FALSE
if(user.z != ZLEVEL_CENTCOM)
@@ -127,25 +125,25 @@
return
used = TRUE
var/mob/dead/observer/theghost = pick(nuke_candidates)
- spawn_antag(theghost.client, get_turf(src), "syndieborg", user.mind)
+ spawn_antag(theghost.client, get_turf(src), "syndieborg")
do_sparks(4, TRUE, src)
qdel(src)
else
to_chat(user, "
Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.")
-/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T)
+/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
- var/code = "BOMB-NOT-FOUND"
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
- if(nuke)
- code = nuke.r_code
- M.mind.make_Nuke(null, code, 0, FALSE)
- var/newname = M.dna.species.random_name(M.gender,0,SSticker.mode.nukeops_lastname)
- M.mind.name = newname
- M.real_name = newname
- M.name = newname
+
+ var/datum/antagonist/nukeop/new_op = new(M.mind)
+ new_op.send_to_spawnpoint = FALSE
+ new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
+
+ var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ if(creator_op)
+ M.mind.add_antag_datum(new_op,creator_op.nuke_team)
+ M.mind.special_role = "Nuclear Operative"
//////SYNDICATE BORG
/obj/item/antag_spawner/nuke_ops/borg_tele
@@ -162,8 +160,12 @@
name = "syndicate medical teleporter"
borg_to_spawn = "Medical"
-/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T)
+/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
var/mob/living/silicon/robot/R
+ 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)
@@ -174,8 +176,8 @@
if(prob(50))
brainfirstname = pick(GLOB.first_names_female)
var/brainopslastname = pick(GLOB.last_names)
- if(SSticker.mode.nukeops_lastname) //the brain inside the syndiborg has the same last name as the other ops.
- brainopslastname = SSticker.mode.nukeops_lastname
+ if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
+ brainopslastname = creator_op.nuke_team.syndicate_name
var/brainopsname = "[brainfirstname] [brainopslastname]"
R.mmi.name = "Man-Machine Interface: [brainopsname]"
@@ -185,7 +187,11 @@
R.real_name = R.name
R.key = C.key
- R.mind.make_Nuke(null, nuke_code = null,leader=0, telecrystals = TRUE)
+
+ 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)
+ R.mind.special_role = "Syndicate Cyborg"
///////////SLAUGHTER DEMON
@@ -213,7 +219,7 @@
return
used = 1
var/mob/dead/observer/theghost = pick(demon_candidates)
- spawn_antag(theghost.client, get_turf(src), initial(demon_type.name),user.mind)
+ spawn_antag(theghost.client, get_turf(src), initial(demon_type.name))
to_chat(user, shatter_msg)
to_chat(user, veil_msg)
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
@@ -222,8 +228,7 @@
to_chat(user, "
You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.")
-/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", datum/mind/user)
-
+/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
S.holder = holder
@@ -232,16 +237,17 @@
S.mind.special_role = S.name
SSticker.mode.traitors += S.mind
var/datum/objective/assassinate/new_objective
- if(user)
+ if(usr)
new_objective = new /datum/objective/assassinate
new_objective.owner = S.mind
- new_objective.target = user
- new_objective.explanation_text = "[objective_verb] [user.name], the one who summoned you."
+ new_objective.target = usr.mind
+ new_objective.explanation_text = "[objective_verb] [usr.real_name], the one who summoned you."
S.mind.objectives += new_objective
var/datum/objective/new_objective2 = new /datum/objective
new_objective2.owner = S.mind
- new_objective2.explanation_text = "[objective_verb] everyone[user ? " else while you're at it":""]."
+ 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/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm
index c5c813ecfc..9e4bf51d41 100644
--- a/code/game/gamemodes/blob/blobs/blob_mobs.dm
+++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm
@@ -42,7 +42,7 @@
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
..()
if(exposed_temperature)
- adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
+ adjustFireLoss(CLAMP(0.01 * exposed_temperature, 1, 5))
else
adjustFireLoss(5)
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index 3fabb0af38..878b747ea9 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
B.hud_used.blobpwrdisplay.maptext = "
[round(blob_core.obj_integrity)]
"
/mob/camera/blob/proc/add_points(points)
- blob_points = Clamp(blob_points + points, 0, max_blob_points)
+ blob_points = CLAMP(blob_points + points, 0, max_blob_points)
hud_used.blobpwrdisplay.maptext = "
[round(blob_points)]
"
/mob/camera/blob/say(message)
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/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
index 4584dc5a67..56003d91eb 100644
--- a/code/game/gamemodes/changeling/powers/absorb.dm
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -58,6 +58,8 @@
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
if(target.mind)//if the victim has got a mind
+ // Absorb a lizard, speak Draconic.
+ user.copy_known_languages_from(target)
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
index 4fdd84040e..e3f486a2f1 100644
--- a/code/game/gamemodes/changeling/powers/tiny_prick.dm
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -20,7 +20,7 @@
to_chat(user, "
We prepare our sting, use alt+click or middle mouse button on target to sting them.")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = src
-
+
user.hud_used.lingstingdisplay.icon_state = sting_icon
user.hud_used.lingstingdisplay.invisibility = 0
@@ -28,7 +28,7 @@
to_chat(user, "
We retract our sting, we can't sting anyone for now.")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = null
-
+
user.hud_used.lingstingdisplay.icon_state = null
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
@@ -90,7 +90,7 @@
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
if(!..())
return
- if((target.disabilities & HUSK) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
+ if((target.has_disability(HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
to_chat(user, "
Our sting appears ineffective against its DNA.")
return 0
return 1
@@ -129,9 +129,11 @@
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
if(!..())
return
- if((target.disabilities & HUSK) || !target.has_dna())
- to_chat(user, "
Our sting appears ineffective against its DNA.")
- return 0
+ if(isliving(target))
+ var/mob/living/L = target
+ if((L.has_disability(HUSK)) || !L.has_dna())
+ to_chat(user, "
Our sting appears ineffective against its DNA.")
+ return 0
return 1
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
@@ -207,7 +209,7 @@
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
add_logs(user, target, "stung", "blind sting")
to_chat(target, "
Your eyes burn horrifically!")
- target.become_nearsighted()
+ target.become_nearsighted(EYE_DAMAGE)
target.blind_eyes(20)
target.blur_eyes(40)
return TRUE
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 e5a8c9b6f3..29655a0ac9 100644
--- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
+++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
@@ -207,7 +207,7 @@
to_chat(cyborg, "
You start to charge from the [sigil_name]...")
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
return
- var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
+ var/giving_power = min(FLOOR(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
if(adjust_clockwork_power(-giving_power))
cyborg.visible_message("
[cyborg] glows a brilliant orange!")
var/previous_color = cyborg.color
@@ -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_helpers/fabrication_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
index a5af47ff05..74f7119193 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
@@ -90,7 +90,7 @@
if(amount_temp < 2)
to_chat(user, "
You need at least 2 floor tiles to convert into power.")
return TRUE
- if(IsOdd(amount_temp))
+ if(ISODD(amount_temp))
amount_temp--
no_delete = TRUE
use(amount_temp)
@@ -239,7 +239,7 @@
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
break
- obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
+ obj_integrity = CLAMP(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
adjust_clockwork_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
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..df9fa45b89 100644
--- a/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
@@ -83,6 +83,7 @@
construct_type = /mob/living/simple_animal/drone/cogscarab
w_class = WEIGHT_CLASS_SMALL
var/infinite_resources = TRUE
+ var/static/obj/item/seasonal_hat //Share it with all other scarabs, since we're from the same cult!
/obj/item/clockwork/construct_chassis/cogscarab/Initialize()
. = ..()
@@ -91,7 +92,14 @@
/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
+ if(!seasonal_hat)
+ var/obj/item/drone_shell/D = locate() in GLOB.poi_list
+ if(D && D.possible_seasonal_hats.len)
+ seasonal_hat = pick(D.possible_seasonal_hats)
+ else
+ seasonal_hat = "none"
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
if(infinite_resources) //Allow them to build stuff and recite scripture
@@ -100,3 +108,6 @@
F.uses_power = FALSE
for(var/obj/item/clockwork/slab/S in cached_stuff)
S.no_cost = TRUE
+ if(seasonal_hat && seasonal_hat != "none")
+ var/obj/item/hat = new seasonal_hat(construct)
+ construct.equip_to_slot_or_del(hat, slot_head)
diff --git a/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm b/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
index fc734ac426..b579326fcc 100644
--- a/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
@@ -32,7 +32,7 @@
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(src == H.glasses && !up)
- if(H.disabilities & BLIND)
+ if(H.has_disability(BLIND))
to_chat(H, "
\"You're blind, idiot. Stop embarrassing yourself.\"")
return
if(blind_cultist(H))
@@ -51,7 +51,7 @@
to_chat(victim, "
\"It looks like Nar-Sie's dogs really don't value their eyes.\"")
to_chat(victim, "
Your eyes explode with horrific pain!")
victim.emote("scream")
- victim.become_blind()
+ victim.become_blind(EYE_DAMAGE)
victim.adjust_blurriness(30)
victim.adjust_blindness(30)
return TRUE
@@ -76,7 +76,7 @@
..()
if(slot != slot_glasses || up)
return
- if(user.disabilities & BLIND)
+ if(user.has_disability(BLIND))
to_chat(user, "
\"You're blind, idiot. Stop embarrassing yourself.\"" )
return
if(blind_cultist(user)) //Cultists instantly go blind
@@ -115,11 +115,11 @@
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
desc = "[glasses_right && !WS.up ? "
":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!":"."]
\
You have taken
[W.eye_damage_done] eye damage from them.
"
- if(L.disabilities & NEARSIGHT)
+ if(L.has_disability(NEARSIGHT))
desc += "
You are nearsighted!"
else if(glasses_right && !WS.up)
desc += "You will become nearsighted at
[W.nearsight_breakpoint] eye damage.
"
- if(L.disabilities & BLIND)
+ if(L.has_disability(BLIND))
desc += "
You are blind!"
else if(glasses_right && !WS.up)
desc += "You will become blind at
[W.blind_breakpoint] eye damage."
@@ -142,8 +142,8 @@
apply_eye_damage(H)
else
if(GLOB.ratvar_awakens)
- H.cure_nearsighted()
- H.cure_blind()
+ H.cure_nearsighted(list(EYE_DAMAGE))
+ H.cure_blind(list(EYE_DAMAGE))
H.adjust_eye_damage(-eye_damage_done)
eye_damage_done = 0
else if(prob(50) && eye_damage_done)
@@ -153,17 +153,20 @@
qdel(src)
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
- if(H.disabilities & BLIND)
+ if(H.has_disability(BLIND))
return
H.adjust_eye_damage(0.5)
eye_damage_done += 0.5
if(eye_damage_done >= 20)
H.adjust_blurriness(2)
if(eye_damage_done >= nearsight_breakpoint)
- if(H.become_nearsighted())
- to_chat(H, "
Your vision doubles, then trebles. Darkness begins to close in. You can't keep this up!")
+ if(!H.has_disability(NEARSIGHT))
+ to_chat(H, "
Your vision doubles, then trembles. Darkness begins to close in. You can't keep this up!")
+ H.become_nearsighted(EYE_DAMAGE)
if(eye_damage_done >= blind_breakpoint)
- if(H.become_blind())
+ if(!H.has_disability(BLIND))
to_chat(H, "
A piercing white light floods your vision. Suddenly, all goes dark!")
+ H.become_blind(EYE_DAMAGE)
+
if(prob(min(20, 5 + eye_damage_done)))
to_chat(H, "
Your eyes continue to burn.")
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
index cc91feeb98..5a8a40a544 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
@@ -1,3 +1,7 @@
+//Helper proc to get an Eminence mob if it exists
+/proc/get_eminence()
+ return locate(/mob/camera/eminence) in servants_and_ghosts()
+
//The Eminence is a unique mob that functions like the leader of the cult. It's incorporeal but can interact with the world in several ways.
/mob/camera/eminence
name = "\the Emininence"
@@ -12,39 +16,50 @@
layer = FLY_LAYER
faction = list("ratvar")
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ var/turf/last_failed_turf
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
/mob/camera/eminence/Move(NewLoc, direct)
var/OldLoc = loc
if(NewLoc && !istype(NewLoc, /turf/open/indestructible/reebe_void))
- forceMove(get_turf(NewLoc))
+ var/turf/T = get_turf(NewLoc)
+ if(T.flags_1 & NOJAUNT_1)
+ if(last_failed_turf != T)
+ T.visible_message("
[T] suddenly emits a ringing sound!", ignore_mob = src)
+ playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
+ last_failed_turf = T
+ to_chat(src, "
This turf is consecrated and can't be crossed!")
+ return
+ if(istype(get_area(T), /area/chapel))
+ to_chat(src, "
The Chapel is hallowed ground under a heretical deity, and can't be accessed!")
+ return
+ forceMove(T)
Moved(OldLoc, direct)
if(GLOB.ratvar_awakens)
for(var/turf/T in range(5, src))
if(prob(166 - (get_dist(src, T) * 33)))
T.ratvar_act() //Causes moving to leave a swath of proselytized area behind the Eminence
+/mob/camera/eminence/Process_Spacemove(movement_dir = 0)
+ return TRUE
+
/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 && C.clock_team.eminence != src)
+ remove_servant_of_ratvar(src,TRUE)
+ qdel(src)
+ return
+ 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
@@ -55,6 +70,12 @@
E.Grant(src)
/mob/camera/eminence/say(message)
+ if(client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+ if(client.handle_spam_prevention(message,MUTE_IC))
+ return
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message)
return
@@ -62,7 +83,13 @@
if(GLOB.ratvar_awakens)
visible_message("
You feel light slam into your mind and form words: \"[capitalize(message)]\"")
playsound(src, 'sound/machines/clockcult/ark_scream.ogg', 50, FALSE)
- hierophant_message("
The Eminence: \"[message]\"")
+ message = "
The [GLOB.ratvar_awakens ? "Radiance" : "Eminence"]: \"[message]\""
+ for(var/mob/M in servants_and_ghosts())
+ if(isobserver(M))
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [message]")
+ else
+ to_chat(M, message)
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(z == ZLEVEL_CITYOFCOGS || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
index 5aa626bac5..da1f5965bd 100644
--- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
+++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
@@ -97,7 +97,7 @@
if(ishuman(M.current))
human_servants++
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
- construct_limit = Clamp(construct_limit, 1, 3)
+ construct_limit = CLAMP(construct_limit, 1, 3)
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
channel_time = initial(channel_time)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
index 63fea1eeb6..21d1159541 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -113,7 +113,7 @@
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/mass_recall()
for(var/V in SSticker.mode.servants_of_ratvar)
var/datum/mind/M = V
- if(!M.current.stat)
+ if(M.current.stat != DEAD)
M.current.forceMove(get_turf(src))
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
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 8d4e936658..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)
@@ -34,7 +38,8 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
- if(SSticker.mode.eminence)
+ var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
+ if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "
There's already an Eminence - too late!")
return
if(!GLOB.servants_active)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
index b95d9cc0db..447b077d87 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
@@ -60,4 +60,4 @@
break
if(!M)
M = H.apply_status_effect(STATUS_EFFECT_MANIAMOTOR, src)
- M.severity = Clamp(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
+ M.severity = CLAMP(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
index c7aea3df7e..76e942037c 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
@@ -110,7 +110,7 @@
if(!(BI.resistance_flags & ON_FIRE))
BI.fire_act()
continue
- if(is_servant_of_ratvar(L) || (L.disabilities & BLIND) || L.null_rod_check())
+ if(is_servant_of_ratvar(L) || (L.has_disability(BLIND)) || L.null_rod_check())
continue
if(L.stat || L.restrained() || L.buckled || L.lying)
continue
diff --git a/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm b/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
index 9d4667ee9f..e417cbbc32 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
@@ -57,5 +57,5 @@
L.confused = min(L.confused + 15, 50)
L.dizziness = min(L.dizziness + 15, 50)
if(L.confused >= 25)
- L.Knockdown(Floor(L.confused * 0.8))
+ L.Knockdown(FLOOR(L.confused * 0.8, 1))
take_damage(max_integrity)
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..98faeae184 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -115,7 +115,7 @@ structure_check() searches for nearby cultist structures required for the invoca
continue
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if((H.disabilities & MUTE) || H.silent)
+ if((H.has_disability(MUTE)) || H.silent)
continue
if(L.stat)
continue
@@ -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 803e73b9e0..a0e5a9f147 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -19,6 +19,7 @@
var/probability = 0
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
+ var/nuke_off_station = 0 //Used for tracking where the nuke hit
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
@@ -73,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)
@@ -241,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 \
@@ -451,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)
@@ -518,15 +444,25 @@
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."
//By default nuke just ends the round
/datum/game_mode/proc/OnNukeExplosion(off_station)
+ nuke_off_station = off_station
if(off_station < 2)
station_was_nuked = TRUE //Will end the round on next check.
+
+//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/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 1c17893a28..9e2e889047 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -304,7 +304,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(30)
if(!owner || QDELETED(owner))
return
- priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/AI/aimalf.ogg')
+ priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/ai/aimalf.ogg')
set_security_level("delta")
var/obj/machinery/doomsday_device/DOOM = new(owner_AI)
owner_AI.nuking = TRUE
diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm
index b7a6580570..efe6dc69e9 100644
--- a/code/game/gamemodes/meteor/meteor.dm
+++ b/code/game/gamemodes/meteor/meteor.dm
@@ -25,35 +25,34 @@
if (prob(meteorminutes/2))
wavetype = GLOB.meteors_catastrophic
- var/ramp_up_final = Clamp(round(meteorminutes/rampupdelta), 1, 10)
+ var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
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..682552e2d1 100644
--- a/code/game/gamemodes/miniantags/monkey/monkey.dm
+++ b/code/game/gamemodes/miniantags/monkey/monkey.dm
@@ -1,5 +1,6 @@
/datum/game_mode
var/list/ape_infectees = list()
+ var/list/ape_leaders = list()
/datum/game_mode/monkey
name = "monkey"
@@ -21,6 +22,9 @@
var/players_per_carrier = 30
+ var/datum/objective_team/monkey/monkey_team
+
+
/datum/game_mode/monkey/pre_setup()
carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1)
@@ -30,88 +34,99 @@
break
var/datum/mind/carrier = pick(antag_candidates)
carriers += carrier
- carrier.special_role = "monkey"
+ carrier.special_role = "Monkey Leader"
carrier.restricted_roles = restricted_jobs
log_game("[carrier.key] (ckey) has been selected as a Jungle Fever carrier")
antag_candidates -= carrier
if(!carriers.len)
- return 0
- return 1
+ return FALSE
+ return TRUE
/datum/game_mode/monkey/announce()
to_chat(world, "The current game mode is - Monkey!")
to_chat(world, "One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to CentCom. Monkeys: Ensure that your kind lives on! Rise up against your captors!")
-
-/datum/game_mode/monkey/proc/greet_carrier(datum/mind/carrier)
- to_chat(carrier.current, "You are the Jungle Fever patient zero!!")
- to_chat(carrier.current, "You have been planted onto this station by the Animal Rights Consortium.")
- to_chat(carrier.current, "Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.")
- to_chat(carrier.current, "While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.")
- to_chat(carrier.current, "Your mission will be deemed a success if any of the live infected monkeys reach CentCom.")
- carrier.current.playsound_local(get_turf(carrier.current), 'sound/ambience/antag/monkey.ogg', 100, FALSE, pressure_affected = FALSE)
- return
-
/datum/game_mode/monkey/post_setup()
for(var/datum/mind/carriermind in carriers)
- greet_carrier(carriermind)
- ape_infectees += carriermind
-
- var/datum/disease/D = new /datum/disease/transformation/jungle_fever
- D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
- D.affected_mob = carriermind.current
- carriermind.current.viruses += D
- ..()
+ var/datum/antagonist/monkey/M = add_monkey_leader(carriermind, monkey_team)
+ if(M)
+ monkey_team = M.monkey_team
+ return ..()
/datum/game_mode/monkey/check_finished()
if((SSshuttle.emergency.mode == SHUTTLE_ENDGAME) || station_was_nuked)
- return 1
+ return TRUE
if(!round_converted)
for(var/datum/mind/monkey_mind in ape_infectees)
- continuous_sanity_checked = 1
+ continuous_sanity_checked = TRUE
if(monkey_mind.current && monkey_mind.current.stat != DEAD)
- return 0
+ return FALSE
var/datum/disease/D = new /datum/disease/transformation/jungle_fever() //ugly but unfortunately needed
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- if(H.mind && H.stat != DEAD)
+ if(!(H.z in GLOB.station_z_levels))
+ continue
+ if(H.mind && H.client && H.stat != DEAD)
if(H.HasDisease(D))
- return 0
+ return FALSE
- ..()
+ return ..()
/datum/game_mode/monkey/proc/check_monkey_victory()
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
- return 0
+ return FALSE
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D))
if(M.onCentCom() || M.onSyndieBase())
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
- return 1
+ return TRUE
else
- return 0
-
-/datum/game_mode/proc/add_monkey(datum/mind/monkey_mind)
- ape_infectees |= monkey_mind
- monkey_mind.special_role = "Infected Monkey"
-
-/datum/game_mode/proc/remove_monkey(datum/mind/monkey_mind)
- ape_infectees.Remove(monkey_mind)
- monkey_mind.special_role = null
+ return FALSE
-/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."
+
+/proc/add_monkey_leader(datum/mind/monkey_mind)
+ if(is_monkey_leader(monkey_mind))
+ return FALSE
+ var/datum/antagonist/monkey/leader/M = monkey_mind.add_antag_datum(ANTAG_DATUM_MONKEY_LEADER)
+ return M
+
+/proc/add_monkey(datum/mind/monkey_mind)
+ if(is_monkey(monkey_mind))
+ return FALSE
+ var/datum/antagonist/monkey/M = monkey_mind.add_antag_datum(ANTAG_DATUM_MONKEY)
+ return M
+
+/proc/remove_monkey(datum/mind/monkey_mind)
+ if(!is_monkey(monkey_mind))
+ return FALSE
+ var/datum/antagonist/monkey/M = monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY)
+ M.on_removal()
+ return TRUE
+
+/proc/is_monkey_leader(datum/mind/monkey_mind)
+ return monkey_mind && monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY_LEADER)
+
+/proc/is_monkey(datum/mind/monkey_mind)
+ return monkey_mind && (monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY) || is_monkey_leader(monkey_mind))
+
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 94c372ef23..890a3bb456 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -1,7 +1,3 @@
-/datum/game_mode
- var/list/datum/mind/syndicates = list()
- var/nukeops_lastname = ""
-
/datum/game_mode/nuclear
name = "nuclear emergency"
config_tag = "nuclear"
@@ -18,12 +14,11 @@
Crew: Defend the nuclear authentication disk and ensure that it leaves with you on the emergency shuttle."
var/const/agents_possible = 5 //If we ever need more syndicate agents.
-
var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
- var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
- var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level
var/list/pre_nukeops = list()
+ 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)
for(var/i = 0, i < n_agents, ++i)
@@ -33,120 +28,23 @@
new_op.special_role = "Nuclear Operative"
log_game("[new_op.key] (ckey) has been selected as a nuclear operative")
return TRUE
-
-////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////
-/datum/game_mode/proc/update_synd_icons_added(datum/mind/synd_mind)
- var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
- opshud.join_hud(synd_mind.current)
- set_antag_hud(synd_mind.current, "synd")
-
-/datum/game_mode/proc/update_synd_icons_removed(datum/mind/synd_mind)
- var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
- opshud.leave_hud(synd_mind.current)
- set_antag_hud(synd_mind.current, null)
-
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/nuclear/post_setup()
- var/nuke_code = random_nukecode()
- var/agent_number = 1
- var/datum/mind/leader = pick(pre_nukeops)
- syndicates += pre_nukeops
- for(var/i = 1 to pre_nukeops.len)
- var/datum/mind/op = pre_nukeops[i]
-
- forge_syndicate_objectives(op)
- greet_syndicate(op)
- equip_syndicate(op.current)
-
- if(nuke_code)
- op.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
- to_chat(op.current, "The nuclear authorization code is: [nuke_code]")
-
- if(op == leader)
- op.current.forceMove(pick(GLOB.nukeop_leader_start))
- prepare_syndicate_leader(op, nuke_code)
- else
- op.current.forceMove(GLOB.nukeop_start[((i - 1) % GLOB.nukeop_start.len) + 1])
- op.current.real_name = "[syndicate_name()] Operative #[agent_number++]"
-
- update_synd_icons_added(op)
- op.current.playsound_local(get_turf(op.current), 'sound/ambience/antag/ops.ogg',100,0)
-
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
- if(nuke)
- nuke.r_code = nuke_code
+ //Assign leader
+ var/datum/mind/leader_mind = pre_nukeops[1]
+ var/datum/antagonist/nukeop/L = leader_mind.add_antag_datum(/datum/antagonist/nukeop/leader)
+ nuke_team = L.nuke_team
+ //Assign the remaining operatives
+ for(var/i = 2 to pre_nukeops.len)
+ var/datum/mind/nuke_mind = pre_nukeops[i]
+ nuke_mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
return ..()
-/datum/game_mode/proc/prepare_syndicate_leader(datum/mind/synd_mind, nuke_code)
- var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
- addtimer(CALLBACK(src, .proc/nuketeam_name_assign, synd_mind), 1)
- synd_mind.current.real_name = "[syndicate_name()] [leader_title]"
- to_chat(synd_mind.current, "You are the Syndicate [leader_title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.")
- to_chat(synd_mind.current, "If you feel you are not up to this task, give your ID to another operative.")
- to_chat(synd_mind.current, "In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.")
-
- var/obj/item/device/nuclear_challenge/challenge = new /obj/item/device/nuclear_challenge
- synd_mind.current.put_in_hands(challenge, TRUE)
-
- var/static/id_cache = typecacheof(/obj/item/card/id)
- var/list/foundIDs = typecache_filter_list(synd_mind.current.GetAllContents(), id_cache)
- if(foundIDs.len)
- for(var/i in 1 to foundIDs.len)
- var/obj/item/card/id/ID = foundIDs[i]
- ID.name = "lead agent card"
- ID.access += ACCESS_SYNDICATE_LEADER
- else
- message_admins("Warning: Nuke Ops spawned without access to leave their spawn area!")
-
- var/obj/item/device/radio/headset/syndicate/alt/A = locate() in synd_mind.current
- if(A)
- A.command = TRUE
-
- if(nuke_code)
- var/obj/item/paper/P = new
- P.info = "The nuclear authorization code is: [nuke_code]"
- P.name = "nuclear bomb code"
- var/mob/living/carbon/human/H = synd_mind.current
- H.put_in_hands(P, TRUE)
- H.update_icons()
- else
- nuke_code = "code will be provided later"
- return
-
-/datum/game_mode/proc/nuketeam_name_assign(datum/mind/synd_mind)
- nukeops_lastname = nukelastname(synd_mind.current)
- NukeNameAssign(nukeops_lastname, syndicates)
-
-
-/datum/game_mode/proc/forge_syndicate_objectives(datum/mind/syndicate)
- var/datum/objective/nuclear/syndobj = new
- syndobj.owner = syndicate
- syndicate.objectives += syndobj
-
-
-/datum/game_mode/proc/greet_syndicate(datum/mind/syndicate, you_are=1)
- if(you_are)
- to_chat(syndicate.current, "You are a [syndicate_name()] agent!")
- syndicate.announce_objectives()
-
-/datum/game_mode/proc/equip_syndicate(mob/living/carbon/human/synd_mob, telecrystals = TRUE)
- synd_mob.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
-
- if(telecrystals)
- synd_mob.equipOutfit(/datum/outfit/syndicate)
- else
- synd_mob.equipOutfit(/datum/outfit/syndicate/no_crystals)
- return TRUE
-
/datum/game_mode/nuclear/OnNukeExplosion(off_station)
..()
nukes_left--
- var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate")
- syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1
- nuke_off_station = off_station
/datum/game_mode/nuclear/check_win()
if (nukes_left == 0)
@@ -154,8 +52,8 @@
return ..()
/datum/game_mode/proc/are_operatives_dead()
- for(var/datum/mind/operative_mind in syndicates)
- if(ishuman(operative_mind.current) && (operative_mind.current.stat!=2))
+ for(var/datum/mind/operative_mind in get_antagonists(/datum/antagonist/nukeop))
+ if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
@@ -164,142 +62,55 @@
return replacementmode.check_finished()
if((SSshuttle.emergency.mode == SHUTTLE_ENDGAME) || station_was_nuked)
return TRUE
- if(are_operatives_dead())
+ if(nuke_team.operatives_dead())
var/obj/machinery/nuclearbomb/N
pass(N) //suppress unused warning
if(N.bomb_set) //snaaaaaaaaaake! It's not over yet!
return FALSE //its a static var btw
..()
-/datum/game_mode/nuclear/declare_completion()
- var/disk_rescued = 1
- for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
- if(!D.onCentCom())
- disk_rescued = 0
- break
- var/crew_evacuated = (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)
-
- if(nuke_off_station == NUKE_SYNDICATE_BASE)
- SSticker.mode_result = "loss - syndicate nuked - disk secured"
- 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!")
-
- SSticker.news_report = NUKE_SYNDICATE_BASE
-
- else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
- SSticker.mode_result = "win - syndicate nuke"
- to_chat(world, "Syndicate Major Victory!")
- to_chat(world, "[syndicate_name()] operatives have destroyed [station_name()]!")
-
- SSticker.news_report = STATION_NUKED
-
- else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
- SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time"
- 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!")
-
- SSticker.news_report = STATION_NUKED
-
- else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
- SSticker.mode_result = "halfwin - blew 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!")
-
- SSticker.news_report = NUKE_MISS
-
- else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
- SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time"
- 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!")
-
- SSticker.news_report = NUKE_MISS
-
- else if ((disk_rescued || SSshuttle.emergency.mode != SHUTTLE_ENDGAME) && are_operatives_dead())
- SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead"
- to_chat(world, "Crew Major Victory!")
- to_chat(world, "The Research Staff has saved the disk and killed the [syndicate_name()] Operatives")
-
- SSticker.news_report = OPERATIVES_KILLED
-
- else if (disk_rescued)
- SSticker.mode_result = "loss - evacuation - disk secured"
- to_chat(world, "Crew Major Victory")
- to_chat(world, "The Research Staff has saved the disk and stopped the [syndicate_name()] Operatives!")
-
- SSticker.news_report = OPERATIVES_KILLED
-
- else if (!disk_rescued && are_operatives_dead())
- SSticker.mode_result = "halfwin - evacuation - disk not secured"
- 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!")
-
- SSticker.news_report = OPERATIVE_SKIRMISH
-
- else if (!disk_rescued && crew_evacuated)
- SSticker.mode_result = "halfwin - detonation averted"
- 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!")
-
- SSticker.news_report = OPERATIVE_SKIRMISH
-
- else if (!disk_rescued && !crew_evacuated)
- SSticker.mode_result = "halfwin - interrupted"
- to_chat(world, "Neutral Victory")
- to_chat(world, "Round was mysteriously interrupted!")
-
- SSticker.news_report = OPERATIVE_SKIRMISH
-
+/datum/game_mode/nuclear/set_round_result()
..()
- return
+ var result = nuke_team.get_result()
+ switch(result)
+ if(NUKE_RESULT_FLUKE)
+ SSticker.mode_result = "loss - syndicate nuked - disk secured"
+ SSticker.news_report = NUKE_SYNDICATE_BASE
+ if(NUKE_RESULT_NUKE_WIN)
+ SSticker.mode_result = "win - syndicate nuke"
+ SSticker.news_report = STATION_NUKED
+ if(NUKE_RESULT_NOSURVIVORS)
+ SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time"
+ SSticker.news_report = STATION_NUKED
+ if(NUKE_RESULT_WRONG_STATION)
+ SSticker.mode_result = "halfwin - blew wrong station"
+ SSticker.news_report = NUKE_MISS
+ if(NUKE_RESULT_WRONG_STATION_DEAD)
+ SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time"
+ SSticker.news_report = NUKE_MISS
+ if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
+ SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead"
+ SSticker.news_report = OPERATIVES_KILLED
+ if(NUKE_RESULT_CREW_WIN)
+ SSticker.mode_result = "loss - evacuation - disk secured"
+ SSticker.news_report = OPERATIVES_KILLED
+ if(NUKE_RESULT_DISK_LOST)
+ SSticker.mode_result = "halfwin - evacuation - disk not secured"
+ SSticker.news_report = OPERATIVE_SKIRMISH
+ if(NUKE_RESULT_DISK_STOLEN)
+ SSticker.mode_result = "halfwin - detonation averted"
+ SSticker.news_report = OPERATIVE_SKIRMISH
+ else
+ SSticker.mode_result = "halfwin - interrupted"
+ SSticker.news_report = OPERATIVE_SKIRMISH
/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()
- if( syndicates.len || (SSticker && istype(SSticker.mode, /datum/game_mode/nuclear)) )
- var/text = "
The syndicate operatives were:"
- var/purchases = ""
- var/TC_uses = 0
- for(var/datum/mind/syndicate in syndicates)
- text += printplayer(syndicate)
- for(var/datum/component/uplink/H in GLOB.uplinks)
- if(H.purchase_log)
- purchases += H.purchase_log.generate_render()
- else
- stack_trace("WARNING: Uplink with no purchase_log in nuclear mode! Owner: [H.owner]")
- text += "
"
- text += "(Syndicates used [TC_uses] TC) [purchases]"
- if(TC_uses == 0 && station_was_nuked && !are_operatives_dead())
- text += "[icon2html('icons/badass.dmi', world, "badass")]"
- to_chat(world, text)
- return TRUE
-
-
-/proc/nukelastname(mob/M) //--All praise goes to NEO|Phyte, all blame goes to DH, and it was Cindi-Kate's idea. Also praise Urist for copypasta ho.
- var/randomname = pick(GLOB.last_names)
- var/newname = copytext(sanitize(input(M,"You are the nuke operative [pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")]. Please choose a last name for your family.", "Name change",randomname)),1,MAX_NAME_LEN)
-
- if (!newname)
- newname = randomname
-
- else
- if (newname == "Unknown" || newname == "floor" || newname == "wall" || newname == "rwall" || newname == "_")
- to_chat(M, "That name is reserved.")
- return nukelastname(M)
-
- return capitalize(newname)
-
-/proc/NukeNameAssign(lastname,list/syndicates)
- for(var/datum/mind/synd_mind in syndicates)
- var/mob/living/carbon/human/H = synd_mind.current
- synd_mind.name = H.dna.species.random_name(H.gender,0,lastname)
- synd_mind.current.real_name = synd_mind.name
- return
-
/proc/is_nuclear_operative(mob/M)
- return M && istype(M) && M.mind && SSticker && SSticker.mode && M.mind in SSticker.mode.syndicates
+ return M && istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/nukeop)
/datum/outfit/syndicate
name = "Syndicate Operative - Basic"
@@ -312,18 +123,28 @@
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
+
+
+/datum/outfit/syndicate/leader
+ name = "Syndicate Leader - Basic"
+ id = /obj/item/card/id/syndicate/nuke_leader
+ r_hand = /obj/item/device/nuclear_challenge
+ command_radio = TRUE
/datum/outfit/syndicate/no_crystals
tc = 0
-
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H)
var/obj/item/device/radio/R = H.ears
R.set_frequency(GLOB.SYND_FREQ)
R.freqlock = 1
+ if(command_radio)
+ R.command = TRUE
if(tc)
var/obj/item/device/radio/uplink/nuclear/U = new(H, H.key, tc)
@@ -348,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/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 908ecd797f..d6d14a3f84 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -77,16 +77,16 @@
icon = 'icons/obj/machines/nuke_terminal.dmi'
icon_state = "nuclearbomb_base"
anchored = TRUE //stops it being moved
- use_tag = TRUE
/obj/machinery/nuclearbomb/syndicate
+ use_tag = TRUE
//ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
var/datum/game_mode/nuclear/NM = SSticker.mode
switch(off_station)
if(0)
- if(istype(NM) && NM.syndies_didnt_escape)
+ if(istype(NM) && !NM.nuke_team.syndies_escaped())
return CINEMATIC_ANNIHILATION
else
return CINEMATIC_NUKE_WIN
@@ -353,7 +353,7 @@
var/N = text2num(user_input)
if(!N)
return
- timer_set = Clamp(N,minimum_timer_set,maximum_timer_set)
+ timer_set = CLAMP(N,minimum_timer_set,maximum_timer_set)
. = TRUE
if("safety")
if(auth && yes_code)
@@ -572,4 +572,4 @@ This is here to make the tiles around the station mininuke change when it's arme
user.visible_message("[user] is pretending to go delta! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(src, 'sound/machines/alarm.ogg', 30, -1, 1)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
- return MANUAL_SUICIDE
\ No newline at end of file
+ return MANUAL_SUICIDE
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm
index 2df573dc6d..7047729294 100644
--- a/code/game/gamemodes/nuclear/pinpointer.dm
+++ b/code/game/gamemodes/nuclear/pinpointer.dm
@@ -71,9 +71,9 @@
target = null
var/list/possible_targets = list()
var/turf/here = get_turf(src)
- for(var/V in SSticker.mode.syndicates)
+ for(var/V in get_antagonists(/datum/antagonist/nukeop))
var/datum/mind/M = V
- if(M.current && M.current.stat != DEAD)
+ if(ishuman(M.current) && M.current.stat != DEAD)
possible_targets |= M.current
var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
if(closest_operative)
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 46f96961c9..ef307c95a0 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -524,7 +524,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
var/list/otherwise = M.GetAllContents()
for(var/obj/item/disk/tech_disk/TD in otherwise)
TD.stored_research.copy_research_to(checking)
- return checking.researched_nodes.len >= target
+ return checking.researched_nodes.len >= target_amount
/datum/objective/capture
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/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm
index cbdc28883f..e9390a3cf5 100644
--- a/code/game/machinery/computer/apc_control.dm
+++ b/code/game/machinery/computer/apc_control.dm
@@ -161,7 +161,7 @@
return
log_activity("changed greater than charge filter to \"[new_filter]\"")
if(new_filter)
- new_filter = Clamp(new_filter, 0, 100)
+ new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Above"] = new_filter
if(href_list["below_filter"])
@@ -171,7 +171,7 @@
return
log_activity("changed lesser than charge filter to \"[new_filter]\"")
if(new_filter)
- new_filter = Clamp(new_filter, 0, 100)
+ new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Below"] = new_filter
if(href_list["access_filter"])
diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm
index 2d1d771203..a4881546cf 100644
--- a/code/game/machinery/computer/atmos_control.dm
+++ b/code/game/machinery/computer/atmos_control.dm
@@ -211,7 +211,7 @@
if("pressure")
var/target = input("New target pressure:", name, output_info ? output_info["internal"] : 0) as num|null
if(!isnull(target) && !..())
- target = Clamp(target, 0, 50 * ONE_ATMOSPHERE)
+ target = CLAMP(target, 0, 50 * ONE_ATMOSPHERE)
signal.data += list("tag" = output_tag, "set_internal_pressure" = target)
. = TRUE
radio_connection.post_signal(src, signal, filter = GLOB.RADIO_ATMOSIA)
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 44d6d5abe4..786deaa56a 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -300,6 +300,9 @@
else if(isspaceturf(T))
to_chat(user, "[prob(1) ? "Servant cannot into space." : "You can't teleport into space."]")
return
+ else if(T.flags_1 & NOJAUNT_1)
+ to_chat(user, "This tile is blessed by holy water and deflects the warp.")
+ return
var/area/AR = get_area(T)
if(!AR.clockwork_warp_allowed)
to_chat(user, "[AR.clockwork_warp_fail]")
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 7814e05138..c4a4d118b3 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -449,7 +449,7 @@
scantemp = "Subject's brain is not responding to scanning stimuli."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
+ if((mob_occupant.has_disability(NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 9fa196bd46..67f79f4c52 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -81,7 +81,7 @@
if(connected && connected.is_operational())
if(connected.occupant) //set occupant_status message
viable_occupant = connected.occupant
- if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.disabilities & NOCLONE) || (connected.scan_level == 3))) //occupant is viable for dna modification
+ if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.has_disability(NOCLONE)) || (connected.scan_level == 3))) //occupant is viable for dna modification
occupant_status += "[viable_occupant.name] => "
switch(viable_occupant.stat)
if(CONSCIOUS)
@@ -337,12 +337,12 @@
if(!num)
num = round(input(usr, "Choose pulse duration:", "Input an Integer", null) as num|null)
if(num)
- radduration = Wrap(num, 1, RADIATION_DURATION_MAX+1)
+ radduration = WRAP(num, 1, RADIATION_DURATION_MAX+1)
if("setstrength")
if(!num)
num = round(input(usr, "Choose pulse strength:", "Input an Integer", null) as num|null)
if(num)
- radstrength = Wrap(num, 1, RADIATION_STRENGTH_MAX+1)
+ radstrength = WRAP(num, 1, RADIATION_STRENGTH_MAX+1)
if("screen")
current_screen = href_list["text"]
if("rejuv")
@@ -353,13 +353,13 @@
if("setbufferlabel")
var/text = sanitize(input(usr, "Input a new label:", "Input an Text", null) as text|null)
if(num && text)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot["label"] = text
if("setbuffer")
if(num && viable_occupant)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = list(
"label"="Buffer[num]:[viable_occupant.real_name]",
"UI"=viable_occupant.dna.uni_identity,
@@ -370,7 +370,7 @@
)
if("clearbuffer")
if(num)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot.Cut()
@@ -387,7 +387,7 @@
apply_buffer(SCANNER_ACTION_MIXED,num)
if("injector")
if(num && injectorready < world.time)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
var/obj/item/dnainjector/timed/I
@@ -436,11 +436,11 @@
injectorready = world.time + INJECTOR_TIMEOUT
if("loaddisk")
if(num && diskette && diskette.fields)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = diskette.fields.Copy()
if("savedisk")
if(num && diskette && !diskette.read_only)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
diskette.name = "data disk \[[buffer_slot["label"]]\]"
@@ -454,8 +454,8 @@
delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num)
if("pulseui","pulsese")
if(num && viable_occupant && connected)
- radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1)
- radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1)
+ radduration = WRAP(radduration, 1, RADIATION_DURATION_MAX+1)
+ radstrength = WRAP(radstrength, 1, RADIATION_STRENGTH_MAX+1)
var/locked_state = connected.locked
connected.locked = TRUE
@@ -471,7 +471,7 @@
switch(href_list["task"]) //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage
if("pulseui")
var/len = length(viable_occupant.dna.uni_identity)
- num = Wrap(num, 1, len+1)
+ num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
//Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -487,7 +487,7 @@
viable_occupant.updateappearance(mutations_overlay_update=1)
if("pulsese")
var/len = length(viable_occupant.dna.struc_enzymes)
- num = Wrap(num, 1, len+1)
+ num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len)
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -518,21 +518,22 @@
ran = round(ran) //negative, so floor it
else
ran = -round(-ran) //positive, so ceiling it
- return num2hex(Wrap(hex2num(input)+ran, 0, 16**length), length)
+ return num2hex(WRAP(hex2num(input)+ran, 0, 16**length), length)
-/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks)
- return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1)
+/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position, radduration, number_of_blocks)
+ var/val = round(gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration) + position, 1)
+ return WRAP(val, 1, number_of_blocks+1)
/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant()
var/mob/living/carbon/viable_occupant = null
if(connected)
viable_occupant = connected.occupant
- if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE))
+ if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.has_disability(NOCLONE)))
viable_occupant = null
return viable_occupant
/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num)
- buffer_num = Clamp(buffer_num, 1, NUMBER_OF_BUFFERS)
+ buffer_num = CLAMP(buffer_num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[buffer_num]
var/mob/living/carbon/viable_occupant = get_viable_occupant()
if(istype(buffer_slot))
diff --git a/code/game/machinery/computer/gulag_teleporter.dm b/code/game/machinery/computer/gulag_teleporter.dm
index 36da1288a9..2419dd2299 100644
--- a/code/game/machinery/computer/gulag_teleporter.dm
+++ b/code/game/machinery/computer/gulag_teleporter.dm
@@ -106,7 +106,7 @@
return
if(!new_goal)
new_goal = default_goal
- id.goal = Clamp(new_goal, 0, 1000) //maximum 1000 points
+ id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points
if("toggle_open")
if(teleporter.locked)
to_chat(usr, "The teleporter is locked")
diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm
index 10f131f8be..8679652a10 100644
--- a/code/game/machinery/computer/telecrystalconsoles.dm
+++ b/code/game/machinery/computer/telecrystalconsoles.dm
@@ -154,8 +154,11 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/boss/proc/getDangerous()//This scales the TC assigned with the round population.
..()
- var/danger = GLOB.joined_player_list.len - SSticker.mode.syndicates.len
- danger = Ceiling(danger, 10)
+ var/list/nukeops = get_antagonists(/datum/antagonist/nukeop)
+ var/danger = GLOB.joined_player_list.len - nukeops.len
+// var/list/nukeops = get_antagonists(/datum/antagonist/nukeop)
+// var/danger = GLOB.joined_player_list.len - nukeops.len
+ danger = CEILING(danger, 10)
scaleTC(danger)
/obj/machinery/computer/telecrystals/boss/proc/scaleTC(amt)//Its own proc, since it'll probably need a lot of tweaks for balance, use a fancier algorhithm, etc.
@@ -223,4 +226,4 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
src.updateUsrDialog()
return
-#undef NUKESCALINGMODIFIER
\ No newline at end of file
+#undef NUKESCALINGMODIFIER
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index f0e1e8a18a..b9a2a68b34 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -33,7 +33,7 @@
to_chat(user, "You begin repairing [src]...")
playsound(loc, WT.usesound, 40, 1)
if(do_after(user, 40*I.toolspeed, target = src))
- obj_integrity = Clamp(obj_integrity + 20, 0, max_integrity)
+ obj_integrity = CLAMP(obj_integrity + 20, 0, max_integrity)
else
return ..()
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index d1189ff8b8..29df5e4949 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -100,7 +100,7 @@
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
if(istype(mob_occupant))
if(locate_computer(/obj/machinery/computer/cloning))
- if(!mob_occupant.suiciding && !(mob_occupant.disabilities & NOCLONE) && !mob_occupant.hellbound)
+ if(!mob_occupant.suiciding && !(mob_occupant.has_disability(NOCLONE)) && !mob_occupant.hellbound)
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
// DNA manipulators cannot operate on severed heads or brains
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 775c9dd894..3d659f104b 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -251,16 +251,13 @@
note = null
update_icon()
-/obj/machinery/door/airlock/proc/unzap() //for addtimer
- justzap = FALSE
-
/obj/machinery/door/airlock/bumpopen(mob/living/user) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite
if(!issilicon(usr))
if(isElectrified())
if(!justzap)
if(shock(user, 100))
justzap = TRUE
- addtimer(CALLBACK(src, .proc/unzap), 10)
+ addtimer(VARSET_CALLBACK(src, justzap, FALSE) , 10)
return
else
return
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 4c0d4a1804..a622f0af3d 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -142,7 +142,7 @@
. /= 10
/obj/machinery/door_timer/proc/set_timer(value)
- var/new_time = Clamp(value,0,MAX_TIMER)
+ var/new_time = CLAMP(value,0,MAX_TIMER)
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 30ae436289..c7a21bf31b 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -195,7 +195,7 @@
/obj/machinery/door/emp_act(severity)
if(prob(20/severity) && (istype(src, /obj/machinery/door/airlock) || istype(src, /obj/machinery/door/window)) )
INVOKE_ASYNC(src, .proc/open)
- if(prob(40/severity))
+ if(prob(severity*10 - 20))
if(secondsElectrified == 0)
secondsElectrified = -1
shockedby += "\[[time_stamp()]\]EM Pulse"
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/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index 06cdfcda7d..a67ce24c9c 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -53,9 +53,9 @@
new /obj/item/pipe_meter(loc)
wait = world.time + 15
if(href_list["layer_up"])
- piping_layer = Clamp(++piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
+ piping_layer = CLAMP(++piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
if(href_list["layer_down"])
- piping_layer = Clamp(--piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
+ piping_layer = CLAMP(--piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
return
/obj/machinery/pipedispenser/attackby(obj/item/W, mob/user, params)
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index 9356314973..cdbdb195cc 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -256,7 +256,7 @@
use_stored_power(50)
/obj/machinery/shieldwallgen/proc/use_stored_power(amount)
- power = Clamp(power - amount, 0, maximum_stored_power)
+ power = CLAMP(power - amount, 0, maximum_stored_power)
update_activity()
/obj/machinery/shieldwallgen/proc/update_activity()
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index 3d3911581d..eb24a04b0f 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -121,7 +121,7 @@
settableTemperatureRange = cap * 30
efficiency = (cap + 1) * 10000
- targetTemperature = Clamp(targetTemperature,
+ targetTemperature = CLAMP(targetTemperature,
max(settableTemperatureMedian - settableTemperatureRange, TCMB),
settableTemperatureMedian + settableTemperatureRange)
@@ -223,7 +223,7 @@
target= text2num(target) + T0C
. = TRUE
if(.)
- targetTemperature = Clamp(round(target),
+ targetTemperature = CLAMP(round(target),
max(settableTemperatureMedian - settableTemperatureRange, TCMB),
settableTemperatureMedian + settableTemperatureRange)
if("eject")
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index 5b510d965e..528faba57f 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -205,7 +205,7 @@
/obj/machinery/syndicatebomb/proc/settings(mob/user)
var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num
if(in_range(src, user) && isliving(user)) //No running off and setting bombs from across the station
- timer_set = Clamp(new_timer, minimum_timer, maximum_timer)
+ timer_set = CLAMP(new_timer, minimum_timer, maximum_timer)
loc.visible_message("[icon2html(src, viewers(src))] timer set for [timer_set] seconds.")
if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && in_range(src, user) && isliving(user))
if(defused || active)
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index bfa89db368..427ffa119a 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -25,8 +25,8 @@
integrity_failure = 100
armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70)
circuit = /obj/item/circuitboard/machine/vendor
- var/active = 1 //No sales pitches if off!
- var/vend_ready = 1 //Are we ready to vend?? Is it time??
+ var/active = TRUE //No sales pitches if off!
+ var/vend_ready = TRUE //Are we ready to vend?? Is it time??
// To be filled out at compile time
var/list/products = list() //For each, use the following pattern:
@@ -175,7 +175,7 @@
for(var/datum/data/vending_product/machine_content in machine)
if(refill.charges[charge_type] == 0)
break
- var/restock = Ceiling(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges)
+ var/restock = CEILING(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges, 1)
if(restock > refill.charges[charge_type])
restock = refill.charges[charge_type]
machine_content.amount += restock
@@ -227,15 +227,15 @@
if(!allowed(user) && !emagged && scan_id)
to_chat(user, "[src]'s chef compartment blinks red: Access denied.")
req_access_txt = "0"
- return 0
+ return FALSE
req_access_txt = "0"
- return 1
+ return TRUE
/obj/machinery/vending/snack/proc/iscompartmentfull(mob/user)
if(contents.len >= 30) // no more than 30 dishes can fit inside
to_chat(user, "[src]'s chef compartment is full.")
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S)
if(dish_quants[S.name])
@@ -350,180 +350,6 @@
/obj/machinery/vending/attack_ai(mob/user)
return attack_hand(user)
-/obj/machinery/vending/attack_hand(mob/user)
- var/dat = ""
- if(panel_open && !isAI(user))
- return wires.interact(user)
- else
- if(stat & (BROKEN|NOPOWER))
- return
-
- dat += "Select an item
"
- dat += ""
- if(product_records.len == 0)
- dat += "
No product loaded!"
- else
- var/list/display_records = product_records
- if(extended_inventory)
- display_records = product_records + hidden_records
- if(coin || bill)
- display_records = product_records + coin_records
- if((coin || bill) && extended_inventory)
- display_records = product_records + hidden_records + coin_records
- dat += "
"
- for (var/datum/data/vending_product/R in display_records)
- dat += "- "
- if(R.amount > 0)
- dat += "Vend "
- else
- dat += "Sold out "
- dat += "[sanitize(R.product_name)]:"
- dat += " [R.amount]"
- dat += "
"
- dat += "
"
- dat += "
"
- if(premium.len > 0)
- dat += "Change Return: "
- if (coin || bill)
- dat += "[(coin ? coin : "")][(bill ? bill : "")] Remove"
- else
- dat += "No money Remove"
- if(istype(src, /obj/machinery/vending/snack))
- dat += "Chef's Food Selection
"
- dat += ""
- for (var/O in dish_quants)
- if(dish_quants[O] > 0)
- var/N = dish_quants[O]
- dat += "
Dispense "
- dat += "
[capitalize(O)]: [N]"
- dat += "
"
- user.set_machine(src)
- if(seconds_electrified && !(stat & NOPOWER))
- if(shock(user, 100))
- return
-
- var/datum/browser/popup = new(user, "vending", (name))
- popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
- popup.open()
-
-
-/obj/machinery/vending/Topic(href, href_list)
- if(..())
- return
-
- if(href_list["remove_coin"])
- if(!(coin || bill))
- to_chat(usr, "There is no money in this machine.")
- return
- if(coin)
- if(!usr.get_active_held_item())
- usr.put_in_hands(coin)
- else
- coin.forceMove(get_turf(src))
- to_chat(usr, "You remove [coin] from [src].")
- coin = null
- if(bill)
- if(!usr.get_active_held_item())
- usr.put_in_hands(bill)
- else
- bill.forceMove(get_turf(src))
- to_chat(usr, "You remove [bill] from [src].")
- bill = null
-
-
- usr.set_machine(src)
-
- if((href_list["dispense"]) && (vend_ready))
- var/N = href_list["dispense"]
- if(dish_quants[N] <= 0) // Sanity check, there are probably ways to press the button when it shouldn't be possible.
- return
- vend_ready = 0
- use_power(5)
-
- dish_quants[N] = max(dish_quants[N] - 1, 0)
- for(var/obj/O in contents)
- if(O.name == N)
- O.forceMove(drop_location())
- break
- vend_ready = 1
- updateUsrDialog()
- return
-
- if((href_list["vend"]) && (vend_ready))
- if(panel_open)
- to_chat(usr, "The vending machine cannot dispense products while its service panel is open!")
- return
-
- if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
- to_chat(usr, "Access denied." )
- flick(icon_deny,src)
- return
-
- vend_ready = 0 //One thing at a time!!
-
- var/datum/data/vending_product/R = locate(href_list["vend"])
- if(!R || !istype(R) || !R.product_path)
- vend_ready = 1
- return
-
- if(R in hidden_records)
- if(!extended_inventory)
- vend_ready = 1
- return
- else if(R in coin_records)
- if(!(coin || bill))
- to_chat(usr, "You need to insert money to get this item!")
- vend_ready = 1
- return
- if(coin && coin.string_attached)
- if(prob(50))
- if(usr.put_in_hands(coin))
- to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.")
- coin = null
- else
- to_chat(usr, "You couldn't pull [coin] out because your hands are full!")
- QDEL_NULL(coin)
- else
- to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!")
- QDEL_NULL(coin)
- else
- QDEL_NULL(coin)
- QDEL_NULL(bill)
-
- else if (!(R in product_records))
- vend_ready = 1
- message_admins("Vending machine exploit attempted by [key_name(usr, usr.client)]!")
- return
-
- if (R.amount <= 0)
- to_chat(usr, "Sold out.")
- vend_ready = 1
- return
- else
- R.amount--
-
- if(((last_reply + 200) <= world.time) && vend_reply)
- speak(vend_reply)
- last_reply = world.time
-
- use_power(5)
- if(icon_vend) //Show the vending animation if needed
- flick(icon_vend,src)
- new R.product_path(get_turf(src))
- SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
- vend_ready = 1
- return
-
- updateUsrDialog()
- return
-
- else if(href_list["togglevoice"] && panel_open)
- shut_up = !shut_up
-
- updateUsrDialog()
-
-
/obj/machinery/vending/process()
if(stat & (BROKEN|NOPOWER))
return
@@ -605,6 +431,96 @@
else
return FALSE
+/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "vending", name, 350, 475, master_ui, state)
+ ui.open()
+
+/obj/machinery/vending/ui_data()
+ var/list/data = list()
+ var/list/listed_products = list()
+ var/list/display_records = product_records
+ if(extended_inventory)
+ display_records += hidden_records
+ if(coin)
+ display_records += coin_records
+ for(var/key = 1 to display_records.len)
+ var/datum/data/vending_product/I = display_records[key]
+ listed_products.Add(list(list(
+ "key" = key,
+ "name" = I.product_name,
+ "color" = I.display_color,
+ "amount" = I.amount)))
+ data["products"] = listed_products
+ if(!isnull(coin))
+ data["coin"] = coin.name
+ data["coinslot"] = premium.len
+ data["canvend"] = vend_ready
+
+ return data
+
+/obj/machinery/vending/ui_act(action, params)
+ if(..())
+ return
+ if(!vend_ready)
+ return
+ switch(action)
+ if("vend")
+ if(!allowed(usr) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
+ to_chat(usr, "Access denied.")
+ flick(icon_deny,src)
+ return
+ vend_ready = FALSE
+ addtimer(VARSET_CALLBACK(src, vend_ready, TRUE), 10)
+ var/key = text2num(params["key"])
+ var/datum/data/vending_product/R = product_records[key]
+ if(R in hidden_records)
+ if(!extended_inventory)
+ return
+ else if(R in coin_records)
+ if(!coin)
+ to_chat(usr, "You need to insert a coin to get this item!")
+ return
+ if(coin.string_attached)
+ if(prob(50))
+ if(usr.put_in_hands(coin))
+ to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.")
+ coin = null
+ else
+ to_chat(usr, "You couldn't pull [coin] out because your hands are full!")
+ QDEL_NULL(coin)
+ else
+ to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!")
+ QDEL_NULL(coin)
+ else
+ QDEL_NULL(coin)
+ else if (!(R in product_records))
+ return
+
+
+
+ if (R.amount <= 0)
+ to_chat(usr, "Sold out.")
+ return
+ R.amount--
+ if(((last_reply + 200) <= world.time) && vend_reply)
+ speak(vend_reply)
+ last_reply = world.time
+ use_power(5)
+ if(icon_vend) //Show the vending animation if needed
+ flick(icon_vend,src)
+ new R.product_path(drop_location())
+ return TRUE
+ if("eject")
+ if(!coin)
+ to_chat(usr, "There is no coin in this machine.")
+ return
+ usr.put_in_hands(coin)
+ to_chat(usr, "You remove [coin] from [src].")
+ coin = null
+
/*
* Vending machine types
*/
@@ -1195,4 +1111,4 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
#undef STANDARD_CHARGE
#undef CONTRABAND_CHARGE
-#undef COIN_CHARGE
\ No newline at end of file
+#undef COIN_CHARGE
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/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 8951a0dbd5..385d112542 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -422,7 +422,7 @@
if(!istype(T))
return
var/datum/gas_mixture/GM = new
- ADD_GAS(/datum/gas/plasma, GM.gases)
+ GM.add_gas(/datum/gas/plasma)
if(prob(10))
GM.gases[/datum/gas/plasma][MOLES] += 100
GM.temperature = 1500+T0C //should be enough to start a fire
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 1766a8cc3a..6ef98120f5 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -188,7 +188,7 @@
return queue.len
/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index)
- if(!isnum(index) || !IsInteger(index) || !istype(queue) || (index<1 || index>queue.len))
+ if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>queue.len))
return FALSE
queue.Cut(index,++index)
return TRUE
@@ -375,8 +375,8 @@
if(href_list["queue_move"] && href_list["index"])
var/index = afilter.getNum("index")
var/new_index = index + afilter.getNum("queue_move")
- if(isnum(index) && isnum(new_index) && IsInteger(index) && IsInteger(new_index))
- if(IsInRange(new_index,1,queue.len))
+ if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index))
+ if(ISINRANGE(new_index,1,queue.len))
queue.Swap(index,new_index)
return update_queue_on_page()
if(href_list["clear_queue"])
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/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 5688214044..a7115abd1d 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -94,7 +94,7 @@
/obj/mecha/working/ripley/mining/Initialize()
. = ..()
if(cell)
- cell.charge = Floor(cell.charge * 0.25) //Starts at very low charge
+ cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge
if(prob(70)) //Maybe add a drill
if(prob(15)) //Possible diamond drill... Feeling lucky?
var/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill/D = new
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 04737f2e4c..76fd5e5cbf 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -26,9 +26,8 @@
aSignal = new(src)
aSignal.name = "[name] core"
aSignal.code = rand(1,100)
-
- aSignal.frequency = rand(1200, 1599)
- if(IsMultiple(aSignal.frequency, 2))//signaller frequencies are always uneven!
+ aSignal.frequency = rand(MIN_FREE_FREQ, MAX_FREE_FREQ)
+ if(ISMULTIPLE(aSignal.frequency, 2))//signaller frequencies are always uneven!
aSignal.frequency++
if(new_lifespan)
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/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 3de8432ee9..4dc985c9a1 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -169,7 +169,7 @@
qdel(H)
var/list/G_gases = G.gases
if(G_gases[/datum/gas/plasma])
- ASSERT_GAS(/datum/gas/nitrogen, G)
+ G.assert_gas(/datum/gas/nitrogen)
G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES])
G_gases[/datum/gas/plasma][MOLES] = 0
G.garbage_collect()
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index caeb1f168c..2708e78535 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -16,7 +16,7 @@
/obj/effect/landmark/start
name = "start"
- icon = 'icons/mob/screen_gen.dmi'
+ icon = 'icons/mob/landmarks.dmi'
icon_state = "x"
anchored = TRUE
var/jobspawn_override = FALSE
@@ -40,9 +40,9 @@
// START LANDMARKS FOLLOW. Don't change the names unless
// you are refactoring shitty landmark code.
-
/obj/effect/landmark/start/assistant
name = "Assistant"
+ icon_state = "Assistant"
/obj/effect/landmark/start/assistant/override
jobspawn_override = TRUE
@@ -50,102 +50,135 @@
/obj/effect/landmark/start/janitor
name = "Janitor"
+ icon_state = "Janitor"
/obj/effect/landmark/start/cargo_technician
name = "Cargo Technician"
+ icon_state = "Cargo Technician"
/obj/effect/landmark/start/bartender
name = "Bartender"
+ icon_state = "Bartender"
/obj/effect/landmark/start/clown
name = "Clown"
+ icon_state = "Clown"
/obj/effect/landmark/start/mime
name = "Mime"
+ icon_state = "Mime"
/obj/effect/landmark/start/quartermaster
name = "Quartermaster"
+ icon_state = "Quartermaster"
/obj/effect/landmark/start/atmospheric_technician
name = "Atmospheric Technician"
+ icon_state = "Atmospheric Technician"
/obj/effect/landmark/start/cook
name = "Cook"
+ icon_state = "Cook"
/obj/effect/landmark/start/shaft_miner
name = "Shaft Miner"
+ icon_state = "Shaft Miner"
/obj/effect/landmark/start/security_officer
name = "Security Officer"
+ icon_state = "Security Officer"
/obj/effect/landmark/start/botanist
name = "Botanist"
+ icon_state = "Botanist"
/obj/effect/landmark/start/head_of_security
name = "Head of Security"
-
-/obj/effect/landmark/start/ai
- name = "AI"
- delete_after_roundstart = FALSE
+ icon_state = "Head of Security"
/obj/effect/landmark/start/captain
name = "Captain"
+ icon_state = "Captain"
/obj/effect/landmark/start/detective
name = "Detective"
+ icon_state = "Detective"
/obj/effect/landmark/start/warden
name = "Warden"
+ icon_state = "Warden"
/obj/effect/landmark/start/chief_engineer
name = "Chief Engineer"
-
-/obj/effect/landmark/start/cyborg
- name = "Cyborg"
+ icon_state = "Chief Engineer"
/obj/effect/landmark/start/head_of_personnel
name = "Head of Personnel"
+ icon_state = "Head of Personnel"
/obj/effect/landmark/start/librarian
name = "Curator"
+ icon_state = "Curator"
/obj/effect/landmark/start/lawyer
name = "Lawyer"
+ icon_state = "Lawyer"
/obj/effect/landmark/start/station_engineer
name = "Station Engineer"
+ icon_state = "Station Engineer"
/obj/effect/landmark/start/medical_doctor
name = "Medical Doctor"
+ icon_state = "Medical Doctor"
/obj/effect/landmark/start/scientist
name = "Scientist"
+ icon_state = "Scientist"
/obj/effect/landmark/start/chemist
name = "Chemist"
+ icon_state = "Chemist"
/obj/effect/landmark/start/roboticist
name = "Roboticist"
+ icon_state = "Roboticist"
/obj/effect/landmark/start/research_director
name = "Research Director"
+ icon_state = "Research Director"
/obj/effect/landmark/start/geneticist
name = "Geneticist"
+ icon_state = "Geneticist"
/obj/effect/landmark/start/chief_medical_officer
name = "Chief Medical Officer"
+ icon_state = "Chief Medical Officer"
/obj/effect/landmark/start/virologist
name = "Virologist"
+ icon_state = "Virologist"
/obj/effect/landmark/start/chaplain
name = "Chaplain"
+ icon_state = "Chaplain"
+
+/obj/effect/landmark/start/cyborg
+ name = "Cyborg"
+ icon_state = "Cyborg"
+
+/obj/effect/landmark/start/ai
+ name = "AI"
+ icon_state = "AI"
+ delete_after_roundstart = FALSE
+
//Department Security spawns
/obj/effect/landmark/start/depsec
name = "department_sec"
+ icon_state = "Security Officer"
/obj/effect/landmark/start/depsec/New()
..()
diff --git a/code/game/objects/effects/temporary_visuals/projectile_beam.dm b/code/game/objects/effects/temporary_visuals/projectile_beam.dm
new file mode 100644
index 0000000000..8918dc8e27
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/projectile_beam.dm
@@ -0,0 +1,70 @@
+/proc/generate_projectile_beam_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
+ if(!istype(starting) || !istype(ending) || !ispath(beam_type))
+ return
+ var/datum/point/midpoint = point_midpoint_points(starting, ending)
+ var/obj/effect/projectile_beam/PB = new beam_type
+ PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
+ . = PB
+ if(qdel_in)
+ QDEL_IN(PB, qdel_in)
+
+/obj/effect/projectile_beam
+ icon = 'icons/obj/projectiles.dmi'
+ layer = ABOVE_MOB_LAYER
+ anchored = TRUE
+ light_power = 1
+ light_range = 2
+ light_color = "#00ffff"
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ flags_1 = ABSTRACT_1
+ appearance_flags = 0
+
+/obj/effect/projectile_beam/singularity_pull()
+ return
+
+/obj/effect/projectile_beam/singularity_act()
+ return
+
+/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
+ var/matrix/M
+ if(!override)
+ M = transform
+ else
+ M = new
+ M.Scale(nx,ny)
+ transform = M
+
+/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
+ var/matrix/M
+ if(!override)
+ M = transform
+ else
+ M = new
+ M.Turn(angle)
+ transform = M
+
+/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
+ if(angle_override && p_x && p_y && color_override && scaling)
+ apply_vars(angle_override, p_x, p_y, color_override, scaling)
+ return ..()
+
+/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
+ var/mutable_appearance/look = new(src)
+ look.pixel_x = p_x
+ look.pixel_y = p_y
+ if(color_override)
+ look.color = color_override
+ appearance = look
+ scale_to(1,scaling, FALSE)
+ turn_to(angle_override, FALSE)
+ if(!isnull(new_loc)) //If you want to null it just delete it...
+ forceMove(new_loc)
+ for(var/i in 1 to increment)
+ pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
+ pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
+
+/obj/effect/projectile_beam/tracer
+ icon_state = "tracer_beam"
+
+/obj/effect/projectile_beam/tracer/aiming
+ icon_state = "gbeam"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index a74b246282..1cca673778 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -286,7 +286,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(!user.put_in_active_hand(src))
dropped(user)
-
/obj/item/attack_paw(mob/user)
if(!user)
return
@@ -400,12 +399,14 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
+ SendSignal(COMSIG_ITEM_DROPPED, user)
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
if(DROPDEL_1 & flags_1)
qdel(src)
in_inventory = FALSE
+ SendSignal(COMSIG_ITEM_DROPPED,user)
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
@@ -431,10 +432,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// for items that can be placed in multiple slots
// note this isn't called during the initial dressing of a player
/obj/item/proc/equipped(mob/user, slot)
+ SendSignal(COMSIG_ITEM_EQUIPPED, user, slot)
for(var/X in actions)
var/datum/action/A = X
if(item_action_slot_check(slot, user)) //some items only give their actions buttons when in a specific slot.
A.Grant(user)
+ SendSignal(COMSIG_ITEM_EQUIPPED,user,slot)
in_inventory = TRUE
//sometimes we only want to grant the item's action if it's equipped in a specific slot.
@@ -536,9 +539,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.adjust_blurriness(15)
if(M.stat != DEAD)
to_chat(M, "Your eyes start to bleed profusely!")
- if(!(M.disabilities & (NEARSIGHT | BLIND)))
- if(M.become_nearsighted())
- to_chat(M, "You become nearsighted!")
+ if(!(M.has_disability(BLIND) || M.has_disability(NEARSIGHT)))
+ to_chat(M, "You become nearsighted!")
+ M.become_nearsighted(EYE_DAMAGE)
if(prob(50))
if(M.stat != DEAD)
if(M.drop_all_held_items())
@@ -547,8 +550,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.Unconscious(20)
M.Knockdown(40)
if (prob(eyes.eye_damage - 10 + 1))
- if(M.become_blind())
- to_chat(M, "You go blind!")
+ M.become_blind(EYE_DAMAGE)
+ to_chat(M, "You go blind!")
/obj/item/clean_blood()
. = ..()
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index ed9a6712a8..0f65281328 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -155,6 +155,11 @@ update_label("John Doe", "Clowny")
name = "agent card"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE)
var/anyone = FALSE //Can anyone forge the ID or just syndicate?
+
+/obj/item/card/id/syndicate/nuke_leader
+ name = "lead agent card"
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
+
/obj/item/card/id/syndicate/Initialize()
. = ..()
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 5d4c85ac4d..7533718c17 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -187,7 +187,7 @@
/obj/effect/chrono_field/update_icon()
var/ttk_frame = 1 - (tickstokill / initial(tickstokill))
- ttk_frame = Clamp(Ceiling(ttk_frame * CHRONO_FRAME_COUNT), 1, CHRONO_FRAME_COUNT)
+ ttk_frame = CLAMP(CEILING(ttk_frame * CHRONO_FRAME_COUNT, 1), 1, CHRONO_FRAME_COUNT)
if(ttk_frame != RPpos)
RPpos = ttk_frame
mob_underlay.icon_state = "frame[RPpos]"
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 9c7c34510c..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()
@@ -129,6 +129,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
reagents.add_reagent_list(list_reagents)
if(starts_lit)
light()
+ AddComponent(/datum/component/knockoff,90,list("mouth"),list(slot_wear_mask))//90% to knock off when wearing a mask
/obj/item/clothing/mask/cigarette/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -659,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/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index a3ad685406..0277ec5371 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -8,7 +8,6 @@
var/colour = "red"
var/open = FALSE
-
/obj/item/lipstick/purple
name = "purple lipstick"
colour = "purple"
@@ -22,7 +21,6 @@
name = "black lipstick"
colour = "black"
-
/obj/item/lipstick/random
name = "lipstick"
icon_state = "random_lipstick"
@@ -33,8 +31,6 @@
colour = pick("red","purple","lime","black","green","blue","white")
name = "[colour] lipstick"
-
-
/obj/item/lipstick/attack_self(mob/user)
cut_overlays()
to_chat(user, "You twist \the [src] [open ? "closed" : "open"].")
@@ -103,7 +99,6 @@
else
..()
-
/obj/item/razor
name = "electric razor"
desc = "The latest and greatest power razor born from the science of shaving."
@@ -112,7 +107,6 @@
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_TINY
-
/obj/item/razor/proc/shave(mob/living/carbon/human/H, location = "mouth")
if(location == "mouth")
H.facial_hair_style = "Shaved"
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index e501e24c6a..a43691cc7b 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -69,7 +69,7 @@
if(powered) //so it doesn't show charge if it's unpowered
if(cell)
var/ratio = cell.charge / cell.maxcharge
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
add_overlay("[initial(icon_state)]-charge[ratio]")
/obj/item/defibrillator/CheckParts(list/parts_list)
@@ -393,7 +393,7 @@
/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/human/H)
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
- return (!H.suiciding && !(H.disabilities & NOCLONE) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
+ return (!H.suiciding && !(H.has_disability(NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
if(isliving(H.pulledby)) //CLEAR!
@@ -514,7 +514,7 @@
shock_touching(30, H)
var/failed
- if (H.suiciding || (H.disabilities & NOCLONE))
+ if (H.suiciding || (H.has_disability(NOCLONE)))
failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile."
else if (H.hellbound)
failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile."
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index bfcda7d271..1b9e2c0e14 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -180,9 +180,9 @@
/obj/item/cartridge/captain
name = "\improper Value-PAK cartridge"
- desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime and Clown)
+ desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime, Clown, and Syndie)
icon_state = "cart-c"
- access = ~(CART_CLOWN | CART_MIME)
+ access = ~(CART_CLOWN | CART_MIME | CART_REMOTE_DOOR)
bot_access_flags = SEC_BOT | MULE_BOT | FLOOR_BOT | CLEAN_BOT | MED_BOT
spam_enabled = 1
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index f656d55afd..7a40d8f3a2 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -48,7 +48,7 @@
add_fingerprint(user)
if(istype(M) && on && user.zone_selected in list("eyes", "mouth"))
- if((user.disabilities & (CLUMSY | DUMB)) && prob(50)) //too dumb to use flashlight properly
+ if((user.has_disability(CLUMSY) || user.has_disability(DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!user.IsAdvancedToolUser())
@@ -82,7 +82,7 @@
else
user.visible_message("[user] directs [src] to [M]'s eyes.", \
"You direct [src] to [M]'s eyes.")
- if(M.stat == DEAD || (M.disabilities & BLIND) || !M.flash_act(visual = 1)) //mob is dead or fully blind
+ if(M.stat == DEAD || (M.has_disability(BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
to_chat(user, "[M]'s pupils don't react to the light!")
else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-RAY vision
to_chat(user, "[M]'s pupils give an eerie glow!")
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index cdd95a2f71..4ea91ccccf 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -169,7 +169,7 @@
// Negative numbers will subtract
/obj/item/device/lightreplacer/proc/AddUses(amount = 1)
- uses = Clamp(uses + amount, 0, max_uses)
+ uses = CLAMP(uses + amount, 0, max_uses)
/obj/item/device/lightreplacer/proc/AddShards(amount = 1, user)
bulb_shards += amount
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 9a60bb0edb..6e67ca886b 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -85,7 +85,7 @@ GAS ANALYZER
/obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
// Clumsiness/brain damage check
- if ((user.disabilities & (CLUMSY | DUMB)) && prob(50))
+ if ((user.has_disability(CLUMSY) || user.has_disability(DUMB)) && prob(50))
to_chat(user, "You stupidly try to analyze the floor's vitals!")
user.visible_message("[user] has analyzed the floor's vitals!")
to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy")
@@ -181,9 +181,12 @@ GAS ANALYZER
to_chat(user, "\t==EAR STATUS==")
if(istype(ears))
var/healthy = TRUE
- if(C.disabilities & DEAF)
+ if(C.has_disability(DEAF, GENETIC_MUTATION))
healthy = FALSE
to_chat(user, "\tSubject is genetically deaf.")
+ else if(C.has_disability(DEAF))
+ healthy = FALSE
+ to_chat(user, "\tSubject is deaf.")
else
if(ears.ear_damage)
to_chat(user, "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.")
@@ -199,10 +202,10 @@ GAS ANALYZER
to_chat(user, "\t==EYE STATUS==")
if(istype(eyes))
var/healthy = TRUE
- if(C.disabilities & BLIND)
+ if(C.has_disability(BLIND))
to_chat(user, "\tSubject is blind.")
healthy = FALSE
- if(C.disabilities & NEARSIGHT)
+ if(C.has_disability(NEARSIGHT))
to_chat(user, "\tSubject is nearsighted.")
healthy = FALSE
if(eyes.eye_damage > 30)
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index 338f113afb..5afc8602ff 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -228,7 +228,7 @@ effective or pretty fucking useless.
charge = max(0,charge - 25)//Quick decrease in light
else
charge = min(max_charge,charge + 50) //Charge in the dark
- animate(user,alpha = Clamp(255 - charge,0,255),time = 10)
+ animate(user,alpha = CLAMP(255 - charge,0,255),time = 10)
/obj/item/device/jammer
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index 334be4a645..e14363a1c1 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -166,7 +166,7 @@
/obj/item/dice/proc/diceroll(mob/user)
result = rand(1, sides)
if(rigged && result != rigged)
- if(prob(Clamp(1/(sides - 1) * 100, 25, 80)))
+ if(prob(CLAMP(1/(sides - 1) * 100, 25, 80)))
result = rigged
var/fake_result = rand(1, sides)//Daredevil isn't as good as he used to be
var/comment = ""
diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index 9644d827ea..19008b43a6 100644
--- a/code/game/objects/items/dna_injector.dm
+++ b/code/game/objects/items/dna_injector.dm
@@ -31,7 +31,7 @@
/obj/item/dnainjector/proc/inject(mob/living/carbon/M, mob/user)
prepare()
- if(M.has_dna() && !(RADIMMUNE in M.dna.species.species_traits) && !(M.disabilities & NOCLONE))
+ if(M.has_dna() && !(RADIMMUNE in M.dna.species.species_traits) && !(M.has_disability(NOCLONE)))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
for(var/datum/mutation/human/HM in remove_mutations)
@@ -313,7 +313,7 @@
to_chat(user, "You can't modify [M]'s DNA while [M.p_theyre()] dead.")
return FALSE
- if(M.has_dna() && !(M.disabilities & NOCLONE))
+ if(M.has_dna() && !(M.has_disability(NOCLONE)))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
var/endtime = world.time+duration
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/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index e444ecce25..257007aba9 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -24,7 +24,7 @@
qdel(src)
/obj/item/grenade/proc/clown_check(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "Huh? How does this thing work?")
preprime(user, 5, FALSE)
return FALSE
diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm
index dd0d397e81..0375e5529e 100644
--- a/code/game/objects/items/grenades/plastic.dm
+++ b/code/game/objects/items/grenades/plastic.dm
@@ -87,7 +87,7 @@
return
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
- newtime = Clamp(newtime, 10, 60000)
+ newtime = CLAMP(newtime, 10, 60000)
det_time = newtime
to_chat(user, "Timer set for [det_time] seconds.")
@@ -204,7 +204,7 @@
/obj/item/grenade/plastic/c4/attack_self(mob/user)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
- newtime = Clamp(newtime, 10, 60000)
+ newtime = CLAMP(newtime, 10, 60000)
timer = newtime
to_chat(user, "Timer set for [timer] seconds.")
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 886a248c8c..7cfc4e220e 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -1,6 +1,19 @@
/obj/item/restraints
breakouttime = 600
+/obj/item/restraints/Destroy()
+ if(iscarbon(loc))
+ var/mob/living/carbon/M = loc
+ if(M.handcuffed == src)
+ M.handcuffed = null
+ M.update_handcuffed()
+ if(M.buckled && M.buckled.buckle_requires_restraints)
+ M.buckled.unbuckle_mob(M)
+ if(M.legcuffed == src)
+ M.legcuffed = null
+ M.update_inv_legcuffed()
+ return ..()
+
//Handcuffs
/obj/item/restraints/handcuffs
@@ -26,7 +39,7 @@
/obj/item/restraints/handcuffs/attack(mob/living/carbon/C, mob/living/carbon/human/user)
if(!istype(C))
return
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "Uh... how do those things work?!")
apply_cuffs(user,user)
return
diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm
index 98121f7772..d13d6cc1dd 100644
--- a/code/game/objects/items/his_grace.dm
+++ b/code/game/objects/items/his_grace.dm
@@ -75,7 +75,7 @@
drowse()
return
if(bloodthirst < HIS_GRACE_CONSUME_OWNER)
- adjust_bloodthirst(1 + Floor(LAZYLEN(contents) * 0.5)) //Maybe adjust this?
+ adjust_bloodthirst(1 + FLOOR(LAZYLEN(contents) * 0.5, 1)) //Maybe adjust this?
else
adjust_bloodthirst(1) //don't cool off rapidly once we're at the point where His Grace consumes all.
var/mob/living/master = get_atom_on_turf(src, /mob/living)
@@ -164,9 +164,9 @@
/obj/item/his_grace/proc/adjust_bloodthirst(amt)
prev_bloodthirst = bloodthirst
if(prev_bloodthirst < HIS_GRACE_CONSUME_OWNER)
- bloodthirst = Clamp(bloodthirst + amt, HIS_GRACE_SATIATED, HIS_GRACE_CONSUME_OWNER)
+ bloodthirst = CLAMP(bloodthirst + amt, HIS_GRACE_SATIATED, HIS_GRACE_CONSUME_OWNER)
else
- bloodthirst = Clamp(bloodthirst + amt, HIS_GRACE_CONSUME_OWNER, HIS_GRACE_FALL_ASLEEP)
+ bloodthirst = CLAMP(bloodthirst + amt, HIS_GRACE_CONSUME_OWNER, HIS_GRACE_FALL_ASLEEP)
update_stats()
/obj/item/his_grace/proc/update_stats()
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index 7ca82c1236..f5b50542d0 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -14,6 +14,9 @@
/obj/item/implant/proc/trigger(emote, mob/living/carbon/source)
return
+/obj/item/implant/proc/on_death(emote, mob/living/carbon/source)
+ return
+
/obj/item/implant/proc/activate()
return
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/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm
index 8b19bb9d96..0dc22c3d83 100644
--- a/code/game/objects/items/implants/implant_explosive.dm
+++ b/code/game/objects/items/implants/implant_explosive.dm
@@ -3,7 +3,7 @@
desc = "And boom goes the weasel."
icon_state = "explosive"
actions_types = list(/datum/action/item_action/explosive_implant)
- // Explosive implant action is always availible.
+ // Explosive implant action is always available.
var/weak = 2
var/medium = 0.8
var/heavy = 0.4
@@ -11,6 +11,9 @@
var/popup = FALSE // is the DOUWANNABLOWUP window open?
var/active = FALSE
+/obj/item/implant/explosive/on_mob_death(mob/living/L, gibbed)
+ activate("death")
+
/obj/item/implant/explosive/get_data()
var/dat = {"Implant Specifications:
Name: Robust Corp RX-78 Employee Management Implant
@@ -23,10 +26,6 @@
"}
return dat
-/obj/item/implant/explosive/trigger(emote, mob/source)
- if(emote == "deathgasp")
- activate("death")
-
/obj/item/implant/explosive/activate(cause)
if(!cause || !imp_in || active)
return 0
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 5a8fcda09b..0a9e356014 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -44,7 +44,7 @@
forkload = null
else if(user.zone_selected == "eyes")
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
else
@@ -70,7 +70,7 @@
/obj/item/kitchen/knife/attack(mob/living/carbon/M, mob/living/carbon/user)
if(user.zone_selected == "eyes")
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
else
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 6e21251b6e..6fb173b905 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -99,7 +99,7 @@
return ..()
add_fingerprint(user)
- if((CLUMSY in user.disabilities) && prob(50))
+ if((user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "You club yourself over the head.")
user.Knockdown(60 * force)
if(ishuman(user))
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index b63c5bcefa..94f7de09bc 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -72,6 +72,6 @@
to_chat(user, "[src] [active ? "is now active":"can now be concealed"].")
/obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
user.take_bodypart_damage(5,5)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index 9bf0b949c0..dc0a2fe286 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -125,14 +125,14 @@
loadedWeightClass += I.w_class
return TRUE
-/obj/item/pneumatic_cannon/afterattack(atom/target, mob/living/carbon/human/user, flag, params)
+/obj/item/pneumatic_cannon/afterattack(atom/target, mob/living/user, flag, params)
if(flag && user.a_intent == INTENT_HARM) //melee attack
return
if(!istype(user))
return
Fire(user, target)
-/obj/item/pneumatic_cannon/proc/Fire(mob/living/carbon/human/user, var/atom/target)
+/obj/item/pneumatic_cannon/proc/Fire(mob/living/user, var/atom/target)
if(!istype(user) && !target)
return
var/discharge = 0
@@ -147,9 +147,10 @@
if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
return
- if(user.disabilities & CLUMSY && prob(75) && clumsyCheck)
- user.visible_message("[user] loses their grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
- user.dropItemToGround(src, TRUE)
+ if(user.has_disability(CLUMSY) && prob(75) && clumsyCheck && iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.visible_message("[C] loses their grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
+ C.dropItemToGround(src, TRUE)
if(prob(10))
target = get_turf(user)
else
@@ -163,9 +164,10 @@
var/turf/T = get_target(target, get_turf(src))
playsound(src.loc, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
fire_items(T, user)
- if(pressureSetting >= 3 && user)
- user.visible_message("[user] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
- user.Knockdown(60)
+ if(pressureSetting >= 3 && iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.visible_message("[C] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
+ C.Knockdown(60)
/obj/item/pneumatic_cannon/proc/fire_items(turf/target, mob/user)
if(fire_mode == PCANNON_FIREALL)
@@ -198,8 +200,8 @@
return target
var/x_o = (target.x - starting.x)
var/y_o = (target.y - starting.y)
- var/new_x = Clamp((starting.x + (x_o * range_multiplier)), 0, world.maxx)
- var/new_y = Clamp((starting.y + (y_o * range_multiplier)), 0, world.maxy)
+ var/new_x = CLAMP((starting.x + (x_o * range_multiplier)), 0, world.maxx)
+ var/new_y = CLAMP((starting.y + (y_o * range_multiplier)), 0, world.maxy)
var/turf/newtarget = locate(new_x, new_y, starting.z)
return newtarget
@@ -271,3 +273,10 @@
selfcharge = TRUE
charge_type = /obj/item/reagent_containers/food/snacks/pie/cream
maxWeightClass = 60 //20 pies.
+
+/obj/item/pneumatic_cannon/pie/selfcharge/cyborg
+ name = "low velocity pie cannon"
+ automatic = FALSE
+ charge_type = /obj/item/reagent_containers/food/snacks/pie/cream/nostun
+ maxWeightClass = 6 //2 pies
+ charge_ticks = 2 //4 second/pie
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index c0c927320c..6c1cf93295 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -355,6 +355,9 @@
var/hitdamage = 0
var/emaggedhitdamage = 3
+/obj/item/borg/lollipop/clown
+ emaggedhitdamage = 0
+
/obj/item/borg/lollipop/equipped()
check_amount()
@@ -637,7 +640,7 @@
continue
usage += projectile_tick_speed_ecost
usage += (tracked[I] * projectile_damage_tick_ecost_coefficient)
- energy = Clamp(energy - usage, 0, maxenergy)
+ energy = CLAMP(energy - usage, 0, maxenergy)
if(energy <= 0)
deactivate_field()
visible_message("[src] blinks \"ENERGY DEPLETED\".")
@@ -647,7 +650,7 @@
if(iscyborg(host.loc))
host = host.loc
else
- energy = Clamp(energy + energy_recharge, 0, maxenergy)
+ energy = CLAMP(energy + energy_recharge, 0, maxenergy)
return
if((host.cell.charge >= (host.cell.maxcharge * cyborg_cell_critical_percentage)) && (energy < maxenergy))
host.cell.use(energy_recharge*energy_recharge_cyborg_drain_coefficient)
diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm
index fb25cb1d76..93056adc99 100644
--- a/code/game/objects/items/sharpener.dm
+++ b/code/game/objects/items/sharpener.dm
@@ -35,14 +35,14 @@
if(TH.force_wielded > initial(TH.force_wielded))
to_chat(user, "[TH] has already been refined before. It cannot be sharpened further!")
return
- TH.force_wielded = Clamp(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
+ TH.force_wielded = CLAMP(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
if(I.force > initial(I.force))
to_chat(user, "[I] has already been refined before. It cannot be sharpened further!")
return
user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.")
I.sharpness = IS_SHARP_ACCURATE
- I.force = Clamp(I.force + increment, 0, max)
- I.throwforce = Clamp(I.throwforce + increment, 0, max)
+ I.force = CLAMP(I.force + increment, 0, max)
+ I.throwforce = CLAMP(I.throwforce + increment, 0, max)
I.name = "[prefix] [I.name]"
name = "worn out [name]"
desc = "[desc] At least, it used to."
diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm
index 57306f498c..113bc9755c 100644
--- a/code/game/objects/items/shields.dm
+++ b/code/game/objects/items/shields.dm
@@ -1,142 +1,142 @@
-/obj/item/shield
- name = "shield"
- block_chance = 50
- armor = list(melee = 50, bullet = 50, laser = 50, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 80, acid = 70)
-
-/obj/item/shield/riot
- name = "riot shield"
- desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "riot"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- slot_flags = SLOT_BACK
- force = 10
- throwforce = 5
- throw_speed = 2
- throw_range = 3
- w_class = WEIGHT_CLASS_BULKY
- materials = list(MAT_GLASS=7500, MAT_METAL=1000)
- attack_verb = list("shoved", "bashed")
- var/cooldown = 0 //shield bash cooldown. based on world.time
-
-
-/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/melee/baton))
- if(cooldown < world.time - 25)
- user.visible_message("[user] bashes [src] with [W]!")
- playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
- cooldown = world.time
- else
- return ..()
-
-/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(attack_type == THROWN_PROJECTILE_ATTACK)
- final_block_chance += 30
- if(attack_type == LEAP_ATTACK)
- final_block_chance = 100
- return ..()
-
-/obj/item/shield/riot/roman
- name = "roman shield"
- desc = "Bears an inscription on the inside: \"Romanes venio domus\"."
- icon_state = "roman_shield"
- item_state = "roman_shield"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
-
-/obj/item/shield/riot/buckler
- name = "wooden buckler"
- desc = "A medieval wooden buckler."
- icon_state = "buckler"
- item_state = "buckler"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- materials = list()
- resistance_flags = FLAMMABLE
- block_chance = 30
-
-/obj/item/shield/energy
- name = "energy combat shield"
- desc = "A shield capable of stopping most melee attacks. Protects user from almost all energy projectiles. It can be retracted, expanded, and stored anywhere."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "eshield0" // eshield1 for expanded
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- force = 3
- throwforce = 3
- throw_speed = 3
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- attack_verb = list("shoved", "bashed")
- var/active = 0
-
-/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- return 0
-
-/obj/item/shield/energy/IsReflect()
- return (active)
-
-/obj/item/shield/energy/attack_self(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
- to_chat(user, "You beat yourself in the head with [src].")
- user.take_bodypart_damage(5)
- active = !active
- icon_state = "eshield[active]"
-
- if(active)
- force = 10
- throwforce = 8
- throw_speed = 2
- w_class = WEIGHT_CLASS_BULKY
- playsound(user, 'sound/weapons/saberon.ogg', 35, 1)
- to_chat(user, "[src] is now active.")
- else
- force = 3
- throwforce = 3
- throw_speed = 3
- w_class = WEIGHT_CLASS_TINY
- playsound(user, 'sound/weapons/saberoff.ogg', 35, 1)
- to_chat(user, "[src] can now be concealed.")
- add_fingerprint(user)
-
-/obj/item/shield/riot/tele
- name = "telescopic shield"
- desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "teleriot0"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- slot_flags = null
- force = 3
- throwforce = 3
- throw_speed = 3
- throw_range = 4
- w_class = WEIGHT_CLASS_NORMAL
- var/active = 0
-
-/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(active)
- return ..()
- return 0
-
-/obj/item/shield/riot/tele/attack_self(mob/living/user)
- active = !active
- icon_state = "teleriot[active]"
- playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
-
- if(active)
- force = 8
- throwforce = 5
- throw_speed = 2
- w_class = WEIGHT_CLASS_BULKY
- slot_flags = SLOT_BACK
- to_chat(user, "You extend \the [src].")
- else
- force = 3
- throwforce = 3
- throw_speed = 3
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = null
- to_chat(user, "[src] can now be concealed.")
- add_fingerprint(user)
+/obj/item/shield
+ name = "shield"
+ block_chance = 50
+ armor = list(melee = 50, bullet = 50, laser = 50, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 80, acid = 70)
+
+/obj/item/shield/riot
+ name = "riot shield"
+ desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "riot"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ slot_flags = SLOT_BACK
+ force = 10
+ throwforce = 5
+ throw_speed = 2
+ throw_range = 3
+ w_class = WEIGHT_CLASS_BULKY
+ materials = list(MAT_GLASS=7500, MAT_METAL=1000)
+ attack_verb = list("shoved", "bashed")
+ var/cooldown = 0 //shield bash cooldown. based on world.time
+
+
+/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/melee/baton))
+ if(cooldown < world.time - 25)
+ user.visible_message("[user] bashes [src] with [W]!")
+ playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
+ cooldown = world.time
+ else
+ return ..()
+
+/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(attack_type == THROWN_PROJECTILE_ATTACK)
+ final_block_chance += 30
+ if(attack_type == LEAP_ATTACK)
+ final_block_chance = 100
+ return ..()
+
+/obj/item/shield/riot/roman
+ name = "roman shield"
+ desc = "Bears an inscription on the inside: \"Romanes venio domus\"."
+ icon_state = "roman_shield"
+ item_state = "roman_shield"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+
+/obj/item/shield/riot/buckler
+ name = "wooden buckler"
+ desc = "A medieval wooden buckler."
+ icon_state = "buckler"
+ item_state = "buckler"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ materials = list()
+ resistance_flags = FLAMMABLE
+ block_chance = 30
+
+/obj/item/shield/energy
+ name = "energy combat shield"
+ desc = "A shield capable of stopping most melee attacks. Protects user from almost all energy projectiles. It can be retracted, expanded, and stored anywhere."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "eshield0" // eshield1 for expanded
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ attack_verb = list("shoved", "bashed")
+ var/active = 0
+
+/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ return 0
+
+/obj/item/shield/energy/IsReflect()
+ return (active)
+
+/obj/item/shield/energy/attack_self(mob/living/carbon/human/user)
+ if(user.has_disability(CLUMSY) && prob(50))
+ to_chat(user, "You beat yourself in the head with [src].")
+ user.take_bodypart_damage(5)
+ active = !active
+ icon_state = "eshield[active]"
+
+ if(active)
+ force = 10
+ throwforce = 8
+ throw_speed = 2
+ w_class = WEIGHT_CLASS_BULKY
+ playsound(user, 'sound/weapons/saberon.ogg', 35, 1)
+ to_chat(user, "[src] is now active.")
+ else
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ w_class = WEIGHT_CLASS_TINY
+ playsound(user, 'sound/weapons/saberoff.ogg', 35, 1)
+ to_chat(user, "[src] can now be concealed.")
+ add_fingerprint(user)
+
+/obj/item/shield/riot/tele
+ name = "telescopic shield"
+ desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "teleriot0"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ slot_flags = null
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ throw_range = 4
+ w_class = WEIGHT_CLASS_NORMAL
+ var/active = 0
+
+/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(active)
+ return ..()
+ return 0
+
+/obj/item/shield/riot/tele/attack_self(mob/living/user)
+ active = !active
+ icon_state = "teleriot[active]"
+ playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
+
+ if(active)
+ force = 8
+ throwforce = 5
+ throw_speed = 2
+ w_class = WEIGHT_CLASS_BULKY
+ slot_flags = SLOT_BACK
+ to_chat(user, "You extend \the [src].")
+ else
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ w_class = WEIGHT_CLASS_NORMAL
+ slot_flags = null
+ to_chat(user, "[src] can now be concealed.")
+ add_fingerprint(user)
diff --git a/code/game/objects/items/signs.dm b/code/game/objects/items/signs.dm
index 350daa0fc3..65716f2f30 100644
--- a/code/game/objects/items/signs.dm
+++ b/code/game/objects/items/signs.dm
@@ -10,13 +10,23 @@
var/label = ""
var/last_wave = 0
+/obj/item/picket_sign/cyborg
+ name = "metallic nano-sign"
+ desc = "A high tech picket sign used by silicons that can reprogram its surface at will. Probably hurts to get hit by, too."
+ force = 13
+ resistance_flags = NONE
+ actions_types = list(/datum/action/item_action/nano_picket_sign)
+
+/obj/item/picket_sign/proc/retext(mob/user)
+ var/txt = stripped_input(user, "What would you like to write on the sign?", "Sign Label", null , 30)
+ if(txt && Adjacent(user))
+ label = txt
+ name = "[label] sign"
+ desc = "It reads: [label]"
+
/obj/item/picket_sign/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen) || istype(W, /obj/item/toy/crayon))
- var/txt = stripped_input(user, "What would you like to write on the sign?", "Sign Label", null , 30)
- if(txt)
- label = txt
- src.name = "[label] sign"
- desc = "It reads: [label]"
+ retext(user)
else
return ..()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index d50239f79d..cef25a0a36 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -48,9 +48,9 @@
/obj/item/stack/proc/update_weight()
if(amount <= (max_amount * (1/3)))
- w_class = Clamp(full_w_class-2, WEIGHT_CLASS_TINY, full_w_class)
+ w_class = CLAMP(full_w_class-2, WEIGHT_CLASS_TINY, full_w_class)
else if (amount <= (max_amount * (2/3)))
- w_class = Clamp(full_w_class-1, WEIGHT_CLASS_TINY, full_w_class)
+ w_class = CLAMP(full_w_class-1, WEIGHT_CLASS_TINY, full_w_class)
else
w_class = full_w_class
@@ -109,7 +109,7 @@
if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list))
var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist]
recipe_list = srl.recipes
- var/t1 = "Amount Left: [amount]
"
+ var/t1 = "Amount Left: [get_amount()]
"
for(var/i in 1 to length(recipe_list))
var/E = recipe_list[i]
if (isnull(E))
@@ -161,8 +161,8 @@
if (href_list["sublist"] && !href_list["make"])
interact(usr, text2num(href_list["sublist"]))
if (href_list["make"])
- if (get_amount() < 1)
- qdel(src) //Never should happen
+ if (get_amount() < 1 && !is_cyborg)
+ qdel(src)
var/list/recipes_list = recipes
if (href_list["sublist"])
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/storage/book.dm b/code/game/objects/items/storage/book.dm
index ef04fc48f5..a06d1a509e 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -94,7 +94,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
to_chat(user, "You don't have the dexterity to do this!")
return
- if (user.disabilities & CLUMSY && prob(50))
+ if (user.has_disability(CLUMSY) && prob(50))
to_chat(user, "[src] slips out of your hand and hits your head.")
user.take_bodypart_damage(10)
user.Unconscious(400)
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index ab82f92c2d..128a313525 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -108,7 +108,7 @@
add_fingerprint(user)
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
- if(status && user.disabilities & CLUMSY && prob(50))
+ if(status && user.has_disability(CLUMSY) && prob(50))
user.visible_message("[user] accidentally hits themself with [src]!", \
"You accidentally hit yourself with [src]!")
user.Knockdown(stunforce*3)
diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm
index f1644f0b1a..6466696b98 100644
--- a/code/game/objects/items/tanks/jetpack.dm
+++ b/code/game/objects/items/tanks/jetpack.dm
@@ -17,7 +17,7 @@
/obj/item/tank/jetpack/New()
..()
if(gas_type)
- ASSERT_GAS(gas_type,air_contents)
+ air_contents.assert_gas(gas_type)
air_contents.gases[gas_type][MOLES] = (6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)
ion_trail = new
diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm
index 7a1fa569a3..4a687b458d 100644
--- a/code/game/objects/items/tanks/tank_types.dm
+++ b/code/game/objects/items/tanks/tank_types.dm
@@ -21,7 +21,7 @@
/obj/item/tank/internals/oxygen/New()
..()
- ASSERT_GAS(/datum/gas/oxygen, air_contents)
+ air_contents.assert_gas(/datum/gas/oxygen)
air_contents.gases[/datum/gas/oxygen][MOLES] = (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -87,7 +87,7 @@
/obj/item/tank/internals/plasma/New()
..()
- ASSERT_GAS(/datum/gas/plasma, air_contents)
+ air_contents.assert_gas(/datum/gas/plasma)
air_contents.gases[/datum/gas/plasma][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -124,7 +124,7 @@
/obj/item/tank/internals/plasmaman/New()
..()
- ASSERT_GAS(/datum/gas/plasma, air_contents)
+ air_contents.assert_gas(/datum/gas/plasma)
air_contents.gases[/datum/gas/plasma][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -166,7 +166,7 @@
/obj/item/tank/internals/emergency_oxygen/New()
..()
- ASSERT_GAS(/datum/gas/oxygen, air_contents)
+ air_contents.assert_gas(/datum/gas/oxygen)
air_contents.gases[/datum/gas/oxygen][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 3d1c091a2b..0109b67b00 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -194,7 +194,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- distribute_pressure = Clamp(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
+ distribute_pressure = CLAMP(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
/obj/item/tank/remove_air(amount)
return air_contents.remove(amount)
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/teleprod.dm b/code/game/objects/items/teleprod.dm
index 92e7a8e9ba..c780d32917 100644
--- a/code/game/objects/items/teleprod.dm
+++ b/code/game/objects/items/teleprod.dm
@@ -8,7 +8,7 @@
/obj/item/melee/baton/cattleprod/teleprod/attack(mob/living/carbon/M, mob/living/carbon/user)//handles making things teleport when hit
..()
- if(status && user.disabilities & CLUMSY && prob(50))
+ if(status && user.has_disability(CLUMSY) && prob(50))
user.visible_message("[user] accidentally hits themself with [src]!", \
"You accidentally hit yourself with [src]!")
if(do_teleport(user, get_turf(user), 50))//honk honk
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index 08f22b7e46..8fd37a3b38 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -75,7 +75,7 @@
return ..()
if(user.zone_selected != "eyes" && user.zone_selected != "head")
return ..()
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
@@ -105,7 +105,7 @@
item_state = "drill"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
//done for balance reasons, making them high value for research, but harder to get
+ materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) //done for balance reasons, making them high value for research, but harder to get
force = 8 //might or might not be too high, subject to change
w_class = WEIGHT_CLASS_SMALL
throwforce = 8
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 1c20c95e93..12c056c9af 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -21,7 +21,7 @@
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30)
resistance_flags = FIRE_PROOF
- materials = list(MAT_METAL=70, MAT_GLASS=30)
+ materials = list(MAT_METAL=70, MAT_GLASS=30)
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower)
var/max_fuel = 20 //The max amount of fuel the welder can hold
@@ -51,7 +51,7 @@
cut_overlays()
if(change_icons)
var/ratio = get_fuel() / max_fuel
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
add_overlay("[initial(icon_state)][ratio]")
update_torch()
return
@@ -89,18 +89,15 @@
flamethrower_screwdriver(I, user)
else if(istype(I, /obj/item/stack/rods))
flamethrower_rods(I, user)
- else if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
- var/amountNeeded = max_fuel - get_fuel()
- var/obj/item/reagent_containers/container = I
- if(length(container.reagents.reagent_list) > 1)
- to_chat(user, "[container] has too many chemicals mixed into it. You wouldn't want to put the wrong chemicals into [src].")
- return ..()
- if(amountNeeded > 0 && container.reagents.has_reagent("welding_fuel"))
- container.reagents.trans_id_to(src, "welding_fuel", amountNeeded)
- to_chat(user, "You transfer some fuel from [container] to [src].")
else
- return ..()
+ . = ..()
+ update_icon()
+/obj/item/weldingtool/proc/explode()
+ var/turf/T = get_turf(loc)
+ var/plasmaAmount = reagents.get_reagent_amount("plasma")
+ dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
+ qdel(src)
/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user)
if(!istype(H))
@@ -123,7 +120,10 @@
/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity)
if(!proximity)
return
-
+ 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()
if(welding)
remove_fuel(1)
var/turf/location = get_turf(user)
@@ -139,6 +139,9 @@
/obj/item/weldingtool/attack_self(mob/user)
+ if(src.reagents.has_reagent("plasma"))
+ message_admins("[key_name_admin(user)] activated a rigged welder.")
+ explode()
switched_on(user)
if(welding)
set_light(light_intensity)
@@ -234,9 +237,11 @@
return
status = !status
if(status)
- to_chat(user, "You resecure [src].")
+ to_chat(user, "You resecure [src] and close the fuel tank.")
+ container_type = NONE
else
- to_chat(user, "[src] can now be attached and modified.")
+ to_chat(user, "[src] can now be attached, modified, and refuelled.")
+ container_type = OPENCONTAINER
add_fingerprint(user)
/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user)
@@ -264,7 +269,7 @@
desc = "A slightly larger welder with a larger tank."
icon_state = "indwelder"
max_fuel = 40
- materials = list(MAT_GLASS=60)
+ materials = list(MAT_GLASS=60)
/obj/item/weldingtool/largetank/cyborg
name = "integrated welding tool"
@@ -294,7 +299,7 @@
icon_state = "welder"
toolspeed = 0.1
light_intensity = 0
- change_icons = 0
+ change_icons = 0
/obj/item/weldingtool/abductor/process()
if(get_fuel() <= max_fuel)
@@ -307,7 +312,7 @@
icon_state = "upindwelder"
item_state = "upindwelder"
max_fuel = 80
- materials = list(MAT_METAL=70, MAT_GLASS=120)
+ materials = list(MAT_METAL=70, MAT_GLASS=120)
/obj/item/weldingtool/experimental
name = "experimental welding tool"
@@ -315,7 +320,7 @@
icon_state = "exwelder"
item_state = "exwelder"
max_fuel = 40
- materials = list(MAT_METAL=70, MAT_GLASS=120)
+ materials = list(MAT_METAL=70, MAT_GLASS=120)
var/last_gen = 0
change_icons = 0
can_off_process = 1
@@ -336,4 +341,5 @@
if(get_fuel() < max_fuel && nextrefueltick < world.time)
nextrefueltick = world.time + 10
reagents.add_reagent("welding_fuel", 1)
-#undef WELDER_FUEL_BURN_INTERVAL
\ No newline at end of file
+
+#undef WELDER_FUEL_BURN_INTERVAL
diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm
index c03469164e..910b98b27a 100644
--- a/code/game/objects/items/tools/wirecutters.dm
+++ b/code/game/objects/items/tools/wirecutters.dm
@@ -14,7 +14,8 @@
materials = list(MAT_METAL=80)
attack_verb = list("pinched", "nipped")
hitsound = 'sound/items/wirecutter.ogg'
- usesound = 'sound/items/wirecutter.ogg'
+ usesound = 'sound/items/wirecutter.ogg'
+
tool_behaviour = TOOL_WIRECUTTER
toolspeed = 1
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 30)
@@ -32,10 +33,6 @@
if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable))
user.visible_message("[user] cuts [C]'s restraints with [src]!")
qdel(C.handcuffed)
- C.handcuffed = null
- if(C.buckled && C.buckled.buckle_requires_restraints)
- C.buckled.unbuckle_mob(C)
- C.update_handcuffed()
return
else
..()
@@ -58,7 +55,8 @@
desc = "Extremely sharp wirecutters, made out of a silvery-green metal."
icon = 'icons/obj/abductor.dmi'
icon_state = "cutters"
- toolspeed = 0.1
+ toolspeed = 0.1
+
random_color = FALSE
/obj/item/wirecutters/cyborg
@@ -70,7 +68,8 @@
name = "jaws of life"
desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head."
icon_state = "jaws_cutter"
- item_state = "jawsoflife"
+ item_state = "jawsoflife"
+
materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
usesound = 'sound/items/jaws_cut.ogg'
toolspeed = 0.25
@@ -92,4 +91,12 @@
var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power
to_chat(user, "You attach the pry jaws to [src].")
qdel(src)
- user.put_in_active_hand(pryjaws)
\ No newline at end of file
+ user.put_in_active_hand(pryjaws)
+
+/obj/item/wirecutters/power/attack(mob/living/carbon/C, mob/user)
+ if(istype(C) && C.handcuffed)
+ user.visible_message("[user] cuts [C]'s restraints with [src]!")
+ qdel(C.handcuffed)
+ return
+ else
+ ..()
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 259193b177..689f50769c 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -182,7 +182,7 @@
src.add_fingerprint(user)
if (src.bullets < 1)
user.show_message("*click*", 2)
- playsound(src, "gun_dry_fire", 60, 1)
+ playsound(src, "gun_dry_fire", 30, 1)
return
playsound(user, 'sound/weapons/gunshot.ogg', 100, 1)
src.bullets--
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index c11d41eaa8..293ef46197 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -302,7 +302,7 @@
unwield()
return
..()
- if(user.disabilities & CLUMSY && (wielded) && prob(40))
+ if(user.has_disability(CLUMSY) && (wielded) && prob(40))
impale(user)
return
if((wielded) && prob(50))
@@ -429,6 +429,10 @@
var/obj/item/grenade/explosive = null
var/war_cry = "AAAAARGH!!!"
+/obj/item/twohanded/spear/Initialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
/obj/item/twohanded/spear/examine(mob/user)
..()
if(explosive)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index ad5f69672b..ff8bcc3e1e 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -198,7 +198,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
if(T.intact && level == 1) //fire can't damage things hidden below the floor.
return
if(exposed_temperature && !(resistance_flags & FIRE_PROOF))
- take_damage(Clamp(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
+ take_damage(CLAMP(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE))
resistance_flags |= ON_FIRE
SSfire_burning.processing[src] = src
diff --git a/code/game/objects/structures/fireplace.dm b/code/game/objects/structures/fireplace.dm
index 04d7f983c0..2735bd7e81 100644
--- a/code/game/objects/structures/fireplace.dm
+++ b/code/game/objects/structures/fireplace.dm
@@ -129,7 +129,7 @@
if(burn_time_remaining() < MAXIMUM_BURN_TIMER)
flame_expiry_timer = world.time + MAXIMUM_BURN_TIMER
else
- fuel_added = Clamp(fuel_added + amount, 0, MAXIMUM_BURN_TIMER)
+ fuel_added = CLAMP(fuel_added + amount, 0, MAXIMUM_BURN_TIMER)
/obj/structure/fireplace/proc/burn_time_remaining()
if(lit)
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/grille.dm b/code/game/objects/structures/grille.dm
index 009bbcd70e..a7bfb92c45 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -30,7 +30,7 @@
return
var/ratio = obj_integrity / max_integrity
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
if(smooth)
queue_smooth(src)
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/lattice.dm b/code/game/objects/structures/lattice.dm
index c0dcd866d8..306d3d0b84 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -67,7 +67,7 @@
resistance_flags |= INDESTRUCTIBLE
/obj/structure/lattice/clockwork/ratvar_act()
- if(IsOdd(x+y))
+ if(ISODD(x+y))
icon = 'icons/obj/smooth_structures/lattice_clockwork_large.dmi'
pixel_x = -9
pixel_y = -9
@@ -124,7 +124,7 @@
resistance_flags |= INDESTRUCTIBLE
/obj/structure/lattice/catwalk/clockwork/ratvar_act()
- if(IsOdd(x+y))
+ if(ISODD(x+y))
icon = 'icons/obj/smooth_structures/catwalk_clockwork_large.dmi'
pixel_x = -9
pixel_y = -9
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/musician.dm b/code/game/objects/structures/musician.dm
index 1265594eff..a73824ca2b 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -119,7 +119,7 @@
else
cur_oct[cur_note] = text2num(ni)
if(user.dizziness > 0 && prob(user.dizziness / 2))
- cur_note = Clamp(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7)
+ cur_note = CLAMP(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7)
if(user.dizziness > 0 && prob(user.dizziness / 5))
if(prob(30))
cur_acc[cur_note] = "#"
diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm
index 36233bc155..d2bee1af36 100644
--- a/code/game/objects/structures/petrified_statue.dm
+++ b/code/game/objects/structures/petrified_statue.dm
@@ -17,7 +17,7 @@
L.buckled.unbuckle_mob(L,force=1)
L.visible_message("[L]'s skin rapidly turns to marble!", "Your body freezes up! Can't... move... can't... think...")
L.forceMove(src)
- L.disabilities |= MUTE
+ L.add_disability(MUTE, STATUE_MUTE)
L.faction += "mimic" //Stops mimics from instaqdeling people in statues
L.status_flags |= GODMODE
obj_integrity = L.health + 100 //stoning damaged mobs will result in easier to shatter statues
@@ -59,7 +59,7 @@
if(petrified_mob)
petrified_mob.status_flags &= ~GODMODE
petrified_mob.forceMove(loc)
- petrified_mob.disabilities &= ~MUTE
+ petrified_mob.remove_disability(MUTE, STATUE_MUTE)
petrified_mob.take_overall_damage((petrified_mob.health - obj_integrity + 100)) //any new damage the statue incurred is transfered to the mob
petrified_mob.faction -= "mimic"
petrified_mob = null
diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm
index e47afd53d4..a8ca42bff5 100644
--- a/code/game/objects/structures/reflector.dm
+++ b/code/game/objects/structures/reflector.dm
@@ -165,7 +165,7 @@
to_chat(user, "You can't do that right now!")
return
if(!isnull(new_angle))
- setAngle(NORM_ROT(new_angle))
+ setAngle(SIMPLIFY_DEGREES(new_angle))
return TRUE
/obj/structure/reflector/AltClick(mob/user)
@@ -197,16 +197,12 @@
anchored = TRUE
/obj/structure/reflector/single/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
- var/incidence = get_angle_of_incidence(rotation_angle, P.Angle)
- var/incidence_norm = get_angle_of_incidence(rotation_angle, P.Angle, FALSE)
- if((incidence_norm > -90) && (incidence_norm < 90))
+ var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, P.Angle)
+ var/norm_inc = WRAP(incidence, -90, 90)
+ var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
+ if(ISINRANGE_EX(norm_inc, -90, 90))
return FALSE
- var/new_angle_s = rotation_angle + incidence
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- while(new_angle_s < -180)
- new_angle_s += 360
- P.Angle = new_angle_s
+ P.setAngle(new_angle)
return ..()
//DOUBLE
@@ -228,17 +224,12 @@
anchored = TRUE
/obj/structure/reflector/double/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
- var/incidence = get_angle_of_incidence(rotation_angle, P.Angle)
- var/incidence_norm = get_angle_of_incidence(rotation_angle, P.Angle, FALSE)
- var/invert = ((incidence_norm > -90) && (incidence_norm < 90))
- var/new_angle_s = rotation_angle + incidence
- if(invert)
- new_angle_s += 180
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- while(new_angle_s < -180)
- new_angle_s += 360
- P.Angle = new_angle_s
+ var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, P.Angle)
+ var/norm_inc = WRAP(incidence, -90, 90)
+ var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
+ if(ISINRANGE_EX(norm_inc, -90, 90))
+ new_angle += 180
+ P.setAngle(new_angle)
return ..()
//BOX
@@ -260,7 +251,7 @@
anchored = TRUE
/obj/structure/reflector/box/auto_reflect(obj/item/projectile/P)
- P.Angle = rotation_angle
+ P.setAngle(rotation_angle)
return ..()
/obj/structure/reflector/ex_act()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 299409b3a3..95c2380802 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -134,8 +134,8 @@
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_x = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_y = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
return 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/objects/structures/window.dm b/code/game/objects/structures/window.dm
index e2da7630df..f5aec5c274 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -379,7 +379,7 @@
return
var/ratio = obj_integrity / max_integrity
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
if(smooth)
queue_smooth(src)
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index 5d83d677de..0eddbc411e 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -355,6 +355,6 @@
if (air.gases[/datum/gas/carbon_dioxide] && air.gases[/datum/gas/oxygen])
air.gases[/datum/gas/carbon_dioxide][MOLES]=max(air.gases[/datum/gas/carbon_dioxide][MOLES]-(pulse_strength/1000),0)
air.gases[/datum/gas/oxygen][MOLES]=max(air.gases[/datum/gas/oxygen][MOLES]-(pulse_strength/2000),0)
- ASSERT_GAS(/datum/gas/pluoxium,air)
+ air.assert_gas(/datum/gas/pluoxium)
air.gases[/datum/gas/pluoxium][MOLES]+=(pulse_strength/4000)
- air.garbage_collect()
\ No newline at end of file
+ air.garbage_collect()
diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm
index 3e7540cdf6..634767c98b 100644
--- a/code/game/turfs/simulated/floor/misc_floor.dm
+++ b/code/game/turfs/simulated/floor/misc_floor.dm
@@ -146,6 +146,9 @@
var/uses_overlay = TRUE
var/obj/effect/clockwork/overlay/floor/realappearence
+/turf/open/floor/clockwork/Bless() //Who needs holy blessings when you have DADDY RATVAR?
+ return
+
/turf/open/floor/clockwork/Initialize()
. = ..()
if(uses_overlay)
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index b2ab28dcae..1419036d07 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -188,7 +188,7 @@
break
var/list/L = list(45)
- if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
+ if(ISODD(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
L += -45
// Expand the edges of our tunnel
diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm
index ecc389af88..0dab10ff92 100644
--- a/code/game/turfs/simulated/wall/misc_walls.dm
+++ b/code/game/turfs/simulated/wall/misc_walls.dm
@@ -70,6 +70,10 @@
if(realappearence)
qdel(realappearence)
realappearence = null
+ if(heated)
+ var/mob/camera/eminence/E = get_eminence()
+ if(E)
+ E.superheated_walls--
return ..()
/turf/closed/wall/clockwork/ReplaceWithLattice()
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 337bb051a8..14b7ef74b5 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -54,14 +54,14 @@
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
- var/incidence_s = get_angle_of_incidence(face_angle, P.Angle)
+ var/incidence_s = WRAP(GET_ANGLE_OF_INCIDENCE(face_angle, P.Angle), -90, 90)
var/new_angle = face_angle + incidence_s
var/new_angle_s = new_angle
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
while(new_angle_s < -180)
new_angle_s += 360
- P.Angle = new_angle_s
+ P.setAngle(new_angle_s)
return TRUE
/turf/closed/wall/proc/dismantle_wall(devastated=0, explode=0)
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/game/world.dm b/code/game/world.dm
index 2853bb2ef6..39d48d28ac 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -251,3 +251,4 @@ GLOBAL_PROTECT(security_mode)
hub_password = "kMZy3U5jJHSiBQjr"
else
hub_password = "SORRYNOPASSWORD"
+
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 fa6e184ab4..2a3812be3b 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -384,9 +384,10 @@
dat += "
[other_players] players in invalid state or the statistics code is bugged!"
dat += "
"
- if(SSticker.mode.syndicates.len)
+ var/list/nukeops = get_antagonists(/datum/antagonist/nukeop)
+ if(nukeops.len)
dat += "
| Syndicates | |
"
- for(var/datum/mind/N in SSticker.mode.syndicates)
+ for(var/datum/mind/N in nukeops)
var/mob/M = N.current
if(M)
dat += "| [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""] | "
@@ -523,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/sound_emitter.dm b/code/modules/admin/sound_emitter.dm
index b7ec8c36b5..87024f7832 100644
--- a/code/modules/admin/sound_emitter.dm
+++ b/code/modules/admin/sound_emitter.dm
@@ -92,7 +92,7 @@
var/new_volume = input(user, "Choose a volume.", "Sound Emitter", sound_volume) as null|num
if(isnull(new_volume))
return
- new_volume = Clamp(new_volume, 0, 100)
+ new_volume = CLAMP(new_volume, 0, 100)
sound_volume = new_volume
to_chat(user, "Volume set to [sound_volume]%.")
if(href_list["edit_mode"])
@@ -115,7 +115,7 @@
var/new_radius = input(user, "Choose a radius.", "Sound Emitter", sound_volume) as null|num
if(isnull(new_radius))
return
- new_radius = Clamp(new_radius, 0, 127)
+ new_radius = CLAMP(new_radius, 0, 127)
play_radius = new_radius
to_chat(user, "Audible radius set to [play_radius].")
if(href_list["play"])
diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm
index 587bd6b26c..38316c904f 100644
--- a/code/modules/admin/sql_message_system.dm
+++ b/code/modules/admin/sql_message_system.dm
@@ -220,7 +220,7 @@
var/nsd = CONFIG_GET(number/note_stale_days)
var/nfd = CONFIG_GET(number/note_fresh_days)
if (agegate && type == "note" && isnum(nsd) && isnum(nfd) && nsd > nfd)
- var/alpha = Clamp(100 - (age - nfd) * (85 / (nsd - nfd)), 15, 100)
+ var/alpha = CLAMP(100 - (age - nfd) * (85 / (nsd - nfd)), 15, 100)
if (alpha < 100)
if (alpha <= 15)
if (skipped)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 2bf915d246..91769ac55a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1943,7 +1943,7 @@
return
var/list/offset = splittext(href_list["offset"],",")
- var/number = Clamp(text2num(href_list["object_count"]), 1, 100)
+ var/number = CLAMP(text2num(href_list["object_count"]), 1, 100)
var/X = offset.len > 0 ? text2num(offset[1]) : 0
var/Y = offset.len > 1 ? text2num(offset[2]) : 0
var/Z = offset.len > 2 ? text2num(offset[3]) : 0
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
index 9e9e727b39..0421807abe 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
@@ -435,7 +435,7 @@
else if(expression[start + 1] == "\[" && islist(v))
var/list/L = v
var/index = SDQL_expression(source, expression[start + 2])
- if(isnum(index) && (!IsInteger(index) || L.len < index))
+ if(isnum(index) && (!ISINTEGER(index) || L.len < index))
to_chat(usr, "Invalid list index: [index]")
return null
return L[index]
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index b02fe03c18..daa1d58de5 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -107,6 +107,8 @@ GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
+GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
+GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(target, procname, list/arguments)
var/current_caller = GLOB.AdminProcCaller
@@ -114,9 +116,14 @@ GLOBAL_PROTECT(LastAdminCalledProc)
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
- to_chat(usr, "Another set of admin called procs are still running, your proc will be run after theirs finish.")
- UNTIL(!GLOB.AdminProcCaller)
- to_chat(usr, "Running your proc")
+ if(!GLOB.AdminProcCallSpamPrevention[ckey])
+ to_chat(usr, "Another set of admin called procs are still running, your proc will be run after theirs finish.")
+ GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
+ UNTIL(!GLOB.AdminProcCaller)
+ to_chat(usr, "Running your proc")
+ GLOB.AdminProcCallSpamPrevention -= ckey
+ else
+ UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
@@ -735,7 +742,7 @@ GLOBAL_PROTECT(LastAdminCalledProc)
if(Rad.anchored)
if(!Rad.loaded_tank)
var/obj/item/tank/internals/plasma/Plasma = new/obj/item/tank/internals/plasma(Rad)
- ASSERT_GAS(/datum/gas/plasma, Plasma.air_contents)
+ Plasma.air_contents.assert_gas(/datum/gas/plasma)
Plasma.air_contents.gases[/datum/gas/plasma][MOLES] = 70
Rad.drainratio = 0
Rad.loaded_tank = Plasma
diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm
index 5d0c2fe833..dcb9137416 100644
--- a/code/modules/admin/verbs/mapping.dm
+++ b/code/modules/admin/verbs/mapping.dm
@@ -45,7 +45,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
/client/proc/manipulate_organs,
/client/proc/start_line_profiling,
/client/proc/stop_line_profiling,
- /client/proc/show_line_profiling
+ /client/proc/show_line_profiling,
+ /client/proc/create_mapping_job_icons
))
/obj/effect/debugging/mapfix_marker
@@ -265,3 +266,31 @@ GLOBAL_VAR_INIT(say_disabled, FALSE)
message_admins("[src.ckey] used 'Disable all communication verbs', killing all communication methods.")
else
message_admins("[src.ckey] used 'Disable all communication verbs', restoring all communication methods.")
+
+//This generates the icon states for job starting location landmarks.
+/client/proc/create_mapping_job_icons()
+ set name = "Generate job landmarks icons"
+ set category = "Mapping"
+ var/icon/final = icon()
+ var/mob/living/carbon/human/dummy/D = new(locate(1,1,1)) //spawn on 1,1,1 so we don't have runtimes when items are deleted
+ D.setDir(SOUTH)
+ for(var/job in subtypesof(/datum/job))
+ var/datum/job/JB = new job
+ switch(JB.title)
+ if("AI")
+ final.Insert(icon('icons/mob/ai.dmi', "ai", SOUTH, 1), "AI")
+ if("Cyborg")
+ final.Insert(icon('icons/mob/robots.dmi', "robot", SOUTH, 1), "Cyborg")
+ else
+ for(var/obj/item/I in D)
+ qdel(I)
+ randomize_human(D)
+ JB.equip(D, TRUE, FALSE)
+ COMPILE_OVERLAYS(D)
+ var/icon/I = icon(getFlatIcon(D), frame = 1)
+ final.Insert(I, JB.title)
+ qdel(D)
+ //Also add the x
+ for(var/x_number in 1 to 4)
+ final.Insert(icon('icons/mob/screen_gen.dmi', "x[x_number == 1 ? "" : x_number]"), "x[x_number == 1 ? "" : x_number]")
+ fcopy(final, "icons/mob/landmarks.dmi")
\ No newline at end of file
diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm
index 3a2e13fdcc..f6e8d93e62 100644
--- a/code/modules/admin/verbs/modifyvariables.dm
+++ b/code/modules/admin/verbs/modifyvariables.dm
@@ -213,7 +213,9 @@ GLOBAL_PROTECT(VVpixelmovement)
.["class"] = null
return
.["type"] = type
- .["value"] = new type()
+ var/atom/newguy = new type()
+ newguy.var_edited = TRUE
+ .["value"] = newguy
if (VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
@@ -221,7 +223,9 @@ GLOBAL_PROTECT(VVpixelmovement)
.["class"] = null
return
.["type"] = type
- .["value"] = new type()
+ var/datum/newguy = new type()
+ newguy.var_edited = TRUE
+ .["value"] = newguy
if (VV_NEW_TYPE)
var/type = current_value
@@ -237,7 +241,10 @@ GLOBAL_PROTECT(VVpixelmovement)
.["class"] = null
return
.["type"] = type
- .["value"] = new type()
+ var/datum/newguy = new type()
+ if(istype(newguy))
+ newguy.var_edited = TRUE
+ .["value"] = newguy
if (VV_NEW_LIST)
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 8a18dc9ac5..ece3775872 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -238,26 +238,17 @@
if(agentcount < 3)
return 0
- var/nuke_code = random_nukecode()
-
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
- if(nuke)
- nuke.r_code = nuke_code
-
//Let's find the spawn locations
var/leader_chosen = FALSE
- var/spawnpos = 1 //Decides where they'll spawn. 1=leader.
-
+ var/datum/team/nuclear/nuke_team
for(var/mob/c in chosen)
- if(spawnpos > GLOB.nukeop_start.len)
- spawnpos = 1 //Ran out of spawns. Let's loop back to the first non-leader position
var/mob/living/carbon/human/new_character=makeBody(c)
if(!leader_chosen)
leader_chosen = TRUE
- new_character.mind.make_Nuke(pick(GLOB.nukeop_leader_start), nuke_code, TRUE)
+ var/datum/antagonist/nukeop/N = new_character.mind.add_antag_datum(/datum/antagonist/nukeop/leader)
+ nuke_team = N.nuke_team
else
- new_character.mind.make_Nuke(GLOB.nukeop_start[spawnpos], nuke_code)
- spawnpos++
+ new_character.mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
return 1
else
return 0
@@ -317,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."
@@ -369,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)
@@ -474,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/playsound.dm b/code/modules/admin/verbs/playsound.dm
index 6b1edf7709..58189e98b0 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -12,7 +12,7 @@
var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num
if(!vol)
return
- vol = Clamp(vol, 1, 100)
+ vol = CLAMP(vol, 1, 100)
var/sound/admin_sound = new()
admin_sound.file = S
@@ -80,14 +80,32 @@
to_chat(src, "For youtube-dl shortcuts like ytsearch: please use the appropriate full url from the website.")
return
var/shell_scrubbed_input = shell_url_scrub(web_sound_input)
- var/list/output = world.shelleo("[ytdl] --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --get-url \"[shell_scrubbed_input]\"")
+ var/list/output = world.shelleo("[ytdl] --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --dump-single-json --no-playlist -- \"[shell_scrubbed_input]\"")
var/errorlevel = output[SHELLEO_ERRORLEVEL]
var/stdout = output[SHELLEO_STDOUT]
var/stderr = output[SHELLEO_STDERR]
if(!errorlevel)
- var/static/regex/content_url_regex = regex("https?://\\S+")
- if(content_url_regex.Find(stdout))
- web_sound_url = content_url_regex.match
+ var/list/data
+ try
+ data = json_decode(stdout)
+ catch(var/exception/e)
+ to_chat(src, "Youtube-dl JSON parsing FAILED:")
+ to_chat(src, "[e]: [stdout]")
+ return
+
+ if (data["url"])
+ web_sound_url = data["url"]
+ var/title = "[data["title"]]"
+ var/webpage_url = title
+ if (data["webpage_url"])
+ webpage_url = "[title]"
+
+ var/res = alert(usr, "Show the title of and link to this song to the players?\n[title]",, "No", "Yes", "Cancel")
+ switch(res)
+ if("Yes")
+ to_chat(world, "An admin played: [webpage_url]")
+ if("Cancel")
+ return
if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS])
pitch = pick(0.5, 0.7, 0.8, 0.85, 0.9, 0.95, 1.1, 1.2, 1.4, 1.6, 2.0, 2.5)
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 48ba94bb76..8f13d887aa 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -386,7 +386,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
A.equip_wizard()
if("Syndicate")
new_character.forceMove(pick(GLOB.nukeop_start))
- call(/datum/game_mode/proc/equip_syndicate)(new_character)
+ var/datum/antagonist/nukeop/N = new_character.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ N.equip_op()
if("Space Ninja")
var/list/ninja_spawn = list()
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
@@ -1206,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
@@ -1228,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/assembly/flash.dm b/code/modules/assembly/flash.dm
index 81f2c75660..8feff99df4 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -30,7 +30,7 @@
holder.update_icon()
/obj/item/device/assembly/flash/proc/clown_check(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
flash_carbon(user, user, 15, 0)
return 0
return 1
diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm
index e8ee742e56..d1b88e68e1 100644
--- a/code/modules/assembly/mousetrap.dm
+++ b/code/modules/assembly/mousetrap.dm
@@ -1,142 +1,142 @@
-/obj/item/device/assembly/mousetrap
- name = "mousetrap"
- desc = "A handy little spring-loaded trap for catching pesty rodents."
- icon_state = "mousetrap"
- materials = list(MAT_METAL=100)
- attachable = 1
- var/armed = 0
-
-
-/obj/item/device/assembly/mousetrap/examine(mob/user)
- ..()
- if(armed)
- to_chat(user, "The mousetrap is armed!")
- else
- to_chat(user, "The mousetrap is not armed.")
-
-/obj/item/device/assembly/mousetrap/activate()
- if(..())
- armed = !armed
- if(!armed)
- if(ishuman(usr))
- var/mob/living/carbon/human/user = usr
- if((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY && prob(50))
- to_chat(user, "Your hand slips, setting off the trigger!")
- pulse(0)
- update_icon()
- if(usr)
- playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
-
-/obj/item/device/assembly/mousetrap/describe()
- return "The pressure switch is [armed?"primed":"safe"]."
-
-/obj/item/device/assembly/mousetrap/update_icon()
- if(armed)
- icon_state = "mousetraparmed"
- else
- icon_state = "mousetrap"
- if(holder)
- holder.update_icon()
-
-/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
- if(!armed)
- return
- var/obj/item/bodypart/affecting = null
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- if(PIERCEIMMUNE in H.dna.species.species_traits)
- playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
- armed = 0
- update_icon()
- pulse(0)
- return 0
- switch(type)
- if("feet")
- if(!H.shoes)
- affecting = H.get_bodypart(pick("l_leg", "r_leg"))
- H.Knockdown(60)
- if("l_hand", "r_hand")
- if(!H.gloves)
- affecting = H.get_bodypart(type)
- H.Stun(60)
- if(affecting)
- if(affecting.receive_damage(1, 0))
- H.update_damage_overlays()
- else if(ismouse(target))
- var/mob/living/simple_animal/mouse/M = target
- visible_message("SPLAT!")
- M.splat()
- playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
- armed = 0
- update_icon()
- pulse(0)
-
-
-/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
- if(!armed)
- to_chat(user, "You arm [src].")
- else
- if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
- var/which_hand = "l_hand"
- if(!(user.active_hand_index % 2))
- which_hand = "r_hand"
- triggered(user, which_hand)
- user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- return
- to_chat(user, "You disarm [src].")
- armed = !armed
- update_icon()
- playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
-
-
-/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
- if(armed)
- if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
- var/which_hand = "l_hand"
- if(!(user.active_hand_index % 2))
- which_hand = "r_hand"
- triggered(user, which_hand)
- user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- return
- ..()
-
-
-/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
- if(armed)
- if(ismob(AM))
- var/mob/MM = AM
- if(!(MM.movement_type & FLYING))
- if(ishuman(AM))
- var/mob/living/carbon/H = AM
- if(H.m_intent == MOVE_INTENT_RUN)
- triggered(H)
- H.visible_message("[H] accidentally steps on [src].", \
- "You accidentally step on [src]")
- else if(ismouse(MM))
- triggered(MM)
- else if(AM.density) // For mousetrap grenades, set off by anything heavy
- triggered(AM)
- ..()
-
-
-/obj/item/device/assembly/mousetrap/on_found(mob/finder)
- if(armed)
- finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
- return 1 //end the search!
- return 0
-
-
-/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
- if(!armed)
- return ..()
- visible_message("[src] is triggered by [A].")
- triggered(null)
-
-
-/obj/item/device/assembly/mousetrap/armed
- icon_state = "mousetraparmed"
- armed = TRUE
+/obj/item/device/assembly/mousetrap
+ name = "mousetrap"
+ desc = "A handy little spring-loaded trap for catching pesty rodents."
+ icon_state = "mousetrap"
+ materials = list(MAT_METAL=100)
+ attachable = 1
+ var/armed = 0
+
+
+/obj/item/device/assembly/mousetrap/examine(mob/user)
+ ..()
+ if(armed)
+ to_chat(user, "The mousetrap is armed!")
+ else
+ to_chat(user, "The mousetrap is not armed.")
+
+/obj/item/device/assembly/mousetrap/activate()
+ if(..())
+ armed = !armed
+ if(!armed)
+ if(ishuman(usr))
+ var/mob/living/carbon/human/user = usr
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ to_chat(user, "Your hand slips, setting off the trigger!")
+ pulse(0)
+ update_icon()
+ if(usr)
+ playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
+
+/obj/item/device/assembly/mousetrap/describe()
+ return "The pressure switch is [armed?"primed":"safe"]."
+
+/obj/item/device/assembly/mousetrap/update_icon()
+ if(armed)
+ icon_state = "mousetraparmed"
+ else
+ icon_state = "mousetrap"
+ if(holder)
+ holder.update_icon()
+
+/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
+ if(!armed)
+ return
+ var/obj/item/bodypart/affecting = null
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(PIERCEIMMUNE in H.dna.species.species_traits)
+ playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
+ armed = 0
+ update_icon()
+ pulse(0)
+ return 0
+ switch(type)
+ if("feet")
+ if(!H.shoes)
+ affecting = H.get_bodypart(pick("l_leg", "r_leg"))
+ H.Knockdown(60)
+ if("l_hand", "r_hand")
+ if(!H.gloves)
+ affecting = H.get_bodypart(type)
+ H.Stun(60)
+ if(affecting)
+ if(affecting.receive_damage(1, 0))
+ H.update_damage_overlays()
+ else if(ismouse(target))
+ var/mob/living/simple_animal/mouse/M = target
+ visible_message("SPLAT!")
+ M.splat()
+ playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
+ armed = 0
+ update_icon()
+ pulse(0)
+
+
+/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
+ if(!armed)
+ to_chat(user, "You arm [src].")
+ else
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ triggered(user, which_hand)
+ user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ return
+ to_chat(user, "You disarm [src].")
+ armed = !armed
+ update_icon()
+ playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
+
+
+/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
+ if(armed)
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ triggered(user, which_hand)
+ user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ return
+ ..()
+
+
+/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
+ if(armed)
+ if(ismob(AM))
+ var/mob/MM = AM
+ if(!(MM.movement_type & FLYING))
+ if(ishuman(AM))
+ var/mob/living/carbon/H = AM
+ if(H.m_intent == MOVE_INTENT_RUN)
+ triggered(H)
+ H.visible_message("[H] accidentally steps on [src].", \
+ "You accidentally step on [src]")
+ else if(ismouse(MM))
+ triggered(MM)
+ else if(AM.density) // For mousetrap grenades, set off by anything heavy
+ triggered(AM)
+ ..()
+
+
+/obj/item/device/assembly/mousetrap/on_found(mob/finder)
+ if(armed)
+ finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
+ return 1 //end the search!
+ return 0
+
+
+/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
+ if(!armed)
+ return ..()
+ visible_message("[src] is triggered by [A].")
+ triggered(null)
+
+
+/obj/item/device/assembly/mousetrap/armed
+ icon_state = "mousetraparmed"
+ armed = 1
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index 64d77a27dc..dd6e4ffe71 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -37,14 +37,24 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
reaction_results = new
//listmos procs
+//use the macros in performance intensive areas. for their definitions, refer to code/__DEFINES/atmospherics.dm
-// The following procs used to live here: thermal_energy(), assert_gas() and add_gas(). They have been moved into defines in code/__DEFINES/atmospherics.dm
+ //assert_gas(gas_id) - used to guarantee that the gas list for this id exists in gas_mixture.gases.
+ //Must be used before adding to a gas. May be used before reading from a gas.
+/datum/gas_mixture/proc/assert_gas(gas_id)
+ ASSERT_GAS(gas_id, src)
//assert_gases(args) - shorthand for calling ASSERT_GAS() once for each gas type.
/datum/gas_mixture/proc/assert_gases()
for(var/id in args)
ASSERT_GAS(id, src)
+ //add_gas(gas_id) - similar to assert_gas(), but does not check for an existing
+ //gas list for this id. This can clobber existing gases.
+ //Used instead of assert_gas() when you know the gas does not exist. Faster than assert_gas().
+/datum/gas_mixture/proc/add_gas(gas_id)
+ ADD_GAS(gas_id, gases)
+
//add_gases(args) - shorthand for calling add_gas() once for each gas_type.
/datum/gas_mixture/proc/add_gases()
var/cached_gases = gases
@@ -101,6 +111,9 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
/datum/gas_mixture/proc/return_volume() //liters
return max(0, volume)
+/datum/gas_mixture/proc/thermal_energy() //joules
+ return THERMAL_ENERGY(src) //see code/__DEFINES/atmospherics.dm; use the define in performance critical areas
+
/datum/gas_mixture/proc/archive()
//Update archived versions of variables
//Returns: 1 in all cases
@@ -399,7 +412,7 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
return ""
/datum/gas_mixture/react(turf/open/dump_location)
- . = 0
+ . = NO_REACTION
reaction_results = new
@@ -423,6 +436,22 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
continue reaction_loop
//at this point, all minimum requirements for the reaction are satisfied.
+ /* currently no reactions have maximum requirements, so we can leave the checks commented out for a slight performance boost
+ PLEASE DO NOT REMOVE THIS CODE. the commenting is here only for a performance increase.
+ enabling these checks should be as easy as possible and the fact that they are disabled should be as clear as possible
+
+ var/list/max_reqs = reaction.max_requirements.Copy()
+ if((max_reqs["TEMP"] && temp > max_reqs["TEMP"]) \
+ || (max_reqs["ENER"] && ener > max_reqs["ENER"]))
+ continue
+ max_reqs -= "TEMP"
+ max_reqs -= "ENER"
+ for(var/id in max_reqs)
+ if(cached_gases[id] && cached_gases[id][MOLES] > max_reqs[id])
+ continue reaction_loop
+ //at this point, all requirements for the reaction are satisfied. we can now react()
+ */
+
. |= reaction.react(src, dump_location)
if (. & STOP_REACTIONS)
break
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 5a88c6837e..aabbe089fb 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -184,7 +184,7 @@
//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting.
/datum/gas_reaction/fusion
- exclude = FALSE
+ exclude = TRUE
priority = 2
name = "Plasmic Fusion"
id = "fusion"
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
index f8204947f1..6f72724e1e 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
@@ -185,13 +185,13 @@ Acts like a normal vent, but has an input AND output.
pump_direction = 1
if("set_input_pressure" in signal.data)
- input_pressure_min = Clamp(text2num(signal.data["set_input_pressure"]),0,ONE_ATMOSPHERE*50)
+ input_pressure_min = CLAMP(text2num(signal.data["set_input_pressure"]),0,ONE_ATMOSPHERE*50)
if("set_output_pressure" in signal.data)
- output_pressure_max = Clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
+ output_pressure_max = CLAMP(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
if("set_external_pressure" in signal.data)
- external_pressure_bound = Clamp(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
+ external_pressure_bound = CLAMP(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
if("status" in signal.data)
spawn(2)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
index 86c5375d07..ef4e487efd 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
@@ -127,7 +127,7 @@ Passive gate is similar to the regular pump except:
pressure = text2num(pressure)
. = TRUE
if(.)
- target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
+ target_pressure = CLAMP(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
@@ -149,7 +149,7 @@ Passive gate is similar to the regular pump except:
on = !on
if("set_output_pressure" in signal.data)
- target_pressure = Clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
+ target_pressure = CLAMP(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
if(on != old_on)
investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
index 97bba0e534..9d581fcb78 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
@@ -133,9 +133,8 @@ Thus, the two variables affect pump operation are set in New():
pressure = text2num(pressure)
. = TRUE
if(.)
- target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
- investigate_log("Pump, [src.name], was set to [target_pressure] kPa by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
- message_admins("Pump, [src.name], was set to [target_pressure] kPa by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
+ target_pressure = CLAMP(pressure, 0, MAX_OUTPUT_PRESSURE)
+ investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
/obj/machinery/atmospherics/components/binary/pump/atmosinit()
@@ -156,7 +155,7 @@ Thus, the two variables affect pump operation are set in New():
on = !on
if("set_output_pressure" in signal.data)
- target_pressure = Clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
+ target_pressure = CLAMP(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
if(on != old_on)
investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
index b154c0d3e4..2803d1bf09 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
@@ -133,9 +133,8 @@ Thus, the two variables affect pump operation are set in New():
rate = text2num(rate)
. = TRUE
if(.)
- transfer_rate = Clamp(rate, 0, MAX_TRANSFER_RATE)
- investigate_log("Volume Pump, [src.name], was set to [transfer_rate] L/s by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
- message_admins("Volume Pump, [src.name], was set to [transfer_rate] L/s by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
+ transfer_rate = CLAMP(rate, 0, MAX_TRANSFER_RATE)
+ investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
/obj/machinery/atmospherics/components/binary/volume_pump/receive_signal(datum/signal/signal)
@@ -152,7 +151,7 @@ Thus, the two variables affect pump operation are set in New():
if("set_transfer_rate" in signal.data)
var/datum/gas_mixture/air1 = AIR1
- transfer_rate = Clamp(text2num(signal.data["set_transfer_rate"]),0,air1.volume)
+ transfer_rate = CLAMP(text2num(signal.data["set_transfer_rate"]),0,air1.volume)
if(on != old_on)
investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
index 4baeb3dd3e..a1d6dc8c7e 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
@@ -103,7 +103,7 @@
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.temperature
- ASSERT_GAS(filter_type, filtered_out)
+ filtered_out.add_gas(filter_type)
filtered_out.gases[filter_type][MOLES] = removed.gases[filter_type][MOLES]
removed.gases[filter_type][MOLES] = 0
@@ -162,7 +162,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
+ target_pressure = CLAMP(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
if("filter")
filter_type = null
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
index b706cd3cd9..b15df59662 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
@@ -152,7 +152,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
+ target_pressure = CLAMP(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
if("node1")
var/value = text2num(params["concentration"])
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
index 37bfb5d952..64e6e56504 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
@@ -131,7 +131,7 @@
if("set_volume_rate" in signal.data)
var/number = text2num(signal.data["set_volume_rate"])
var/datum/gas_mixture/air_contents = AIR1
- volume_rate = Clamp(number, 0, air_contents.volume)
+ volume_rate = CLAMP(number, 0, air_contents.volume)
if("status" in signal.data)
spawn(2)
@@ -180,7 +180,7 @@
rate = text2num(rate)
. = TRUE
if(.)
- volume_rate = Clamp(rate, 0, MAX_TRANSFER_RATE)
+ volume_rate = CLAMP(rate, 0, MAX_TRANSFER_RATE)
investigate_log("was set to [volume_rate] L/s by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
broadcast_status()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
index ec1fcdfc52..4e9df101a6 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
@@ -17,7 +17,7 @@
air_contents.volume = volume
air_contents.temperature = T20C
if(gas_type)
- ASSERT_GAS(gas_type, air_contents)
+ air_contents.assert_gas(gas_type)
air_contents.gases[gas_type][MOLES] = AIR_CONTENTS
name = "[name] ([air_contents.gases[gas_type][GAS_META][META_GAS_NAME]])"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index fa336c7a34..8d34d5adfa 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -153,7 +153,7 @@
target = text2num(target)
. = TRUE
if(.)
- target_temperature = Clamp(target, min_temperature, max_temperature)
+ target_temperature = CLAMP(target, min_temperature, max_temperature)
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
index a05a13217d..2c9a308ec9 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -244,10 +244,10 @@
pump_direction = text2num(signal.data["direction"])
if("set_internal_pressure" in signal.data)
- internal_pressure_bound = Clamp(text2num(signal.data["set_internal_pressure"]),0,ONE_ATMOSPHERE*50)
+ internal_pressure_bound = CLAMP(text2num(signal.data["set_internal_pressure"]),0,ONE_ATMOSPHERE*50)
if("set_external_pressure" in signal.data)
- external_pressure_bound = Clamp(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
+ external_pressure_bound = CLAMP(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
if("reset_external_pressure" in signal.data)
external_pressure_bound = ONE_ATMOSPHERE
@@ -256,10 +256,10 @@
internal_pressure_bound = 0
if("adjust_internal_pressure" in signal.data)
- internal_pressure_bound = Clamp(internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),0,ONE_ATMOSPHERE*50)
+ internal_pressure_bound = CLAMP(internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),0,ONE_ATMOSPHERE*50)
if("adjust_external_pressure" in signal.data)
- external_pressure_bound = Clamp(external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),0,ONE_ATMOSPHERE*50)
+ external_pressure_bound = CLAMP(external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),0,ONE_ATMOSPHERE*50)
if("init" in signal.data)
name = signal.data["init"]
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index b3ade6f0fb..8fffd70840 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -179,7 +179,7 @@
filtered_out.temperature = removed.temperature
for(var/gas in filter_types & removed_gases)
- ADD_GAS(gas, filtered_gases)
+ filtered_out.add_gas(gas)
filtered_gases[gas][MOLES] = removed_gases[gas][MOLES]
removed_gases[gas][MOLES] = 0
diff --git a/code/modules/atmospherics/machinery/other/miner.dm b/code/modules/atmospherics/machinery/other/miner.dm
index cb28f17802..f63065b431 100644
--- a/code/modules/atmospherics/machinery/other/miner.dm
+++ b/code/modules/atmospherics/machinery/other/miner.dm
@@ -132,7 +132,7 @@
if(!isopenturf(O))
return FALSE
var/datum/gas_mixture/merger = new
- ASSERT_GAS(spawn_id, merger)
+ merger.assert_gas(spawn_id)
merger.gases[spawn_id][MOLES] = (spawn_mol)
merger.temperature = spawn_temp
O.assume_air(merger)
diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
index fee00baf50..d2f85c7667 100644
--- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm
+++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
@@ -121,7 +121,7 @@
if(initialize_directions & dir)
return ..()
if((NORTH|EAST) & dir)
- user.ventcrawl_layer = Clamp(user.ventcrawl_layer + 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
+ user.ventcrawl_layer = CLAMP(user.ventcrawl_layer + 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
if((SOUTH|WEST) & dir)
- user.ventcrawl_layer = Clamp(user.ventcrawl_layer - 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
+ user.ventcrawl_layer = CLAMP(user.ventcrawl_layer - 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
to_chat(user, "You align yourself with the [user.ventcrawl_layer]\th output.")
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 585b6e896a..7b6351e939 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -196,7 +196,7 @@
/obj/machinery/portable_atmospherics/canister/proc/create_gas()
if(gas_type)
- ADD_GAS(gas_type, air_contents.gases)
+ air_contents.add_gas(gas_type)
if(starter_temp)
air_contents.temperature = starter_temp
air_contents.gases[gas_type][MOLES] = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
@@ -411,7 +411,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- release_pressure = Clamp(round(pressure), can_min_release_pressure, can_max_release_pressure)
+ release_pressure = CLAMP(round(pressure), can_min_release_pressure, can_max_release_pressure)
investigate_log("was set to [release_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
if("valve")
var/logmsg
@@ -455,7 +455,7 @@
var/N = text2num(user_input)
if(!N)
return
- timer_set = Clamp(N,minimum_timer_set,maximum_timer_set)
+ timer_set = CLAMP(N,minimum_timer_set,maximum_timer_set)
log_admin("[key_name(usr)] has activated a prototype valve timer")
. = TRUE
if("toggle_timer")
diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm
index db153d60a4..36dd30731e 100644
--- a/code/modules/atmospherics/machinery/portable/pump.dm
+++ b/code/modules/atmospherics/machinery/portable/pump.dm
@@ -131,7 +131,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- pump.target_pressure = Clamp(round(pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
+ pump.target_pressure = CLAMP(round(pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
if("eject")
if(holding)
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index 3ba7e0a110..4bb7b02288 100644
--- a/code/modules/atmospherics/machinery/portable/scrubber.dm
+++ b/code/modules/atmospherics/machinery/portable/scrubber.dm
@@ -45,7 +45,7 @@
filtered.temperature = filtering.temperature
for(var/gas in filtering.gases & scrubbing)
- ADD_GAS(gas, filtered.gases)
+ filtered.add_gas(gas)
filtered.gases[gas][MOLES] = filtering.gases[gas][MOLES] // Shuffle the "bad" gasses to the filtered mixture.
filtering.gases[gas][MOLES] = 0
filtering.garbage_collect() // Now that the gasses are set to 0, clean up the mixture.
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/cargo/exports.dm b/code/modules/cargo/exports.dm
index 92b953e7b2..b4c0aa350d 100644
--- a/code/modules/cargo/exports.dm
+++ b/code/modules/cargo/exports.dm
@@ -86,7 +86,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
/datum/export/process()
..()
- cost *= GLOB.E**(k_elasticity * (1/30))
+ cost *= NUM_E**(k_elasticity * (1/30))
if(cost > init_cost)
cost = init_cost
@@ -94,7 +94,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
/datum/export/proc/get_cost(obj/O, contr = 0, emag = 0)
var/amount = get_amount(O, contr, emag)
if(k_elasticity!=0)
- return round((cost/k_elasticity) * (1 - GLOB.E**(-1 * k_elasticity * amount))) //anti-derivative of the marginal cost function
+ return round((cost/k_elasticity) * (1 - NUM_E**(-1 * k_elasticity * amount))) //anti-derivative of the marginal cost function
else
return round(cost * amount) //alternative form derived from L'Hopital to avoid division by 0
@@ -131,7 +131,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
else
total_amount += amount
- cost *= GLOB.E**(-1*k_elasticity*amount) //marginal cost modifier
+ cost *= NUM_E**(-1*k_elasticity*amount) //marginal cost modifier
SSblackbox.record_feedback("nested tally", "export_sold_cost", 1, list("[O.type]", "[the_cost]"))
// Total printout for the cargo console.
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 3704494050..28875e3dc2 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -372,3 +372,39 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/meter = icon('icons/obj/atmospherics/pipes/simple.dmi', "meterX", SOUTH, frame, movement_states)
if(meter)
register_asset(sanitize_filename("[prefix].south.meterX.png"), fcopy_rsc(meter))
+
+// Representative icons for each research design
+/datum/asset/simple/research_designs/register()
+ for (var/path in subtypesof(/datum/design))
+ var/datum/design/D = path
+
+ // construct the icon and slap it into the resource cache
+ var/atom/item = initial(D.build_path)
+ if (!ispath(item, /atom))
+ // biogenerator outputs to beakers by default
+ if (initial(D.build_type) & BIOGENERATOR)
+ item = /obj/item/reagent_containers/glass/beaker/large
+ else
+ continue // 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)
+
+ assets["design_[initial(D.id)].png"] = I
+ return ..()
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 cb1712dff5..4c5d8e7a4c 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -152,7 +152,7 @@ GLOBAL_LIST(external_rsc_urls)
#if (PRELOAD_RSC == 0)
var/static/next_external_rsc = 0
if(external_rsc_urls && external_rsc_urls.len)
- next_external_rsc = Wrap(next_external_rsc+1, 1, external_rsc_urls.len+1)
+ next_external_rsc = WRAP(next_external_rsc+1, 1, external_rsc_urls.len+1)
preload_rsc = external_rsc_urls[next_external_rsc]
#endif
@@ -199,9 +199,7 @@ GLOBAL_LIST(external_rsc_urls)
prefs.parent = src
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
- if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps)
- vars["fps"] = prefs.clientfps
- sethotkeys(1) //set hoykeys from preferences (from_pref = 1)
+ fps = prefs.clientfps
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[byond_version]")
var/alert_mob_dupe_login = FALSE
@@ -227,6 +225,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
@@ -673,6 +678,13 @@ GLOBAL_LIST(external_rsc_urls)
return TRUE
. = ..()
+/client/proc/rescale_view(change, min, max)
+ var/viewscale = getviewsize(view)
+ var/x = viewscale[1]
+ var/y = viewscale[2]
+ x = CLAMP(x+change, min, max)
+ y = CLAMP(y+change, min,max)
+ change_view("[x]x[y]")
/client/proc/change_view(new_size)
if (isnull(new_size))
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/client/preferences.dm b/code/modules/client/preferences.dm
index 175a23c91e..730b98ede5 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1282,16 +1282,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
preferred_map = maplist[pickedmap]
if ("clientfps")
- var/version_message
- if (user.client && user.client.byond_version < 511)
- version_message = "\nYou need to be using byond version 511 or later to take advantage of this feature, your version of [user.client.byond_version] is too low"
- if (world.byond_version < 511)
- version_message += "\nThis server does not currently support client side fps. You can set now for when it does."
- var/desiredfps = input(user, "Choose your desired fps.[version_message]\n(0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
+ var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
if (!isnull(desiredfps))
clientfps = desiredfps
- if (world.byond_version >= 511 && user.client && user.client.byond_version >= 511)
- user.client.vars["fps"] = clientfps
+ parent.fps = desiredfps
if("ui")
var/pickedui = input(user, "Choose your UI style.", "Character Preference") as null|anything in list("Midnight", "Plasmafire", "Retro", "Slimecore", "Operative", "Clockwork")
if(pickedui)
@@ -1596,12 +1590,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
toggles ^= MIDROUND_ANTAG
if("parallaxup")
- parallax = Wrap(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
if (parent && parent.mob && parent.mob.hud_used)
parent.mob.hud_used.update_parallax_pref(parent.mob)
if("parallaxdown")
- parallax = Wrap(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
if (parent && parent.mob && parent.mob.hud_used)
parent.mob.hud_used.update_parallax_pref(parent.mob)
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 29990a299b..ddb1cf5545 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -41,7 +41,7 @@
/obj/item/clothing/glasses/proc/thermal_overload()
if(ishuman(src.loc))
var/mob/living/carbon/human/H = src.loc
- if(!(H.disabilities & BLIND))
+ if(!(H.has_disability(BLIND)))
if(H.glasses == src)
to_chat(H, "[src] overloads and blinds you!")
H.flash_act(visual = 1)
diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm
index 7e4b0bad89..681ba3e789 100644
--- a/code/modules/clothing/spacesuits/flightsuit.dm
+++ b/code/modules/clothing/spacesuits/flightsuit.dm
@@ -164,7 +164,7 @@
assembled = TRUE
boost_chargerate *= cap
boost_drain -= manip
- powersetting_high = Clamp(laser, 0, 3)
+ powersetting_high = CLAMP(laser, 0, 3)
emp_disable_threshold = bin*1.25
stabilizer_decay_amount = scan*3.5
airbrake_decay_amount = manip*8
@@ -194,15 +194,15 @@
/obj/item/device/flightpack/proc/adjust_momentum(amountx, amounty, reduce_amount_total = 0)
if(reduce_amount_total != 0)
if(momentum_x > 0)
- momentum_x = Clamp(momentum_x - reduce_amount_total, 0, momentum_max)
+ momentum_x = CLAMP(momentum_x - reduce_amount_total, 0, momentum_max)
else if(momentum_x < 0)
- momentum_x = Clamp(momentum_x + reduce_amount_total, -momentum_max, 0)
+ momentum_x = CLAMP(momentum_x + reduce_amount_total, -momentum_max, 0)
if(momentum_y > 0)
- momentum_y = Clamp(momentum_y - reduce_amount_total, 0, momentum_max)
+ momentum_y = CLAMP(momentum_y - reduce_amount_total, 0, momentum_max)
else if(momentum_y < 0)
- momentum_y = Clamp(momentum_y + reduce_amount_total, -momentum_max, 0)
- momentum_x = Clamp(momentum_x + amountx, -momentum_max, momentum_max)
- momentum_y = Clamp(momentum_y + amounty, -momentum_max, momentum_max)
+ momentum_y = CLAMP(momentum_y + reduce_amount_total, -momentum_max, 0)
+ momentum_x = CLAMP(momentum_x + amountx, -momentum_max, momentum_max)
+ momentum_y = CLAMP(momentum_y + amounty, -momentum_max, momentum_max)
calculate_momentum_speed()
/obj/item/device/flightpack/intercept_user_move(dir, mob, newLoc, oldLoc)
@@ -314,7 +314,7 @@
/obj/item/device/flightpack/proc/handle_damage()
if(emp_damage)
- emp_damage = Clamp(emp_damage-emp_heal_amount, 0, emp_disable_threshold * 10)
+ emp_damage = CLAMP(emp_damage-emp_heal_amount, 0, emp_disable_threshold * 10)
if(emp_damage >= emp_disable_threshold)
emp_disabled = TRUE
if(emp_disabled && (emp_damage <= 0.5))
@@ -347,11 +347,11 @@
/obj/item/device/flightpack/proc/handle_boost()
if(boost)
- boost_charge = Clamp(boost_charge-boost_drain, 0, boost_maxcharge)
+ boost_charge = CLAMP(boost_charge-boost_drain, 0, boost_maxcharge)
if(boost_charge < 1)
deactivate_booster()
if(boost_charge < boost_maxcharge)
- boost_charge = Clamp(boost_charge+boost_chargerate, 0, boost_maxcharge)
+ boost_charge = CLAMP(boost_charge+boost_chargerate, 0, boost_maxcharge)
/obj/item/device/flightpack/proc/cycle_power()
powersetting < powersetting_high? (powersetting++) : (powersetting = 1)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 8e2251980d..58eac96f78 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -654,7 +654,7 @@
/obj/item/clothing/suit/space/hardsuit/shielded/process()
if(world.time > recharge_cooldown && current_charges < max_charges)
- current_charges = Clamp((current_charges + recharge_rate), 0, max_charges)
+ current_charges = CLAMP((current_charges + recharge_rate), 0, max_charges)
playsound(loc, 'sound/magic/charge.ogg', 50, 1)
if(current_charges == max_charges)
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index f50f6eaf6a..7c7599af3d 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -1,48 +1,49 @@
-/obj/item/clothing/suit/toggle/labcoat
- name = "labcoat"
- desc = "A suit that protects against minor chemical spills."
- icon_state = "labcoat"
- item_state = "labcoat"
- blood_overlay_type = "coat"
- body_parts_covered = CHEST|ARMS
- allowed = list(/obj/item/device/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/device/healthanalyzer, /obj/item/device/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/soap, /obj/item/device/sensor_device, /obj/item/tank/internals/emergency_oxygen)
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0, fire = 50, acid = 50)
- togglename = "buttons"
-
-/obj/item/clothing/suit/toggle/labcoat/cmo
- name = "chief medical officer's labcoat"
- desc = "Bluer than the standard model."
- icon_state = "labcoat_cmo"
- item_state = "labcoat_cmo"
-
-/obj/item/clothing/suit/toggle/labcoat/emt
- name = "EMT's jacket"
- desc = "A dark blue jacket with reflective strips for emergency medical technicians."
- icon_state = "labcoat_emt"
- item_state = "labcoat_cmo"
-
-/obj/item/clothing/suit/toggle/labcoat/mad
- name = "\improper The Mad's labcoat"
- desc = "It makes you look capable of konking someone on the noggin and shooting them into space."
- icon_state = "labgreen"
- item_state = "labgreen"
-
-/obj/item/clothing/suit/toggle/labcoat/genetics
- name = "geneticist labcoat"
- desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
- icon_state = "labcoat_gen"
-
-/obj/item/clothing/suit/toggle/labcoat/chemist
- name = "chemist labcoat"
- desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder."
- icon_state = "labcoat_chem"
-
-/obj/item/clothing/suit/toggle/labcoat/virologist
- name = "virologist labcoat"
- desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
- icon_state = "labcoat_vir"
-
-/obj/item/clothing/suit/toggle/labcoat/science
- name = "scientist labcoat"
- desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
- icon_state = "labcoat_tox"
\ No newline at end of file
+/obj/item/clothing/suit/toggle/labcoat
+ name = "labcoat"
+ desc = "A suit that protects against minor chemical spills."
+ icon_state = "labcoat"
+ item_state = "labcoat"
+ blood_overlay_type = "coat"
+ body_parts_covered = CHEST|ARMS
+ allowed = list(/obj/item/device/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/device/healthanalyzer, /obj/item/device/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/soap, /obj/item/device/sensor_device, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0, fire = 50, acid = 50)
+ togglename = "buttons"
+ species_exception = list(/datum/species/golem)
+
+/obj/item/clothing/suit/toggle/labcoat/cmo
+ name = "chief medical officer's labcoat"
+ desc = "Bluer than the standard model."
+ icon_state = "labcoat_cmo"
+ item_state = "labcoat_cmo"
+
+/obj/item/clothing/suit/toggle/labcoat/emt
+ name = "EMT's jacket"
+ desc = "A dark blue jacket with reflective strips for emergency medical technicians."
+ icon_state = "labcoat_emt"
+ item_state = "labcoat_cmo"
+
+/obj/item/clothing/suit/toggle/labcoat/mad
+ name = "\improper The Mad's labcoat"
+ desc = "It makes you look capable of konking someone on the noggin and shooting them into space."
+ icon_state = "labgreen"
+ item_state = "labgreen"
+
+/obj/item/clothing/suit/toggle/labcoat/genetics
+ name = "geneticist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
+ icon_state = "labcoat_gen"
+
+/obj/item/clothing/suit/toggle/labcoat/chemist
+ name = "chemist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder."
+ icon_state = "labcoat_chem"
+
+/obj/item/clothing/suit/toggle/labcoat/virologist
+ name = "virologist labcoat"
+ desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
+ icon_state = "labcoat_vir"
+
+/obj/item/clothing/suit/toggle/labcoat/science
+ name = "scientist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
+ icon_state = "labcoat_tox"
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/_event.dm b/code/modules/events/_event.dm
index a5b23623f2..471dad12d7 100644
--- a/code/modules/events/_event.dm
+++ b/code/modules/events/_event.dm
@@ -29,8 +29,8 @@
/datum/round_event_control/New()
if(config && !wizardevent) // Magic is unaffected by configs
- earliest_start = Ceiling(earliest_start * CONFIG_GET(number/events_min_time_mul))
- min_players = Ceiling(min_players * CONFIG_GET(number/events_min_players_mul))
+ earliest_start = CEILING(earliest_start * CONFIG_GET(number/events_min_time_mul), 1)
+ min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1)
/datum/round_event_control/wizard
wizardevent = 1
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index e898729f2d..c2f98be8d5 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -67,12 +67,12 @@
kill()
return
- if(IsMultiple(activeFor, 4))
+ if(ISMULTIPLE(activeFor, 4))
var/obj/machinery/vending/rebel = pick(vendingMachines)
vendingMachines.Remove(rebel)
infectedMachines.Add(rebel)
rebel.shut_up = 0
rebel.shoot_inventory = 1
- if(IsMultiple(activeFor, 8))
+ if(ISMULTIPLE(activeFor, 8))
originMachine.speak(pick(rampant_speeches))
\ No newline at end of file
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index eb7625e08c..5c28632c89 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -10,6 +10,8 @@
var/virus_type
+ var/max_severity = 3
+
/datum/round_event/disease_outbreak/announce(fake)
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak7.ogg')
@@ -17,8 +19,14 @@
/datum/round_event/disease_outbreak/setup()
announceWhen = rand(15, 30)
+
/datum/round_event/disease_outbreak/start()
- if(!virus_type)
+ var/advanced_virus = FALSE
+ max_severity = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes
+ if(prob(20 + (10 * max_severity)))
+ advanced_virus = TRUE
+
+ if(!virus_type && !advanced_virus)
virus_type = pick(/datum/disease/dnaspread, /datum/disease/advance/flu, /datum/disease/advance/cold, /datum/disease/brainrot, /datum/disease/magnitis)
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
@@ -41,16 +49,48 @@
continue
var/datum/disease/D
- if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
- if(!H.dna || (H.disabilities & BLIND)) //A blindness disease would be the worst.
- continue
- D = new virus_type()
- var/datum/disease/dnaspread/DS = D
- DS.strain_data["name"] = H.real_name
- DS.strain_data["UI"] = H.dna.uni_identity
- DS.strain_data["SE"] = H.dna.struc_enzymes
+ if(!advanced_virus)
+ if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
+ if(!H.dna || (H.has_disability(BLIND))) //A blindness disease would be the worst.
+ continue
+ D = new virus_type()
+ var/datum/disease/dnaspread/DS = D
+ DS.strain_data["name"] = H.real_name
+ DS.strain_data["UI"] = H.dna.uni_identity
+ DS.strain_data["SE"] = H.dna.struc_enzymes
+ else
+ D = new virus_type()
else
- D = new virus_type()
+ D = make_virus(max_severity, max_severity)
D.carrier = TRUE
H.AddDisease(D)
- break
\ No newline at end of file
+
+ if(advanced_virus)
+ var/datum/disease/advance/A = D
+ var/list/name_symptoms = list() //for feedback
+ for(var/datum/symptom/S in A.symptoms)
+ name_symptoms += S.name
+ message_admins("An event has triggered a random advanced virus outbreak on [key_name_admin(H)]! It has these symptoms: [english_list(name_symptoms)]")
+ log_game("An event has triggered a random advanced virus outbreak on [key_name(H)]! It has these symptoms: [english_list(name_symptoms)]")
+ break
+
+/datum/round_event/disease_outbreak/proc/make_virus(max_symptoms, max_level)
+ if(max_symptoms > SYMPTOM_LIMIT)
+ max_symptoms = SYMPTOM_LIMIT
+ var/datum/disease/advance/A = new(FALSE, null)
+ A.symptoms = list()
+ var/list/datum/symptom/possible_symptoms = list()
+ for(var/symptom in subtypesof(/datum/symptom))
+ var/datum/symptom/S = symptom
+ if(initial(S.level) > max_level)
+ continue
+ if(initial(S.level) <= 0) //unobtainable symptoms
+ continue
+ possible_symptoms += S
+ for(var/i in 1 to max_symptoms)
+ var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
+ if(chosen_symptom)
+ var/datum/symptom/S = new chosen_symptom
+ A.symptoms += S
+ A.Refresh() //just in case someone already made and named the same disease
+ return A
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/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index 35eb02f082..798bcf82dd 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -49,7 +49,7 @@
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
- if(IsMultiple(activeFor, 3))
+ if(ISMULTIPLE(activeFor, 3))
spawn_meteors(5, wave_type) //meteor list types defined in gamemode/meteor/meteors.dm
/datum/round_event_control/meteor_wave/threatening
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/operative.dm b/code/modules/events/operative.dm
index 47130ff924..894ad7e995 100644
--- a/code/modules/events/operative.dm
+++ b/code/modules/events/operative.dm
@@ -27,31 +27,13 @@
A.copy_to(operative)
operative.dna.update_dna_identity()
- operative.equipOutfit(/datum/outfit/syndicate/full)
-
var/datum/mind/Mind = new /datum/mind(selected.key)
Mind.assigned_role = "Lone Operative"
Mind.special_role = "Lone Operative"
- SSticker.mode.traitors |= Mind
Mind.active = 1
- var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.machines
- if(nuke)
- var/nuke_code
- if(!nuke.r_code || nuke.r_code == "ADMIN")
- nuke_code = random_nukecode()
- nuke.r_code = nuke_code
- else
- nuke_code = nuke.r_code
-
- Mind.store_memory("Station Self-Destruct Device Code: [nuke_code]", 0, 0)
- to_chat(Mind.current, "The nuclear authorization code is: [nuke_code]")
-
- var/datum/objective/nuclear/O = new()
- O.owner = Mind
- Mind.objectives += O
-
Mind.transfer_to(operative)
+ Mind.add_antag_datum(/datum/antagonist/nukeop/lone)
message_admins("[key_name_admin(operative)] has been made into lone operative by an event.")
log_game("[key_name(operative)] was spawned as a lone operative by an event.")
diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm
index 7e17124d59..55d9e69f71 100644
--- a/code/modules/events/portal_storm.dm
+++ b/code/modules/events/portal_storm.dm
@@ -64,7 +64,7 @@
T = safepick(get_area_turfs(pick(station_areas)))
hostiles_spawn += T
- next_boss_spawn = startWhen + Ceiling(2 * number_of_hostiles / number_of_bosses)
+ next_boss_spawn = startWhen + CEILING(2 * number_of_hostiles / number_of_bosses, 1)
/datum/round_event/portal_storm/announce(fake)
set waitfor = 0
@@ -117,14 +117,14 @@
/datum/round_event/portal_storm/proc/spawn_hostile()
if(!hostile_types || !hostile_types.len)
return 0
- return IsMultiple(activeFor, 2)
+ return ISMULTIPLE(activeFor, 2)
/datum/round_event/portal_storm/proc/spawn_boss()
if(!boss_types || !boss_types.len)
return 0
if(activeFor == next_boss_spawn)
- next_boss_spawn += Ceiling(number_of_hostiles / number_of_bosses)
+ next_boss_spawn += CEILING(number_of_hostiles / number_of_bosses, 1)
return 1
/datum/round_event/portal_storm/proc/time_to_end()
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/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 194edd77b1..92dc109bbc 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -80,6 +80,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
/obj/effect/hallucination
invisibility = INVISIBILITY_OBSERVER
+ anchored = TRUE
var/mob/living/carbon/target = null
/obj/effect/hallucination/simple
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/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm
index 977bd60da1..1ec5bb3499 100644
--- a/code/modules/food_and_drinks/food/snacks_pie.dm
+++ b/code/modules/food_and_drinks/food/snacks_pie.dm
@@ -27,6 +27,7 @@
list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2)
tastes = list("pie" = 1)
foodtype = GRAIN | DAIRY | SUGAR
+ var/stunning = TRUE
/obj/item/reagent_containers/food/snacks/pie/cream/throw_impact(atom/hit_atom)
. = ..()
@@ -46,15 +47,18 @@
creamoverlay.icon_state = "creampie_lizard"
else
creamoverlay.icon_state = "creampie_human"
- H.Knockdown(20) //splat!
+ if(stunning)
+ H.Knockdown(20) //splat!
H.adjust_blurriness(1)
H.visible_message("[H] is creamed by [src]!", "You've been creamed by [src]!")
playsound(H, "desceration", 50, TRUE)
- if (!H.creamed) // one layer at a time
+ if(!H.creamed) // one layer at a time
H.add_overlay(creamoverlay)
H.creamed = TRUE
qdel(src)
+/obj/item/reagent_containers/food/snacks/pie/cream/nostun
+ stunning = FALSE
/obj/item/reagent_containers/food/snacks/pie/berryclafoutis
name = "berry clafoutis"
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 8573a84c9b..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
. = ..()
@@ -123,7 +123,7 @@
break
if(href_list["portion"])
- portion = Clamp(input("How much drink do you want to dispense per glass?") as num, 0, 50)
+ portion = CLAMP(input("How much drink do you want to dispense per glass?") as num, 0, 50)
if(href_list["pour"] || href_list["m_pour"])
if(glasses-- <= 0)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index 372c085adb..99a3de90e1 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -1,4 +1,3 @@
-
/obj/machinery/gibber
name = "gibber"
desc = "The name isn't descriptive enough?"
@@ -12,10 +11,10 @@
circuit = /obj/item/circuitboard/machine/gibber
var/operating = FALSE //Is it on?
- var/dirty = 0 // Does it need cleaning?
+ var/dirty = FALSE // Does it need cleaning?
var/gibtime = 40 // Time from starting until meat appears
var/meat_produced = 0
- var/ignore_clothing = 0
+ var/ignore_clothing = FALSE
/obj/machinery/gibber/Initialize()
@@ -30,7 +29,7 @@
gib_time -= 5 * M.rating
gibtime = gib_time
if(M.rating >= 2)
- ignore_clothing = 1
+ ignore_clothing = TRUE
/obj/machinery/gibber/update_icon()
cut_overlays()
@@ -61,6 +60,10 @@
to_chat(user, "It's locked and running.")
return
+ if(!anchored)
+ to_chat(user, "[src] cannot be used unless bolted to the ground.")
+ return
+
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(!iscarbon(L))
@@ -70,12 +73,17 @@
if(C.buckled ||C.has_buckled_mobs())
to_chat(user, "[C] is attached to something!")
return
- if(C.abiotic(1) && !ignore_clothing)
- to_chat(user, "Subject may not have abiotic items on.")
- return
+
+ if(!ignore_clothing)
+ for(var/obj/item/I in C.held_items + C.get_equipped_items())
+ if(!(I.flags_1 & NODROP_1))
+ to_chat(user, "Subject may not have abiotic items on.")
+ return
user.visible_message("[user] starts to put [C] into the gibber!")
- src.add_fingerprint(user)
+
+ add_fingerprint(user)
+
if(do_after(user, gibtime, target = src))
if(C && user.pulling == C && !C.buckled && !C.has_buckled_mobs() && !occupant)
user.visible_message("[user] stuffs [C] into the gibber!")
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/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm
index 82ba8ab405..6ef8e5e4e9 100644
--- a/code/modules/food_and_drinks/pizzabox.dm
+++ b/code/modules/food_and_drinks/pizzabox.dm
@@ -124,7 +124,7 @@
return
else
bomb_timer = input(user, "Set the [bomb] timer from [BOMB_TIMER_MIN] to [BOMB_TIMER_MAX].", bomb, bomb_timer) as num
- bomb_timer = Clamp(Ceiling(bomb_timer / 2), BOMB_TIMER_MIN, BOMB_TIMER_MAX)
+ bomb_timer = CLAMP(CEILING(bomb_timer / 2, 1), BOMB_TIMER_MIN, BOMB_TIMER_MAX)
bomb_defused = FALSE
var/message = "[ADMIN_LOOKUPFLW(user)] has trapped a [src] with [bomb] set to [bomb_timer * 2] seconds."
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 5bfcb9963d..0832f372c8 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -132,7 +132,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
/datum/chatOutput/proc/setMusicVolume(volume = "")
if(volume)
- adminMusicVolume = Clamp(text2num(volume), 0, 100)
+ adminMusicVolume = CLAMP(text2num(volume), 0, 100)
//Sends client connection details to the chat to handle and save
/datum/chatOutput/proc/sendClientData()
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index 3403253c07..a35748e13e 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;
@@ -399,6 +399,9 @@ h1.alert, h2.alert {color: #000000;}
.love {color: #FF69Bf;}
.lovebold {color: #FF69Bf; font-weight: bold;}
+.monkeyhive {color: #774704;}
+.monkeylead {color: #774704; font-size: 2;}
+
.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
.connectionClosed.restored {background: green;}
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..1177e889db 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -9,6 +9,8 @@
var/begin_weekday = FALSE //If set to a weekday, then this will trigger the holiday on the above week
var/always_celebrate = FALSE // for christmas neverending, or testing.
+ var/obj/item/drone_hat //If this is defined, drones without a default hat will spawn with this one during the holiday; check drones_as_items.dm to see this used
+
// This proc gets run before the game starts when the holiday is activated. Do festive shit here.
/datum/holiday/proc/celebrate()
return
@@ -172,11 +174,13 @@
name = "Labor Day"
begin_day = 1
begin_month = MAY
+ drone_hat = /obj/item/clothing/head/hardhat
/datum/holiday/firefighter
name = "Firefighter's Day"
begin_day = 4
begin_month = MAY
+ drone_hat = /obj/item/clothing/head/hardhat/red
/datum/holiday/firefighter/getStationPrefix()
return pick("Burning","Blazing","Plasma","Fire")
@@ -190,6 +194,7 @@
name = "Doctor's Day"
begin_day = 1
begin_month = JULY
+ drone_hat = /obj/item/clothing/head/nursehat
/datum/holiday/UFO
name = "UFO Day"
@@ -221,6 +226,7 @@
name = "Talk-Like-a-Pirate Day"
begin_day = 19
begin_month = SEPTEMBER
+ drone_hat = /obj/item/clothing/head/pirate
/datum/holiday/pirate/greet()
return "Ye be talkin' like a pirate today or else ye'r walkin' tha plank, matey!"
@@ -321,6 +327,7 @@
begin_week = 4
begin_month = NOVEMBER
begin_weekday = THURSDAY
+ drone_hat = /obj/item/clothing/head/that //This is the closest we can get to a pilgrim's hat
/datum/holiday/thanksgiving/canada
name = "Thanksgiving in Canada"
@@ -384,12 +391,14 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
name = "Mayan Doomsday Anniversary"
begin_day = 21
begin_month = DECEMBER
+ drone_hat = /obj/item/clothing/mask/rat/tribal
/datum/holiday/xmas
name = CHRISTMAS
- begin_day = 23
+ begin_day = 22
begin_month = DECEMBER
- end_day = 25
+ end_day = 27
+ drone_hat = /obj/item/clothing/head/santa
/datum/holiday/xmas/greet()
return "Have a merry Christmas!"
@@ -399,6 +408,7 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
begin_day = 1
begin_month = DECEMBER
end_day = 31
+ drone_hat = /obj/item/clothing/head/santa
/datum/holiday/festive_season/greet()
return "Have a nice festive season!"
@@ -421,6 +431,7 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
/datum/holiday/easter
name = EASTER
+ drone_hat = /obj/item/clothing/head/rabbitears
var/const/days_early = 1 //to make editing the holiday easier
var/const/days_extra = 1
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index e369826c04..87c860b50e 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -42,7 +42,7 @@
for(var/obj/item/stock_parts/micro_laser/ML in component_parts)
var/wratemod = ML.rating * 2.5
- min_wrate = Floor(10-wratemod,1) // 7,5,2,0 Clamps at 0 and 10 You want this low
+ min_wrate = FLOOR(10-wratemod,1) // 7,5,2,0 Clamps at 0 and 10 You want this low
min_wchance = 67-(ML.rating*16) // 48,35,19,3 Clamps at 0 and 67 You want this low
for(var/obj/item/circuitboard/machine/plantgenes/vaultcheck in component_parts)
if(istype(vaultcheck, /obj/item/circuitboard/machine/plantgenes/vault)) // DUMB BOTANY TUTS
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 643ac056e4..dadf077c8a 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -37,7 +37,7 @@
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_new(src, loc)
seed.prepare_result(src)
- transform *= TransformUsingVariable(seed.potency, 100, 0.5) //Makes the resulting produce's sprite larger or smaller based on potency!
+ transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5 //Makes the resulting produce's sprite larger or smaller based on potency!
add_juice()
@@ -146,7 +146,7 @@
/obj/item/reagent_containers/food/snacks/grown/on_grind()
var/nutriment = reagents.get_reagent_amount("nutriment")
- if(grind_results.len)
+ if(grind_results&&grind_results.len)
for(var/i in 1 to grind_results.len)
grind_results[grind_results[i]] = nutriment
reagents.del_reagent("nutriment")
@@ -154,7 +154,7 @@
/obj/item/reagent_containers/food/snacks/grown/on_juice()
var/nutriment = reagents.get_reagent_amount("nutriment")
- if(juice_results.len)
+ if(juice_results&&juice_results.len)
for(var/i in 1 to juice_results.len)
juice_results[juice_results[i]] = nutriment
reagents.del_reagent("nutriment")
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 59af735b01..1a3db5ef03 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -154,8 +154,8 @@
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- W.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- W.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ W.pixel_x = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ W.pixel_y = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
else
return ..()
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 3b80fae6c0..1c53f296cc 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -28,7 +28,7 @@
if(istype(src, seed.product)) // no adding reagents if it is just a trash item
seed.prepare_result(src)
- transform *= TransformUsingVariable(seed.potency, 100, 0.5)
+ transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5
add_juice()
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 5c1fafc1c4..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)
@@ -881,26 +881,26 @@
/// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds.///
/obj/machinery/hydroponics/proc/adjustNutri(adjustamt)
- nutrilevel = Clamp(nutrilevel + adjustamt, 0, maxnutri)
+ nutrilevel = CLAMP(nutrilevel + adjustamt, 0, maxnutri)
/obj/machinery/hydroponics/proc/adjustWater(adjustamt)
- waterlevel = Clamp(waterlevel + adjustamt, 0, maxwater)
+ waterlevel = CLAMP(waterlevel + adjustamt, 0, maxwater)
if(adjustamt>0)
adjustToxic(-round(adjustamt/4))//Toxicity dilutation code. The more water you put in, the lesser the toxin concentration.
/obj/machinery/hydroponics/proc/adjustHealth(adjustamt)
if(myseed && !dead)
- plant_health = Clamp(plant_health + adjustamt, 0, myseed.endurance)
+ plant_health = CLAMP(plant_health + adjustamt, 0, myseed.endurance)
/obj/machinery/hydroponics/proc/adjustToxic(adjustamt)
- toxic = Clamp(toxic + adjustamt, 0, 100)
+ toxic = CLAMP(toxic + adjustamt, 0, 100)
/obj/machinery/hydroponics/proc/adjustPests(adjustamt)
- pestlevel = Clamp(pestlevel + adjustamt, 0, 10)
+ pestlevel = CLAMP(pestlevel + adjustamt, 0, 10)
/obj/machinery/hydroponics/proc/adjustWeeds(adjustamt)
- weedlevel = Clamp(weedlevel + adjustamt, 0, 10)
+ weedlevel = CLAMP(weedlevel + adjustamt, 0, 10)
/obj/machinery/hydroponics/proc/spawnplant() // why would you put strange reagent in a hydro tray you monster I bet you also feed them blood
var/list/livingplants = list(/mob/living/simple_animal/hostile/tree, /mob/living/simple_animal/hostile/killertomato)
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index aa35b4ae07..56f80c548d 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -170,7 +170,7 @@
/// Setters procs ///
/obj/item/seeds/proc/adjust_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = Clamp(yield + adjustamt, 0, 10)
+ yield = CLAMP(yield + adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
@@ -179,39 +179,39 @@
C.value = yield
/obj/item/seeds/proc/adjust_lifespan(adjustamt)
- lifespan = Clamp(lifespan + adjustamt, 10, 100)
+ lifespan = CLAMP(lifespan + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/adjust_endurance(adjustamt)
- endurance = Clamp(endurance + adjustamt, 10, 100)
+ endurance = CLAMP(endurance + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/adjust_production(adjustamt)
if(yield != -1)
- production = Clamp(production + adjustamt, 1, 10)
+ production = CLAMP(production + adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/adjust_potency(adjustamt)
if(potency != -1)
- potency = Clamp(potency + adjustamt, 0, 100)
+ potency = CLAMP(potency + adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
- weed_rate = Clamp(weed_rate + adjustamt, 0, 10)
+ weed_rate = CLAMP(weed_rate + adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
- weed_chance = Clamp(weed_chance + adjustamt, 0, 67)
+ weed_chance = CLAMP(weed_chance + adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
@@ -220,7 +220,7 @@
/obj/item/seeds/proc/set_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = Clamp(adjustamt, 0, 10)
+ yield = CLAMP(adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
@@ -229,39 +229,39 @@
C.value = yield
/obj/item/seeds/proc/set_lifespan(adjustamt)
- lifespan = Clamp(adjustamt, 10, 100)
+ lifespan = CLAMP(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/set_endurance(adjustamt)
- endurance = Clamp(adjustamt, 10, 100)
+ endurance = CLAMP(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/set_production(adjustamt)
if(yield != -1)
- production = Clamp(adjustamt, 1, 10)
+ production = CLAMP(adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/set_potency(adjustamt)
if(potency != -1)
- potency = Clamp(adjustamt, 0, 100)
+ potency = CLAMP(adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/set_weed_rate(adjustamt)
- weed_rate = Clamp(adjustamt, 0, 10)
+ weed_rate = CLAMP(adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/set_weed_chance(adjustamt)
- weed_chance = Clamp(adjustamt, 0, 67)
+ weed_chance = CLAMP(adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm
index 805cf787f7..637c3bfcee 100644
--- a/code/modules/integrated_electronics/core/assemblies.dm
+++ b/code/modules/integrated_electronics/core/assemblies.dm
@@ -20,6 +20,8 @@
var/charge_tick = FALSE
var/charge_delay = 4
var/use_cyborg_cell = TRUE
+ max_integrity = 50
+ armor = list(melee = 50, bullet = 70, laser = 70, energy = 100, bomb = 10, bio = 100, rad = 100, fire = 0, acid = 0)
/obj/item/device/electronic_assembly/proc/check_interactivity(mob/user)
return user.canUseTopic(src,be_close = TRUE)
@@ -30,8 +32,6 @@
START_PROCESSING(SScircuit, src)
materials[MAT_METAL] = round((max_complexity + max_components) / 4) * SScircuit.cost_multiplier
-
-
/obj/item/device/electronic_assembly/Destroy()
STOP_PROCESSING(SScircuit, src)
return ..()
@@ -273,22 +273,9 @@
/obj/item/device/electronic_assembly/afterattack(atom/target, mob/user, proximity)
- for(var/obj/item/integrated_circuit/input/sensor/S in assembly_components)
- if(!proximity)
- if(istype(S,/obj/item/integrated_circuit/input/sensor/ranged)||(!user))
- if(user.client)
- if(!(target in view(user.client)))
- continue
- else
- if(!(target in view(user)))
- continue
- else
- continue
- S.set_pin_data(IC_OUTPUT, 1, WEAKREF(target))
- S.check_then_do_work()
- S.scan(target)
-
- visible_message("
[user] waves [src] around [target].")
+ for(var/obj/item/integrated_circuit/input/S in assembly_components)
+ if(S.sense(target,user,proximity))
+ visible_message("
[user] waves [src] around [target].")
/obj/item/device/electronic_assembly/screwdriver_act(mob/living/user, obj/item/S)
@@ -326,8 +313,11 @@
interact(user)
return TRUE
else
+ for(var/obj/item/integrated_circuit/input/S in assembly_components)
+ S.attackby_react(I,user,user.a_intent)
return ..()
+
/obj/item/device/electronic_assembly/attack_self(mob/user)
if(!check_interactivity(user))
return
@@ -391,7 +381,6 @@
/obj/item/device/electronic_assembly/proc/get_object()
return src
-
// Returns the location to be used for dropping items.
// Same as the regular drop_location(), but with checks being run on acting_object if necessary.
/obj/item/integrated_circuit/drop_location()
@@ -406,6 +395,7 @@
/obj/item/device/electronic_assembly/default //The /default electronic_assemblys are to allow the introduction of the new naming scheme without breaking old saves.
name = "type-a electronic assembly"
+
/obj/item/device/electronic_assembly/calc
name = "type-b electronic assembly"
icon_state = "setup_small_calc"
@@ -507,4 +497,4 @@
/obj/item/device/electronic_assembly/drone/arms
name = "type-b electronic drone"
icon_state = "setup_drone_arms"
- desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
\ No newline at end of file
+ desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
diff --git a/code/modules/integrated_electronics/core/debugger.dm b/code/modules/integrated_electronics/core/debugger.dm
index ac6f5c1a1e..666fcf00d6 100644
--- a/code/modules/integrated_electronics/core/debugger.dm
+++ b/code/modules/integrated_electronics/core/debugger.dm
@@ -56,7 +56,7 @@
data_to_show = A.name
to_chat(user, "
You write '[data_to_write ? data_to_show : "NULL"]' to the '[io]' pin of \the [io.holder].")
else if(io.io_type == PULSE_CHANNEL)
- io.holder.check_then_do_work(ignore_power = TRUE)
+ io.holder.check_then_do_work(io.ord,ignore_power = TRUE)
to_chat(user, "
You pulse \the [io.holder]'s [io].")
io.holder.interact(user) // This is to update the UI.
diff --git a/code/modules/integrated_electronics/core/helpers.dm b/code/modules/integrated_electronics/core/helpers.dm
index e84823f201..773c4f0684 100644
--- a/code/modules/integrated_electronics/core/helpers.dm
+++ b/code/modules/integrated_electronics/core/helpers.dm
@@ -15,9 +15,9 @@
io_type_override = io_list_copy[io_entry]
if(io_type_override)
- io_list.Add(new io_type_override(src, io_entry, default_data, pin_type))
+ io_list.Add(new io_type_override(src, io_entry, default_data, pin_type,i))
else
- io_list.Add(new io_type(src, io_entry, default_data, pin_type))
+ io_list.Add(new io_type(src, io_entry, default_data, pin_type,i))
/obj/item/integrated_circuit/proc/set_pin_data(pin_type, pin_number, datum/new_data)
diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm
index 069ca4245c..0c1a2fdad5 100644
--- a/code/modules/integrated_electronics/core/integrated_circuit.dm
+++ b/code/modules/integrated_electronics/core/integrated_circuit.dm
@@ -58,6 +58,12 @@ a creative player the means to solve many problems. Circuits are held inside an
/obj/item/integrated_circuit/proc/any_examine(mob/user)
return
+/obj/item/integrated_circuit/proc/attackby_react(var/atom/movable/A,mob/user)
+ return
+
+/obj/item/integrated_circuit/proc/sense(var/atom/movable/A,mob/user,prox)
+ return
+
/obj/item/integrated_circuit/proc/check_interactivity(mob/user)
if(assembly)
return assembly.check_interactivity(user)
@@ -291,17 +297,18 @@ a creative player the means to solve many problems. Circuits are held inside an
return TRUE // Battery has enough.
return FALSE // Not enough power.
-/obj/item/integrated_circuit/proc/check_then_do_work(var/ignore_power = FALSE)
+/obj/item/integrated_circuit/proc/check_then_do_work(ord,var/ignore_power = FALSE)
if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam.
- return
+ return FALSE
if(power_draw_per_use && !ignore_power)
if(!check_power())
power_fail()
- return
+ return FALSE
next_use = world.time + cooldown_per_use
- do_work()
+ do_work(ord)
+ return TRUE
-/obj/item/integrated_circuit/proc/do_work()
+/obj/item/integrated_circuit/proc/do_work(ord)
return
/obj/item/integrated_circuit/proc/disconnect_all()
@@ -369,4 +376,3 @@ a creative player the means to solve many problems. Circuits are held inside an
return TRUE
return FALSE
-
diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm
index bff96b713c..528281c3b7 100644
--- a/code/modules/integrated_electronics/core/pins.dm
+++ b/code/modules/integrated_electronics/core/pins.dm
@@ -25,14 +25,16 @@ D [1]/ ||
var/list/linked = list()
var/io_type = DATA_CHANNEL
var/pin_type // IC_INPUT, IC_OUTPUT, IC_ACTIVATOR - used in saving assembly wiring
+ var/ord
-
-/datum/integrated_io/New(loc, _name, _data, _pin_type)
+/datum/integrated_io/New(loc, _name, _data, _pin_type,_ord)
name = _name
if(_data)
data = _data
if(_pin_type)
pin_type = _pin_type
+ if(_ord)
+ ord = _ord
holder = loc
@@ -148,7 +150,7 @@ D [1]/ ||
/datum/integrated_io/activate/push_data()
for(var/k in 1 to linked.len)
var/datum/integrated_io/io = linked[k]
- io.holder.check_then_do_work()
+ io.holder.check_then_do_work(io.ord)
/datum/integrated_io/proc/pull_data()
for(var/k in 1 to linked.len)
@@ -207,7 +209,7 @@ D [1]/ ||
write_data_to_pin(new_data)
/datum/integrated_io/activate/ask_for_pin_data(mob/user) // This just pulses the pin.
- holder.check_then_do_work(ignore_power = TRUE)
+ holder.check_then_do_work(ord,ignore_power = TRUE)
to_chat(user, "
You pulse \the [holder]'s [src] pin.")
/datum/integrated_io/activate
diff --git a/code/modules/integrated_electronics/core/special_pins/index_pin.dm b/code/modules/integrated_electronics/core/special_pins/index_pin.dm
index 802a2612d3..06267eec61 100644
--- a/code/modules/integrated_electronics/core/special_pins/index_pin.dm
+++ b/code/modules/integrated_electronics/core/special_pins/index_pin.dm
@@ -1,4 +1,4 @@
-// These pins can only contain integer numbers between 1 and IC_MAX_LIST_LENGTH. Null is not allowed.
+// These pins can only contain integer numbers between 0 and IC_MAX_LIST_LENGTH. Null is allowed.
/datum/integrated_io/index
name = "index pin"
data = 1
@@ -11,10 +11,10 @@
/datum/integrated_io/index/write_data_to_pin(new_data)
if(isnull(new_data))
- new_data = 1
+ new_data = 0
if(isnum(new_data))
- data = Clamp(round(new_data), 1, IC_MAX_LIST_LENGTH)
+ data = CLAMP(round(new_data), 0, IC_MAX_LIST_LENGTH)
holder.on_data_written()
/datum/integrated_io/index/display_pin_type()
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/arithmetic.dm b/code/modules/integrated_electronics/subtypes/arithmetic.dm
index 7dec779f83..e491a34a69 100644
--- a/code/modules/integrated_electronics/subtypes/arithmetic.dm
+++ b/code/modules/integrated_electronics/subtypes/arithmetic.dm
@@ -30,10 +30,9 @@
/obj/item/integrated_circuit/arithmetic/addition/do_work()
var/result = 0
for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- I.pull_data()
- if(isnum(I.data))
- result = result + I.data
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I))
+ result += I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -56,13 +55,10 @@
return
var/result = A.data
- for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- if(I == A)
- continue
- I.pull_data()
- if(isnum(I.data))
- result = result - I.data
+ for(var/k in 2 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I))
+ result -= I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -85,13 +81,10 @@
if(!isnum(A.data))
return
var/result = A.data
- for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- if(I == A)
- continue
- I.pull_data()
- if(isnum(I.data))
- result = result * I.data
+ for(var/k in 2 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I))
+ result *= I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -114,13 +107,12 @@
return
var/result = A.data
- for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- if(I == A)
- continue
- I.pull_data()
- if(isnum(I.data) && I.data != 0) //No runtimes here.
- result = result / I.data
+
+ for(var/k in 2 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I) && (I != 0))
+ result /= I
+
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -228,12 +220,11 @@
/obj/item/integrated_circuit/arithmetic/average/do_work()
var/result = 0
var/inputs_used = 0
- for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- I.pull_data()
- if(isnum(I.data))
+ for(var/k in 2 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I))
inputs_used++
- result = result + I.data
+ result += I
if(inputs_used)
result = result / inputs_used
@@ -288,11 +279,10 @@
/obj/item/integrated_circuit/arithmetic/square_root/do_work()
var/result = 0
- for(var/k in 1 to inputs.len)
- var/datum/integrated_io/I = inputs[k]
- I.pull_data()
- if(isnum(I.data))
- result = sqrt(I.data)
+ for(var/k in 2 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(isnum(I))
+ result += sqrt(I)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm
index e2046fd456..cd9306d0da 100644
--- a/code/modules/integrated_electronics/subtypes/converters.dm
+++ b/code/modules/integrated_electronics/subtypes/converters.dm
@@ -160,10 +160,10 @@
/obj/item/integrated_circuit/converter/concatenator/do_work()
var/result = null
- for(var/datum/integrated_io/I in inputs)
- I.pull_data()
- if(!isnull(I.data))
- result = result + I.data
+ for(var/k in 1 to inputs.len)
+ var/I = get_pin_data(IC_INPUT, k)
+ if(!isnull(I))
+ result = result + I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -265,7 +265,7 @@
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
- result = ToDegrees(incoming)
+ result = TODEGREES(incoming)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -283,7 +283,7 @@
pull_data()
var/incoming = get_pin_data(IC_INPUT, 1)
if(!isnull(incoming))
- result = ToRadians(incoming)
+ result = TORADIANS(incoming)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/code/modules/integrated_electronics/subtypes/data_transfer.dm
index 20b80926c8..a769a16768 100644
--- a/code/modules/integrated_electronics/subtypes/data_transfer.dm
+++ b/code/modules/integrated_electronics/subtypes/data_transfer.dm
@@ -123,7 +123,7 @@
/obj/item/integrated_circuit/transfer/pulsedemultiplexer/do_work()
var/output_index = get_pin_data(IC_INPUT, 1)
- if(output_index == Clamp(output_index, 1, number_of_pins))
+ if(output_index == CLAMP(output_index, 1, number_of_pins))
activate_pin(round(output_index + 1 ,1))
/obj/item/integrated_circuit/transfer/pulsedemultiplexer/medium
diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm
index 276d3d9ca0..91b4b437e3 100644
--- a/code/modules/integrated_electronics/subtypes/input.dm
+++ b/code/modules/integrated_electronics/subtypes/input.dm
@@ -128,7 +128,7 @@
var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/human)
if(!istype(H)) //Invalid input
return
- if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
+ if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
var/total_health = round(H.health/H.getMaxHealth(), 0.01)*100
var/missing_health = H.getMaxHealth() - H.health
@@ -143,6 +143,49 @@
push_data()
activate_pin(2)
+/obj/item/integrated_circuit/input/slime_scanner
+ name = "slime_scanner"
+ desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime."
+ icon_state = "medscan_adv"
+ complexity = 12
+ inputs = list("\
[ target")
+ outputs = list(
+ "colour" = IC_PINTYPE_STRING,
+ "adult" = IC_PINTYPE_BOOLEAN,
+ "nutrition" = IC_PINTYPE_NUMBER,
+ "charge" = IC_PINTYPE_NUMBER,
+ "health" = IC_PINTYPE_NUMBER,
+ "possible mutation" = IC_PINTYPE_LIST,
+ "genetic destability"= IC_PINTYPE_NUMBER,
+ "slime core amount" = IC_PINTYPE_NUMBER,
+ "Growth progress" = IC_PINTYPE_NUMBER,
+ )
+ activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
+ spawn_flags = IC_SPAWN_RESEARCH
+ power_draw_per_use = 80
+
+/obj/item/integrated_circuit/input/slime_scanner/do_work()
+ var/mob/living/simple_animal/slime/T = get_pin_data_as_type(IC_INPUT, 1, /mob/living/simple_animal/slime)
+ if(!isslime(T)) //Invalid input
+ return
+ if(T in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
+
+ set_pin_data(IC_OUTPUT, 1, T.colour)
+ set_pin_data(IC_OUTPUT, 2, T.is_adult)
+ set_pin_data(IC_OUTPUT, 3, T.nutrition/T.get_max_nutrition())
+ set_pin_data(IC_OUTPUT, 4, T.powerlevel)
+ set_pin_data(IC_OUTPUT, 5, round(T.health/T.maxHealth,0.01)*100)
+ set_pin_data(IC_OUTPUT, 6, uniqueList(T.slime_mutation))
+ set_pin_data(IC_OUTPUT, 7, T.mutation_chance)
+ set_pin_data(IC_OUTPUT, 8, T.cores)
+ set_pin_data(IC_OUTPUT, 9, T.amount_grown/SLIME_EVOLUTION_THRESHOLD)
+
+
+ push_data()
+ activate_pin(2)
+
+
+
/obj/item/integrated_circuit/input/plant_scanner
name = "integrated plant analyzer"
desc = "A very small version of the plant analyser. This allows the machine to know all valuable params of plants in trays. \
@@ -180,7 +223,7 @@
return
for(var/i=1, i<=outputs.len, i++)
set_pin_data(IC_OUTPUT, i, null)
- if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
+ if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
if(H.myseed)
set_pin_data(IC_OUTPUT, 1, H.myseed.plantname)
set_pin_data(IC_OUTPUT, 2, H.age)
@@ -228,7 +271,7 @@
return
for(var/i=1, i<=outputs.len, i++)
set_pin_data(IC_OUTPUT, i, null)
- if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
+ if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
if(H.myseed)
for(var/datum/plant_gene/reagent/G in H.myseed.genes)
greagents.Add(G.get_name())
@@ -373,7 +416,7 @@
var/rad = get_pin_data(IC_INPUT, 2)
if(isnum(rad))
- rad = Clamp(rad, 0, 8)
+ rad = CLAMP(rad, 0, 8)
radius = rad
/obj/item/integrated_circuit/input/advanced_locator_list/do_work()
@@ -426,7 +469,7 @@
/obj/item/integrated_circuit/input/advanced_locator/on_data_written()
var/rad = get_pin_data(IC_INPUT, 2)
if(isnum(rad))
- rad = Clamp(rad, 0, 8)
+ rad = CLAMP(rad, 0, 8)
radius = rad
/obj/item/integrated_circuit/input/advanced_locator/do_work()
@@ -671,12 +714,15 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
-/obj/item/integrated_circuit/input/sensor/proc/scan(var/atom/A)
+/obj/item/integrated_circuit/input/sensor/sense(var/atom/A,mob/user,prox)
+ if(!prox)
+ return FALSE
+ if(!check_then_do_work())
+ return FALSE
var/ignore_bags = get_pin_data(IC_INPUT, 1)
if(ignore_bags)
if(istype(A, /obj/item/storage))
return FALSE
-
set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
push_data()
activate_pin(1)
@@ -694,6 +740,52 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
+/obj/item/integrated_circuit/input/sensor/ranged/sense(var/atom/A,mob/user)
+ if(!user)
+ return FALSE
+ if(user.client)
+ if(!(A in view(user.client)))
+ return FALSE
+ else
+ if(!(A in view(user)))
+ return FALSE
+ if(!check_then_do_work())
+ return FALSE
+ var/ignore_bags = get_pin_data(IC_INPUT, 1)
+ if(ignore_bags)
+ if(istype(A, /obj/item/storage))
+ return FALSE
+ set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
+ push_data()
+ activate_pin(1)
+ return TRUE
+
+/obj/item/integrated_circuit/input/objscaner
+ name = "scaner"
+ desc = "Scans and obtains a reference for any objects you use on assembly."
+ extended_desc = "If 'put down' pin is set to true, assembly will take scanned object from your hands to it's location.\
+ useful for interaction with grabber. Scaner works only with help intent."
+ icon_state = "recorder"
+ complexity = 4
+ inputs = list("put down" = IC_PINTYPE_BOOLEAN)
+ outputs = list("scanned" = IC_PINTYPE_REF)
+ activators = list("on scanned" = IC_PINTYPE_PULSE_OUT)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+ power_draw_per_use = 20
+
+/obj/item/integrated_circuit/input/objscaner/attackby_react(var/atom/A,var/mob/user,intent)
+ if(intent!=INTENT_HELP)
+ return FALSE
+ if(!check_then_do_work())
+ return FALSE
+ var/pu = get_pin_data(IC_INPUT, 1)
+ if(pu)
+ user.transferItemToLoc(A,drop_location())
+ set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
+ push_data()
+ activate_pin(1)
+ return TRUE
+
/obj/item/integrated_circuit/input/internalbm
name = "internal battery monitor"
desc = "This monitors the charge level of an internal battery."
@@ -760,3 +852,38 @@
activate_pin(2)
push_data()
return
+
+/obj/item/integrated_circuit/input/ntnetsc
+ name = "NTnet scaner"
+ desc = "This can return NTnet id of component insi given object, if there is any."
+ icon_state = "signalsc"
+ w_class = WEIGHT_CLASS_TINY
+ complexity = 2
+ inputs = list("target" = IC_PINTYPE_REF)
+ outputs = list(
+ "id" = IC_PINTYPE_STRING
+ )
+ activators = list("read" = IC_PINTYPE_PULSE_IN, "found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+ power_draw_per_use = 1
+
+/obj/item/integrated_circuit/input/ntnetsc/do_work()
+
+ var/atom/AM = get_pin_data_as_type(IC_INPUT, 1, /atom)
+ var/list/processing_list = list(AM)
+ var/datum/component/ntnet_interface/net = null
+ set_pin_data(IC_OUTPUT, 1, null)
+ while(processing_list.len && !net)
+ var/atom/A = processing_list[1]
+ processing_list.Cut(1, 2)
+ //Byond does not allow things to be in multiple contents, or double parent-child hierarchies, so only += is needed
+ //This is also why we don't need to check against assembled as we go along
+ processing_list += A.contents
+ net = A.GetComponent(/datum/component/ntnet_interface)
+ if(net)
+ set_pin_data(IC_OUTPUT, 1, net.hardware_id)
+ activate_pin(2)
+ else
+ activate_pin(3)
+ push_data()
+ return
diff --git a/code/modules/integrated_electronics/subtypes/logic.dm b/code/modules/integrated_electronics/subtypes/logic.dm
index 627301ef10..f8e858ef94 100644
--- a/code/modules/integrated_electronics/subtypes/logic.dm
+++ b/code/modules/integrated_electronics/subtypes/logic.dm
@@ -2,7 +2,7 @@
name = "logic gate"
desc = "This tiny chip will decide for you!"
extended_desc = "Logic circuits will treat a null, 0, and a \"\" string value as FALSE and anything else as TRUE."
- complexity = 3
+ complexity = 1
outputs = list("result")
activators = list("compare" = IC_PINTYPE_PULSE_IN)
category_text = "Logic"
diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm
index 42a55f1a1d..5099547197 100644
--- a/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ b/code/modules/integrated_electronics/subtypes/manipulation.dm
@@ -93,8 +93,8 @@
yo.data = round(yo.data, 1)
var/turf/T = get_turf(assembly)
- var/target_x = Clamp(T.x + xo.data, 0, world.maxx)
- var/target_y = Clamp(T.y + yo.data, 0, world.maxy)
+ var/target_x = CLAMP(T.x + xo.data, 0, world.maxx)
+ var/target_y = CLAMP(T.y + yo.data, 0, world.maxy)
shootAt(locate(target_x, target_y, T.z))
@@ -155,9 +155,11 @@
if(isnum(wanted_dir.data))
if(step(assembly, wanted_dir.data))
activate_pin(2)
+ return
else
activate_pin(3)
return FALSE
+ return FALSE
/obj/item/integrated_circuit/manipulation/grenade
name = "grenade primer"
@@ -210,7 +212,7 @@
var/datum/integrated_io/detonation_time = inputs[1]
var/dt
if(isnum(detonation_time.data) && detonation_time.data > 0)
- dt = Clamp(detonation_time.data, 1, 12)*10
+ dt = CLAMP(detonation_time.data, 1, 12)*10
else
dt = 15
addtimer(CALLBACK(attached_grenade, /obj/item/grenade.proc/prime), dt)
@@ -247,9 +249,14 @@
/obj/item/integrated_circuit/manipulation/plant_module/do_work()
..()
var/turf/T = get_turf(src)
- var/obj/machinery/hydroponics/AM = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/hydroponics)
- if(!istype(AM)) //Invalid input
+ var/obj/OM = get_pin_data_as_type(IC_INPUT, 1, /obj)
+ if(istype(OM,/obj/structure/spacevine) && get_pin_data(IC_INPUT, 2) == 2)
+ qdel(OM)
+ activate_pin(2)
return
+ var/obj/machinery/hydroponics/AM = OM
+ if(!istype(AM)) //Invalid input
+ return FALSE
var/mob/living/M = get_turf(AM)
if(!M.Adjacent(T))
return //Can't reach
@@ -276,6 +283,7 @@
qdel(AM.myseed)
AM.myseed = null
AM.weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
+ AM.dead = 0
AM.update_icon()
else
activate_pin(2)
@@ -284,7 +292,7 @@
/obj/item/integrated_circuit/manipulation/grabber
name = "grabber"
- desc = "A circuit with it's own inventory for small/medium items, used to grab and store things."
+ desc = "A circuit with it's own inventory for tiny/small items, used to grab and store things."
icon_state = "grabber"
extended_desc = "The circuit accepts a reference to thing to be grabbed. It can store up to 10 things. Modes: 1 for grab. 0 for eject the first thing. -1 for eject all."
w_class = WEIGHT_CLASS_SMALL
@@ -307,7 +315,7 @@
var/mode = get_pin_data(IC_INPUT, 2)
if(mode == 1)
- if(check_target(AM, exclude_contents = TRUE))
+ if(check_target(AM))
if((contents.len < max_items) && (!max_w_class || AM.w_class <= max_w_class))
AM.forceMove(src)
if(mode == 0)
@@ -389,9 +397,9 @@
if(!M.temporarilyRemoveItemFromInventory(A))
return
- var/x_abs = Clamp(T.x + target_x_rel, 0, world.maxx)
- var/y_abs = Clamp(T.y + target_y_rel, 0, world.maxy)
- var/range = round(Clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
+ var/x_abs = CLAMP(T.x + target_x_rel, 0, world.maxx)
+ var/y_abs = CLAMP(T.y + target_y_rel, 0, world.maxy)
+ var/range = round(CLAMP(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
A.forceMove(drop_location())
A.throw_at(locate(x_abs, y_abs, T.z), range, 3)
diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm
index ef6cc644d8..6a90ff5f2a 100644
--- a/code/modules/integrated_electronics/subtypes/output.dm
+++ b/code/modules/integrated_electronics/subtypes/output.dm
@@ -88,7 +88,7 @@
var/brightness = get_pin_data(IC_INPUT, 2)
if(new_color && isnum(brightness))
- brightness = Clamp(brightness, 0, 6)
+ brightness = CLAMP(brightness, 0, 6)
light_rgb = new_color
light_brightness = brightness
@@ -146,7 +146,7 @@
var/selected_sound = sounds[ID]
if(!selected_sound)
return
- vol = Clamp(vol ,0 , 100)
+ vol = CLAMP(vol ,0 , 100)
playsound(get_turf(src), selected_sound, vol, freq, -1)
/obj/item/integrated_circuit/output/sound/on_data_written()
diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm
index 564c3a4851..0c66c3a943 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
@@ -7,8 +9,11 @@
. = ..()
if(volume)
create_reagents(volume)
+ push_vol()
-
+/obj/item/integrated_circuit/reagent/proc/push_vol()
+ set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
+ push_data()
/obj/item/integrated_circuit/reagent/smoke
name = "smoke generator"
@@ -17,7 +22,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
@@ -29,7 +34,8 @@
)
activators = list(
"create smoke" = IC_PINTYPE_PULSE_IN,
- "on smoked" = IC_PINTYPE_PULSE_OUT
+ "on smoked" = IC_PINTYPE_PULSE_OUT,
+ "push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 20
@@ -40,24 +46,27 @@
//reset warning only if we have reagents now
if(changetype == ADD_REAGENT)
notified = FALSE
- set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
- push_data()
-
-/obj/item/integrated_circuit/reagent/smoke/do_work()
- var/location = get_turf(src)
- var/datum/effect_system/smoke_spread/chem/S = new
- S.attach(location)
- playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
- if(S)
- S.set_up(reagents, smoke_radius, location, notified)
- if(!notified)
- notified = TRUE
- S.start()
-
- if(reagents)
- reagents.clear_reagents()
- activate_pin(2)
+ push_vol()
+/obj/item/integrated_circuit/reagent/smoke/do_work(ord)
+ switch(ord)
+ if(1)
+ 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)
+ playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
+ if(S)
+ S.set_up(reagents, smoke_radius, location, notified)
+ if(!notified)
+ notified = TRUE
+ S.start()
+ reagents.clear_reagents()
+ activate_pin(2)
+ if(3)
+ set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
+ push_data()
/obj/item/integrated_circuit/reagent/injector
name = "integrated hypo-injector"
@@ -66,7 +75,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
@@ -85,7 +94,9 @@
activators = list(
"inject" = IC_PINTYPE_PULSE_IN,
"on injected" = IC_PINTYPE_PULSE_OUT,
- "on fail" = IC_PINTYPE_PULSE_OUT
+ "on fail" = IC_PINTYPE_PULSE_OUT,
+ "push ref" = IC_PINTYPE_PULSE_IN
+
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 15
@@ -93,15 +104,8 @@
var/transfer_amount = 10
var/busy = FALSE
-/obj/item/integrated_circuit/reagent/injector/interact(mob/user)
- set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
- push_data()
- ..()
-
-
/obj/item/integrated_circuit/reagent/injector/on_reagent_change(changetype)
- set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
- push_data()
+ push_vol()
/obj/item/integrated_circuit/reagent/injector/on_data_written()
var/new_amount = get_pin_data(IC_INPUT, 2)
@@ -111,7 +115,7 @@
else
direction_mode = SYRINGE_INJECT
if(isnum(new_amount))
- new_amount = Clamp(new_amount, 0, volume)
+ new_amount = CLAMP(new_amount, 0, volume)
transfer_amount = new_amount
// Hydroponics trays have no reagents holder and handle reagents in their own snowflakey way.
@@ -127,7 +131,15 @@
temp_reagents.clear_reagents()
qdel(temp_reagents)
-/obj/item/integrated_circuit/reagent/injector/do_work()
+/obj/item/integrated_circuit/reagent/injector/do_work(ord)
+ switch(ord)
+ if(1)
+ inject()
+ if(4)
+ set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
+ push_data()
+
+/obj/item/integrated_circuit/reagent/injector/proc/inject()
set waitfor = FALSE // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
var/atom/movable/acting_object = get_object()
@@ -145,7 +157,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 +168,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 +177,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
@@ -184,7 +193,7 @@
activate_pin(3)
return
- var/tramount = Clamp(transfer_amount, 0, reagents.total_volume)
+ var/tramount = CLAMP(transfer_amount, 0, reagents.total_volume)
if(isliving(AM))
var/mob/living/L = AM
@@ -235,7 +244,7 @@
else
direction_mode = SYRINGE_INJECT
if(isnum(new_amount))
- new_amount = Clamp(new_amount, 0, 50)
+ new_amount = CLAMP(new_amount, 0, 50)
transfer_amount = new_amount
/obj/item/integrated_circuit/reagent/pump/do_work()
@@ -263,8 +272,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 +284,7 @@
icon_state = "reagent_storage"
extended_desc = "This is effectively an internal beaker."
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
volume = 60
complexity = 4
@@ -285,17 +293,15 @@
"volume used" = IC_PINTYPE_NUMBER,
"self reference" = IC_PINTYPE_REF
)
- activators = list()
+ activators = list("push ref" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
-/obj/item/integrated_circuit/reagent/storage/interact(mob/user)
+/obj/item/integrated_circuit/reagent/storage/do_work()
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
- ..()
/obj/item/integrated_circuit/reagent/storage/on_reagent_change(changetype)
- set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
- push_data()
+ push_vol()
/obj/item/integrated_circuit/reagent/storage/cryo
name = "cryo reagent storage"
@@ -310,6 +316,7 @@
. = ..()
reagents.set_reacting(FALSE)
+
/obj/item/integrated_circuit/reagent/storage/big
name = "big reagent storage"
desc = "Stores liquid inside, and away from electrical components. Can store up to 180u."
@@ -321,6 +328,99 @@
complexity = 16
spawn_flags = IC_SPAWN_RESEARCH
+/obj/item/integrated_circuit/reagent/storage/grinder
+ name = "reagent grinder"
+ desc = "This is reagent grinder.It accepts ref to something and refines it into reagents. Can store up to 100u."
+ icon_state = "blender"
+ extended_desc = ""
+ inputs = list(
+ "target" = IC_PINTYPE_REF,
+ )
+ outputs = list(
+ "volume used" = IC_PINTYPE_NUMBER,
+ "self reference" = IC_PINTYPE_REF
+ )
+ activators = list(
+ "grind" = IC_PINTYPE_PULSE_IN,
+ "on grind" = IC_PINTYPE_PULSE_OUT,
+ "on fail" = IC_PINTYPE_PULSE_OUT,
+ "push ref" = IC_PINTYPE_PULSE_IN
+ )
+ volume = 100
+ power_draw_per_use = 150
+ complexity = 16
+ spawn_flags = IC_SPAWN_RESEARCH
+
+
+/obj/item/integrated_circuit/reagent/storage/grinder/do_work(ord)
+ switch(ord)
+ if(1)
+ grind()
+ if(4)
+ set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
+ push_data()
+
+/obj/item/integrated_circuit/reagent/storage/grinder/proc/grind()
+ if(reagents.total_volume >= reagents.maximum_volume)
+ activate_pin(3)
+ return FALSE
+ var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
+ if(istype(I)&&(I.grind_results)&&check_target(I)&&(I.on_grind(src) != -1))
+ reagents.add_reagent_list(I.grind_results)
+ if(I.reagents)
+ I.reagents.trans_to(src, I.reagents.total_volume)
+ qdel(I)
+ activate_pin(2)
+ return TRUE
+ activate_pin(3)
+ return FALSE
+
+obj/item/integrated_circuit/reagent/storage/juicer
+ name = "reagent juicer"
+ desc = "This is reagent juicer.It accepts ref to something and refines it into reagents. Can store up to 100u."
+ icon_state = "blender"
+ extended_desc = ""
+ inputs = list(
+ "target" = IC_PINTYPE_REF,
+ )
+ outputs = list(
+ "volume used" = IC_PINTYPE_NUMBER,
+ "self reference" = IC_PINTYPE_REF
+ )
+ activators = list(
+ "juice" = IC_PINTYPE_PULSE_IN,
+ "on juice" = IC_PINTYPE_PULSE_OUT,
+ "on fail" = IC_PINTYPE_PULSE_OUT,
+ "push ref" = IC_PINTYPE_PULSE_IN
+ )
+ volume = 100
+ power_draw_per_use = 150
+ complexity = 16
+ spawn_flags = IC_SPAWN_RESEARCH
+
+/obj/item/integrated_circuit/reagent/storage/juicer/do_work(ord)
+ switch(ord)
+ if(1)
+ juice()
+ if(4)
+ set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
+ push_data()
+
+/obj/item/integrated_circuit/reagent/storage/juicer/proc/juice()
+ if(reagents.total_volume >= reagents.maximum_volume)
+ activate_pin(3)
+ return FALSE
+ var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
+ if(istype(I)&&check_target(I)&&(I.juice_results)&&(I.on_juice() != -1))
+ reagents.add_reagent_list(I.juice_results)
+ qdel(I)
+ activate_pin(2)
+ return TRUE
+ activate_pin(3)
+ return FALSE
+
+
+
/obj/item/integrated_circuit/reagent/storage/scan
name = "reagent scanner"
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. On pulse this beaker will send list of contained reagents."
@@ -334,17 +434,22 @@
"list of reagents" = IC_PINTYPE_LIST
)
activators = list(
- "scan" = IC_PINTYPE_PULSE_IN
+ "scan" = IC_PINTYPE_PULSE_IN,
+ "push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
-/obj/item/integrated_circuit/reagent/storage/scan/do_work()
- var/cont[0]
- for(var/datum/reagent/RE in reagents.reagent_list)
- cont += RE.id
- set_pin_data(IC_OUTPUT, 3, cont)
- push_data()
-
+/obj/item/integrated_circuit/reagent/storage/scan/do_work(ord)
+ switch(ord)
+ if(1)
+ var/cont[0]
+ for(var/datum/reagent/RE in reagents.reagent_list)
+ cont += RE.id
+ set_pin_data(IC_OUTPUT, 3, cont)
+ push_data()
+ if(2)
+ set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
+ push_data()
/obj/item/integrated_circuit/reagent/filter
name = "reagent filter"
@@ -383,7 +488,7 @@
else
direction_mode = SYRINGE_INJECT
if(isnum(new_amount))
- new_amount = Clamp(new_amount, 0, 50)
+ new_amount = CLAMP(new_amount, 0, 50)
transfer_amount = new_amount
/obj/item/integrated_circuit/reagent/filter/do_work()
@@ -415,3 +520,45 @@
activate_pin(2)
push_data()
+/obj/item/integrated_circuit/reagent/storage/heater
+ name = "chemical heater"
+ desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. Will heat or freeze reagents \
+ to target temperature, when turned on."
+ icon_state = "heater"
+ container_type = OPENCONTAINER
+ complexity = 8
+ inputs = list(
+ "target temperature" = IC_PINTYPE_NUMBER,
+ "on" = IC_PINTYPE_BOOLEAN
+ )
+ inputs_default = list("1" = 300)
+ outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF,"temperature" = IC_PINTYPE_NUMBER)
+ spawn_flags = IC_SPAWN_RESEARCH
+ var/heater_coefficient = 0.1
+
+/obj/item/integrated_circuit/reagent/storage/heater/on_data_written()
+ if(get_pin_data(IC_INPUT, 2))
+ power_draw_idle = 30
+ else
+ power_draw_idle = 0
+
+/obj/item/integrated_circuit/reagent/storage/heater/Initialize()
+ .=..()
+ START_PROCESSING(SScircuit, src)
+
+/obj/item/integrated_circuit/reagent/storage/heater/Destroy()
+ STOP_PROCESSING(SScircuit, src)
+ return ..()
+
+/obj/item/integrated_circuit/reagent/storage/heater/process()
+ if(power_draw_idle)
+ var/target_temperature = get_pin_data(IC_INPUT, 1)
+ if(reagents.chem_temp > target_temperature)
+ reagents.chem_temp += min(-1, (target_temperature - reagents.chem_temp) * heater_coefficient)
+ if(reagents.chem_temp < target_temperature)
+ reagents.chem_temp += max(1, (target_temperature - reagents.chem_temp) * heater_coefficient)
+
+ reagents.chem_temp = round(reagents.chem_temp)
+ reagents.handle_reactions()
+ set_pin_data(IC_OUTPUT, 3, reagents.chem_temp)
+ push_data()
diff --git a/code/modules/integrated_electronics/subtypes/smart.dm b/code/modules/integrated_electronics/subtypes/smart.dm
index ec59c3cab1..37a38677b0 100644
--- a/code/modules/integrated_electronics/subtypes/smart.dm
+++ b/code/modules/integrated_electronics/subtypes/smart.dm
@@ -27,6 +27,6 @@
push_data()
return // Can't see the target.
- set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
+ set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
push_data()
activate_pin(2)
diff --git a/code/modules/integrated_electronics/subtypes/time.dm b/code/modules/integrated_electronics/subtypes/time.dm
index 57fc16ccf9..d93aafef58 100644
--- a/code/modules/integrated_electronics/subtypes/time.dm
+++ b/code/modules/integrated_electronics/subtypes/time.dm
@@ -62,7 +62,7 @@
/obj/item/integrated_circuit/time/delay/custom/do_work()
var/delay_input = get_pin_data(IC_INPUT, 1)
if(delay_input && isnum(delay_input) )
- var/new_delay = Clamp(delay_input ,1 ,36000) //An hour.
+ var/new_delay = CLAMP(delay_input ,1 ,36000) //An hour.
delay = new_delay
..()
diff --git a/code/modules/integrated_electronics/subtypes/trig.dm b/code/modules/integrated_electronics/subtypes/trig.dm
index 1d7f660bd4..cefa25e945 100644
--- a/code/modules/integrated_electronics/subtypes/trig.dm
+++ b/code/modules/integrated_electronics/subtypes/trig.dm
@@ -71,7 +71,7 @@
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
- result = Tan(A)
+ result = TAN(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -91,7 +91,7 @@
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
- result = Csc(A)
+ result = CSC(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -111,7 +111,7 @@
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
- result = Sec(A)
+ result = SEC(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -131,7 +131,7 @@
var/result = null
var/A = get_pin_data(IC_INPUT, 1)
if(!isnull(A))
- result = Cot(A)
+ result = COT(A)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm
new file mode 100644
index 0000000000..9738175d2d
--- /dev/null
+++ b/code/modules/keybindings/bindings_atom.dm
@@ -0,0 +1,18 @@
+// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
+// Only way to do that is to tie the behavior into the focus's keyLoop().
+
+/atom/movable/keyLoop(client/user)
+ if(!user.keys_held["Ctrl"])
+ var/movement_dir = NONE
+ for(var/_key in user.keys_held)
+ movement_dir = movement_dir | GLOB.movement_keys[_key]
+ if(user.next_move_dir_add)
+ movement_dir |= user.next_move_dir_add
+ if(user.next_move_dir_sub)
+ movement_dir &= ~user.next_move_dir_sub
+ // Sanity checks in case you hold left and right and up to make sure you only go up
+ if((movement_dir & NORTH) && (movement_dir & SOUTH))
+ movement_dir &= ~(NORTH|SOUTH)
+ if((movement_dir & EAST) && (movement_dir & WEST))
+ movement_dir &= ~(EAST|WEST)
+ user.Move(get_step(src, movement_dir), movement_dir)
\ No newline at end of file
diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm
new file mode 100644
index 0000000000..070a792ecd
--- /dev/null
+++ b/code/modules/language/aphasia.dm
@@ -0,0 +1,13 @@
+/datum/language/aphasia
+ name = "Gibbering"
+ desc = "It is theorized that any sufficiently brain-damaged person can speak this language."
+ speech_verb = "garbles"
+ ask_verb = "mumbles"
+ whisper_verb = "mutters"
+ exclaim_verb = "screams incoherently"
+ flags_1 = LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
+ key = "i"
+ syllables = list("m","n","gh","h","l","s","r","a","e","i","o","u")
+ space_chance = 20
+ default_priority = 10
+ icon_state = "aphasia"
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
index 67881f7510..598fb41e6c 100644
--- a/code/modules/language/language.dm
+++ b/code/modules/language/language.dm
@@ -49,7 +49,7 @@
for(var/i in 0 to name_count)
new_name = ""
- var/Y = rand(Floor(syllable_count/syllable_divisor), syllable_count)
+ var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count)
for(var/x in Y to 0)
new_name += pick(syllables)
full_name += " [capitalize(lowertext(new_name))]"
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 54a6caffef..5aa048a5fd 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -263,7 +263,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
dat += "(Order book by SS13BN)]
"
dat += ""
dat += "| AUTHOR | TITLE | CATEGORY | |
"
- dat += libcomp_menu[Clamp(page,1,libcomp_menu.len)]
+ dat += libcomp_menu[CLAMP(page,1,libcomp_menu.len)]
dat += "| <<<< | | | >>>> |
"
dat += "
"
dat += "
(Return to main menu)
"
@@ -444,7 +444,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
else
var/orderid = input("Enter your order:") as num|null
if(orderid)
- if(isnum(orderid) && IsInteger(orderid))
+ if(isnum(orderid) && ISINTEGER(orderid))
href_list["targetid"] = num2text(orderid)
if(href_list["targetid"])
diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm
index cee4665f07..fd75ba4351 100644
--- a/code/modules/library/soapstone.dm
+++ b/code/modules/library/soapstone.dm
@@ -142,7 +142,7 @@
hidden_message = newmessage
creator_name = user.real_name
creator_key = user.ckey
- realdate = world.timeofday
+ realdate = world.realtime
map = SSmapping.config.map_name
update_icon()
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index 8e56acc2fb..a6c28b4146 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -232,8 +232,8 @@
var/turf/T
if (source_turf)
var/oldlum = source_turf.luminosity
- source_turf.luminosity = Ceiling(light_range)
- for(T in view(Ceiling(light_range), source_turf))
+ source_turf.luminosity = CEILING(light_range, 1)
+ for(T in view(CEILING(light_range, 1), source_turf))
for (thing in T.get_corners(source_turf))
C = thing
corners[C] = 0
diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm
index 862de852bc..559a93b87f 100644
--- a/code/modules/mapping/reader.dm
+++ b/code/modules/mapping/reader.dm
@@ -102,7 +102,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
if(!no_changeturf)
WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/AfterChange is called")
- bounds[MAP_MINX] = min(bounds[MAP_MINX], Clamp(xcrdStart, x_lower, x_upper))
+ bounds[MAP_MINX] = min(bounds[MAP_MINX], CLAMP(xcrdStart, x_lower, x_upper))
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd)
@@ -119,15 +119,15 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
if(gridLines.len && gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
- bounds[MAP_MINY] = min(bounds[MAP_MINY], Clamp(ycrd, y_lower, y_upper))
+ bounds[MAP_MINY] = min(bounds[MAP_MINY], CLAMP(ycrd, y_lower, y_upper))
ycrd += gridLines.len - 1 // Start at the top and work down
if(!cropMap && ycrd > world.maxy)
if(!measureOnly)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
- bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(ycrd, y_lower, y_upper))
+ bounds[MAP_MAXY] = max(bounds[MAP_MAXY], CLAMP(ycrd, y_lower, y_upper))
else
- bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(min(ycrd, world.maxy), y_lower, y_upper))
+ bounds[MAP_MAXY] = max(bounds[MAP_MAXY], CLAMP(min(ycrd, world.maxy), y_lower, y_upper))
var/maxx = xcrdStart
if(measureOnly)
@@ -166,7 +166,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
++xcrd
--ycrd
- bounds[MAP_MAXX] = Clamp(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper)
+ bounds[MAP_MAXX] = CLAMP(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper)
CHECK_TICK
diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm
index 6b364e63e7..4e419646bc 100644
--- a/code/modules/mining/aux_base.dm
+++ b/code/modules/mining/aux_base.dm
@@ -1,9 +1,10 @@
///Mining Base////
+#define ZONE_SET 0
#define BAD_ZLEVEL 1
#define BAD_AREA 2
#define BAD_COORDS 3
-#define ZONE_SET 4
+#define BAD_TURF 4
/area/shuttle/auxillary_base
name = "Auxillary Base"
@@ -134,21 +135,31 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
possible_destinations = "mining_home;mining_away;landing_zone_dock;mining_public"
/obj/machinery/computer/auxillary_base/proc/set_landing_zone(turf/T, mob/user, var/no_restrictions)
-
var/obj/docking_port/mobile/auxillary_base/base_dock = locate(/obj/docking_port/mobile/auxillary_base) in SSshuttle.mobile
if(!base_dock) //Not all maps have an Aux base. This object is useless in that case.
to_chat(user, "This station is not equipped with an auxillary base. Please contact your Nanotrasen contractor.")
return
if(!no_restrictions)
+ var/static/list/disallowed_turf_types = typecacheof(list(
+ /turf/open/lava,
+ /turf/closed/indestructible,
+ /turf/open/indestructible,
+ ))
+
if(T.z != ZLEVEL_MINING)
return BAD_ZLEVEL
- var/colony_radius = max(base_dock.width, base_dock.height)*0.5
- if(T.x - colony_radius < 1 || T.x + colony_radius >= world.maxx || T.y - colony_radius < 1 || T.y + colony_radius >= world.maxx)
- return BAD_COORDS //Avoid dropping the base too close to map boundaries, as it results in parts of it being left in space
- var/list/area_counter = get_areas_in_range(colony_radius, T)
- if(area_counter.len > 1) //Avoid smashing ruins unless you are inside a really big one
- return BAD_AREA
+ var/colony_radius = CEILING(max(base_dock.width, base_dock.height)*0.5, 1)
+ var/list/colony_turfs = block(locate(T.x - colony_radius, T.y - colony_radius, T.z), locate(T.x + colony_radius, T.y + colony_radius, T.z))
+ for(var/i in 1 to colony_turfs.len)
+ CHECK_TICK
+ var/turf/place = colony_turfs[i]
+ if(!place)
+ return BAD_COORDS
+ if(!istype(place.loc, /area/lavaland/surface))
+ return BAD_AREA
+ if(disallowed_turf_types[place.type])
+ return BAD_TURF
var/area/A = get_area(T)
@@ -208,14 +219,16 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
return
switch(AB.set_landing_zone(T, user, no_restrictions))
+ if(ZONE_SET)
+ qdel(src)
if(BAD_ZLEVEL)
to_chat(user, "This uplink can only be used in a designed mining zone.")
if(BAD_AREA)
to_chat(user, "Unable to acquire a targeting lock. Find an area clear of stuctures or entirely within one.")
if(BAD_COORDS)
to_chat(user, "Location is too close to the edge of the station's scanning range. Move several paces away and try again.")
- if(ZONE_SET)
- qdel(src)
+ if(BAD_TURF)
+ to_chat(user, "The landing zone contains turfs unsuitable for a base.")
/obj/item/device/assault_pod/mining/unrestricted
name = "omni-locational landing field designator"
@@ -348,7 +361,8 @@ obj/docking_port/stationary/public_mining_dock
/obj/structure/mining_shuttle_beacon/attack_robot(mob/user)
return attack_hand(user) //So borgies can help
+#undef ZONE_SET
#undef BAD_ZLEVEL
#undef BAD_AREA
#undef BAD_COORDS
-#undef ZONE_SET
+#undef BAD_TURF
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 9d6d522c11..d655ed6e94 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -656,7 +656,7 @@
playsound(user, 'sound/magic/clockwork/fellowship_armory.ogg', 35, TRUE, frequency = 90000 - (active * 30000))
/obj/item/melee/transforming/cleaving_saw/clumsy_transform_effect(mob/living/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
user.take_bodypart_damage(10)
@@ -799,13 +799,13 @@
force = 0
var/ghost_counter = ghost_check()
- force = Clamp((ghost_counter * 4), 0, 75)
+ force = CLAMP((ghost_counter * 4), 0, 75)
user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!")
..()
/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
var/ghost_counter = ghost_check()
- final_block_chance += Clamp((ghost_counter * 5), 0, 75)
+ final_block_chance += CLAMP((ghost_counter * 5), 0, 75)
owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!")
return ..()
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 60715ef26a..e16eb0e5b2 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -82,7 +82,7 @@
if(!M || !redemption_mat)
return FALSE
- var/smeltable_sheets = Floor(redemption_mat.amount / M)
+ var/smeltable_sheets = FLOOR(redemption_mat.amount / M, 1)
if(!smeltable_sheets)
return FALSE
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index fe4c2fab84..ca21456163 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -68,7 +68,7 @@
if(materials.materials[href_list["choose"]])
chosen = href_list["choose"]
if(href_list["chooseAmt"])
- coinsToProduce = Clamp(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000)
+ coinsToProduce = CLAMP(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000)
if(href_list["makeCoins"])
var/temp_coins = coinsToProduce
processing = TRUE
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 66a6e07180..573183df96 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -185,7 +185,7 @@
var/pollid = href_list["pollid"]
if(istext(pollid))
pollid = text2num(pollid)
- if(isnum(pollid) && IsInteger(pollid))
+ if(isnum(pollid) && ISINTEGER(pollid))
src.poll_player(pollid)
return
@@ -223,7 +223,7 @@
rating = null
else
rating = text2num(href_list["o[optionid]"])
- if(!isnum(rating) || !IsInteger(rating))
+ if(!isnum(rating) || !ISINTEGER(rating))
return
if(!vote_on_numval_poll(pollid, optionid, rating))
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 98bd14ac1f..4481de1e36 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -462,7 +462,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
views |= i
var/new_view = input("Choose your new view", "Modify view range", 7) as null|anything in views
if(new_view)
- client.change_view(Clamp(new_view, 7, max_view))
+ client.change_view(CLAMP(new_view, 7, max_view))
else
client.change_view(CONFIG_GET(string/default_view))
@@ -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/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm
index ad64c53fc7..d2224a5965 100644
--- a/code/modules/mob/dead/observer/say.dm
+++ b/code/modules/mob/dead/observer/say.dm
@@ -1,25 +1,27 @@
-/mob/dead/observer/say(message)
- message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
-
- if (!message)
- return
-
+/mob/dead/observer/say(message)
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ if (!message)
+ return
+
log_talk(src,"Ghost/[src.key] : [message]", LOGSAY)
-
- . = src.say_dead(message)
-
-/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
- var/atom/movable/to_follow = speaker
- if(radio_freq)
- var/atom/movable/virtualspeaker/V = speaker
-
- if(isAI(V.source))
- var/mob/living/silicon/ai/S = V.source
- to_follow = S.eyeobj
- else
- to_follow = V.source
- var/link = FOLLOW_LINK(src, to_follow)
- // Recompose the message, because it's scrambled by default
- message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
- to_chat(src, "[link] [message]")
-
+
+ if(check_emote(message))
+ return
+
+ . = say_dead(message)
+
+/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+ var/atom/movable/to_follow = speaker
+ if(radio_freq)
+ var/atom/movable/virtualspeaker/V = speaker
+
+ if(isAI(V.source))
+ var/mob/living/silicon/ai/S = V.source
+ to_follow = S.eyeobj
+ else
+ to_follow = V.source
+ var/link = FOLLOW_LINK(src, to_follow)
+ // Recompose the message, because it's scrambled by default
+ message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ to_chat(src, "[link] [message]")
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
new file mode 100644
index 0000000000..5487b5b284
--- /dev/null
+++ b/code/modules/mob/emote.dm
@@ -0,0 +1,48 @@
+//The code execution of the emote datum is located at code/datums/emotes.dm
+/mob/emote(act, m_type = null, message = null)
+ act = lowertext(act)
+ var/param = message
+ var/custom_param = findchar(act, " ")
+ if(custom_param)
+ param = copytext(act, custom_param + 1, length(act) + 1)
+ act = copytext(act, 1, custom_param)
+
+ var/datum/emote/E
+ E = E.emote_list[act]
+ if(!E)
+ to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
+ return
+ E.run_emote(src, param, m_type)
+
+/datum/emote/flip
+ key = "flip"
+ key_third_person = "flips"
+ restraint_check = TRUE
+ mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
+ mob_type_ignore_stat_typecache = list(/mob/dead/observer)
+
+/datum/emote/flip/run_emote(mob/user, params)
+ . = ..()
+ if(.)
+ user.SpinAnimation(7,1)
+
+/datum/emote/spin
+ key = "spin"
+ key_third_person = "spins"
+ restraint_check = TRUE
+ mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
+ mob_type_ignore_stat_typecache = list(/mob/dead/observer)
+
+/datum/emote/spin/run_emote(mob/user)
+ . = ..()
+ if(.)
+ user.spin(20, 1)
+
+ if(iscyborg(user) && user.has_buckled_mobs())
+ var/mob/living/silicon/robot/R = user
+ GET_COMPONENT_FROM(riding_datum, /datum/component/riding, R)
+ if(riding_datum)
+ for(var/mob/M in R.buckled_mobs)
+ riding_datum.force_dismount(M)
+ else
+ R.unbuckle_all_mobs()
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 45f26d55c3..c1ea547b34 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -16,7 +16,7 @@
/mob/living/carbon/monkey/handle_blood()
- if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
+ if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
@@ -28,7 +28,7 @@
bleed_rate = 0
return
- if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
+ if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL && !(NOHUNGER in dna.species.species_traits))
@@ -201,13 +201,13 @@
return "blood"
/mob/living/carbon/monkey/get_blood_id()
- if(!(disabilities & NOCLONE))
+ if(!(has_disability(NOCLONE)))
return "blood"
/mob/living/carbon/human/get_blood_id()
if(dna.species.exotic_blood)
return dna.species.exotic_blood
- else if((NOBLOOD in dna.species.species_traits) || (disabilities & NOCLONE))
+ else if((NOBLOOD in dna.species.species_traits) || (has_disability(NOCLONE)))
return
return "blood"
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index db48302f49..b01c7c09ac 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -79,8 +79,8 @@
if(!brainmob.stored_dna)
brainmob.stored_dna = new /datum/dna/stored(brainmob)
C.dna.copy_dna(brainmob.stored_dna)
- if(L.disabilities & NOCLONE)
- brainmob.disabilities |= NOCLONE //This is so you can't just decapitate a husked guy and clone them without needing to get a new body
+ if(L.has_disability(NOCLONE))
+ brainmob.disabilities[NOCLONE] = L.disabilities[NOCLONE]
var/obj/item/organ/zombie_infection/ZI = L.getorganslot(ORGAN_SLOT_ZOMBIE)
if(ZI)
brainmob.set_species(ZI.old_species) //For if the brain is cloned
@@ -154,7 +154,7 @@
var/adjusted_amount
if(amount >= 0 && maximum)
var/brainloss = get_brain_damage()
- var/new_brainloss = Clamp(brainloss + amount, 0, maximum)
+ var/new_brainloss = CLAMP(brainloss + amount, 0, maximum)
if(brainloss > new_brainloss) //brainloss is over the cap already
return 0
adjusted_amount = new_brainloss - brainloss
diff --git a/code/modules/mob/living/carbon/alien/status_procs.dm b/code/modules/mob/living/carbon/alien/status_procs.dm
index 61de87b6cb..33ba8fea1d 100644
--- a/code/modules/mob/living/carbon/alien/status_procs.dm
+++ b/code/modules/mob/living/carbon/alien/status_procs.dm
@@ -17,4 +17,4 @@
/mob/living/carbon/alien/AdjustStun(amount, updating = 1, ignore_canstun = 0)
. = ..()
if(!.)
- move_delay_add = Clamp(move_delay_add + round(amount/2), 0, 10)
+ move_delay_add = CLAMP(move_delay_add + round(amount/2), 0, 10)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index edb82e7ad4..8b1b47612b 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -157,6 +157,8 @@
if(!throwable_mob.buckled)
thrown_thing = throwable_mob
stop_pulling()
+ if(has_disability(PACIFISM))
+ to_chat(src, "You gently let go of [throwable_mob].")
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
if(start_T && end_T)
@@ -168,6 +170,10 @@
thrown_thing = I
dropItemToGround(I)
+ if(has_disability(PACIFISM) && I.throwforce)
+ to_chat(src, "You set [I] down gently on the ground.")
+ return
+
if(thrown_thing)
visible_message("[src] has thrown [thrown_thing].")
add_logs(src, thrown_thing, "has thrown")
@@ -359,16 +365,9 @@
to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
if(cuff_break)
+ . = !((I == handcuffed) || (I == legcuffed))
qdel(I)
- if(I == handcuffed)
- handcuffed = null
- update_handcuffed()
- return
- else if(I == legcuffed)
- legcuffed = null
- update_inv_legcuffed()
- return
- return TRUE
+ return
else
if(I == handcuffed)
@@ -403,7 +402,7 @@
dropItemToGround(I)
var/modifier = 0
- if(disabilities & CLUMSY)
+ if(has_disability(CLUMSY))
modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
switch(rand(1,100)+modifier) //91-100=Nothing special happens
@@ -512,7 +511,7 @@
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
update_stat()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
- become_husk()
+ become_husk("burn")
med_hud_set_health()
/mob/living/carbon/update_sight()
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 0bfa287a09..a6d4f3536b 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -306,11 +306,15 @@
if(eyes.eye_damage > 20)
if(prob(eyes.eye_damage - 20))
- if(become_nearsighted())
+ if(!has_disability(NEARSIGHT))
to_chat(src, "Your eyes start to burn badly!")
+ become_nearsighted(EYE_DAMAGE)
+
else if(prob(eyes.eye_damage - 25))
- if(become_blind())
+ if(!has_disability(BLIND))
to_chat(src, "You can't see anything!")
+ become_blind(EYE_DAMAGE)
+
else
to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!")
if(has_bane(BANE_LIGHT))
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index aecf966350..9ba1dcc033 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -185,7 +185,7 @@
/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1)
if(status_flags & GODMODE)
return 0
- staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2)
+ staminaloss = CLAMP(staminaloss + amount, 0, maxHealth*2)
if(updating_stamina)
update_stamina()
@@ -198,7 +198,7 @@
update_stamina()
/mob/living/carbon/getBrainLoss()
- . = BRAIN_DAMAGE_DEATH
+ . = 0
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
. = B.get_brain_damage()
@@ -207,6 +207,7 @@
/mob/living/carbon/adjustBrainLoss(amount, maximum = BRAIN_DAMAGE_DEATH)
if(status_flags & GODMODE)
return 0
+ var/prev_brainloss = getBrainLoss()
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(!B)
return
@@ -224,6 +225,13 @@
else
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
+ if(prev_brainloss < 40 && brainloss >= 40)
+ to_chat(src, "You feel lightheaded.")
+ else if(prev_brainloss < 120 && brainloss >= 120)
+ to_chat(src, "You feel less in control of your thoughts.")
+ else if(prev_brainloss < 180 && brainloss >= 180)
+ to_chat(src, "You can feel your mind flickering on and off...")
+
/mob/living/carbon/setBrainLoss(amount)
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 8c97bc71a3..b8d9d510fd 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -43,31 +43,32 @@
msg += ""
var/temp = getBruteLoss()
- if(temp)
- if (temp < 25)
- msg += "[t_He] [t_has] minor bruising.\n"
- else if (temp < 50)
- msg += "[t_He] [t_has] moderate bruising!\n"
- else
- msg += "[t_He] [t_has] severe bruising!\n"
+ if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
+ if(temp)
+ if (temp < 25)
+ msg += "[t_He] [t_has] minor bruising.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_has] moderate bruising!\n"
+ else
+ msg += "[t_He] [t_has] severe bruising!\n"
- temp = getFireLoss()
- if(temp)
- if (temp < 25)
- msg += "[t_He] [t_has] minor burns.\n"
- else if (temp < 50)
- msg += "[t_He] [t_has] moderate burns!\n"
- else
- msg += "[t_He] [t_has] severe burns!\n"
+ temp = getFireLoss()
+ if(temp)
+ if (temp < 25)
+ msg += "[t_He] [t_has] minor burns.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_has] moderate burns!\n"
+ else
+ msg += "[t_He] [t_has] severe burns!\n"
- temp = getCloneLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_is] slightly deformed.\n"
- else if (temp < 50)
- msg += "[t_He] [t_is] moderately deformed!\n"
- else
- msg += "[t_He] [t_is] severely deformed!\n"
+ temp = getCloneLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_is] slightly deformed.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_is] moderately deformed!\n"
+ else
+ msg += "[t_He] [t_is] severely deformed!\n"
if(disabilities & DUMB)
msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n"
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 4b1afe0780..4453c33436 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -48,7 +48,7 @@
/mob/living/carbon/proc/Drain()
- become_husk()
- disabilities |= NOCLONE
+ become_husk(CHANGELING_DRAIN)
+ add_disability(NOCLONE, CHANGELING_DRAIN)
blood_volume = 0
return 1
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 6ed9291b83..39caec803b 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -187,31 +187,32 @@
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
msg += "[t_He] [p_do()]n't seem all there.\n"
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor bruising.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate bruising!\n"
- else
- msg += "[t_He] [t_has] severe bruising!\n"
+ if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor bruising.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate bruising!\n"
+ else
+ msg += "[t_He] [t_has] severe bruising!\n"
- temp = getFireLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor burns.\n"
- else if (temp < 50)
- msg += "[t_He] [t_has] moderate burns!\n"
- else
- msg += "[t_He] [t_has] severe burns!\n"
+ temp = getFireLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor burns.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_has] moderate burns!\n"
+ else
+ msg += "[t_He] [t_has] severe burns!\n"
- temp = getCloneLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor cellular damage.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate cellular damage!\n"
- else
- msg += "[t_He] [t_has] severe cellular damage!\n"
+ temp = getCloneLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor cellular damage.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate cellular damage!\n"
+ else
+ msg += "[t_He] [t_has] severe cellular damage!\n"
if(fire_stacks > 0)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index f0c630421d..b153f914f3 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -847,7 +847,8 @@
return TRUE
/mob/living/carbon/human/update_gravity(has_gravity,override = 0)
- override = dna.species.override_float
+ if(dna && dna.species) //prevents a runtime while a human is being monkeyfied
+ override = dna.species.override_float
..()
/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = 0, stun = 1, distance = 0, message = 1, toxic = 0)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index a515ef23b1..f0835ed7bf 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -44,7 +44,10 @@
if(mind.martial_art && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
- visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!")
+ if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;)
+ visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!")
+ else
+ visible_message("[src] deflects the projectile!", "You deflect the projectile!")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
return 0
@@ -89,15 +92,15 @@
for(var/obj/item/I in held_items)
if(!istype(I, /obj/item/clothing))
- var/final_block_chance = I.block_chance - (Clamp((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(wear_suit)
- var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
+ var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(w_uniform)
- var/final_block_chance = w_uniform.block_chance - (Clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
+ var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return 0
@@ -140,8 +143,8 @@
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
- if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
- vore_attack(user, pulling)
+ if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (has_disability(FAT)) && ismonkey(pulling))
+ devour_mob(pulling)
else
..()
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index d1d657652b..84da846bfd 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -91,19 +91,8 @@
return wear_id.GetID()
-/mob/living/carbon/human/abiotic(full_body = 0)
- var/abiotic_hands = FALSE
- for(var/obj/item/I in held_items)
- if(!(I.flags_1 & NODROP_1))
- abiotic_hands = TRUE
- break
- if(full_body && abiotic_hands && ((back && !(back.flags_1&NODROP_1)) || (wear_mask && !(wear_mask.flags_1&NODROP_1)) || (head && !(head.flags_1&NODROP_1)) || (shoes && !(shoes.flags_1&NODROP_1)) || (w_uniform && !(w_uniform.flags_1&NODROP_1)) || (wear_suit && !(wear_suit.flags_1&NODROP_1)) || (glasses && !(glasses.flags_1&NODROP_1)) || (ears && !(ears.flags_1&NODROP_1)) || (gloves && !(gloves.flags_1&NODROP_1)) ) )
- return TRUE
- return abiotic_hands
-
-
/mob/living/carbon/human/IsAdvancedToolUser()
- if(disabilities & MONKEYLIKE)
+ if(has_disability(MONKEYLIKE))
return FALSE
return TRUE//Humans can use guns and such
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index c90d1a0231..6e5d8c7373 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -23,7 +23,7 @@
. = 1
/mob/living/carbon/human/mob_negates_gravity()
- return ((shoes && shoes.negates_gravity()) || dna.species.negates_gravity(src))
+ return ((shoes && shoes.negates_gravity()) || (dna.species.negates_gravity(src)))
/mob/living/carbon/human/Move(NewLoc, direct)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/interactive.dm b/code/modules/mob/living/carbon/human/interactive.dm
index 38dfad5787..8c913349c5 100644
--- a/code/modules/mob/living/carbon/human/interactive.dm
+++ b/code/modules/mob/living/carbon/human/interactive.dm
@@ -339,7 +339,7 @@
if(TRAITS & TRAIT_SMART)
smartness = 75
else if(TRAITS & TRAIT_DUMB)
- disabilities |= CLUMSY
+ add_disability(CLUMSY, GENETIC_MUTATION)
smartness = 25
if(TRAITS & TRAIT_MEAN)
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 4f41c2d40c..640447fc4d 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -187,7 +187,7 @@
if(G.tint)
update_tint()
if(G.vision_correction)
- if(disabilities & NEARSIGHT)
+ if(has_disability(NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
adjust_eye_damage(0)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index a84683c5ae..80db28b99d 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -93,19 +93,18 @@
failed_last_breath = 1
- if(dna && dna.species)
- var/datum/species/S = dna.species
+ var/datum/species/S = dna.species
- if(S.breathid == "o2")
- throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
- else if(S.breathid == "tox")
- throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
- else if(S.breathid == "co2")
- throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
- else if(S.breathid == "n2")
- throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro)
+ if(S.breathid == "o2")
+ throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
+ else if(S.breathid == "tox")
+ throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
+ else if(S.breathid == "co2")
+ throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
+ else if(S.breathid == "n2")
+ throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro)
- return 0
+ return FALSE
else
if(istype(L, /obj/item/organ/lungs))
var/obj/item/organ/lungs/lun = L
@@ -238,10 +237,10 @@
/mob/living/carbon/human/proc/get_cold_protection(temperature)
if(dna.check_mutation(COLDRES))
- return 1 //Fully protected from the cold.
+ return TRUE //Fully protected from the cold.
- if(dna && (RESISTCOLD in dna.species.species_traits))
- return 1
+ if(RESISTCOLD in dna.species.species_traits)
+ return TRUE
if(istype(loc, /obj/item/device/dogborg/sleeper))
return 1 //freezing to death in sleepers ruins fun.
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 0b02a2c711..451fadab62 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -312,7 +312,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!HD) //Decapitated
return
- if(H.disabilities & HUSK)
+ if(H.has_disability(HUSK))
return
var/datum/sprite_accessory/S
var/list/standing = list()
@@ -453,7 +453,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/obj/item/bodypart/head/HD = H.get_bodypart("head")
- if(HD && !(H.disabilities & HUSK))
+ if(HD && !(H.has_disability(HUSK)))
// lipstick
if(H.lip_style && (LIPS in species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
@@ -724,7 +724,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
- if(!(H.disabilities & HUSK))
+ if(!(H.has_disability(HUSK)))
if(!forced_colour)
switch(S.color_src)
if(MUTCOLORS)
@@ -1103,16 +1103,16 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
//The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
- if(H.disabilities & FAT)//I share your pain, past coder.
+ if(H.has_disability(FAT))//I share your pain, past coder.
if(H.overeatduration < 100)
to_chat(H, "You feel fit again!")
- H.disabilities &= ~FAT
+ H.remove_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration > 500)
to_chat(H, "You suddenly feel blubbery!")
- H.disabilities |= FAT
+ H.add_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
@@ -1269,7 +1269,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
. += (health_deficiency / 25)
if((hungry >= 70) && !flight) //Being hungry won't stop you from using flightpack controls/flapping your wings although it probably will in the wing case but who cares.
. += hungry / 50
- if(H.disabilities & FAT)
+ if(H.has_disability(FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
@@ -1315,11 +1315,14 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(user.has_disability(PACIFISM))
+ to_chat(user, "You don't want to harm [target]!")
+ return FALSE
if(target.check_block())
target.visible_message("[target] blocks [user]'s attack!")
- return 0
+ return FALSE
if(attacker_style && attacker_style.harm_act(user,target))
- return 1
+ return TRUE
else
var/atk_verb = user.dna.species.attack_verb
@@ -1344,7 +1347,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
playsound(target.loc, user.dna.species.miss_sound, 25, 1, -1)
target.visible_message("[user] has attempted to [atk_verb] [target]!",\
"[user] has attempted to [atk_verb] [target]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
var/armor_block = target.run_armor_check(affecting, "melee")
@@ -1366,8 +1369,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else if(target.lying)
target.forcesay(GLOB.hit_appends)
-
-
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
var/aim_for_mouth = user.zone_selected == "mouth"
var/target_on_help_and_unarmed = target.a_intent == INTENT_HELP && !target.get_active_held_item()
@@ -1387,10 +1388,12 @@ GLOBAL_LIST_EMPTY(roundstart_races)
return 1
else
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
-
+
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
- var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
+ var/randomized_zone = ran_zone(user.zone_selected)
+ target.SendSignal(COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
+ var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone)
var/randn = rand(1, 100)
if(randn <= 25)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
@@ -1511,8 +1514,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.confused = max(H.confused, 20)
H.adjustBrainLoss(20)
H.adjust_blurriness(10)
- if(prob(20))
+ if(prob(10))
H.gain_trauma(/datum/brain_trauma/mild/concussion)
+ else
+ if(!I.is_sharp())
+ H.adjustBrainLoss(I.force / 5)
if(prob(I.force + ((100 - H.health)/2)) && H != user)
var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
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/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index d2c83fa39f..34859a257f 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -369,7 +369,7 @@
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/target = get_turf(P.starting)
// redirect the projectile
- P.preparePixelProjectile(locate(Clamp(target.x + new_x, 1, world.maxx), Clamp(target.y + new_y, 1, world.maxy), H.z), H)
+ P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
return -1
return 0
@@ -725,7 +725,7 @@
/obj/structure/cloth_pile/proc/revive()
if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
return
- if(cloth_golem.suiciding || cloth_golem.disabilities & NOCLONE)
+ if(cloth_golem.suiciding || cloth_golem.has_disability(NOCLONE))
QDEL_NULL(cloth_golem)
return
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index fe0acc4feb..31883b4dcd 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -19,6 +19,11 @@
if(H)
H.endTailWag()
+/datum/species/human/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ H.endTailWag()
+ . = ..()
+
/datum/species/human/space_move(mob/living/carbon/human/H)
var/obj/item/device/flightpack/F = H.get_flightpack()
if(istype(F) && (F.flight) && F.allow_thrust(0.01, src))
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 257abf63d0..0d006196aa 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -42,6 +42,11 @@
if(H)
H.endTailWag()
+/datum/species/lizard/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ H.endTailWag()
+ . = ..()
+
/*
Lizard subspecies: ASHWALKERS
*/
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 6d1384f12f..aff8440930 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -94,8 +94,8 @@
to_chat(victim, "[H] is draining your blood!")
to_chat(H, "You drain some blood!")
playsound(H, 'sound/items/drink.ogg', 30, 1, -2)
- victim.blood_volume = Clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
- H.blood_volume = Clamp(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ victim.blood_volume = CLAMP(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ H.blood_volume = CLAMP(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
if(!victim.blood_volume)
to_chat(H, "You finish off [victim]'s blood supply!")
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index aca6973355..cf3d676e90 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -11,12 +11,12 @@
amount = dna.species.spec_stun(src,amount)
return ..()
-/mob/living/carbon/human/cure_husk()
+/mob/living/carbon/human/cure_husk(list/sources)
. = ..()
if(.)
update_hair()
-/mob/living/carbon/human/become_husk()
+/mob/living/carbon/human/become_husk(source)
if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks.
cure_husk()
return
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 7264e9ad95..14f294fd90 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -609,7 +609,7 @@ generate/load female uniform sprites matching all previously decided variables
if(BP.dmg_overlay_type)
. += "-[BP.dmg_overlay_type]"
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
. += "-husk"
/mob/living/carbon/human/load_limb_from_cache()
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 5eb09a8d83..4399607984 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -182,7 +182,7 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
var/ratio = (breath_gases[/datum/gas/plasma][MOLES]/safe_tox_max) * 10
- adjustToxLoss(Clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
+ adjustToxLoss(CLAMP(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
clear_alert("too_much_tox")
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index d6afdbdbc2..3e6b7f3ddd 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -120,16 +120,17 @@
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
if(L == src)
- return 0
-
+ return FALSE
+ if(has_disability(PACIFISM))
+ return FALSE
if(enemies[L])
- return 1
+ return TRUE
// target non-monkey mobs when aggressive, with a small probability of monkey v monkey
if(aggressive && (!istype(L, /mob/living/carbon/monkey/) || prob(MONKEY_AGGRESSIVE_MVM_PROB)))
- return 1
+ return TRUE
- return 0
+ return FALSE
/mob/living/carbon/monkey/proc/handle_combat()
// Don't do any AI if inside another mob (devoured)
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 7c65e4a604..59a19c7b84 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -11,7 +11,7 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
gib_type = /obj/effect/decal/cleanable/blood/gibs
- unique_name = 1
+ unique_name = TRUE
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
devourable = TRUE
@@ -62,7 +62,7 @@
if (bodytemperature < 283.222)
. += (283.222 - bodytemperature) / 10 * 1.75
-
+
var/static/config_monkey_delay
if(isnull(config_monkey_delay))
config_monkey_delay = CONFIG_GET(number/monkey_delay)
@@ -89,13 +89,15 @@
/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
- return 0
+ if(mind && is_monkey(mind))
+ return TRUE
+ return FALSE
/mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents
- return 0
+ return FALSE
/mob/living/carbon/monkey/canBeHandcuffed()
- return 1
+ return TRUE
/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
if(judgement_criteria & JUDGE_EMAGGED)
diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
index 96cafa4501..3d7619b6d2 100644
--- a/code/modules/mob/living/carbon/monkey/monkey_defense.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
@@ -160,13 +160,13 @@
if(!bodyzone_hit || bodyzone_hit == "head")
if(wear_mask)
if(!(wear_mask.resistance_flags & UNACIDABLE))
- wear_mask.acid_act(acidpwr)
+ wear_mask.acid_act(acidpwr, acid_volume)
else
to_chat(src, "Your mask protects you from the acid.")
return
if(head)
if(!(head.resistance_flags & UNACIDABLE))
- head.acid_act(acidpwr)
+ head.acid_act(acidpwr, acid_volume)
else
to_chat(src, "Your hat protects you from the acid.")
return
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index 5a4ba686b2..87058ce76d 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -19,7 +19,7 @@
if(!HD) //Decapitated
return
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
return
var/hair_hidden = 0
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index e46ae2f8e6..1d5525edd9 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -59,48 +59,13 @@
clear_alert("high")
/mob/living/carbon/adjust_disgust(amount)
- disgust = Clamp(disgust+amount, 0, DISGUST_LEVEL_MAXEDOUT)
+ disgust = CLAMP(disgust+amount, 0, DISGUST_LEVEL_MAXEDOUT)
/mob/living/carbon/set_disgust(amount)
- disgust = Clamp(amount, 0, DISGUST_LEVEL_MAXEDOUT)
+ disgust = CLAMP(amount, 0, DISGUST_LEVEL_MAXEDOUT)
-/mob/living/carbon/cure_blind()
- if(disabilities & BLIND)
- disabilities &= ~BLIND
- adjust_blindness(-1)
- return 1
-/mob/living/carbon/become_blind()
- if(!(disabilities & BLIND))
- disabilities |= BLIND
- blind_eyes(1)
- return 1
-/mob/living/carbon/cure_nearsighted()
- if(disabilities & NEARSIGHT)
- disabilities &= ~NEARSIGHT
- clear_fullscreen("nearsighted")
- return 1
-
-/mob/living/carbon/become_nearsighted()
- if(!(disabilities & NEARSIGHT))
- disabilities |= NEARSIGHT
- overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
- return 1
-
-/mob/living/carbon/cure_husk()
- if(disabilities & HUSK)
- disabilities &= ~HUSK
- status_flags &= ~DISFIGURED
- update_body()
- return 1
-
-/mob/living/carbon/become_husk()
- if(disabilities & HUSK)
- return
- disabilities |= HUSK
- status_flags |= DISFIGURED //makes them unknown
- update_body()
- return 1
+////////////////////////////////////////TRAUMAS/////////////////////////////////////////
/mob/living/carbon/proc/get_traumas()
. = list()
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index 701fa0c7bc..5034abfbbe 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -290,7 +290,7 @@
else
. += "-robotic"
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
. += "-husk"
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index dbc8da5a05..9517e1b705 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -157,7 +157,7 @@
/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- bruteloss = Clamp((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ bruteloss = CLAMP((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -168,7 +168,7 @@
/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- oxyloss = Clamp((oxyloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ oxyloss = CLAMP((oxyloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -187,7 +187,7 @@
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- toxloss = Clamp((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ toxloss = CLAMP((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -206,7 +206,7 @@
/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- fireloss = Clamp((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ fireloss = CLAMP((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -217,7 +217,7 @@
/mob/living/proc/adjustCloneLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- cloneloss = Clamp((cloneloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ cloneloss = CLAMP((cloneloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 9f541aaf67..fd3c521cd1 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -1,18 +1,3 @@
-//The code execution of the emote datum is located at code/datums/emotes.dm
-/mob/living/emote(act, m_type = null, message = null)
- act = lowertext(act)
- var/param = message
- var/custom_param = findchar(act, " ")
- if(custom_param)
- param = copytext(act, custom_param + 1, length(act) + 1)
- act = copytext(act, 1, custom_param)
-
- var/datum/emote/E
- E = E.emote_list[act]
- if(!E)
- to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
- return
- E.run_emote(src, param, m_type)
/* EMOTE DATUMS */
/datum/emote/living
@@ -143,16 +128,6 @@
restraint_check = TRUE
wing_time = 10
-/datum/emote/living/flip
- key = "flip"
- key_third_person = "flips"
- restraint_check = TRUE
-
-/datum/emote/living/flip/run_emote(mob/user, params)
- . = ..()
- if(.)
- user.SpinAnimation(7,1)
-
/datum/emote/living/frown
key = "frown"
key_third_person = "frowns"
@@ -482,25 +457,6 @@
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
-/datum/emote/living/spin
- key = "spin"
- key_third_person = "spins"
- restraint_check = TRUE
-
-/datum/emote/living/spin/run_emote(mob/user)
- . = ..()
- if(.)
- user.spin(20, 1)
- if(iscyborg(user) && user.has_buckled_mobs())
- var/mob/living/silicon/robot/R = user
- GET_COMPONENT_FROM(riding_datum, /datum/component/riding, R)
- if(riding_datum)
- for(var/mob/M in R.buckled_mobs)
- riding_datum.force_dismount(M)
- else
- R.unbuckle_all_mobs()
-
-
/datum/emote/living/circle
key = "circle"
key_third_person = "circles"
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 0aafef753f..41c4572103 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -126,7 +126,7 @@
/mob/living/proc/handle_disabilities()
//Eyes
if(eye_blind) //blindness, heals slowly over time
- if(!stat && !(disabilities & BLIND))
+ if(!stat && !(has_disability(BLIND)))
eye_blind = max(eye_blind-1,0)
if(client && !eye_blind)
clear_alert("blind")
@@ -137,6 +137,9 @@
eye_blurry = max(eye_blurry-1, 0)
if(client && !eye_blurry)
clear_fullscreen("blurry")
+ if(has_disability(PACIFISM) && a_intent == INTENT_HARM)
+ to_chat(src, "You don't feel like harming anybody.")
+ a_intent_change(INTENT_HELP)
/mob/living/proc/update_damage_hud()
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index f589ecbb20..9b47a8c66b 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
@@ -406,7 +413,6 @@
cure_nearsighted()
cure_blind()
cure_husk()
- disabilities = 0
hallucination = 0
heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
@@ -809,9 +815,12 @@
to_chat(src, "You don't have the dexterity to do this!")
return
/mob/living/proc/can_use_guns(obj/item/G)
- if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
+ if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, "You don't have the dexterity to do this!")
return FALSE
+ if(has_disability(PACIFISM))
+ to_chat(src, "You don't want to risk harming anyone!")
+ return FALSE
return TRUE
/mob/living/carbon/proc/update_stamina()
@@ -918,7 +927,7 @@
update_fire()
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
- fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
+ fire_stacks = CLAMP(fire_stacks + add_fire_stacks, -20, 20)
if(on_fire && fire_stacks <= 0)
ExtinguishMob()
@@ -1054,4 +1063,4 @@
/mob/living/onTransitZ(old_z,new_z)
..()
- update_z(new_z)
\ No newline at end of file
+ update_z(new_z)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f77c65225f..4800d9fb26 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -55,9 +55,9 @@
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
if(throwforce && w_class)
- return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
+ return CLAMP((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
else if(w_class)
- return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
+ return CLAMP(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
else
return 0
@@ -127,14 +127,17 @@
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src || anchored || !isturf(user.loc))
- return 0
+ return FALSE
if(!user.pulling || user.pulling != src)
user.start_pulling(src, supress_message)
return
if(!(status_flags & CANPUSH))
to_chat(user, "[src] can't be grabbed more aggressively!")
- return 0
+ return FALSE
+ if(user.has_disability(PACIFISM))
+ to_chat(user, "You don't want to risk hurting [src]!")
+ return FALSE
grippedby(user)
//proc to upgrade a simple pull into a more aggressive grab.
@@ -188,83 +191,97 @@
M.Feedstop()
return // can't attack while eating!
+ if(has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if (stat != DEAD)
add_logs(M, src, "attacked")
M.do_attack_animation(src)
visible_message("The [M.name] glomps [src]!", \
"The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE)
- return 1
+ return TRUE
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
if(M.melee_damage_upper == 0)
M.visible_message("\The [M] [M.friendly] [src]!")
- return 0
+ return FALSE
else
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
visible_message("\The [M] [M.attacktext] [src]!", \
"\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE)
add_logs(M, src, "attacked")
- return 1
+ return TRUE
/mob/living/attack_paw(mob/living/carbon/monkey/M)
if(isturf(loc) && istype(loc.loc, /area/start))
to_chat(M, "No attacking people at spawn, you jackass.")
- return 0
+ return FALSE
if (M.a_intent == INTENT_HARM)
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
to_chat(M, "You can't bite with your mouth covered!")
- return 0
+ return FALSE
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
if (prob(75))
add_logs(M, src, "attacked")
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
visible_message("[M.name] bites [src]!", \
"[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
- return 1
+ return TRUE
else
visible_message("[M.name] has attempted to bite [src]!", \
"[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
switch(L.a_intent)
if("help")
visible_message("[L.name] rubs its head against [src].")
- return 0
+ return FALSE
else
+ if(L.has_disability(PACIFISM))
+ to_chat(L, "You don't want to hurt anyone!")
+ return
L.do_attack_animation(src)
if(prob(90))
add_logs(L, src, "attacked")
visible_message("[L.name] bites [src]!", \
"[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
- return 1
+ return TRUE
else
visible_message("[L.name] has attempted to bite [src]!", \
"[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
switch(M.a_intent)
if ("help")
visible_message("[M] caresses [src] with its scythe like arm.")
- return 0
-
+ return FALSE
if ("grab")
grabbedby(M)
- return 0
+ return FALSE
if("harm")
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
M.do_attack_animation(src)
- return 1
+ return TRUE
if("disarm")
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- return 1
+ return TRUE
/mob/living/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
@@ -347,7 +364,7 @@
//called when the mob receives a bright flash
/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
- if(get_eye_protection() < intensity && (override_blindness_check || !(disabilities & BLIND)))
+ if(get_eye_protection() < intensity && (override_blindness_check || !(has_disability(BLIND))))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
return 1
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 50f2ce4db0..6990262409 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -26,6 +26,8 @@
var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas
//and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt
+ var/list/disabilities = list()
+
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
var/now_pushing = null //used by living/Collide() and living/PushAM() to prevent potential infinite loop.
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index b1d0484086..4e731567f1 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -285,7 +285,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
- if(disabilities & MUTE)
+ if(has_disability(MUTE))
return 0
if(is_muzzled())
@@ -296,11 +296,6 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
-/mob/living/proc/check_emote(message)
- if(copytext(message, 1, 2) == "*")
- emote(copytext(message, 2))
- return 1
-
/mob/living/proc/get_message_mode(message)
var/key = copytext(message, 1, 2)
if(key == "#")
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 1d2598c63d..b5b1bd082b 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -16,7 +16,6 @@
// It will also stream the chunk that the new loc is in.
/mob/camera/aiEye/proc/setLoc(T)
-
if(ai)
if(!isturf(ai.loc))
return
@@ -34,6 +33,8 @@
if(istype(ai.current, /obj/machinery/holopad))
var/obj/machinery/holopad/H = ai.current
H.move_hologram(ai, T)
+ if(ai.camera_light_on)
+ ai.light_cameras()
/mob/camera/aiEye/Move()
return 0
@@ -85,11 +86,6 @@
if(!user.tracking)
user.cameraFollow = null
- //user.unset_machine() //Uncomment this if it causes problems.
- //user.lightNearbyCamera()
- if(user.camera_light_on)
- user.light_cameras()
-
// Return to the Core.
/mob/living/silicon/ai/proc/view_core()
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index b12430d26d..924ab615b8 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -138,7 +138,7 @@
/mob/living/silicon/pai/proc/process_hack()
if(cable && cable.machine && istype(cable.machine, /obj/machinery/door) && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
- hackprogress = Clamp(hackprogress + 4, 0, 100)
+ hackprogress = CLAMP(hackprogress + 4, 0, 100)
else
temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
@@ -283,8 +283,8 @@
/mob/living/silicon/pai/process()
- emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
- hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
+ emitterhealth = CLAMP((emitterhealth + emitterregen), -50, emittermaxhealth)
+ hit_slowdown = CLAMP((hit_slowdown - 1), 0, 100)
/mob/living/silicon/pai/generateStaticOverlay()
return
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index 83da7d9087..2c6c42e3bb 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -57,7 +57,7 @@
return FALSE //No we're not flammable
/mob/living/silicon/pai/proc/take_holo_damage(amount)
- emitterhealth = Clamp((emitterhealth - amount), -50, emittermaxhealth)
+ emitterhealth = CLAMP((emitterhealth - amount), -50, emittermaxhealth)
if(emitterhealth < 0)
fold_in(force = TRUE)
to_chat(src, "The impact degrades your holochassis!")
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index aab1f204f6..5445941ed3 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -23,7 +23,7 @@
if(cell && cell.charge)
if(cell.charge <= 100)
uneq_all()
- var/amt = Clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
+ var/amt = CLAMP((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
else
uneq_all()
@@ -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.dm b/code/modules/mob/living/silicon/robot/robot.dm
index db10f4a81c..9b44c7cff3 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -827,6 +827,9 @@
/mob/living/silicon/robot/modules/security
set_module = /obj/item/robot_module/security
+/mob/living/silicon/robot/modules/clown
+ set_module = /obj/item/robot_module/clown
+
/mob/living/silicon/robot/modules/peacekeeper
set_module = /obj/item/robot_module/peacekeeper
@@ -1029,9 +1032,9 @@
status_flags &= ~CANPUSH
if(module.clean_on_move)
- flags_1 |= CLEAN_ON_MOVE_1
+ AddComponent(/datum/component/cleaning)
else
- flags_1 &= ~CLEAN_ON_MOVE_1
+ qdel(GetComponent(/datum/component/cleaning))
hat_offset = module.hat_offset
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index b1be1c3076..2f1eb7d378 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
@@ -513,6 +513,37 @@
if(CL)
CL.reagents.add_reagent("lube", 2 * coeff)
+/obj/item/robot_module/clown
+ name = "Clown"
+ basic_modules = list(
+ /obj/item/device/assembly/flash/cyborg,
+ /obj/item/toy/crayon/rainbow,
+ /obj/item/device/instrument/bikehorn,
+ /obj/item/stamp/clown,
+ /obj/item/bikehorn,
+ /obj/item/bikehorn/airhorn,
+ /obj/item/paint/anycolor,
+ /obj/item/soap/nanotrasen,
+ /obj/item/pneumatic_cannon/pie/selfcharge/cyborg,
+ /obj/item/razor, //killbait material
+ /obj/item/lipstick/purple,
+ /obj/item/reagent_containers/spray/waterflower/cyborg,
+ /obj/item/borg/cyborghug/peacekeeper,
+ /obj/item/borg/lollipop/clown,
+ /obj/item/picket_sign/cyborg,
+ /obj/item/reagent_containers/borghypo/clown,
+ /obj/item/extinguisher/mini)
+ emag_modules = list(
+ /obj/item/reagent_containers/borghypo/clown/hacked,
+ /obj/item/reagent_containers/spray/waterflower/cyborg/hacked)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg,
+ /obj/item/clockwork/weapon/ratvarian_spear,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ moduleselect_icon = "service"
+ cyborg_base_icon = "clown"
+ hat_offset = -2
+
/obj/item/robot_module/butler
name = "Service"
basic_modules = list(
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index efe289b222..186d0c5a41 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -125,7 +125,7 @@
if(!target) //Search for decals then.
target = scan(/obj/effect/decal/cleanable)
-
+
if(!target) //Checks for remains
target = scan(/obj/effect/decal/remains)
@@ -242,7 +242,7 @@
say(phrase)
victim.emote("scream")
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
- victim.acid_act(5, 2, 100)
+ victim.acid_act(5, 100)
else if(A == src) // Wets floors and spawns foam randomly
if(prob(75))
var/turf/open/T = loc
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/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm
index 5405ee03c6..bb6794a36a 100644
--- a/code/modules/mob/living/simple_animal/damage_procs.dm
+++ b/code/modules/mob/living/simple_animal/damage_procs.dm
@@ -2,7 +2,7 @@
/mob/living/simple_animal/proc/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
+ bruteloss = CLAMP(bruteloss + amount, 0, maxHealth)
if(updating_health)
updatehealth()
return amount
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index c0a57e3739..20e25e3a18 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -14,6 +14,8 @@
icon = 'icons/mob/drone.dmi'
icon_state = "drone_maint_hat"//yes reuse the _hat state.
var/drone_type = /mob/living/simple_animal/drone //Type of drone that will be spawned
+ var/seasonal_hats = TRUE //If TRUE, and there are no default hats, different holidays will grant different hats
+ var/static/list/possible_seasonal_hats //This is built automatically in build_seasonal_hats() but can also be edited by admins!
/obj/item/drone_shell/New()
..()
@@ -21,6 +23,17 @@
if(A)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
GLOB.poi_list |= src
+ if(isnull(possible_seasonal_hats))
+ build_seasonal_hats()
+
+/obj/item/drone_shell/proc/build_seasonal_hats()
+ possible_seasonal_hats = list()
+ if(!SSevents.holidays.len)
+ return //no holidays, no hats; we'll keep the empty list so we never call this proc again
+ for(var/V in SSevents.holidays)
+ var/datum/holiday/holiday = SSevents.holidays[V]
+ if(holiday.drone_hat)
+ possible_seasonal_hats += holiday.drone_hat
/obj/item/drone_shell/Destroy()
GLOB.poi_list -= src
@@ -42,6 +55,10 @@
if(be_drone == "No" || QDELETED(src) || !isobserver(user))
return
var/mob/living/simple_animal/drone/D = new drone_type(get_turf(loc))
+ if(!D.default_hatmask && seasonal_hats && possible_seasonal_hats.len)
+ var/hat_type = pick(possible_seasonal_hats)
+ var/obj/item/new_hat = new hat_type(D)
+ D.equip_to_slot_or_del(new_hat, slot_head)
D.admin_spawned = admin_spawned
D.key = user.key
qdel(src)
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/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index a977338008..c6f0f6a91c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -79,10 +79,10 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
- move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
+ move_to_delay = CLAMP((health/maxHealth) * 10, 5, 10)
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/60),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/60),0,20)
if(charging)
return
ranged_cooldown = world.time + ranged_cooldown_time
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 58e3e0837b..79bedbe264 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -57,7 +57,7 @@ Difficulty: Very Hard
L.dust()
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
if(enrage(target))
@@ -558,7 +558,7 @@ Difficulty: Very Hard
H.regenerate_limbs()
H.regenerate_organs()
H.revive(1,0)
- H.disabilities |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal
+ H.add_disability(NOCLONE, MAGIC_DISABILITY) //Free revives, but significantly limits your options for reviving except via the crystal
H.grab_ghost(force = TRUE)
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
@@ -719,7 +719,7 @@ Difficulty: Very Hard
if(isliving(A) && holder_animal)
var/mob/living/L = A
L.notransform = 1
- L.disabilities |= MUTE
+ L.add_disability(MUTE, STASIS_MUTE)
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession
@@ -729,7 +729,7 @@ Difficulty: Very Hard
/obj/structure/closet/stasis/dump_contents(var/kill = 1)
STOP_PROCESSING(SSobj, src)
for(var/mob/living/L in src)
- L.disabilities &= ~MUTE
+ L.remove_disability(MUTE, STASIS_MUTE)
L.status_flags &= ~GODMODE
L.notransform = 0
if(holder_animal)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
index 7f12e684e8..724e4fc5c7 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
@@ -101,7 +101,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
if(swooping)
return
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + ranged_cooldown_time
if(prob(15 + anger_modifier) && !client)
@@ -227,10 +227,10 @@ Difficulty: Medium
//ensure swoop direction continuity.
if(negative)
- if(IsInRange(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
+ if(ISINRANGE(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
negative = FALSE
else
- if(IsInRange(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
+ if(ISINRANGE(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
negative = TRUE
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
new /obj/effect/temp_visual/dragon_swoop(loc)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 02fb81a1ed..8dc1780e5e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -187,7 +187,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
- anger_modifier = Clamp(((maxHealth - health) / 42),0,50)
+ anger_modifier = CLAMP(((maxHealth - health) / 42),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index a4851bb432..4c5b94f2e3 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -111,7 +111,7 @@
/mob/living/simple_animal/updatehealth()
..()
- health = Clamp(health, 0, maxHealth)
+ health = CLAMP(health, 0, maxHealth)
/mob/living/simple_animal/update_stat()
if(status_flags & GODMODE)
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index e7e71bf091..9654f91b6c 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -166,7 +166,7 @@
step_away(M,src)
M.Friends = Friends.Copy()
babies += M
- M.mutation_chance = Clamp(mutation_chance+(rand(5,-5)),0,100)
+ M.mutation_chance = CLAMP(mutation_chance+(rand(5,-5)),0,100)
SSblackbox.record_feedback("tally", "slime_babies_born", 1, M.colour)
var/mob/living/simple_animal/slime/new_slime = pick(babies)
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 3d50f03e17..0149c98a3e 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -137,3 +137,76 @@
to_chat(src, "[priority_absorb_key["self_message"]]")
priority_absorb_key["stuns_absorbed"] += amount
return TRUE
+
+/////////////////////////////////// DISABILITIES ////////////////////////////////////
+
+/mob/living/proc/add_disability(disability, source)
+ if(!disabilities[disability])
+ disabilities[disability] = list(source)
+ else
+ disabilities[disability] |= list(source)
+
+/mob/living/proc/remove_disability(disability, list/sources)
+ if(!disabilities[disability])
+ return
+
+ if(LAZYLEN(sources))
+ for(var/S in sources)
+ if(S in disabilities[disability])
+ disabilities[disability] -= S
+ else
+ disabilities[disability] = list()
+
+ if(!LAZYLEN(disabilities[disability]))
+ disabilities -= disability
+
+/mob/living/proc/has_disability(disability, list/sources)
+ if(!disabilities[disability])
+ return FALSE
+
+ . = FALSE
+
+ if(LAZYLEN(sources))
+ for(var/S in sources)
+ if(S in disabilities[disability])
+ return TRUE
+ else
+ if(LAZYLEN(disabilities[disability]))
+ return TRUE
+
+/mob/living/proc/remove_all_disabilities()
+ disabilities = list()
+
+/////////////////////////////////// DISABILITY PROCS ////////////////////////////////////
+
+/mob/living/proc/cure_blind(list/sources)
+ remove_disability(BLIND, sources)
+ if(!has_disability(BLIND))
+ adjust_blindness(-1)
+
+/mob/living/proc/become_blind(source)
+ if(!has_disability(BLIND))
+ blind_eyes(1)
+ add_disability(BLIND, source)
+
+/mob/living/proc/cure_nearsighted(list/sources)
+ remove_disability(NEARSIGHT, sources)
+ if(!has_disability(NEARSIGHT))
+ clear_fullscreen("nearsighted")
+
+/mob/living/proc/become_nearsighted(source)
+ if(!has_disability(NEARSIGHT))
+ overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
+ add_disability(NEARSIGHT, source)
+
+/mob/living/proc/cure_husk(list/sources)
+ remove_disability(HUSK, sources)
+ if(!has_disability(HUSK))
+ status_flags &= ~DISFIGURED
+ update_body()
+
+/mob/living/proc/become_husk(source)
+ if(!has_disability(HUSK))
+ status_flags |= DISFIGURED //makes them unknown
+ update_body()
+ add_disability(HUSK, source)
\ No newline at end of file
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/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index edbf11654b..ecbaea015f 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -32,7 +32,6 @@
var/obj/machinery/machine = null
var/other_mobs = null
- var/disabilities = 0 //Carbon
var/atom/movable/pulling = null
var/grab_state = 0
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 3dc56c936b..10c9a04a6e 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -285,11 +285,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
firstname.Find(real_name)
return firstname.match
-/mob/proc/abiotic(full_body = 0)
- for(var/obj/item/I in held_items)
- if(!(I.flags_1 & NODROP_1))
- return 1
- return 0
//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left
/mob/verb/a_intent_change(input as text)
@@ -363,7 +358,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if(M.mind in SSticker.mode.cult)
return 2
if("nuclear")
- if(M.mind in SSticker.mode.syndicates)
+ if(M.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
return 2
if("changeling")
if(M.mind.has_antag_datum(/datum/antagonist/changeling,TRUE))
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 1ee7f27452..f9ee14b638 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -1,82 +1,88 @@
-//Speech verbs.
-/mob/verb/say_verb(message as text)
- set name = "Say"
- set category = "IC"
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
- usr.say(message)
-
-
-/mob/verb/whisper_verb(message as text)
- set name = "Whisper"
- set category = "IC"
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
- whisper(message)
-
-/mob/proc/whisper(message, datum/language/language=null)
- say(message, language) //only living mobs actually whisper, everything else just talks
-
-/mob/verb/me_verb(message as text)
- set name = "Me"
- set category = "IC"
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
-
- message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
-
- usr.emote("me",1,message)
-
-/mob/proc/say_dead(var/message)
- var/name = real_name
- var/alt_name = ""
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
-
- if(jobban_isbanned(src, "OOC"))
- to_chat(src, "You have been banned from deadchat.")
- return
-
- if (src.client)
- if(src.client.prefs.muted & MUTE_DEADCHAT)
- to_chat(src, "You cannot talk in deadchat (muted).")
- return
-
- if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
- return
-
- var/mob/dead/observer/O = src
- if(isobserver(src) && O.deadchat_name)
- name = "[O.deadchat_name]"
- else
- if(mind && mind.name)
- name = "[mind.name]"
- else
- name = real_name
- if(name != real_name)
- alt_name = " (died as [real_name])"
-
- var/K
-
- if(key)
- K = src.key
-
- message = src.say_quote(message, get_spans())
- var/rendered = "DEAD: [name][alt_name] [message]"
-
- deadchat_broadcast(rendered, follow_target = src, speaker_key = K)
-
-/mob/proc/emote(var/act)
- return
-
-/mob/proc/hivecheck()
- return 0
-
-/mob/proc/lingcheck()
- return LINGHIVE_NONE
+//Speech verbs.
+/mob/verb/say_verb(message as text)
+ set name = "Say"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ if(message)
+ say(message)
+
+
+/mob/verb/whisper_verb(message as text)
+ set name = "Whisper"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ whisper(message)
+
+/mob/proc/whisper(message, datum/language/language=null)
+ say(message, language) //only living mobs actually whisper, everything else just talks
+
+/mob/verb/me_verb(message as text)
+ set name = "Me"
+ set category = "IC"
+
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ usr.emote("me",1,message)
+
+/mob/proc/say_dead(var/message)
+ var/name = real_name
+ var/alt_name = ""
+
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+
+ if(jobban_isbanned(src, "OOC"))
+ to_chat(src, "You have been banned from deadchat.")
+ return
+
+ if (src.client)
+ if(src.client.prefs.muted & MUTE_DEADCHAT)
+ to_chat(src, "You cannot talk in deadchat (muted).")
+ return
+
+ if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
+ return
+
+ var/mob/dead/observer/O = src
+ if(isobserver(src) && O.deadchat_name)
+ name = "[O.deadchat_name]"
+ else
+ if(mind && mind.name)
+ name = "[mind.name]"
+ else
+ name = real_name
+ if(name != real_name)
+ alt_name = " (died as [real_name])"
+
+ var/K
+
+ if(key)
+ K = src.key
+
+ message = src.say_quote(message, get_spans())
+ var/rendered = "DEAD: [name][alt_name] [message]"
+
+ deadchat_broadcast(rendered, follow_target = src, speaker_key = K)
+
+/mob/proc/check_emote(message)
+ if(copytext(message, 1, 2) == "*")
+ emote(copytext(message, 2))
+ return 1
+
+/mob/proc/emote(var/act)
+ return
+
+/mob/proc/hivecheck()
+ return 0
+
+/mob/proc/lingcheck()
+ return LINGHIVE_NONE
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 80ab6929d5..8dfadf70f5 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -160,8 +160,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
- if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
+ if((stat != CONSCIOUS && stat != SOFT_CRIT))
blind_minimum = 1
+ if(isliving(src))
+ var/mob/living/L = src
+ if(L.has_disability(BLIND))
+ blind_minimum = 1
eye_blind = max(eye_blind+amount, blind_minimum)
if(!eye_blind)
clear_alert("blind")
@@ -177,8 +181,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
- if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
+ if(stat != CONSCIOUS && stat != SOFT_CRIT)
blind_minimum = 1
+ if(isliving(src))
+ var/mob/living/L = src
+ if(L.has_disability(BLIND))
+ blind_minimum = 1
eye_blind = blind_minimum
if(!eye_blind)
clear_alert("blind")
@@ -227,31 +235,6 @@
/mob/proc/set_disgust(amount)
return
-/////////////////////////////////// BLIND DISABILITY ////////////////////////////////////
-
-/mob/proc/cure_blind() //when we want to cure the BLIND disability only.
- return
-
-/mob/proc/become_blind()
- return
-
-/////////////////////////////////// NEARSIGHT DISABILITY ////////////////////////////////////
-
-/mob/proc/cure_nearsighted()
- return
-
-/mob/proc/become_nearsighted()
- return
-
-
-//////////////////////////////// HUSK DISABILITY ///////////////////////////:
-
-/mob/proc/cure_husk()
- return
-
-/mob/proc/become_husk()
- return
-
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/paper.dm b/code/modules/paperwork/paper.dm
index 1fb1846f4c..00fbcdc6f7 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -93,7 +93,7 @@
return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
- if(H.disabilities & CLUMSY && prob(25))
+ if(H.has_disability(CLUMSY) && prob(25))
to_chat(H, "You cut yourself on the paper! Ahhhh! Ahhhhh!")
H.damageoverlaytemp = 9001
H.update_damage_hud()
@@ -317,7 +317,7 @@
to_chat(user, "You stamp the paper with your rubber stamp.")
if(P.is_hot())
- if(user.disabilities & CLUMSY && prob(10))
+ if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("[user] accidentally ignites themselves!", \
"You miss the paper and accidentally light yourself on fire!")
user.dropItemToGround(P)
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 2d5fcc6e3a..17e2fe2a00 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -65,7 +65,7 @@
update_icon()
else if(P.is_hot())
- if(user.disabilities & CLUMSY && prob(10))
+ if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("[user] accidentally ignites themselves!", \
"You miss [src] and accidentally light yourself on fire!")
user.dropItemToGround(P)
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/apc.dm b/code/modules/power/apc.dm
index cbe8f335de..548651f9c8 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -153,7 +153,7 @@
GLOB.apcs_list -= src
if(malfai && operating)
- malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000)
+ malfai.malf_picker.processing_time = CLAMP(malfai.malf_picker.processing_time - 10,0,1000)
area.power_light = FALSE
area.power_equip = FALSE
area.power_environ = FALSE
@@ -1253,7 +1253,7 @@
/obj/machinery/power/apc/proc/set_broken()
if(malfai && operating)
- malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000)
+ malfai.malf_picker.processing_time = CLAMP(malfai.malf_picker.processing_time - 10,0,1000)
stat |= BROKEN
operating = FALSE
if(occupier)
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 8258d7ce0d..cd24dbb928 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -157,7 +157,7 @@
/obj/item/stock_parts/cell/proc/get_electrocute_damage()
if(charge >= 1000)
- return Clamp(round(charge/10000), 10, 90) + rand(-5,5)
+ return CLAMP(round(charge/10000), 10, 90) + rand(-5,5)
else
return 0
@@ -336,7 +336,7 @@
return
/obj/item/stock_parts/cell/beam_rifle/emp_act(severity)
- charge = Clamp((charge-(10000/severity)),0,maxcharge)
+ charge = CLAMP((charge-(10000/severity)),0,maxcharge)
/obj/item/stock_parts/cell/emergency_light
name = "miniature power cell"
diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm
index b6f61103ca..c34edc53f3 100644
--- a/code/modules/power/powernet.dm
+++ b/code/modules/power/powernet.dm
@@ -94,6 +94,6 @@
/datum/powernet/proc/get_electrocute_damage()
if(avail >= 1000)
- return Clamp(round(avail/10000), 10, 90) + rand(-5,5)
+ return CLAMP(round(avail/10000), 10, 90) + rand(-5,5)
else
return 0
\ No newline at end of file
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 36dd615e86..a5e9db1fde 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -37,7 +37,7 @@
eject()
else
loaded_tank.air_contents.gases[/datum/gas/plasma][MOLES] -= 0.001*drainratio
- ASSERT_GAS(/datum/gas/tritium,loaded_tank.air_contents)
+ loaded_tank.air_contents.assert_gas(/datum/gas/tritium)
loaded_tank.air_contents.gases[/datum/gas/tritium][MOLES] += 0.001*drainratio
loaded_tank.air_contents.garbage_collect()
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/power/smes.dm b/code/modules/power/smes.dm
index 70776b5c05..95b78ff0b5 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -227,7 +227,7 @@
/obj/machinery/power/smes/proc/chargedisplay()
- return Clamp(round(5.5*charge/capacity),0,5)
+ return CLAMP(round(5.5*charge/capacity),0,5)
/obj/machinery/power/smes/process()
if(stat & BROKEN)
@@ -382,7 +382,7 @@
target = text2num(target)
. = TRUE
if(.)
- input_level = Clamp(target, 0, input_level_max)
+ input_level = CLAMP(target, 0, input_level_max)
log_smes(usr.ckey)
if("output")
var/target = params["target"]
@@ -404,7 +404,7 @@
target = text2num(target)
. = TRUE
if(.)
- output_level = Clamp(target, 0, output_level_max)
+ output_level = CLAMP(target, 0, output_level_max)
log_smes(usr.ckey)
/obj/machinery/power/smes/proc/log_smes(user = "")
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 435cfe4156..af81b632d7 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -378,14 +378,14 @@
if("direction")
var/adjust = text2num(params["adjust"])
if(adjust)
- currentdir = Clamp((360 + adjust + currentdir) % 360, 0, 359)
+ currentdir = CLAMP((360 + adjust + currentdir) % 360, 0, 359)
targetdir = currentdir
set_panels(currentdir)
. = TRUE
if("rate")
var/adjust = text2num(params["adjust"])
if(adjust)
- trackrate = Clamp(trackrate + adjust, -7200, 7200)
+ trackrate = CLAMP(trackrate + adjust, -7200, 7200)
if(trackrate)
nexttime = world.time + 36000 / abs(trackrate)
. = TRUE
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 02cc80291e..5f9f6042d3 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -317,10 +317,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25)
if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && co2comp > POWERLOSS_INHIBITION_GAS_THRESHOLD)
- powerloss_dynamic_scaling = Clamp(powerloss_dynamic_scaling + Clamp(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1)
+ powerloss_dynamic_scaling = CLAMP(powerloss_dynamic_scaling + CLAMP(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1)
else
- powerloss_dynamic_scaling = Clamp(powerloss_dynamic_scaling - 0.05,0, 1)
- powerloss_inhibitor = Clamp(1-(powerloss_dynamic_scaling * Clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1)
+ powerloss_dynamic_scaling = CLAMP(powerloss_dynamic_scaling - 0.05,0, 1)
+ powerloss_inhibitor = CLAMP(1-(powerloss_dynamic_scaling * CLAMP(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1)
if(matter_power)
var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40)
@@ -368,7 +368,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
var/D = sqrt(1 / max(1, get_dist(l, src)))
l.hallucination += power * config_hallucination_power * D
- l.hallucination = Clamp(0, 200, l.hallucination)
+ l.hallucination = CLAMP(0, 200, l.hallucination)
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) )
@@ -386,7 +386,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
supermatter_zap(src, 5, min(power*2, 20000))
else if (damage > damage_penalty_point && prob(20))
playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10)
- supermatter_zap(src, 5, Clamp(power*2, 4000, 20000))
+ supermatter_zap(src, 5, CLAMP(power*2, 4000, 20000))
if(prob(15) && power > POWER_PENALTY_THRESHOLD)
supermatter_pull(src, power/750)
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index 4a26950217..51cb99a34f 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -62,7 +62,7 @@
pixel_x = -32
pixel_y = -32
for (var/ball in orbiting_balls)
- var/range = rand(1, Clamp(orbiting_balls.len, 3, 7))
+ var/range = rand(1, CLAMP(orbiting_balls.len, 3, 7))
tesla_zap(ball, range, TESLA_MINI_POWER/7*range, TRUE)
else
energy = 0 // ensure we dont have miniballs of miniballs
@@ -268,7 +268,7 @@
closest_grounding_rod.tesla_act(power, explosive, stun_mobs)
else if(closest_mob)
- var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
+ var/shock_damage = CLAMP(round(power/400), 10, 90) + rand(-5, 5)
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = stun_mobs)
if(issilicon(closest_mob))
var/mob/living/silicon/S = closest_mob
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/boxes_magazines/external_mag.dm b/code/modules/projectiles/boxes_magazines/external_mag.dm
index 09ae7cb905..b7b3a3e286 100644
--- a/code/modules/projectiles/boxes_magazines/external_mag.dm
+++ b/code/modules/projectiles/boxes_magazines/external_mag.dm
@@ -176,7 +176,7 @@
/obj/item/ammo_box/magazine/m12g/update_icon()
..()
- icon_state = "[initial(icon_state)]-[Ceiling(ammo_count(0)/8)*8]"
+ icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/8, 1)*8]"
/obj/item/ammo_box/magazine/m12g/buckshot
name = "shotgun magazine (12g buckshot slugs)"
diff --git a/code/modules/projectiles/boxes_magazines/internal_mag.dm b/code/modules/projectiles/boxes_magazines/internal_mag.dm
index f486be732d..07ce388abb 100644
--- a/code/modules/projectiles/boxes_magazines/internal_mag.dm
+++ b/code/modules/projectiles/boxes_magazines/internal_mag.dm
@@ -2,6 +2,7 @@
/obj/item/ammo_box/magazine/internal
desc = "Oh god, this shouldn't be here"
+ flags_1 = CONDUCT_1|ABSTRACT_1
//internals magazines are accessible, so replace spent ammo if full when trying to put a live one in
/obj/item/ammo_box/magazine/internal/give_round(obj/item/ammo_casing/R)
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 047243cb45..97a907031c 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -107,7 +107,7 @@
/obj/item/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj)
to_chat(user, "*click*")
- playsound(src, "gun_dry_fire", 60, 1)
+ playsound(src, "gun_dry_fire", 30, 1)
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
@@ -158,7 +158,7 @@
//Exclude lasertag guns from the CLUMSY check.
if(clumsy_check)
if(istype(user))
- if (user.disabilities & CLUMSY && prob(40))
+ if (user.has_disability(CLUMSY) && prob(40))
to_chat(user, "You shoot yourself in the foot with [src]!")
var/shot_leg = pick("l_leg", "r_leg")
process_fire(user,user,0,params, zone_override = shot_leg)
@@ -400,7 +400,8 @@
/obj/item/gun/dropped(mob/user)
..()
- zoom(user,FALSE)
+ if(zoomed)
+ zoom(user,FALSE)
if(azoom)
azoom.Remove(user)
if(alight)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index f5d846c912..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)
@@ -175,7 +173,7 @@
return(OXYLOSS)
else
user.visible_message("[user] is pretending to blow [user.p_their()] brain[user.p_s()] out with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(src, "gun_dry_fire", 60, 1)
+ playsound(src, "gun_dry_fire", 30, 1)
return (OXYLOSS)
#undef BRAINS_BLOWN_THROW_SPEED
#undef BRAINS_BLOWN_THROW_RANGE
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index f2eb15b381..9724f9be01 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -108,7 +108,7 @@
/obj/item/gun/ballistic/automatic/c20r/update_icon()
..()
- icon_state = "c20r[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
+ icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
/obj/item/gun/ballistic/automatic/wt550
name = "security auto rifle"
@@ -123,7 +123,7 @@
/obj/item/gun/ballistic/automatic/wt550/update_icon()
..()
- icon_state = "wt550[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""]"
+ icon_state = "wt550[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""]"
/obj/item/gun/ballistic/automatic/mini_uzi
name = "\improper Type U3 Uzi"
@@ -304,7 +304,7 @@
/obj/item/gun/ballistic/automatic/l6_saw/update_icon()
- icon_state = "l6[cover_open ? "open" : "closed"][magazine ? Ceiling(get_ammo(0)/12.5)*25 : "-empty"][suppressed ? "-suppressed" : ""]"
+ icon_state = "l6[cover_open ? "open" : "closed"][magazine ? CEILING(get_ammo(0)/12.5, 1)*25 : "-empty"][suppressed ? "-suppressed" : ""]"
item_state = "l6[cover_open ? "openmag" : "closedmag"]"
@@ -415,5 +415,5 @@
/obj/item/gun/ballistic/automatic/laser/update_icon()
..()
- icon_state = "oldrifle[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""]"
+ icon_state = "oldrifle[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""]"
return
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index a802ca8bbe..b98bdaf957 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].")
@@ -229,7 +227,7 @@
return
user.visible_message("*click*")
- playsound(src, "gun_dry_fire", 60, 1)
+ playsound(src, "gun_dry_fire", 30, 1)
/obj/item/gun/ballistic/revolver/russian/proc/shoot_self(mob/living/carbon/human/user, affecting = "head")
user.apply_damage(300, BRUTE, affecting)
@@ -351,7 +349,7 @@
clumsy_check = 0
/obj/item/gun/ballistic/revolver/reverse/can_trigger_gun(mob/living/user)
- if((user.disabilities & CLUMSY) || (user.mind && user.mind.assigned_role == "Clown"))
+ if((user.has_disability(CLUMSY)) || (user.mind && user.mind.assigned_role == "Clown"))
return ..()
if(process_fire(user, user, 0, zone_override = "head"))
user.visible_message("[user] somehow manages to shoot [user.p_them()]self in the face!", "You somehow shoot yourself in the face! How the hell?!")
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/beam_rifle.dm b/code/modules/projectiles/guns/beam_rifle.dm
index 407943f254..a2ea7dfb59 100644
--- a/code/modules/projectiles/guns/beam_rifle.dm
+++ b/code/modules/projectiles/guns/beam_rifle.dm
@@ -4,9 +4,6 @@
#define ZOOM_LOCK_CENTER_VIEW 2
#define ZOOM_LOCK_OFF 3
-#define ZOOM_SPEED_STEP 0
-#define ZOOM_SPEED_INSTANT 1
-
#define AUTOZOOM_PIXEL_STEP_FACTOR 48
#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1
@@ -45,7 +42,7 @@
var/lastangle = 0
var/aiming_lastangle = 0
var/mob/current_user = null
- var/obj/effect/projectile_beam/current_tracer
+ var/list/obj/effect/projectile_beam/current_tracers
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
var/structure_bleed_coeff = 0.7
@@ -69,9 +66,8 @@
//ZOOMING
var/zoom_current_view_increase = 0
var/zoom_target_view_increase = 10
- var/zoom_speed = ZOOM_SPEED_STEP
var/zooming = FALSE
- var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE
+ var/zoom_lock = ZOOM_LOCK_OFF
var/zooming_angle
var/current_zoom_x = 0
var/current_zoom_y = 0
@@ -80,7 +76,6 @@
var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged")
var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty")
- var/datum/action/item_action/zoom_speed_action/zoom_speed_action
var/datum/action/item_action/zoom_lock_action/zoom_lock_action
/obj/item/gun/energy/beam_rifle/debug
@@ -103,15 +98,6 @@
. = ..()
/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action)
- if(istype(action, /datum/action/item_action/zoom_speed_action))
- zoom_speed++
- if(zoom_speed > 1)
- zoom_speed = ZOOM_SPEED_STEP
- switch(zoom_speed)
- if(ZOOM_SPEED_STEP)
- to_chat(owner, "You switch [src]'s digital zoom to stepper mode.")
- if(ZOOM_SPEED_INSTANT)
- to_chat(owner, "You switch [src]'s digital zoom to instant mode.")
if(istype(action, /datum/action/item_action/zoom_lock_action))
zoom_lock++
if(zoom_lock > 3)
@@ -135,8 +121,6 @@
var/total_time = SSfastprocess.wait
if(delay_override)
total_time = delay_override
- if(zoom_speed == ZOOM_SPEED_INSTANT)
- total_time = 0
zoom_animating = total_time
animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL)
zoom_animating = 0
@@ -150,18 +134,10 @@
/obj/item/gun/energy/beam_rifle/proc/handle_zooming()
if(!zooming || !check_user())
return
- if(zoom_speed == ZOOM_SPEED_INSTANT)
- current_user.client.change_view(world.view + zoom_target_view_increase)
- zoom_current_view_increase = zoom_target_view_increase
- set_autozoom_pixel_offsets_immediate(zooming_angle)
- smooth_zooming()
- return
- if(zoom_current_view_increase > zoom_target_view_increase)
- return
- zoom_current_view_increase++
- current_user.client.change_view(zoom_current_view_increase + world.view)
+ current_user.client.change_view(world.view + zoom_target_view_increase)
+ zoom_current_view_increase = zoom_target_view_increase
set_autozoom_pixel_offsets_immediate(zooming_angle)
- smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed)
+ smooth_zooming()
/obj/item/gun/energy/beam_rifle/proc/start_zooming()
if(zoom_lock == ZOOM_LOCK_OFF)
@@ -169,8 +145,9 @@
zooming = TRUE
/obj/item/gun/energy/beam_rifle/proc/stop_zooming()
- zooming = FALSE
- reset_zooming()
+ if(zooming)
+ zooming = FALSE
+ reset_zooming()
/obj/item/gun/energy/beam_rifle/proc/reset_zooming()
if(!check_user(FALSE))
@@ -204,14 +181,14 @@
/obj/item/gun/energy/beam_rifle/Initialize()
. = ..()
+ current_tracers = list()
START_PROCESSING(SSprojectiles, src)
- zoom_speed_action = new(src)
zoom_lock_action = new(src)
/obj/item/gun/energy/beam_rifle/Destroy()
STOP_PROCESSING(SSfastprocess, src)
set_user(null)
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/emp_act(severity)
@@ -245,6 +222,7 @@
/obj/item/gun/energy/beam_rifle/process()
if(!aiming)
+ last_process = world.time
return
check_user()
handle_zooming()
@@ -299,7 +277,7 @@
set waitfor = FALSE
aiming_time_left = aiming_time
aiming = FALSE
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
stop_zooming()
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
@@ -341,7 +319,7 @@
sync_ammo()
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
stop_aiming()
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
@@ -365,7 +343,7 @@
AC.sync_stats()
/obj/item/gun/energy/beam_rifle/proc/delay_penalty(amount)
- aiming_time_left = Clamp(aiming_time_left + amount, 0, aiming_time)
+ aiming_time_left = CLAMP(aiming_time_left + amount, 0, aiming_time)
/obj/item/ammo_casing/energy/beam_rifle
name = "particle acceleration lens"
@@ -416,11 +394,11 @@
HS_BB.stun = projectile_stun
HS_BB.impact_structure_damage = impact_structure_damage
HS_BB.aoe_mob_damage = aoe_mob_damage
- HS_BB.aoe_mob_range = Clamp(aoe_mob_range, 0, 15) //Badmin safety lock
+ HS_BB.aoe_mob_range = CLAMP(aoe_mob_range, 0, 15) //Badmin safety lock
HS_BB.aoe_fire_chance = aoe_fire_chance
HS_BB.aoe_fire_range = aoe_fire_range
HS_BB.aoe_structure_damage = aoe_structure_damage
- HS_BB.aoe_structure_range = Clamp(aoe_structure_range, 0, 15) //Badmin safety lock
+ HS_BB.aoe_structure_range = CLAMP(aoe_structure_range, 0, 15) //Badmin safety lock
HS_BB.wall_devastate = wall_devastate
HS_BB.wall_pierce_amount = wall_pierce_amount
HS_BB.structure_pierce_amount = structure_piercing
@@ -555,136 +533,103 @@
handle_impact(target)
/obj/item/projectile/beam/beam_rifle/Collide(atom/target)
- paused = TRUE
if(check_pierce(target))
permutated += target
return FALSE
if(!QDELETED(target))
cached = get_turf(target)
- paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
- paused = TRUE
if(!QDELETED(target))
cached = get_turf(target)
handle_hit(target)
- paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/hitscan
icon_state = ""
var/tracer_type = /obj/effect/projectile_beam/tracer
- var/starting_z
- var/starting_p_x
- var/starting_p_y
+ var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
var/constant_tracer = FALSE
- var/travelled_p_x = 0
- var/travelled_p_y = 0
- var/tracer_spawned = FALSE
+ var/beam_index
/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
- paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED!
- spawn_tracer(constant_tracer)
+ if(loc)
+ var/datum/point/pcache = trajectory.copy_to()
+ beam_segments[beam_index] = pcache
+ generate_tracers(constant_tracer)
return ..()
-/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE)
- if(tracer_spawned)
- return
- tracer_spawned = TRUE
- //Remind me to port baystation trajectories so this shit isn't needed...
- var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1)
- var/scaling = pixels_travelled/world.icon_size
- var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2))
- var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2))
- var/tracer_px = midpoint_p_x % world.icon_size
- var/tracer_py = midpoint_p_y % world.icon_size
- var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size
- var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size
- var/obj/effect/projectile_beam/PB = new tracer_type(src)
- PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z))
- if(put_in_rifle && istype(gun))
- if(gun.current_tracer)
- QDEL_NULL(gun.current_tracer)
- gun.current_tracer = PB
- else
- QDEL_IN(PB, 5)
+/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
+ var/datum/point/pcache = trajectory.copy_to()
+ . = ..()
+ if(. && !QDELETED(src)) //successful touch and not destroyed.
+ beam_segments[beam_index] = pcache
+ beam_index = pcache
+ beam_segments[beam_index] = null
-/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T)
- if(!istype(T))
- return TRUE
- var/tx = T.x
- var/ty = T.y
- if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10))
- return TRUE
- return FALSE
+/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
+ var/datum/point/pcache = trajectory.copy_to()
+ beam_segments[beam_index] = pcache
+ beam_index = RETURN_PRECISE_POINT(newloc)
+ beam_segments[beam_index] = null
+ return ..()
+
+/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
+ set waitfor = FALSE
+ if(highlander && istype(gun))
+ QDEL_LIST(gun.current_tracers)
+ for(var/datum/point/p in beam_segments)
+ gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
+ else
+ for(var/datum/point/p in beam_segments)
+ generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
+ if(cleanup)
+ QDEL_LIST(beam_segments)
+ beam_segments = null
+ QDEL_NULL(beam_index)
/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
- set waitfor = 0
+ set waitfor = FALSE
+ var/turf/starting = get_turf(src)
+ trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
if(!log_override && firer && original)
add_logs(firer, original, "fired at", src, " [get_area(src)]")
+ fired = TRUE
if(setAngle)
Angle = setAngle
- var/next_run = world.time
- var/old_pixel_x = pixel_x
- var/old_pixel_y = pixel_y
var/safety = 0 //The code works fine, but... just in case...
var/turf/c2
- var/starting_x = loc.x
- var/starting_y = loc.y
- starting_z = loc.z
- starting_p_x = starting_x * world.icon_size + pixel_x
- starting_p_y = starting_y * world.icon_size + pixel_y
+ beam_segments = list() //initialize segment list with the list for the first segment
+ beam_index = RETURN_PRECISE_POINT(src)
+ beam_segments[beam_index] = null //record start.
+ if(spread)
+ Angle += (rand() - 0.5) * spread
while(loc)
+ if(paused || QDELETED(src))
+ return
if(++safety > (range * 3)) //If it's looping for way, way too long...
+ qdel(src)
+ stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
return //Kill!
- if(spread)
- Angle += (rand() - 0.5) * spread
var/matrix/M = new
M.Turn(Angle)
transform = M
- var/Pixel_x=sin(Angle)+16*sin(Angle)*2
- var/Pixel_y=cos(Angle)+16*cos(Angle)*2
- travelled_p_x += Pixel_x
- travelled_p_y += Pixel_y
- var/pixel_x_offset = old_pixel_x + Pixel_x
- var/pixel_y_offset = old_pixel_y + Pixel_y
- var/new_x = x
- var/new_y = y
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- old_pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- old_pixel_x += 32
- new_x--
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- old_pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- old_pixel_y += 32
- new_y--
- pixel_x = old_pixel_x
- pixel_y = old_pixel_y
- step_towards(src, locate(new_x, new_y, z))
- next_run += max(world.tick_lag, speed)
- var/delay = next_run - world.time
- if(delay <= world.tick_lag*2)
- pixel_x = pixel_x_offset
- pixel_y = pixel_y_offset
+ trajectory.increment()
+ var/turf/T = trajectory.return_turf()
+ if(T.z != loc.z)
+ before_z_change(loc, T)
+ trajectory_ignore_forcemove = TRUE
+ forceMove(T)
+ trajectory_ignore_forcemove = FALSE
else
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
- old_pixel_x = pixel_x_offset
- old_pixel_y = pixel_y_offset
+ step_towards(src, T)
+ animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
+
if(can_hit_target(original, permutated))
Collide(original)
- c2 = loc
Range()
- if(check_for_turf_edge(loc))
- spawn_tracer(constant_tracer)
+ c2 = get_turf(src)
if(istype(c2))
cached = c2
@@ -704,76 +649,3 @@
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
qdel(src)
return FALSE
-
-/obj/effect/projectile_beam
- icon = 'icons/obj/projectiles.dmi'
- layer = ABOVE_MOB_LAYER
- anchored = TRUE
- light_power = 1
- light_range = 2
- light_color = "#00ffff"
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- flags_1 = ABSTRACT_1
- appearance_flags = 0
-
-/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
- var/matrix/M
- if(!override)
- M = transform
- else
- M = new
- M.Scale(nx,ny)
- transform = M
-
-/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
- var/matrix/M
- if(!override)
- M = transform
- else
- M = new
- M.Turn(angle)
- transform = M
-
-/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
- if(angle_override && p_x && p_y && color_override && scaling)
- apply_vars(angle_override, p_x, p_y, color_override, scaling)
- return ..()
-
-/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0)
- var/mutable_appearance/look = new(src)
- look.pixel_x = p_x
- look.pixel_y = p_y
- if(color_override)
- look.color = color_override
- appearance = look
- scale_to(1,scaling, FALSE)
- turn_to(angle_override, FALSE)
- if(!isnull(new_loc)) //If you want to null it just delete it...
- forceMove(new_loc)
- for(var/i in 1 to increment)
- pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
- pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
-
-/obj/effect/projectile_beam/tracer
- icon_state = "tracer_beam"
-
-/obj/effect/projectile_beam/tracer/aiming
- icon_state = "gbeam"
-
-/datum/action/item_action/zoom_speed_action
- name = "Toggle Zooming Speed"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
- button_icon_state = "projectile"
- background_icon_state = "bg_tech"
-
-/datum/action/item_action/zoom_lock_action
- name = "Switch Zoom Mode"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
- button_icon_state = "zoom_mode"
- background_icon_state = "bg_tech"
-
-/obj/effect/projectile_beam/singularity_pull()
- return
-
-/obj/effect/projectile_beam/singularity_act()
- return
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index f556bd3f58..b52a56426b 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -130,7 +130,7 @@
..()
if(!automatic_charge_overlays)
return
- var/ratio = Ceiling((cell.charge / cell.maxcharge) * charge_sections)
+ var/ratio = CEILING((cell.charge / cell.maxcharge) * charge_sections, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/iconState = "[icon_state]_charge"
var/itemState = null
@@ -175,7 +175,7 @@
return(OXYLOSS)
else
user.visible_message("[user] is pretending to blow [user.p_their()] brains out with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(src, "gun_dry_fire", 60, 1)
+ playsound(src, "gun_dry_fire", 30, 1)
return (OXYLOSS)
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/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 27fb040de4..bf3ade0748 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -12,9 +12,9 @@
/obj/item/gun/magic/wand/Initialize()
if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
if(prob(33))
- max_charges = Ceiling(max_charges / 3)
+ max_charges = CEILING(max_charges / 3, 1)
else
- max_charges = Ceiling(max_charges / 2)
+ max_charges = CEILING(max_charges / 2, 1)
return ..()
/obj/item/gun/magic/wand/examine(mob/user)
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index faf7de9010..6cbe2de450 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -129,7 +129,7 @@
// A gun with ultra-honk pin is useful for clown and useless for everyone else.
/obj/item/device/firing_pin/clown/ultra/pin_auth(mob/living/user)
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
- if(!(user.disabilities & CLUMSY) && !(user.mind && user.mind.assigned_role == "Clown"))
+ if(!(user.has_disability(CLUMSY)) && !(user.mind && user.mind.assigned_role == "Clown"))
return 0
return 1
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 0e3bd98c68..08142f1e8d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -31,16 +31,11 @@
var/last_projectile_move = 0
var/last_process = 0
var/time_offset = 0
- var/old_pixel_x = 0
- var/old_pixel_y = 0
- var/pixel_x_increment = 0
- var/pixel_y_increment = 0
- var/pixel_x_offset = 0
- var/pixel_y_offset = 0
- var/new_x = 0
- var/new_y = 0
+ var/datum/point/vector/trajectory
+ var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
+ var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
var/Angle = 0
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
var/spread = 0 //amount (in degrees) of projectile spread
@@ -48,6 +43,9 @@
var/ricochets = 0
var/ricochets_max = 2
var/ricochet_chance = 30
+
+ var/colliding = FALSE //pause processing..
+
var/ignore_source_check = FALSE
var/damage = 10
@@ -168,27 +166,35 @@
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
- return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
+ return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
+/obj/item/projectile/proc/on_ricochet(atom/A)
+ return
+
/obj/item/projectile/Collide(atom/A)
+ colliding = TRUE
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
ricochets++
if(A.handle_ricochet(src))
+ on_ricochet(A)
ignore_source_check = TRUE
range = initial(range)
- return FALSE
+ return TRUE
if(firer && !ignore_source_check)
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
- loc = A.loc
+ trajectory_ignore_forcemove = TRUE
+ forceMove(get_turf(A))
+ trajectory_ignore_forcemove = FALSE
+ colliding = FALSE
return FALSE
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
- var/volume = Clamp(vol_by_damage() + 20, 0, 100)
+ var/volume = CLAMP(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
@@ -197,25 +203,32 @@
if(!prehit(A))
if(forcedodge)
- loc = target_turf
+ trajectory_ignore_forcemove = TRUE
+ forceMove(target_turf)
+ trajectory_ignore_forcemove = FALSE
+ colliding = FALSE
return FALSE
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
- loc = target_turf
+ trajectory_ignore_forcemove = TRUE
+ forceMove(target_turf)
+ trajectory_ignore_forcemove = FALSE
if(A)
permutated.Add(A)
+ colliding = FALSE
return FALSE
else
var/atom/alt = select_target(A)
if(alt)
if(!prehit(alt))
+ colliding = FALSE
return FALSE
alt.bullet_act(src, def_zone)
qdel(src)
+ colliding = FALSE
return TRUE
-
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
return
@@ -246,12 +259,30 @@
return TRUE
return FALSE
+/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
+ if(!trajectory && isnull(forced_angle) && isnull(Angle))
+ return FALSE
+ var/datum/point/vector/current = trajectory
+ if(!current)
+ var/turf/T = get_turf(src)
+ current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed)
+ var/datum/point/vector/v = current.return_vector_after_increments(moves)
+ return v.return_turf()
+
+/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
+ var/turf/current = get_turf(src)
+ var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
+ return getline(current, ending)
+
+/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
+ return
+
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return TRUE //Bullets don't drift in space
/obj/item/projectile/process()
last_process = world.time
- if(!loc || !fired)
+ if(!loc || !fired || !trajectory)
fired = FALSE
return PROCESS_KILL
if(paused || !isturf(loc))
@@ -259,7 +290,7 @@
return
var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset
time_offset = 0
- var/required_moves = speed > 0? Floor(elapsed_time_deciseconds / speed) : MOVES_HITSCAN //Would be better if a 0 speed made hitscan but everyone hates those so I can't make it a universal system :<
+ var/required_moves = speed > 0? FLOOR(elapsed_time_deciseconds / speed, 1) : MOVES_HITSCAN //Would be better if a 0 speed made hitscan but everyone hates those so I can't make it a universal system :<
if(required_moves == MOVES_HITSCAN)
required_moves = SSprojectiles.global_max_tick_moves
else
@@ -267,7 +298,7 @@
var/overrun = required_moves - SSprojectiles.global_max_tick_moves
required_moves = SSprojectiles.global_max_tick_moves
time_offset += overrun * speed
- time_offset += Modulus(elapsed_time_deciseconds, speed)
+ time_offset += MODULUS(elapsed_time_deciseconds, speed)
for(var/i in 1 to required_moves)
pixel_move(required_moves)
@@ -285,73 +316,70 @@
setAngle(angle)
if(spread)
setAngle(Angle + ((rand() - 0.5) * spread))
+ var/turf/starting = get_turf(src)
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
- var/turf/starting = get_turf(src)
- var/turf/target = locate(Clamp(starting + xo, 1, world.maxx), Clamp(starting + yo, 1, world.maxy), starting.z)
+ if(isnull(xo) || isnull(yo))
+ stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
+ qdel(src)
+ return
+ var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
setAngle(Get_Angle(src, target))
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
- old_pixel_x = pixel_x
- old_pixel_y = pixel_y
+ trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
last_projectile_move = world.time
fired = TRUE
if(!isprocessing)
START_PROCESSING(SSprojectiles, src)
+ pixel_move(1) //move it now!
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
Angle = new_angle
- return TRUE
-
-/obj/item/projectile/proc/pixel_move(moves)
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
+ if(trajectory)
+ trajectory.set_angle(new_angle)
+ return TRUE
- pixel_x_increment=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
- pixel_y_increment=round((cos(Angle)+16*cos(Angle)*2), 1)
- pixel_x_offset = old_pixel_x + pixel_x_increment
- pixel_y_offset = old_pixel_y + pixel_y_increment
- new_x = x
- new_y = y
+/obj/item/projectile/forceMove(atom/target)
+ . = ..()
+ if(trajectory && !trajectory_ignore_forcemove && isturf(target))
+ trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- old_pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- old_pixel_x += 32
- new_x--
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- old_pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- old_pixel_y += 32
- new_y--
+/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
+ if(!loc || !trajectory)
+ return
+ last_projectile_move = world.time
+ if(!nondirectional_sprite)
+ var/matrix/M = new
+ M.Turn(Angle)
+ transform = M
+ trajectory.increment(trajectory_multiplier)
+ var/turf/T = trajectory.return_turf()
+ if(T.z != loc.z)
+ before_z_change(loc, T)
+ trajectory_ignore_forcemove = TRUE
+ forceMove(T)
+ trajectory_ignore_forcemove = FALSE
+ pixel_x = trajectory.return_px()
+ pixel_y = trajectory.return_py()
+ else
+ step_towards(src, T)
+ pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
+ pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
+ animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
- step_towards(src, locate(new_x, new_y, z))
- pixel_x = old_pixel_x
- pixel_y = old_pixel_y
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = 1, flags = ANIMATION_END_NOW)
- old_pixel_x = pixel_x_offset
- old_pixel_y = pixel_y_offset
if(can_hit_target(original, permutated))
Collide(original)
Range()
- last_projectile_move = world.time
//Returns true if the target atom is on our current turf and above the right layer
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
- if(target && (target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target))
- if(loc == get_turf(target))
- if(!(target in passthrough))
- return TRUE
- return FALSE
+ return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
var/turf/curloc = get_turf(source)
@@ -362,7 +390,8 @@
if(targloc || !params)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
-
+ setAngle(Get_Angle(src, targloc))
+
if(isliving(source) && params)
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
p_x = calculated[2]
@@ -372,8 +401,13 @@
setAngle(calculated[1] + spread)
else
setAngle(calculated[1])
- else
+ else if(targloc)
+ yo = targloc.y - curloc.y
+ xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc))
+ else
+ stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
+ qdel(src)
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
var/list/mouse_control = params2list(params)
@@ -403,7 +437,7 @@
var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
- angle = Atan2(y - oy, x - ox)
+ angle = ATAN2(y - oy, x - ox)
return list(angle, p_x, p_y)
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 9c4bff72cb..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
@@ -580,7 +592,7 @@
if (R.id == reagent)
//clamp the removal amount to be between current reagent amount
//and zero, to prevent removing more than the holder has stored
- amount = Clamp(amount, 0, R.volume)
+ amount = CLAMP(amount, 0, R.volume)
R.volume -= amount
update_total()
if(!safety)//So it does not handle reactions when it need not to
@@ -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 745843474e..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)
@@ -211,7 +211,7 @@
/obj/machinery/chem_dispenser/emp_act(severity)
var/list/datum/reagents/R = list()
- var/total = min(rand(7,15), Floor(cell.charge*powerefficiency))
+ var/total = min(rand(7,15), FLOOR(cell.charge*powerefficiency, 1))
var/datum/reagents/Q = new(total*10)
if(beaker && beaker.reagents)
R += beaker.reagents
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index a6d958220a..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]!")
@@ -126,7 +126,7 @@
target = text2num(target)
. = TRUE
if(.)
- target_temperature = Clamp(target, 0, 1000)
+ target_temperature = CLAMP(target, 0, 1000)
if("eject")
on = FALSE
eject_beaker()
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 3e06449e3a..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!")
@@ -215,7 +215,7 @@
var/amount = 1
var/vol_each = min(reagents.total_volume, 50)
if(text2num(many))
- amount = Clamp(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0, 10)
+ amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 50)
@@ -251,7 +251,7 @@
var/amount = 1
var/vol_each = min(reagents.total_volume, 40)
if(text2num(many))
- amount = Clamp(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0, 10)
+ amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 40)
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 223259f6f3..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!")
@@ -294,7 +294,7 @@
/obj/machinery/reagentgrinder/proc/mix_complete()
if(beaker && beaker.reagents.total_volume)
//Recipe to make Butter
- var/butter_amt = Floor(beaker.reagents.get_reagent_amount("milk") / MILK_TO_BUTTER_COEFF)
+ var/butter_amt = FLOOR(beaker.reagents.get_reagent_amount("milk") / MILK_TO_BUTTER_COEFF, 1)
beaker.reagents.remove_reagent("milk", MILK_TO_BUTTER_COEFF * butter_amt)
for(var/i in 1 to butter_amt)
new /obj/item/reagent_containers/food/snacks/butter(drop_location())
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.dm b/code/modules/reagents/chemistry/reagents.dm
index 5f76a87654..9f8e129420 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -41,7 +41,7 @@
return 0
if(method == VAPOR) //smoke, foam, spray
if(M.reagents)
- var/modifier = Clamp((1 - touch_protection), 0, 1)
+ var/modifier = CLAMP((1 - touch_protection), 0, 1)
var/amount = round(reac_volume*modifier, 0.1)
if(amount >= 0.5)
M.reagents.add_reagent(id, amount)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 6a3b1a1637..00fd7d56a3 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -961,7 +961,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
var/datum/antagonist/changeling/changeling = M.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
changeling.chem_charges += metabolization_rate
- changeling.chem_charges = Clamp(changeling.chem_charges, 0, changeling.chem_storage)
+ changeling.chem_charges = CLAMP(changeling.chem_charges, 0, changeling.chem_storage)
return ..()
/datum/reagent/consumable/ethanol/irishcarbomb
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index b62afb80c0..0bb00f5b49 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -70,7 +70,7 @@
//nothing
if(21 to INFINITY)
if(prob(current_cycle-10))
- M.cure_nearsighted()
+ M.cure_nearsighted(list(EYE_DAMAGE))
..()
return
@@ -172,6 +172,22 @@
M.emote("laugh")
..()
+/datum/reagent/consumable/superlaughter
+ name = "Super Laughter"
+ id = "superlaughter"
+ description = "Funny until you're the one laughing."
+ metabolization_rate = 1.5 * REAGENTS_METABOLISM
+ color = "#FF4DD2"
+ taste_description = "laughter"
+
+/datum/reagent/consumable/superlaughter/on_mob_life(mob/living/carbon/M)
+ if(!iscarbon(M))
+ return
+ if(prob(30))
+ M.visible_message("[M] bursts out into a fit of uncontrollable laughter!", "You burst out in a fit of uncontrollable laughter!")
+ M.Stun(5)
+ ..()
+
/datum/reagent/consumable/potato_juice
name = "Potato Juice"
id = "potato"
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/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index ddb08db032..03134784a4 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -44,7 +44,7 @@
M.adjustToxLoss(-5, 0)
M.hallucination = 0
M.setBrainLoss(0)
- M.disabilities = 0
+ M.remove_all_disabilities()
M.set_blurriness(0)
M.set_blindness(0)
M.SetKnockdown(0, 0)
@@ -667,16 +667,16 @@
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
return
- if(M.disabilities & BLIND)
+ if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "Your vision slowly returns...")
- M.cure_blind()
- M.cure_nearsighted()
+ M.cure_blind(EYE_DAMAGE)
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
- else if(M.disabilities & NEARSIGHT)
+ else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "The blackness in your peripheral vision fades.")
- M.cure_nearsighted()
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
@@ -765,7 +765,7 @@
M.visible_message("[M]'s body convulses a bit, and then falls still once more.")
return
M.visible_message("[M]'s body convulses a bit.")
- if(!M.suiciding && !(M.disabilities & NOCLONE) && !M.hellbound)
+ if(!M.suiciding && !(M.has_disability(NOCLONE)) && !M.hellbound)
if(!M)
return
if(M.notify_ghost_cloning(source = M))
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 711c333896..0a6288896a 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -141,7 +141,7 @@
taste_description = "mint"
/datum/reagent/toxin/minttoxin/on_mob_life(mob/living/M)
- if(M.disabilities & FAT)
+ if(M.has_disability(FAT))
M.gib()
return ..()
@@ -850,9 +850,9 @@
/datum/reagent/toxin/peaceborg/confuse/on_mob_life(mob/living/M)
if(M.confused < 6)
- M.confused = Clamp(M.confused + 3, 0, 5)
+ M.confused = CLAMP(M.confused + 3, 0, 5)
if(M.dizziness < 6)
- M.dizziness = Clamp(M.dizziness + 3, 0, 5)
+ M.dizziness = CLAMP(M.dizziness + 3, 0, 5)
if(prob(20))
to_chat(M, "You feel confused and disorientated.")
..()
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 0e645e3798..b77dcc435a 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -168,7 +168,7 @@
return
holder.remove_reagent("sorium", created_volume*4)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume*4), 1, 6)
+ var/range = CLAMP(sqrt(created_volume*4), 1, 6)
goonchem_vortex(T, 1, range)
/datum/chemical_reaction/sorium_vortex
@@ -179,7 +179,7 @@
/datum/chemical_reaction/sorium_vortex/on_reaction(datum/reagents/holder, created_volume)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume), 1, 6)
+ var/range = CLAMP(sqrt(created_volume), 1, 6)
goonchem_vortex(T, 1, range)
/datum/chemical_reaction/liquid_dark_matter
@@ -193,7 +193,7 @@
return
holder.remove_reagent("liquid_dark_matter", created_volume*3)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume*3), 1, 6)
+ var/range = CLAMP(sqrt(created_volume*3), 1, 6)
goonchem_vortex(T, 0, range)
/datum/chemical_reaction/ldm_vortex
@@ -204,7 +204,7 @@
/datum/chemical_reaction/ldm_vortex/on_reaction(datum/reagents/holder, created_volume)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume/2), 1, 6)
+ var/range = CLAMP(sqrt(created_volume/2), 1, 6)
goonchem_vortex(T, 0, range)
/datum/chemical_reaction/flash_powder
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..e736c344db 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -130,6 +130,18 @@ Borg Hypospray
reagent_ids = list ("facid", "mutetoxin", "cyanide", "sodium_thiopental", "heparin", "lexorin")
accepts_reagent_upgrades = FALSE
+/obj/item/reagent_containers/borghypo/clown
+ name = "laughter injector"
+ desc = "Keeps the crew happy and productive!"
+ reagent_ids = list("laughter")
+ accepts_reagent_upgrades = FALSE
+
+/obj/item/reagent_containers/borghypo/clown/hacked
+ name = "laughter injector"
+ desc = "Keeps the crew so happy they don't work!"
+ reagent_ids = list("superlaughter")
+ accepts_reagent_upgrades = FALSE
+
/obj/item/reagent_containers/borghypo/syndicate
name = "syndicate cyborg hypospray"
desc = "An experimental piece of Syndicate technology used to produce powerful restorative nanites used to very quickly restore injuries of all types. Also metabolizes potassium iodide, for radiation poisoning, and morphine, for offense."
@@ -173,7 +185,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..f79418eee5 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
@@ -18,22 +18,22 @@
var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode.
var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode.
var/stream_amount = 10 //the amount of reagents transfered when in stream mode.
+ var/can_fill_from_container = TRUE
amount_per_transfer_from_this = 5
volume = 250
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 && can_fill_from_container)
+ 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"
@@ -197,6 +205,46 @@
/obj/item/reagent_containers/spray/waterflower/attack_self(mob/user) //Don't allow changing how much the flower sprays
return
+/obj/item/reagent_containers/spray/waterflower/cyborg
+ container_type = NONE
+ volume = 100
+ list_reagents = list("water" = 100)
+ var/generate_amount = 5
+ var/generate_type = "water"
+ var/last_generate = 0
+ var/generate_delay = 10 //deciseconds
+ can_fill_from_container = FALSE
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/hacked
+ name = "nova flower"
+ desc = "This doesn't look safe at all..."
+ list_reagents = list("clf3" = 3)
+ volume = 3
+ generate_type = "clf3"
+ generate_amount = 1
+ generate_delay = 40 //deciseconds
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Initialize()
+ . = ..()
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/process()
+ if(world.time > last_generate + generate_delay)
+ return
+ last_generate = world.time
+ generate_reagents()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/empty()
+ to_chat(usr, "You can not empty this!")
+ return
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/proc/generate_reagents()
+ reagents.add_reagent(generate_type, generate_amount)
+
//chemsprayer
/obj/item/reagent_containers/spray/chemsprayer
name = "chem sprayer"
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 87fb2b8a9e..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)
@@ -157,7 +154,7 @@
/obj/item/reagent_containers/syringe/update_icon()
- var/rounded_vol = Clamp(round((reagents.total_volume / volume * 15),5), 0, 15)
+ var/rounded_vol = CLAMP(round((reagents.total_volume / volume * 15),5), 0, 15)
cut_overlays()
if(ismob(loc))
var/injoverlay
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/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index aa41763cfa..62965f7ca1 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -297,7 +297,7 @@
data["full_pressure"] = full_pressure
data["pressure_charging"] = pressure_charging
data["panel_open"] = panel_open
- var/per = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
+ var/per = CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
data["per"] = round(per, 1)
data["isai"] = isAI(user)
return data
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..b3b0f8df99 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -43,11 +43,17 @@ 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)
+ send_asset(user, "design_[id].png", 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 39fd0bf182..ebcea57b6d 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"
@@ -681,7 +673,7 @@
category = list("hacked", "Security")
/datum/design/a357
- name = "Ammo Box (.357)"
+ name = "Speed Loader (.357)"
id = "a357"
build_type = AUTOLATHE
materials = list(MAT_METAL = 30000)
@@ -822,3 +814,12 @@
materials = list(MAT_METAL = 1000)
build_path = /obj/item/disk/holodisk
category = list("initial", "Misc")
+
+//CITADEL
+/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")
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 2343bd8814..059d9c982c 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -111,6 +111,7 @@
desc = "The circuit board for a sleeper."
id = "sleeper"
build_path = /obj/item/circuitboard/machine/sleeper
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/cryotube
@@ -118,6 +119,7 @@
desc = "The circuit board for a cryotube."
id = "cryotube"
build_path = /obj/item/circuitboard/machine/cryo_tube
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/chem_dispenser
@@ -125,12 +127,14 @@
desc = "The circuit board for a portable chem dispenser."
id = "chem_dispenser"
build_path = /obj/item/circuitboard/machine/chem_dispenser
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/chem_master
name = "Machine Design (Chem Master Board)"
desc = "The circuit board for a Chem Master 3000."
id = "chem_master"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/chem_master
category = list ("Medical Machinery")
@@ -138,6 +142,7 @@
name = "Machine Design (Chemical Heater Board)"
desc = "The circuit board for a chemical heater."
id = "chem_heater"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/chem_heater
category = list ("Medical Machinery")
@@ -153,12 +158,14 @@
desc = "Allows for the construction of circuit boards used to build a new Cloning Machine console."
id = "clonecontrol"
build_path = /obj/item/circuitboard/computer/cloning
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list("Medical Machinery")
/datum/design/board/clonepod
name = "Machine Design (Clone Pod)"
desc = "Allows for the construction of circuit boards used to build a Cloning Pod."
id = "clonepod"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/clonepod
category = list("Medical Machinery")
@@ -166,6 +173,7 @@
name = "Machine Design (Cloning Scanner)"
desc = "Allows for the construction of circuit boards used to build a Cloning Scanner."
id = "clonescanner"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/clonescanner
category = list("Medical Machinery")
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 6c52fd4678..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
..()
@@ -93,7 +93,7 @@ Note: Must be placed west/left of and R&D console to function.
return FALSE
var/power = 1000
- amount = Clamp(amount, 1, 10)
+ amount = CLAMP(amount, 1, 10)
for(var/M in D.materials)
power += round(D.materials[M] * amount / 5)
power = max(3000, power)
@@ -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 7d8ff00e91..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
@@ -295,7 +295,7 @@
return ..()
to_chat(user, "
You feed the slime the stabilizer. It is now less likely to mutate.")
- M.mutation_chance = Clamp(M.mutation_chance-15,0,100)
+ M.mutation_chance = CLAMP(M.mutation_chance-15,0,100)
qdel(src)
/obj/item/slimepotion/mutator
@@ -319,7 +319,7 @@
return ..()
to_chat(user, "
You feed the slime the mutator. It is now more likely to mutate.")
- M.mutation_chance = Clamp(M.mutation_chance+12,0,100)
+ M.mutation_chance = CLAMP(M.mutation_chance+12,0,100)
M.mutator_used = TRUE
qdel(src)
@@ -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/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index de1b0022f6..263901a763 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -119,7 +119,7 @@
return
if(!my_port)
- my_port = new(locate(eyeobj.x - x_offset, eyeobj.y - y_offset, eyeobj.z))
+ my_port = new()
my_port.name = shuttlePortName
my_port.id = shuttlePortId
my_port.height = shuttle_port.height
@@ -128,6 +128,7 @@
my_port.dwidth = shuttle_port.dwidth
my_port.hidden = shuttle_port.hidden
my_port.dir = the_eye.dir
+ my_port.forceMove(locate(eyeobj.x - x_offset, eyeobj.y - y_offset, eyeobj.z))
if(current_user.client)
current_user.client.images -= the_eye.placed_images
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index e97bdc41c6..962a17caeb 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -146,13 +146,13 @@
var/y0 = bounds[2]
var/x1 = bounds[3]
var/y1 = bounds[4]
- if(x0 <= x1 && !IsInRange(T.x, x0, x1))
+ if(x0 <= x1 && !ISINRANGE(T.x, x0, x1))
return FALSE
- else if(!IsInRange(T.x, x1, x0))
+ else if(!ISINRANGE(T.x, x1, x0))
return FALSE
- if(y0 <= y1 && !IsInRange(T.y, y0, y1))
+ if(y0 <= y1 && !ISINRANGE(T.y, y0, y1))
return FALSE
- else if(!IsInRange(T.y, y1, y0))
+ else if(!ISINRANGE(T.y, y1, y0))
return FALSE
return TRUE
@@ -697,13 +697,13 @@
var/change_per_engine = (1 - ENGINE_COEFF_MIN) / ENGINE_DEFAULT_MAXSPEED_ENGINES // 5 by default
if(initial_engines > 0)
change_per_engine = (1 - ENGINE_COEFF_MIN) / initial_engines // or however many it had
- return Clamp(1 - delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
+ return CLAMP(1 - delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
if(new_value < initial_engines)
var/delta = initial_engines - new_value
var/change_per_engine = 1 //doesn't really matter should not be happening for 0 engine shuttles
if(initial_engines > 0)
change_per_engine = (ENGINE_COEFF_MAX - 1) / initial_engines //just linear drop to max delay
- return Clamp(1 + delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
+ return CLAMP(1 + delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
/obj/docking_port/mobile/proc/in_flight()
diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm
index 283ac0f35c..ee5a435a86 100644
--- a/code/modules/shuttle/syndicate.dm
+++ b/code/modules/shuttle/syndicate.dm
@@ -56,8 +56,8 @@
shuttlePortName = "custom location"
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
view_range = 13
- x_offset = -4
- y_offset = -2
+ x_offset = -7
+ y_offset = -1
see_hidden = TRUE
#undef SYNDICATE_CHALLENGE_TIMER
\ No newline at end of file
diff --git a/code/modules/space_transition/space_transition.dm b/code/modules/space_transition/space_transition.dm
index 2a8be8a761..edcad9b620 100644
--- a/code/modules/space_transition/space_transition.dm
+++ b/code/modules/space_transition/space_transition.dm
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[A] = src
/datum/space_level/proc/set_neigbours(list/L)
- for(var/datum/point/P in L)
+ for(var/datum/space_transition_point/P in L)
if(P.x == xi)
if(P.y == yi+1)
neigbours[TEXT_NORTH] = P.spl
@@ -35,13 +35,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[TEXT_WEST] = P.spl
P.spl.neigbours[TEXT_EAST] = src
-/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
+/datum/space_transition_point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
var/list/neigbours = list()
var/x
var/y
var/datum/space_level/spl
-/datum/point/New(nx, ny, list/point_grid)
+/datum/space_transition_point/New(nx, ny, list/point_grid)
if(!point_grid)
qdel(src)
return
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
return
point_grid[x][y] = src
-/datum/point/proc/set_neigbours(list/grid)
+/datum/space_transition_point/proc/set_neigbours(list/grid)
var/max_X = grid.len
var/list/max_Y = grid[1]
max_Y = max_Y.len
@@ -86,13 +86,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
k++
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
var/list/grid = list()
- var/datum/point/P
+ var/datum/space_transition_point/P
for(var/i = 1, i<=conf_set_len*2+1, i++)
for(var/j = 1, j<=conf_set_len*2+1, j++)
- P = new/datum/point(i,j, point_grid)
+ P = new/datum/space_transition_point(i,j, point_grid)
point_grid[i][j] = P
grid.Add(P)
- for(var/datum/point/pnt in grid)
+ for(var/datum/space_transition_point/pnt in grid)
pnt.set_neigbours(point_grid)
P = point_grid[conf_set_len+1][conf_set_len+1]
var/list/possible_points = list()
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index ca6a534ee0..8e9b4fb1e4 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -209,12 +209,14 @@
to_chat(target, "
A freezing darkness surrounds you...")
target.playsound_local(get_turf(target), 'sound/hallucinations/i_see_you1.ogg', 50, 1)
user.playsound_local(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
- target.adjust_blindness(5)
+ target.become_blind("abyssal_gaze")
addtimer(CALLBACK(src, .proc/cure_blindness, target), 40)
target.bodytemperature -= 200
/obj/effect/proc_holder/spell/targeted/abyssal_gaze/proc/cure_blindness(mob/target)
- target.adjust_blindness(-5)
+ if(isliving(target))
+ var/mob/living/L = target
+ L.cure_blind(BLIND, "abyssal_gaze")
/obj/effect/proc_holder/spell/targeted/dominate
name = "Dominate"
diff --git a/code/modules/spells/spell_types/genetic.dm b/code/modules/spells/spell_types/genetic.dm
index c6945dab50..1b60800458 100644
--- a/code/modules/spells/spell_types/genetic.dm
+++ b/code/modules/spells/spell_types/genetic.dm
@@ -1,32 +1,34 @@
-/obj/effect/proc_holder/spell/targeted/genetic
- name = "Genetic"
- desc = "This spell inflicts a set of mutations and disabilities upon the target."
-
- var/disabilities = 0 //bits
- var/list/mutations = list() //mutation strings
- var/duration = 100 //deciseconds
- /*
- Disabilities
- 1st bit - ?
- 2nd bit - ?
- 3rd bit - ?
- 4th bit - ?
- 5th bit - ?
- 6th bit - ?
- */
-
-/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
- playMagSound()
- for(var/mob/living/carbon/target in targets)
- if(!target.dna)
- continue
- for(var/A in mutations)
- target.dna.add_mutation(A)
- target.disabilities |= disabilities
+/obj/effect/proc_holder/spell/targeted/genetic
+ name = "Genetic"
+ desc = "This spell inflicts a set of mutations and disabilities upon the target."
+
+ var/list/disabilities = list() //disabilities
+ var/list/mutations = list() //mutation strings
+ var/duration = 100 //deciseconds
+ /*
+ Disabilities
+ 1st bit - ?
+ 2nd bit - ?
+ 3rd bit - ?
+ 4th bit - ?
+ 5th bit - ?
+ 6th bit - ?
+ */
+
+/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
+ playMagSound()
+ for(var/mob/living/carbon/target in targets)
+ if(!target.dna)
+ continue
+ for(var/A in mutations)
+ target.dna.add_mutation(A)
+ for(var/A in disabilities)
+ target.add_disability(A, GENETICS_SPELL)
addtimer(CALLBACK(src, .proc/remove, target), duration)
/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target)
if(!QDELETED(target))
for(var/A in mutations)
target.dna.remove_mutation(A)
- target.disabilities &= ~disabilities
+ for(var/A in disabilities)
+ target.remove_disability(A, GENETICS_SPELL)
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/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm
index ab4be6bafc..b36dfc885d 100644
--- a/code/modules/spells/spell_types/wizard.dm
+++ b/code/modules/spells/spell_types/wizard.dm
@@ -289,7 +289,7 @@
var/mob/living/M = AM
M.Knockdown(stun_amt)
to_chat(M, "
You're thrown back by [user]!")
- AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time.
+ AM.throw_at(throwtarget, ((CLAMP((maxthrow - (CLAMP(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time.
/obj/effect/proc_holder/spell/aoe_turf/repulse/xeno //i fixed conflicts only to find out that this is in the WIZARD file instead of the xeno file?!
name = "Tail Sweep"
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/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 790942d897..474075591f 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -217,7 +217,7 @@
C = owner
no_update = 0
- if(C.disabilities & HUSK)
+ if(C.has_disability(HUSK))
species_id = "husk" //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 0078c0594f..63b955a571 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -18,7 +18,7 @@
return 0
var/obj/item/bodypart/affecting = C.get_bodypart("chest")
- affecting.receive_damage(Clamp(brute_dam/2, 15, 50), Clamp(burn_dam/2, 0, 50)) //Damage the chest based on limb's existing damage
+ affecting.receive_damage(CLAMP(brute_dam/2, 15, 50), CLAMP(burn_dam/2, 0, 50)) //Damage the chest based on limb's existing damage
C.visible_message("
[C]'s [src.name] has been violently dismembered!")
C.emote("scream")
drop_limb()
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index f631400bee..464da21e44 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -61,7 +61,7 @@
C = owner
real_name = C.real_name
- if(C.disabilities & HUSK)
+ if(C.has_disability(HUSK))
real_name = "Unknown"
hair_style = "Bald"
facial_hair_style = "Shaved"
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index c8a47d2096..00a9a99bb0 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -23,9 +23,9 @@
/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] successfully fixes [target]'s eyes!", "
You succeed in fixing [target]'s eyes.")
- target.cure_blind()
+ target.cure_blind(list(EYE_DAMAGE))
target.set_blindness(0)
- target.cure_nearsighted()
+ target.cure_nearsighted(list(EYE_DAMAGE))
target.blur_eyes(35) //this will fix itself slowly.
target.set_eye_damage(0)
return TRUE
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index 488f2e81b1..ba43a5cc3b 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -4,7 +4,7 @@
possible_locs = list("chest")
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
- if(target.disabilities & FAT)
+ if(target.has_disability(FAT))
return 1
return 0
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/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm
index 98b2a84ac0..905f9c2e1f 100644
--- a/code/modules/surgery/organs/ears.dm
+++ b/code/modules/surgery/organs/ears.dm
@@ -25,7 +25,7 @@
return
var/mob/living/carbon/C = owner
// genetic deafness prevents the body from using the ears, even if healthy
- if(C.disabilities & DEAF)
+ if(C.has_disability(DEAF))
deaf = max(deaf, 1)
else
if(C.ears && (C.ears.flags_2 & HEALS_EARS_2))
@@ -42,7 +42,7 @@
var/mob/living/carbon/C = owner
- if(iscarbon(owner) && C.disabilities & DEAF)
+ if(iscarbon(owner) && C.has_disability(DEAF))
deaf = 1
/obj/item/organ/ears/proc/adjustEarDamage(ddmg, ddeaf)
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 51e39605c4..f8f57c650f 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -199,7 +199,7 @@
return
var/range = input(user, "Enter range (0 - [max_light_beam_distance])", "Range Select", 0) as null|num
- set_distance(Clamp(range, 0, max_light_beam_distance))
+ set_distance(CLAMP(range, 0, max_light_beam_distance))
assume_rgb(C)
/obj/item/organ/eyes/robotic/glow/proc/assume_rgb(newcolor)
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 21d15fb609..5da89f125f 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -152,3 +152,17 @@
/obj/item/organ/heart/cybernetic/emp_act()
Stop()
+
+/obj/item/organ/heart/freedom
+ name = "heart of freedom"
+ desc = "This heart pumps with the passion to give... something freedom."
+ var/min_next_adrenaline = 0
+
+/obj/item/organ/heart/freedom/on_life()
+ . = ..()
+ if(owner.health < 5 && world.time > min_next_adrenaline)
+ min_next_adrenaline = world.time + rand(250, 600) //anywhere from 4.5 to 10 minutes
+ to_chat(owner, "
You feel yourself dying, but you refuse to give up!")
+ owner.heal_overall_damage(15, 15)
+ if(owner.reagents.get_reagent_amount("ephedrine") < 20)
+ owner.reagents.add_reagent("ephedrine", 10)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 02f1ee4ec3..102ac9720f 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -111,7 +111,7 @@
if(safe_oxygen_max)
if(O2_pp > safe_oxygen_max)
var/ratio = (breath_gases[/datum/gas/oxygen][MOLES]/safe_oxygen_max) * 10
- H.apply_damage_type(Clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type)
+ H.apply_damage_type(CLAMP(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type)
H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
else
H.clear_alert("too_much_oxy")
@@ -139,7 +139,7 @@
if(safe_nitro_max)
if(N2_pp > safe_nitro_max)
var/ratio = (breath_gases[/datum/gas/nitrogen][MOLES]/safe_nitro_max) * 10
- H.apply_damage_type(Clamp(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type)
+ H.apply_damage_type(CLAMP(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type)
H.throw_alert("too_much_nitro", /obj/screen/alert/too_much_nitro)
else
H.clear_alert("too_much_nitro")
@@ -205,7 +205,7 @@
if(safe_toxins_max)
if(Toxins_pp > safe_toxins_max)
var/ratio = (breath_gases[/datum/gas/plasma][MOLES]/safe_toxins_max) * 10
- H.apply_damage_type(Clamp(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type)
+ H.apply_damage_type(CLAMP(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type)
H.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
H.clear_alert("too_much_tox")
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index a8d6e7840a..ba988f450d 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -15,7 +15,8 @@
/datum/language/monkey,
/datum/language/narsie,
/datum/language/beachbum,
- /datum/language/ratvar
+ /datum/language/ratvar,
+ /datum/language/aphasia
))
/obj/item/organ/tongue/Initialize(mapload)
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 78f258be67..cc0324ab6a 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -119,7 +119,7 @@
///////////VOICE OF GOD///////////////
//////////////////////////////////////
-/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1)
+/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, message_admins = TRUE)
var/cooldown = 0
if(!user || !user.can_speak() || user.stat)
@@ -139,7 +139,9 @@
message = lowertext(message)
var/mob/living/list/listeners = list()
for(var/mob/living/L in get_hearers_in_view(8, user))
- if(L.can_hear() && !L.null_rod_check() && L != user && L.stat != DEAD)
+ if(L.can_hear() && !L.null_rod_check() && L.stat != DEAD)
+ if(L == user && !include_speaker)
+ continue
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
@@ -209,12 +211,12 @@
var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown")
var/static/regex/sleep_words = regex("sleep|slumber|rest")
- var/static/regex/vomit_words = regex("vomit|throw up")
- var/static/regex/silence_words = regex("shut up|silence|ssh|quiet|hush")
+ var/static/regex/vomit_words = regex("vomit|throw up|sick")
+ var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush")
var/static/regex/hallucinate_words = regex("see the truth|hallucinate")
var/static/regex/wakeup_words = regex("wake up|awaken")
- var/static/regex/heal_words = regex("live|heal|survive|mend|heroes never die")
- var/static/regex/hurt_words = regex("die|suffer|hurt|pain")
+ var/static/regex/heal_words = regex("live|heal|survive|mend|life|heroes never die")
+ var/static/regex/hurt_words = regex("die|suffer|hurt|pain|death")
var/static/regex/bleed_words = regex("bleed|there will be blood")
var/static/regex/burn_words = regex("burn|ignite")
var/static/regex/hot_words = regex("heat|hot|hell")
@@ -566,7 +568,8 @@
else
cooldown = COOLDOWN_NONE
- message_admins("[key_name_admin(user)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
+ if(message_admins)
+ message_admins("[key_name_admin(user)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
log_game("[key_name(user)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
SSblackbox.record_feedback("tally", "voice_of_god", 1, log_message)
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/code/modules/vehicles/pimpin_ride.dm b/code/modules/vehicles/pimpin_ride.dm
index 3925b863ff..88524366a6 100644
--- a/code/modules/vehicles/pimpin_ride.dm
+++ b/code/modules/vehicles/pimpin_ride.dm
@@ -13,6 +13,9 @@
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 7), TEXT_EAST = list(-12, 7), TEXT_WEST = list( 12, 7)))
+ if(floorbuffer)
+ AddComponent(/datum/component/cleaning)
+
/obj/vehicle/ridden/janicart/Destroy()
if(mybag)
qdel(mybag)
@@ -47,7 +50,7 @@
floorbuffer = TRUE
qdel(I)
to_chat(user, "
You upgrade [src] with the floor buffer.")
- flags_1 |= CLEAN_ON_MOVE_1
+ AddComponent(/datum/component/cleaning)
update_icon()
else
return ..()
diff --git a/config/config.txt b/config/config.txt
index fb648a5fa9..e43b38b568 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -1,3 +1,9 @@
+# You can use the "$include" directive to split your configs however you want
+
+$include game_options.txt
+$include dbconfig.txt
+$include comms.txt
+
# You can use the @ character at the beginning of a config option to lock it from being edited in-game
# Example usage:
# @SERVERNAME tgstation
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-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-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-4440.yml b/html/changelogs/AutoChangeLog-pr-4440.yml
new file mode 100644
index 0000000000..9d14363c8a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4440.yml
@@ -0,0 +1,4 @@
+author: "ninjanomnom"
+delete-after: True
+changes:
+ - bugfix: "Non movement keys pressed while moving no longer stop movement."
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-4447.yml b/html/changelogs/AutoChangeLog-pr-4447.yml
new file mode 100644
index 0000000000..09e363d971
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4447.yml
@@ -0,0 +1,4 @@
+author: "coiax"
+delete-after: True
+changes:
+ - rscadd: "Golems can now wear labcoats."
diff --git a/html/changelogs/AutoChangeLog-pr-4472.yml b/html/changelogs/AutoChangeLog-pr-4472.yml
new file mode 100644
index 0000000000..c6c38c1ae6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4472.yml
@@ -0,0 +1,7 @@
+author: "Xhuis"
+delete-after: True
+changes:
+ - bugfix: "You can no longer elect two Eminences simultaneously."
+ - bugfix: "The Eminence no longer drifts in space."
+ - tweak: "The Eminence's mass recall now works on unconscious servants."
+ - tweak: "The Eminence's messages now have follow links for observers."
diff --git a/html/changelogs/AutoChangeLog-pr-4482.yml b/html/changelogs/AutoChangeLog-pr-4482.yml
new file mode 100644
index 0000000000..210ad03b5b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4482.yml
@@ -0,0 +1,5 @@
+author: "Xhuis"
+delete-after: True
+changes:
+ - balance: "Floors blessed with holy water prevent servants from warping in and the Eminence from crossing them."
+ - balance: "The Eminence can never enter the Chapel."
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-4492.yml b/html/changelogs/AutoChangeLog-pr-4492.yml
new file mode 100644
index 0000000000..3b8e0de7e3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4492.yml
@@ -0,0 +1,4 @@
+author: "Awesine"
+delete-after: True
+changes:
+ - rscadd: "added some things which happen to be mining scanner things to that gulag thing"
diff --git a/html/changelogs/AutoChangeLog-pr-4494.yml b/html/changelogs/AutoChangeLog-pr-4494.yml
new file mode 100644
index 0000000000..d873e211a5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4494.yml
@@ -0,0 +1,6 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "Projectiles that pierce objects will no longer be thrown off course when doing so!"
+ - code_imp: "Projectiles now use /datum/point/vectors for trajectory calculations."
+ - bugfix: "Beam rifle reflections will no longer glitch out."
diff --git a/html/changelogs/AutoChangeLog-pr-4497.yml b/html/changelogs/AutoChangeLog-pr-4497.yml
new file mode 100644
index 0000000000..05673f222c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4497.yml
@@ -0,0 +1,4 @@
+author: "WJohnston"
+delete-after: True
+changes:
+ - tweak: "Syndicate nuke op infiltrator shuttle is no longer lopsided."
diff --git a/html/changelogs/AutoChangeLog-pr-4503.yml b/html/changelogs/AutoChangeLog-pr-4503.yml
new file mode 100644
index 0000000000..3cd060a535
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4503.yml
@@ -0,0 +1,5 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Clown modules have been added for cyborgs! Modules: Bikehorn, Airhorn, instrumental bikehorn, clown stamp, multicolor paint, rainbow crayon, soap, razor, purple lipstick, nonstunning selfcharging creampie cannon, nonslipping selfcharging water sprayer, lollipop fabricator, metallic picket sign, mini extinguisher, laughter reagent hypospray, and the ability to hug.
+experimental: When emagged they get a fire spray, \"super\" laughter injector, and shocking or crushing hugs. Also, the module is adminspawn only at the moment."
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/html/changelogs/AutoChangeLog-pr-4505.yml b/html/changelogs/AutoChangeLog-pr-4505.yml
new file mode 100644
index 0000000000..baf8daa374
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4505.yml
@@ -0,0 +1,6 @@
+author: "coiax"
+delete-after: True
+changes:
+ - balance: "The kitchen gibber must be anchored in order to use."
+ - balance: "The gibber requires bodies to have no external items or
+equipment."
diff --git a/html/changelogs/AutoChangeLog-pr-4506.yml b/html/changelogs/AutoChangeLog-pr-4506.yml
new file mode 100644
index 0000000000..0b2d10fffe
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4506.yml
@@ -0,0 +1,4 @@
+author: "Dax Dupont"
+delete-after: True
+changes:
+ - bugfix: "Borgs will no longer have their metal/glass/etc stacks commit sudoku when it runs out of metal. They will also show the correct amount instead of a constant of \"1\" on menu interaction."
diff --git a/html/changelogs/AutoChangeLog-pr-4507.yml b/html/changelogs/AutoChangeLog-pr-4507.yml
new file mode 100644
index 0000000000..3076537362
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4507.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-4509.yml b/html/changelogs/AutoChangeLog-pr-4509.yml
new file mode 100644
index 0000000000..0be18e6c47
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4509.yml
@@ -0,0 +1,4 @@
+author: "Robustin"
+delete-after: True
+changes:
+ - tweak: "The EMP door shocking effect has a new formula. Heavy EMP's will no longer shock doors while light EMP's have a 10% chance (down from 13.33%)."
diff --git a/html/changelogs/AutoChangeLog-pr-4516.yml b/html/changelogs/AutoChangeLog-pr-4516.yml
new file mode 100644
index 0000000000..66e1e9c6f3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4516.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "\"Download N research nodes\" objective is now checked correctly again."
diff --git a/html/changelogs/AutoChangeLog-pr-4519.yml b/html/changelogs/AutoChangeLog-pr-4519.yml
new file mode 100644
index 0000000000..aa0bf5a78d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4519.yml
@@ -0,0 +1,4 @@
+author: "Frozenguy5"
+delete-after: True
+changes:
+ - bugfix: "Soapstones now give the correct time they were placed down."
diff --git a/html/changelogs/AutoChangeLog-pr-4521.yml b/html/changelogs/AutoChangeLog-pr-4521.yml
new file mode 100644
index 0000000000..2b5553d55f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4521.yml
@@ -0,0 +1,4 @@
+author: "More Robust Than You"
+delete-after: True
+changes:
+ - tweak: "Vending machines now use TGUI"
diff --git a/html/changelogs/AutoChangeLog-pr-4527.yml b/html/changelogs/AutoChangeLog-pr-4527.yml
new file mode 100644
index 0000000000..0dbcc75089
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4527.yml
@@ -0,0 +1,4 @@
+author: "coiax"
+delete-after: True
+changes:
+ - rscadd: "Ghosts can now use the *spin and *flip emotes."
diff --git a/html/changelogs/AutoChangeLog-pr-4534.yml b/html/changelogs/AutoChangeLog-pr-4534.yml
new file mode 100644
index 0000000000..a699579ab8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4534.yml
@@ -0,0 +1,4 @@
+author: "ninjanomnom"
+delete-after: True
+changes:
+ - bugfix: "The auxiliary mining base can no longer be placed on top of lava, indestructible turfs, or inside particularly large ruins."
diff --git a/html/changelogs/AutoChangeLog-pr-4536.yml b/html/changelogs/AutoChangeLog-pr-4536.yml
new file mode 100644
index 0000000000..66d81c0738
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4536.yml
@@ -0,0 +1,4 @@
+author: "PsyKzz"
+delete-after: True
+changes:
+ - rscadd: "Jaws of life can now cut handcuffs"
diff --git a/html/changelogs/AutoChangeLog-pr-4542.yml b/html/changelogs/AutoChangeLog-pr-4542.yml
new file mode 100644
index 0000000000..f0edae6b07
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4542.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - admin: "Play Internet Sound now has an option to show the song title to players."
diff --git a/html/changelogs/AutoChangeLog-pr-4543.yml b/html/changelogs/AutoChangeLog-pr-4543.yml
new file mode 100644
index 0000000000..f8e25ac31a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4543.yml
@@ -0,0 +1,8 @@
+author: "XDTM"
+delete-after: True
+changes:
+ - balance: "Rebalanced healing symptoms."
+ - balance: "Cellular Molding was replaced by Nocturnal Regeneration, which only works in darkness."
+ - balance: "All healing symptoms now heal both brute and burn damage, although the basic ones will still be more effective on one damage type."
+ - balance: "Plasma Fixation and Radioactive Metabolism heal toxin damage, offsetting the damage done by their healing sources."
+ - balance: "Changed healing symptoms' stats, generally making them less punishing."
diff --git a/html/changelogs/AutoChangeLog-pr-4544.yml b/html/changelogs/AutoChangeLog-pr-4544.yml
new file mode 100644
index 0000000000..b2ab500474
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4544.yml
@@ -0,0 +1,5 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "Emagged cleanbots can acid people again"
+ - bugfix: "Headgear worn by monkeys can be affected by acid"
diff --git a/html/changelogs/AutoChangeLog-pr-4546.yml b/html/changelogs/AutoChangeLog-pr-4546.yml
new file mode 100644
index 0000000000..6a34ac9447
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4546.yml
@@ -0,0 +1,4 @@
+author: "Xhuis"
+delete-after: True
+changes:
+ - rscadd: "Maintenance drones and cogscarabs can now spawn with holiday-related hats on some holidays!"
diff --git a/html/changelogs/AutoChangeLog-pr-4551.yml b/html/changelogs/AutoChangeLog-pr-4551.yml
new file mode 100644
index 0000000000..e1aa612d9d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4551.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - code_imp: "The R&D console has been made more responsive by tweaking how design icons are loaded."
diff --git a/icons/misc/language.dmi b/icons/misc/language.dmi
index f4894c2b90..4e627f16c7 100644
Binary files a/icons/misc/language.dmi and b/icons/misc/language.dmi differ
diff --git a/icons/mob/landmarks.dmi b/icons/mob/landmarks.dmi
new file mode 100644
index 0000000000..120745ed44
Binary files /dev/null and b/icons/mob/landmarks.dmi differ
diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi
index 5d8bfa629b..fd145092a7 100644
Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ
diff --git a/icons/obj/assemblies/electronic_components.dmi b/icons/obj/assemblies/electronic_components.dmi
index 1852079e73..a9dac06d6b 100644
Binary files a/icons/obj/assemblies/electronic_components.dmi and b/icons/obj/assemblies/electronic_components.dmi differ
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/interface/stylesheet.dm b/interface/stylesheet.dm
index e1505d6088..ece61736ba 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -168,4 +168,7 @@ h1.alert, h2.alert {color: #000000;}
.resonate {color: #298F85;}
.love {color: #FF69Bf;}
.lovebold {color: #FF69Bf; font-weight: bold;}
+
+.monkeyhive {color: #774704;}
+.monkeylead {color: #774704; font-size: 2;}
"}
diff --git a/strings/brain_damage_lines.json b/strings/traumas.json
similarity index 82%
rename from strings/brain_damage_lines.json
rename to strings/traumas.json
index 4a28998e2c..9b14a7b530 100644
--- a/strings/brain_damage_lines.json
+++ b/strings/traumas.json
@@ -186,33 +186,55 @@
"",
";",
".h"
- ],
-
- "roles": [
- "heds",
- "ceptin",
- "hop",
- "arrdee",
- "sek"
- ],
-
- "cargo": [
- "GUNS",
- "HATS",
- "PIZEH",
- "MEMES",
- "GLOWY CYSTAL"
-
- ],
-
- "s_roles": [
- "ert",
- "shadowlig",
- "ninja",
- "admen",
- "mantor",
- "bluh daymon",
- "wizzerd"
-
- ]
+ ],
+
+ "god_foe": [
+ "MORTALS",
+ "HERETICS",
+ "INSECTS",
+ "UNBELIEVERS",
+ "BLASPHEMERS",
+ "PARASITES",
+ "WEAKLINGS",
+ "PEASANTS"
+ ],
+
+ "god_aggressive": [
+ "BEGONE, @pick(god_foe)!",
+ "DIE, @pick(god_foe)!",
+ "BLEED, @pick(god_foe)!",
+ "BURN, @pick(god_foe)!",
+ "ALL WILL FALL BEFORE ME!",
+ "ENDLESS SUFFERING AWAITS YOU, @pick(god_foe).",
+ "DEATH TO @pick(god_foe)!"
+ ],
+
+ "god_neutral": [
+ "STOP",
+ "HALT.",
+ "BE SILENT.",
+ "QUIET",
+ "SEE THE TRUTH BEFORE YOU, MORTALS.",
+ "MORTALS, SAY YOUR NAME",
+ "BEGONE, MORTALS.",
+ "BE HEALED, MORTALS. I AM FEELING MERCIFUL.",
+ "DANCE FOR ME, LITTLE MORTALS.",
+ "YOU. STOP.",
+ "REST, MORTALS, TOMORROW IS A LONG DAY.",
+ "YOU MORTALS MAKE ME SICK.",
+ "HONK..."
+ ],
+
+ "god_unstun": [
+ "GET UP. I HAVE NO TIME TO LOSE.",
+ "GET UP, PRIEST.",
+ "GET UP."
+ ],
+
+ "god_heal": [
+ "YOU WILL LIVE TO SEE ANOTHER DAY.",
+ "YOU SHALL SURVIVE THIS, MY PRIEST.",
+ "BE HEALED, PRIEST.",
+ "YOUR LIFE IS IMPORTANT. KEEP IT."
+ ]
}
diff --git a/tgstation.dme b/tgstation.dme
index 0be8f4f8b8..cebbabd8da 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -54,7 +54,7 @@
#include "code\__DEFINES\logging.dm"
#include "code\__DEFINES\machines.dm"
#include "code\__DEFINES\maps.dm"
-#include "code\__DEFINES\math.dm"
+#include "code\__DEFINES\maths.dm"
#include "code\__DEFINES\MC.dm"
#include "code\__DEFINES\menu.dm"
#include "code\__DEFINES\misc.dm"
@@ -101,7 +101,6 @@
#include "code\__HELPERS\global_lists.dm"
#include "code\__HELPERS\icon_smoothing.dm"
#include "code\__HELPERS\icons.dm"
-#include "code\__HELPERS\maths.dm"
#include "code\__HELPERS\matrices.dm"
#include "code\__HELPERS\mobs.dm"
#include "code\__HELPERS\names.dm"
@@ -109,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"
@@ -224,9 +224,9 @@
#include "code\controllers\configuration\config_entry.dm"
#include "code\controllers\configuration\configuration.dm"
#include "code\controllers\configuration\entries\comms.dm"
-#include "code\controllers\configuration\entries\config.dm"
#include "code\controllers\configuration\entries\dbconfig.dm"
#include "code\controllers\configuration\entries\game_options.dm"
+#include "code\controllers\configuration\entries\general.dm"
#include "code\controllers\subsystem\acid.dm"
#include "code\controllers\subsystem\air.dm"
#include "code\controllers\subsystem\assets.dm"
@@ -306,6 +306,7 @@
#include "code\datums\mutable_appearance.dm"
#include "code\datums\mutations.dm"
#include "code\datums\outfit.dm"
+#include "code\datums\position_point_vector.dm"
#include "code\datums\profiling.dm"
#include "code\datums\progressbar.dm"
#include "code\datums\radiation_wave.dm"
@@ -318,6 +319,7 @@
#include "code\datums\verbs.dm"
#include "code\datums\weakrefs.dm"
#include "code\datums\world_topic.dm"
+#include "code\datums\actions\beam_rifle.dm"
#include "code\datums\actions\flightsuit.dm"
#include "code\datums\actions\ninja.dm"
#include "code\datums\antagonists\abductor.dm"
@@ -329,11 +331,14 @@
#include "code\datums\antagonists\datum_traitor.dm"
#include "code\datums\antagonists\devil.dm"
#include "code\datums\antagonists\internal_affairs.dm"
+#include "code\datums\antagonists\monkey.dm"
#include "code\datums\antagonists\ninja.dm"
+#include "code\datums\antagonists\nukeop.dm"
#include "code\datums\antagonists\pirate.dm"
#include "code\datums\antagonists\revolution.dm"
#include "code\datums\antagonists\wizard.dm"
#include "code\datums\brain_damage\brain_trauma.dm"
+#include "code\datums\brain_damage\imaginary_friend.dm"
#include "code\datums\brain_damage\mild.dm"
#include "code\datums\brain_damage\phobia.dm"
#include "code\datums\brain_damage\severe.dm"
@@ -343,8 +348,11 @@
#include "code\datums\components\archaeology.dm"
#include "code\datums\components\caltrop.dm"
#include "code\datums\components\chasm.dm"
+#include "code\datums\components\cleaning.dm"
#include "code\datums\components\decal.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"
@@ -488,6 +496,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"
@@ -846,6 +855,7 @@
#include "code\game\objects\effects\temporary_visuals\clockcult.dm"
#include "code\game\objects\effects\temporary_visuals\cult.dm"
#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
+#include "code\game\objects\effects\temporary_visuals\projectile_beam.dm"
#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
#include "code\game\objects\items\AI_modules.dm"
#include "code\game\objects\items\airlock_painter.dm"
@@ -1304,6 +1314,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"
@@ -1622,6 +1633,7 @@
#include "code\modules\jobs\job_types\security.dm"
#include "code\modules\jobs\job_types\silicon.dm"
#include "code\modules\jobs\map_changes\map_changes.dm"
+#include "code\modules\language\aphasia.dm"
#include "code\modules\language\beachbum.dm"
#include "code\modules\language\codespeak.dm"
#include "code\modules\language\common.dm"
@@ -1690,6 +1702,7 @@
#include "code\modules\mining\lavaland\necropolis_chests.dm"
#include "code\modules\mining\lavaland\ruins\gym.dm"
#include "code\modules\mob\death.dm"
+#include "code\modules\mob\emote.dm"
#include "code\modules\mob\inventory.dm"
#include "code\modules\mob\login.dm"
#include "code\modules\mob\logout.dm"
@@ -2452,7 +2465,7 @@
#include "modular_citadel\cydonian_armor.dm"
#include "modular_citadel\polychromic_clothes.dm"
#include "modular_citadel\code\datums\uplink_items_cit.dm"
+#include "modular_citadel\code\game\objects\items\devices\PDA\PDA.dm"
#include "modular_citadel\code\game\objects\items\melee\eutactic_blades.dm"
#include "modular_citadel\code\modules\crafting\recipes.dm"
-#include "modular_citadel\code\game\objects\items\devices\PDA\PDA.dm"
// END_INCLUDE
diff --git a/tgui/assets/tgui.css b/tgui/assets/tgui.css
index 256b53c106..c73fc2adfa 100644
--- a/tgui/assets/tgui.css
+++ b/tgui/assets/tgui.css
@@ -1 +1 @@
-@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgNDI1IDIwMCIgb3BhY2l0eT0iLjMzIj4NCiAgPHBhdGggZD0ibSAxNzguMDAzOTksMC4wMzg2OSAtNzEuMjAzOTMsMCBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTYuNzYxMzQsNi4wMjU1NSBsIDAsMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM0LDYuMDI1NTQgbCA1My4xMDcyLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xMDEuNTQ0MDE4IDcyLjIxNjI4LDEwNC42OTkzOTggYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDUuNzYwMTUsMi44NzAxNiBsIDczLjU1NDg3LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xODcuODcxNDcgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM1LC02LjAyNTU1IGwgLTU0LjcxNjQ0LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTMzLDYuMDI1NTUgbCAwLDEwMi42MTkzNSBMIDE4My43NjQxMywyLjkwODg2IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNS43NjAxNCwtMi44NzAxNyB6IiAvPg0KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPg0KICA8cGF0aCBkPSJtIDQyMC4xNTUzNSwxNzcuODkxMTkgYSAxMy40MTIwMzgsMTIuNTAxODQyIDAgMCAxIC04LjYzMjk1LDIyLjA2OTUxIGwgLTY2LjExODMyLDAgYSA1LjM2NDgxNTIsNS4wMDA3MzcgMCAwIDEgLTUuMzY0ODIsLTUuMDAwNzQgbCAwLC03OS44NzkzMSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgMjAwIDI4OS43NDIiIG9wYWNpdHk9Ii4zMyI+DQogIDxwYXRoIGQ9Im0gOTMuNTM3Njc3LDAgYyAtMTguMTEzMTI1LDAgLTM0LjIyMDEzMywzLjExMTY0IC00OC4zMjM0ODQsOS4zMzQzNyAtMTMuOTY1MDkyLDYuMjIxNjcgLTI0LjYxMjQ0MiwxNS4wNzExNCAtMzEuOTQwNjUxLDI2LjU0NzEgLTcuMTg5OTM5OCwxMS4zMzc4OSAtMTAuMzAxMjI2NiwyNC43NDkxMSAtMTAuMzAxMjI2Niw0MC4yMzQ3OCAwLDEwLjY0NjYyIDIuNzI1MDAyNiwyMC40NjQ2NSA4LjE3NTExMTYsMjkuNDUyNTggNS42MTUyNzcsOC45ODY4NiAxNC4wMzgyNzcsMTcuMzUyMDQgMjUuMjY4ODIxLDI1LjA5NDM2IDExLjIzMDU0NCw3LjYwNTMxIDI2LjUwNzQyMSwxNS40MTgzNSA0NS44MzA1MTQsMjMuNDM3ODIgMTkuOTgzNzQ4LDguMjk1NTcgMzQuODQ4ODQ4LDE1LjU1NDcxIDQ0LjU5Mjk5OCwyMS43NzYzOCA5Ljc0NDE0LDYuMjIyNzMgMTYuNzYxNywxMi44NTg1IDIxLjA1NTcyLDE5LjkwOTUxIDQuMjk0MDQsNy4wNTIwOCA2LjQ0MTkzLDE1Ljc2NDA4IDYuNDQxOTMsMjYuMTM0NTkgMCwxNi4xNzcwMiAtNS4yMDE5NiwyOC40ODIyMiAtMTUuNjA2NzMsMzYuOTE2ODIgLTEwLjIzOTYsOC40MzQ3IC0yNS4wMjIwMywxMi42NTIzIC00NC4zNDUxNjksMTIuNjUyMyAtMTQuMDM4MTcxLDAgLTI1LjUxNTI0NywtMS42NTk0IC0zNC40MzM2MTgsLTQuOTc3NyAtOC45MTgzNywtMy40NTY2IC0xNi4xODU1NzIsLTguNzExMyAtMjEuODAwODM5LC0xNS43NjMzIC01LjYxNTI3NywtNy4wNTIxIC0xMC4wNzQ3OTUsLTE2LjY2MDg4IC0xMy4zNzc4OTksLTI4LjgyODEyIGwgLTI0Ljc3MzE2MjYyOTM5NDUsMCAwLDU2LjgyNjMyIEMgMzMuODU2NzY5LDI4Ni4wNzYwMSA2My43NDkwNCwyODkuNzQyMDEgODkuNjc4MzgzLDI4OS43NDIwMSBjIDE2LjAyMDAyNywwIDMwLjcxOTc4NywtMS4zODI3IDQ0LjA5NzMzNywtNC4xNDc5IDEzLjU0MjcyLC0yLjkwNDMgMjUuMTA0MSwtNy40Njc2IDM0LjY4MzA5LC0xMy42ODkzIDkuNzQ0MTMsLTYuMzU5NyAxNy4zNDA0MiwtMTQuNTE5NSAyMi43OTA1MiwtMjQuNDc0OCA1LjQ1MDEsLTEwLjA5MzMyIDguMTc1MTEsLTIyLjM5OTU5IDguMTc1MTEsLTM2LjkxNjgyIDAsLTEyLjk5NzY0IC0zLjMwMjEsLTI0LjMzNTM5IC05LjkwODI5LC0zNC4wMTQ2IC02LjQ0MTA1LC05LjgxNzI1IC0xNS41MjU0NSwtMTguNTI3MDcgLTI3LjI1MTQ2LC0yNi4xMzEzMyAtMTEuNTYwODUsLTcuNjA0MjcgLTI3LjkxMDgzLC0xNS44MzE0MiAtNDkuMDUwNjYsLTI0LjY4MDIyIC0xNy41MDY0NCwtNy4xOTAxMiAtMzAuNzE5NjY4LC0xMy42ODk0OCAtMzkuNjM4MDM4LC0xOS40OTcwMSAtOC45MTgzNzEsLTUuODA3NTIgLTE4LjYwNzQ3NCwtMTIuNDM0MDkgLTI0LjA5NjUyNCwtMTguODc0MTcgLTUuNDI2MDQzLC02LjM2NjE2IC05LjY1ODgyNiwtMTUuMDcwMDMgLTkuNjU4ODI2LC0yNC44ODcyOSAwLC05LjI2NDAxIDIuMDc1NDE0LC0xNy4yMTM0NSA2LjIyMzQ1NCwtMjMuODUwMzMgMTEuMDk4Mjk4LC0xNC4zOTc0OCA0MS4yODY2MzgsLTEuNzk1MDcgNDUuMDc1NjA5LDI0LjM0NzYyIDQuODM5MzkyLDYuNzc0OTEgOC44NDkzNSwxNi4yNDcyOSAxMi4wMjk1MTUsMjguNDE1NiBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNC40NzgyNSwtNS45MjQ0OCAtOS45NTQ4OCwtMTAuNjMyMjIgLTE1LjkwODM3LC0xNC4zNzQxMSAxLjY0MDU1LDAuNDc5MDUgMy4xOTAzOSwxLjAyMzc2IDQuNjM4NjUsMS42NDAyNCA2LjQ5ODYxLDIuNjI2MDcgMTIuMTY3OTMsNy4zMjc0NyAxNy4wMDczLDE0LjEwMzQ1IDQuODM5MzksNi43NzQ5MSA4Ljg0OTM1LDE2LjI0NTY3IDEyLjAyOTUyLDI4LjQxMzk3IDAsMCA4LjQ4MTI4LC0wLjEyODk0IDguNDg5NzgsLTAuMDAyIDAuNDE3NzYsNi40MTQ5NCAtMS43NTMzOSw5LjQ1Mjg2IC00LjEyMzQyLDEyLjU2MTA0IC0yLjQxNzQsMy4xNjk3OCAtNS4xNDQ4Niw2Ljc4OTczIC00LjAwMjc4LDEzLjAwMjkgMS41MDc4Niw4LjIwMzE4IDEwLjE4MzU0LDEwLjU5NjQyIDE0LjYyMTk0LDkuMzExNTQgLTMuMzE4NDIsLTAuNDk5MTEgLTUuMzE4NTUsLTEuNzQ5NDggLTUuMzE4NTUsLTEuNzQ5NDggMCwwIDEuODc2NDYsMC45OTg2OCA1LjY1MTE3LC0xLjM1OTgxIC0zLjI3Njk1LDAuOTU1NzEgLTEwLjcwNTI5LC0wLjc5NzM4IC0xMS44MDEyNSwtNi43NjMxMyAtMC45NTc1MiwtNS4yMDg2MSAwLjk0NjU0LC03LjI5NTE0IDMuNDAxMTMsLTEwLjUxNDgyIDIuNDU0NjIsLTMuMjE5NjggNS4yODQyNiwtNi45NTgzMSA0LjY4NDMsLTE0LjQ4ODI0IGwgMC4wMDMsMC4wMDIgOC45MjY3NiwwIDAsLTU1Ljk5OTY3IGMgLTE1LjA3MTI1LC0zLjg3MTY4IC0yNy42NTMxNCwtNi4zNjA0MiAtMzcuNzQ2NzEsLTcuNDY1ODYgLTkuOTU1MzEsLTEuMTA3NTUgLTIwLjE4ODIzLC0xLjY1OTgxIC0zMC42OTY2MTMsLTEuNjU5ODEgeiBtIDcwLjMyMTYwMywxNy4zMDg5MyAwLjIzODA1LDQwLjMwNDkgYyAxLjMxODA4LDEuMjI2NjYgMi40Mzk2NSwyLjI3ODE1IDMuMzQwODEsMy4xMDYwMiA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNCwxNi4yNDU2NiAxMi4wMjk1MSwyOC40MTM5NyBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNi42NzczMSwtNC41OTM4MSAtMTkuODM2NDMsLTEwLjQ3MzA5IC0zNi4xNDA3MSwtMTUuODI1MjIgeiBtIC0yOC4xMjA0OSw1LjYwNTUxIDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzcsLTYuNDY2OTcgLTEzLjg0Njc4LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDUsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gMTUuMjIxOTUsMjQuMDA4NDggOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzOCwtNi40NjY5NyAtMTMuODQ2NzksLTkuNzE3MjYgLTguNTY0NzksLTE3LjcxNjU1IHogbSAyMi43OTcwNCwwIGMgMi43NzE1LDcuOTk5MjkgMS43ODc0MSwxMS4yNDk1OCAtNC40OTM1NCwxNy43MTY1NSBsIDQuNDkzNTQsLTE3LjcxNjU1IHogbSAtOTkuMTEzODQsMi4yMDc2NCA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM4MiwtNi40NjY5NyAtMTMuODQ2NzgyLC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk1NDIsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"}
\ No newline at end of file
+@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCA0MjUgMjAwIiBvcGFjaXR5PSIuMzMiPgogIDxwYXRoIGQ9Im0gMTc4LjAwMzk5LDAuMDM4NjkgLTcxLjIwMzkzLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM0LDYuMDI1NTUgbCAwLDE4Ny44NzE0NyBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgNi43NjEzNCw2LjAyNTU0IGwgNTMuMTA3MiwwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM1LC02LjAyNTU0IGwgMCwtMTAxLjU0NDAxOCA3Mi4yMTYyOCwxMDQuNjk5Mzk4IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA1Ljc2MDE1LDIuODcwMTYgbCA3My41NTQ4NywwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM1LC02LjAyNTU0IGwgMCwtMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNi43NjEzNSwtNi4wMjU1NSBsIC01NC43MTY0NCwwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNi43NjEzMyw2LjAyNTU1IGwgMCwxMDIuNjE5MzUgTCAxODMuNzY0MTMsMi45MDg4NiBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTUuNzYwMTQsLTIuODcwMTcgeiIgLz4KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPgogIDxwYXRoIGQ9Im0gNDIwLjE1NTM1LDE3Ny44OTExOSBhIDEzLjQxMjAzOCwxMi41MDE4NDIgMCAwIDEgLTguNjMyOTUsMjIuMDY5NTEgbCAtNjYuMTE4MzIsMCBhIDUuMzY0ODE1Miw1LjAwMDczNyAwIDAgMSAtNS4zNjQ4MiwtNS4wMDA3NCBsIDAsLTc5Ljg3OTMxIHoiIC8+Cjwvc3ZnPgo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4KPCEtLSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS80LjAvIC0tPgo=") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCAyMDAgMjg5Ljc0MiIgb3BhY2l0eT0iLjMzIj4KICA8cGF0aCBkPSJtIDkzLjUzNzY3NywwIGMgLTE4LjExMzEyNSwwIC0zNC4yMjAxMzMsMy4xMTE2NCAtNDguMzIzNDg0LDkuMzM0MzcgLTEzLjk2NTA5Miw2LjIyMTY3IC0yNC42MTI0NDIsMTUuMDcxMTQgLTMxLjk0MDY1MSwyNi41NDcxIC03LjE4OTkzOTgsMTEuMzM3ODkgLTEwLjMwMTIyNjYsMjQuNzQ5MTEgLTEwLjMwMTIyNjYsNDAuMjM0NzggMCwxMC42NDY2MiAyLjcyNTAwMjYsMjAuNDY0NjUgOC4xNzUxMTE2LDI5LjQ1MjU4IDUuNjE1Mjc3LDguOTg2ODYgMTQuMDM4Mjc3LDE3LjM1MjA0IDI1LjI2ODgyMSwyNS4wOTQzNiAxMS4yMzA1NDQsNy42MDUzMSAyNi41MDc0MjEsMTUuNDE4MzUgNDUuODMwNTE0LDIzLjQzNzgyIDE5Ljk4Mzc0OCw4LjI5NTU3IDM0Ljg0ODg0OCwxNS41NTQ3MSA0NC41OTI5OTgsMjEuNzc2MzggOS43NDQxNCw2LjIyMjczIDE2Ljc2MTcsMTIuODU4NSAyMS4wNTU3MiwxOS45MDk1MSA0LjI5NDA0LDcuMDUyMDggNi40NDE5MywxNS43NjQwOCA2LjQ0MTkzLDI2LjEzNDU5IDAsMTYuMTc3MDIgLTUuMjAxOTYsMjguNDgyMjIgLTE1LjYwNjczLDM2LjkxNjgyIC0xMC4yMzk2LDguNDM0NyAtMjUuMDIyMDMsMTIuNjUyMyAtNDQuMzQ1MTY5LDEyLjY1MjMgLTE0LjAzODE3MSwwIC0yNS41MTUyNDcsLTEuNjU5NCAtMzQuNDMzNjE4LC00Ljk3NzcgLTguOTE4MzcsLTMuNDU2NiAtMTYuMTg1NTcyLC04LjcxMTMgLTIxLjgwMDgzOSwtMTUuNzYzMyAtNS42MTUyNzcsLTcuMDUyMSAtMTAuMDc0Nzk1LC0xNi42NjA4OCAtMTMuMzc3ODk5LC0yOC44MjgxMiBsIC0yNC43NzMxNjI2MjkzOTQ1LDAgMCw1Ni44MjYzMiBDIDMzLjg1Njc2OSwyODYuMDc2MDEgNjMuNzQ5MDQsMjg5Ljc0MjAxIDg5LjY3ODM4MywyODkuNzQyMDEgYyAxNi4wMjAwMjcsMCAzMC43MTk3ODcsLTEuMzgyNyA0NC4wOTczMzcsLTQuMTQ3OSAxMy41NDI3MiwtMi45MDQzIDI1LjEwNDEsLTcuNDY3NiAzNC42ODMwOSwtMTMuNjg5MyA5Ljc0NDEzLC02LjM1OTcgMTcuMzQwNDIsLTE0LjUxOTUgMjIuNzkwNTIsLTI0LjQ3NDggNS40NTAxLC0xMC4wOTMzMiA4LjE3NTExLC0yMi4zOTk1OSA4LjE3NTExLC0zNi45MTY4MiAwLC0xMi45OTc2NCAtMy4zMDIxLC0yNC4zMzUzOSAtOS45MDgyOSwtMzQuMDE0NiAtNi40NDEwNSwtOS44MTcyNSAtMTUuNTI1NDUsLTE4LjUyNzA3IC0yNy4yNTE0NiwtMjYuMTMxMzMgLTExLjU2MDg1LC03LjYwNDI3IC0yNy45MTA4MywtMTUuODMxNDIgLTQ5LjA1MDY2LC0yNC42ODAyMiAtMTcuNTA2NDQsLTcuMTkwMTIgLTMwLjcxOTY2OCwtMTMuNjg5NDggLTM5LjYzODAzOCwtMTkuNDk3MDEgLTguOTE4MzcxLC01LjgwNzUyIC0xOC42MDc0NzQsLTEyLjQzNDA5IC0yNC4wOTY1MjQsLTE4Ljg3NDE3IC01LjQyNjA0MywtNi4zNjYxNiAtOS42NTg4MjYsLTE1LjA3MDAzIC05LjY1ODgyNiwtMjQuODg3MjkgMCwtOS4yNjQwMSAyLjA3NTQxNCwtMTcuMjEzNDUgNi4yMjM0NTQsLTIzLjg1MDMzIDExLjA5ODI5OCwtMTQuMzk3NDggNDEuMjg2NjM4LC0xLjc5NTA3IDQ1LjA3NTYwOSwyNC4zNDc2MiA0LjgzOTM5Miw2Ljc3NDkxIDguODQ5MzUsMTYuMjQ3MjkgMTIuMDI5NTE1LDI4LjQxNTYgbCAyMC41MzIzNCwwIDAsLTU1Ljk5OTY3IGMgLTQuNDc4MjUsLTUuOTI0NDggLTkuOTU0ODgsLTEwLjYzMjIyIC0xNS45MDgzNywtMTQuMzc0MTEgMS42NDA1NSwwLjQ3OTA1IDMuMTkwMzksMS4wMjM3NiA0LjYzODY1LDEuNjQwMjQgNi40OTg2MSwyLjYyNjA3IDEyLjE2NzkzLDcuMzI3NDcgMTcuMDA3MywxNC4xMDM0NSA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNSwxNi4yNDU2NyAxMi4wMjk1MiwyOC40MTM5NyAwLDAgOC40ODEyOCwtMC4xMjg5NCA4LjQ4OTc4LC0wLjAwMiAwLjQxNzc2LDYuNDE0OTQgLTEuNzUzMzksOS40NTI4NiAtNC4xMjM0MiwxMi41NjEwNCAtMi40MTc0LDMuMTY5NzggLTUuMTQ0ODYsNi43ODk3MyAtNC4wMDI3OCwxMy4wMDI5IDEuNTA3ODYsOC4yMDMxOCAxMC4xODM1NCwxMC41OTY0MiAxNC42MjE5NCw5LjMxMTU0IC0zLjMxODQyLC0wLjQ5OTExIC01LjMxODU1LC0xLjc0OTQ4IC01LjMxODU1LC0xLjc0OTQ4IDAsMCAxLjg3NjQ2LDAuOTk4NjggNS42NTExNywtMS4zNTk4MSAtMy4yNzY5NSwwLjk1NTcxIC0xMC43MDUyOSwtMC43OTczOCAtMTEuODAxMjUsLTYuNzYzMTMgLTAuOTU3NTIsLTUuMjA4NjEgMC45NDY1NCwtNy4yOTUxNCAzLjQwMTEzLC0xMC41MTQ4MiAyLjQ1NDYyLC0zLjIxOTY4IDUuMjg0MjYsLTYuOTU4MzEgNC42ODQzLC0xNC40ODgyNCBsIDAuMDAzLDAuMDAyIDguOTI2NzYsMCAwLC01NS45OTk2NyBjIC0xNS4wNzEyNSwtMy44NzE2OCAtMjcuNjUzMTQsLTYuMzYwNDIgLTM3Ljc0NjcxLC03LjQ2NTg2IC05Ljk1NTMxLC0xLjEwNzU1IC0yMC4xODgyMywtMS42NTk4MSAtMzAuNjk2NjEzLC0xLjY1OTgxIHogbSA3MC4zMjE2MDMsMTcuMzA4OTMgMC4yMzgwNSw0MC4zMDQ5IGMgMS4zMTgwOCwxLjIyNjY2IDIuNDM5NjUsMi4yNzgxNSAzLjM0MDgxLDMuMTA2MDIgNC44MzkzOSw2Ljc3NDkxIDguODQ5MzQsMTYuMjQ1NjYgMTIuMDI5NTEsMjguNDEzOTcgbCAyMC41MzIzNCwwIDAsLTU1Ljk5OTY3IGMgLTYuNjc3MzEsLTQuNTkzODEgLTE5LjgzNjQzLC0xMC40NzMwOSAtMzYuMTQwNzEsLTE1LjgyNTIyIHogbSAtMjguMTIwNDksNS42MDU1MSA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM3LC02LjQ2Njk3IC0xMy44NDY3OCwtOS43MTcyNiAtOC41NjQ3OSwtMTcuNzE2NTUgeiBtIDIyLjc5NzA1LDAgYyAyLjc3MTUsNy45OTkyOSAxLjc4NzQxLDExLjI0OTU4IC00LjQ5MzU0LDE3LjcxNjU1IGwgNC40OTM1NCwtMTcuNzE2NTUgeiBtIDE1LjIyMTk1LDI0LjAwODQ4IDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzgsLTYuNDY2OTcgLTEzLjg0Njc5LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDQsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gLTk5LjExMzg0LDIuMjA3NjQgOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzODIsLTYuNDY2OTcgLTEzLjg0Njc4MiwtOS43MTcyNiAtOC41NjQ3OSwtMTcuNzE2NTUgeiBtIDIyLjc5NTQyLDAgYyAyLjc3MTUsNy45OTkyOSAxLjc4NzQxLDExLjI0OTU4IC00LjQ5MzU0LDE3LjcxNjU1IGwgNC40OTM1NCwtMTcuNzE2NTUgeiIgLz4KPC9zdmc+CjwhLS0gVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIC0tPgo8IS0tIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8gLS0+Cg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"}
\ No newline at end of file
diff --git a/tgui/package.json b/tgui/package.json
index 007ee04ab9..52662139a6 100644
--- a/tgui/package.json
+++ b/tgui/package.json
@@ -22,7 +22,7 @@
"es3ify": "0.2.1",
"fg-loadcss": "1.0.0-0",
"fontfaceobserver": "1.6.3",
- "gulp": "github:gulpjs/gulp#4.0",
+ "gulp": "github:gulpjs/gulp#6d71a65",
"gulp-bytediff": "1.0.0",
"gulp-cssnano": "2.1.2",
"gulp-if": "2.0.0",
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