"
+ 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..52319b7866 100755
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -257,8 +257,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 8718751d81..2dddce8542 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -58,7 +58,7 @@
SendSignal(COMSIG_ITEM_ATTACK, M, user)
if(flags_1 & NOBLUDGEON_1)
return
- if(user.has_disability(PACIFISM))
+ if(user.disabilities & PACIFISM)
return
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
@@ -121,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/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 1eddc725d2..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
@@ -478,4 +478,35 @@
/datum/antagonist/changeling/xenobio
name = "Xenobio Changeling"
give_objectives = FALSE
+ show_in_roundend = FALSE //These are here for admin tracking purposes only
you_are_greet = FALSE
+
+/datum/antagonist/changeling/roundend_report()
+ var/list/parts = list()
+
+ var/changelingwin = 1
+ if(!owner.current)
+ changelingwin = 0
+
+ parts += printplayer(owner)
+
+ //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
+ parts += "
Changeling ID: [changelingID]."
+ parts += "
Genomes Extracted: [absorbedcount]"
+ parts += " "
+ if(objectives.len)
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ changelingwin = 0
+ count++
+
+ if(changelingwin)
+ parts += "
The changeling was successful!"
+ else
+ parts += "
The changeling has failed."
+
+ return parts.Join("
")
\ No newline at end of file
diff --git a/code/datums/antagonists/clockcult.dm b/code/datums/antagonists/clockcult.dm
index 8cc1c9e9a7..48f9b53425 100644
--- a/code/datums/antagonists/clockcult.dm
+++ b/code/datums/antagonists/clockcult.dm
@@ -1,8 +1,11 @@
//CLOCKCULT PROOF OF CONCEPT
/datum/antagonist/clockcult
name = "Clock Cultist"
- var/datum/action/innate/hierophant/hierophant_network = new()
+ roundend_category = "clock cultists"
job_rank = ROLE_SERVANT_OF_RATVAR
+ var/datum/action/innate/hierophant/hierophant_network = new()
+ var/datum/team/clockcult/clock_team
+ var/make_team = TRUE //This should be only false for tutorial scarabs
/datum/antagonist/clockcult/silent
silent = TRUE
@@ -11,6 +14,22 @@
qdel(hierophant_network)
return ..()
+/datum/antagonist/clockcult/get_team()
+ return clock_team
+
+/datum/antagonist/clockcult/create_team(datum/team/clockcult/new_team)
+ if(!new_team && make_team)
+ //TODO blah blah same as the others, allow multiple
+ for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
+ if(H.clock_team)
+ clock_team = H.clock_team
+ return
+ clock_team = new /datum/team/clockcult
+ return
+ if(make_team && !istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ clock_team = new_team
+
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -156,7 +175,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
- owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
+ owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
to_chat(owner, "
A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
owner.current.log_message("
Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG)
owner.wipe_memory()
@@ -164,3 +183,35 @@
if(iscyborg(owner.current))
to_chat(owner.current, "
Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.")
. = ..()
+
+
+/datum/team/clockcult
+ name = "Clockcult"
+ var/list/objective
+ var/datum/mind/eminence
+
+/datum/team/clockcult/proc/check_clockwork_victory()
+ if(GLOB.clockwork_gateway_activated)
+ return TRUE
+ return FALSE
+
+/datum/team/clockcult/roundend_report()
+ var/list/parts = list()
+
+ if(check_clockwork_victory())
+ parts += "
Ratvar's servants defended the Ark until its activation!"
+ else
+ parts += "
The Ark was destroyed! Ratvar will rust away for all eternity!"
+ parts += " "
+ parts += "
The servants' objective was: [CLOCKCULT_OBJECTIVE]."
+ parts += "
Construction Value(CV) was:
[GLOB.clockwork_construction_value]"
+ for(var/i in SSticker.scripture_states)
+ if(i != SCRIPTURE_DRIVER)
+ parts += "
[i] scripture was:
[SSticker.scripture_states[i] ? "UN":""]LOCKED"
+ if(eminence)
+ parts += " [printplayer(eminence)]"
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members - eminence)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/cult.dm b/code/datums/antagonists/cult.dm
index c26b0f8108..916123ddff 100644
--- a/code/datums/antagonists/cult.dm
+++ b/code/datums/antagonists/cult.dm
@@ -2,84 +2,103 @@
/datum/antagonist/cult
name = "Cultist"
+ roundend_category = "cultists"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
+ var/give_equipment = FALSE
+
+ var/datum/team/cult/cult_team
+
+/datum/antagonist/cult/get_team()
+ return cult_team
+
+/datum/antagonist/cult/create_team(datum/team/cult/new_team)
+ if(!new_team)
+ //todo remove this and allow admin buttons to create more than one cult
+ for(var/datum/antagonist/cult/H in GLOB.antagonists)
+ if(H.cult_team)
+ cult_team = H.cult_team
+ return
+ cult_team = new /datum/team/cult
+ cult_team.setup_objectives()
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ cult_team = new_team
+
+/datum/antagonist/cult/proc/add_objectives()
+ objectives |= cult_team.objectives
+ owner.objectives |= objectives
+
+/datum/antagonist/cult/proc/remove_objectives()
+ owner.objectives -= objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
QDEL_NULL(vote)
return ..()
-/datum/antagonist/cult/proc/add_objectives()
- var/list/target_candidates = list()
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- if(target_candidates.len == 0)
- message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- listclearnulls(target_candidates)
- if(LAZYLEN(target_candidates))
- GLOB.sac_mind = pick(target_candidates)
- if(!GLOB.sac_mind)
- message_admins("Cult Sacrifice: ERROR - Null target chosen!")
- else
- var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
- var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- GLOB.sac_image = reshape
- else
- message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
- GLOB.sac_complete = TRUE
- SSticker.mode.cult_objectives += "sacrifice"
- if(!GLOB.summon_spots.len)
- while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
- var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
- if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
- GLOB.summon_spots += summon
- SSticker.mode.cult_objectives += "eldergod"
-
-/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
- var/mob/living/current = cult_mind.current
- for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
- var/explanation
- switch(SSticker.mode.cult_objectives[obj_count])
- if("sacrifice")
- if(GLOB.sac_mind)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
- else
- explanation = "The veil has already been weakened here, proceed to the final objective."
- GLOB.sac_complete = TRUE
- if("eldergod")
- explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin."
- if(!silent)
- to_chat(current, "
Objective #[obj_count]: [explanation]")
- cult_mind.memory += "
Objective #[obj_count]: [explanation]
"
-
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
- . = is_convertable_to_cult(new_owner.current)
+ . = is_convertable_to_cult(new_owner.current,cult_team)
+
+/datum/antagonist/cult/greet()
+ to_chat(owner, "
You are a member of the cult!")
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
+ owner.announce_objectives()
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
- if(!LAZYLEN(SSticker.mode.cult_objectives))
- add_objectives()
+ add_objectives()
+ if(give_equipment)
+ equip_cultist()
SSticker.mode.cult += owner // Only add after they've been given objectives
- cult_memorization(owner)
SSticker.mode.update_cult_icons_added(owner)
current.log_message("
Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && current.client)
- current.client.images += GLOB.blood_target_image
+
+ if(cult_team.blood_target && cult_team.blood_target_image && current.client)
+ current.client.images += cult_team.blood_target_image
+
+
+/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
+ var/mob/living/carbon/H = owner.current
+ if(!istype(H))
+ return
+ if (owner.assigned_role == "Clown")
+ to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
+ H.dna.remove_mutation(CLOWNMUT)
+
+ if(tome)
+ . += cult_give_item(/obj/item/tome, H)
+ else
+ . += cult_give_item(/obj/item/paper/talisman/supply, H)
+ to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
+
+
+/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
+ var/list/slots = list(
+ "backpack" = slot_in_backpack,
+ "left pocket" = slot_l_store,
+ "right pocket" = slot_r_store
+ )
+
+ var/T = new item_path(mob)
+ var/item_name = initial(item_path.name)
+ var/where = mob.equip_in_one_of_slots(T, slots)
+ if(!where)
+ to_chat(mob, "
Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).")
+ return 0
+ else
+ to_chat(mob, "
You have a [item_name] in your [where].")
+ if(where == "backpack")
+ var/obj/item/storage/B = mob.back
+ B.orient2hud(mob)
+ B.show_to(mob)
+ return 1
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -89,7 +108,7 @@
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
- if(!GLOB.cult_mastered)
+ if(!cult_team.cult_mastered)
vote.Grant(current)
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
@@ -107,6 +126,7 @@
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
+ remove_objectives()
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
@@ -114,8 +134,8 @@
owner.current.visible_message("
[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!", ignored_mob = owner.current)
to_chat(owner.current, "
An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
owner.current.log_message("
Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
- owner.current.client.images -= GLOB.blood_target_image
+ if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
+ owner.current.client.images -= cult_team.blood_target_image
. = ..()
/datum/antagonist/cult/master
@@ -145,7 +165,7 @@
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
- if(!GLOB.reckoning_complete)
+ if(!cult_team.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
@@ -162,3 +182,118 @@
throwing.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
+
+/datum/team/cult
+ name = "Cult"
+
+ var/blood_target
+ var/image/blood_target_image
+ var/blood_target_reset_timer
+
+ var/cult_vote_called = FALSE
+ var/cult_mastered = FALSE
+ var/reckoning_complete = FALSE
+
+
+/datum/team/cult/proc/setup_objectives()
+ //SAC OBJECTIVE , todo: move this to objective internals
+ var/list/target_candidates = list()
+ var/datum/objective/sacrifice/sac_objective = new
+ sac_objective.team = src
+
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && player.stat != DEAD)
+ target_candidates += player.mind
+
+ if(target_candidates.len == 0)
+ message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && player.stat != DEAD)
+ target_candidates += player.mind
+ listclearnulls(target_candidates)
+ if(LAZYLEN(target_candidates))
+ sac_objective.target = pick(target_candidates)
+ sac_objective.update_explanation_text()
+
+ var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
+ var/datum/preferences/sacface = sac_objective.target.current.client.prefs
+ var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
+ reshape.Shift(SOUTH, 4)
+ reshape.Shift(EAST, 1)
+ reshape.Crop(7,4,26,31)
+ reshape.Crop(-5,-3,26,30)
+ sac_objective.sac_image = reshape
+
+ objectives += sac_objective
+ else
+ message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
+
+
+ //SUMMON OBJECTIVE
+
+ var/datum/objective/eldergod/summon_objective = new()
+ summon_objective.team = src
+ objectives += summon_objective
+
+/datum/objective/sacrifice
+ var/sacced = FALSE
+ var/sac_image
+
+/datum/objective/sacrifice/check_completion()
+ return sacced || completed
+
+/datum/objective/sacrifice/update_explanation_text()
+ if(target && !sacced)
+ explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
+ else
+ explanation_text = "The veil has already been weakened here, proceed to the final objective."
+
+/datum/objective/eldergod
+ var/summoned = FALSE
+ var/list/summon_spots = list()
+
+/datum/objective/eldergod/New()
+ ..()
+ var/sanity = 0
+ while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
+ var/area/summon = pick(GLOB.sortedAreas - summon_spots)
+ if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
+ summon_spots += summon
+ sanity++
+ update_explanation_text()
+
+/datum/objective/eldergod/update_explanation_text()
+ explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin."
+
+/datum/objective/eldergod/check_completion()
+ return summoned || completed
+
+/datum/team/cult/proc/check_cult_victory()
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ return FALSE
+ return TRUE
+
+/datum/team/cult/roundend_report()
+ var/list/parts = list()
+
+ if(check_cult_victory())
+ parts += "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!"
+ else
+ parts += "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!"
+
+ if(objectives.len)
+ parts += "
The cultists' objectives were:"
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ count++
+
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index d386c79c25..3ccdc7ddfb 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -1,5 +1,6 @@
/datum/antagonist/traitor
name = "Traitor"
+ roundend_category = "traitors"
job_rank = ROLE_TRAITOR
var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
@@ -8,7 +9,6 @@
var/employer = "The Syndicate"
var/give_objectives = TRUE
var/should_give_codewords = TRUE
- var/list/objectives_given = list()
/datum/antagonist/traitor/human
var/should_equip = TRUE
@@ -52,9 +52,9 @@
if(should_specialise)
return ..()//we never did any of this anyway
SSticker.mode.traitors -= owner
- for(var/O in objectives_given)
+ for(var/O in objectives)
owner.objectives -= O
- objectives_given = list()
+ objectives = list()
if(!silent && owner.current)
to_chat(owner.current,"
You are no longer the [special_role]! ")
owner.special_role = null
@@ -71,11 +71,11 @@
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
owner.objectives += O
- objectives_given += O
+ objectives += O
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
owner.objectives -= O
- objectives_given -= O
+ objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
@@ -294,3 +294,53 @@
where = "In your [equipped_slot]"
to_chat(mob, "
[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.")
+//TODO Collate
+/datum/antagonist/traitor/roundend_report()
+ var/list/result = list()
+
+ var/traitorwin = TRUE
+
+ result += printplayer(owner)
+
+ var/TC_uses = 0
+ var/uplink_true = FALSE
+ var/purchases = ""
+ for(var/datum/component/uplink/H in GLOB.uplinks)
+ if(H && H.owner && H.owner == owner.key)
+ TC_uses += H.spent_telecrystals
+ uplink_true = TRUE
+ purchases += H.purchase_log.generate_render(FALSE)
+
+ var/objectives_text = ""
+ if(objectives.len)//If the traitor had no objectives, don't need to process this.
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Fail."
+ traitorwin = FALSE
+ count++
+
+ if(uplink_true)
+ var/uplink_text = "(used [TC_uses] TC) [purchases]"
+ if(TC_uses==0 && traitorwin)
+ var/static/icon/badass = icon('icons/badass.dmi', "badass")
+ uplink_text += "
[icon2html(badass, world)]"
+ result += uplink_text
+
+ result += objectives_text
+
+ var/special_role_text = lowertext(name)
+
+ if(traitorwin)
+ result += "
The [special_role_text] was successful!"
+ else
+ result += "
The [special_role_text] has failed!"
+ SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
+
+ return result.Join("
")
+
+/datum/antagonist/traitor/roundend_report_footer()
+ return "
The code phrases were: [GLOB.syndicate_code_phrase]\
+
The code responses were: [GLOB.syndicate_code_response]"
\ No newline at end of file
diff --git a/code/datums/antagonists/devil.dm b/code/datums/antagonists/devil.dm
index 416a8f3752..97e0d8c18a 100644
--- a/code/datums/antagonists/devil.dm
+++ b/code/datums/antagonists/devil.dm
@@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon",
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
name = "Devil"
+ roundend_category = "devils"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
@@ -508,6 +509,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
owner.RemoveSpell(S)
.=..()
+/datum/antagonist/devil/proc/printdevilinfo()
+ var/list/parts = list()
+ parts += "The devil's true name is: [truename]"
+ parts += "The devil's bans were:"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report()
+ var/list/parts = list()
+ parts += printplayer(owner)
+ parts += printdevilinfo()
+ parts += printobjectives(owner)
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report_footer()
+ //sintouched go here for now as a hack , TODO proper antag datum for these
+ var/list/parts = list()
+ if(SSticker.mode.sintouched.len)
+ parts += ""
+ var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
+ for(var/S in sintouchedUnique)
+ var/datum/mind/sintouched_mind = S
+ parts += printplayer(sintouched_mind)
+ parts += printobjectives(sintouched_mind)
+ return parts.Join("
")
+
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm
index ab4822dd79..8201cd879d 100644
--- a/code/datums/antagonists/ninja.dm
+++ b/code/datums/antagonists/ninja.dm
@@ -37,19 +37,20 @@
else if(M.assigned_role in GLOB.command_positions)
possible_targets[M] = 1 //good-guy
- var/list/objectives = list(1,2,3,4)
- while(owner.objectives.len < quantity)
- switch(pick_n_take(objectives))
+ var/list/possible_objectives = list(1,2,3,4)
+
+ while(objectives.len < quantity)
+ switch(pick_n_take(possible_objectives))
if(1) //research
var/datum/objective/download/O = new /datum/objective/download()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
if(2) //steal
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
O.owner = owner
- owner.objectives += O
+ objectives += O
if(3) //protect/kill
if(!possible_targets.len) continue
@@ -63,13 +64,13 @@
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
- owner.objectives += O
+ objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
O.owner = owner
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
- owner.objectives += O
+ objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
@@ -82,17 +83,17 @@
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
- owner.objectives += O
+ objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
else
break
var/datum/objective/O = new /datum/objective/survive()
O.owner = owner
- owner.objectives += O
+ owner.objectives |= objectives
/proc/remove_ninja(mob/living/L)
diff --git a/code/datums/antagonists/nukeop.dm b/code/datums/antagonists/nukeop.dm
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 29d08b4ce1..d5ccc71ef9 100644
--- a/code/datums/brain_damage/mild.dm
+++ b/code/datums/brain_damage/mild.dm
@@ -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 381515e42e..a138073040 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -7,7 +7,7 @@
/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."
@@ -19,6 +19,29 @@
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
name = "Cerebral Blindness"
desc = "Patient's brain is no longer connected to its eyes."
@@ -180,3 +203,18 @@
/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/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/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/hud.dm b/code/datums/hud.dm
index 837e7a6a95..fc6c09be14 100644
--- a/code/datums/hud.dm
+++ b/code/datums/hud.dm
@@ -10,6 +10,7 @@ GLOBAL_LIST_INIT(huds, list(
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
+ DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 562311180d..b84133faf7 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -32,7 +32,7 @@
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
mid_length = 2
end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
- volume = 25
+ volume = 15
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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/mind.dm b/code/datums/mind.dm
index c0ab1dc015..231ce66f28 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -149,7 +149,7 @@
return
LAZYADD(antag_datums, A)
A.create_team(team)
- var/datum/objective_team/antag_team = A.get_team()
+ var/datum/team/antag_team = A.get_team()
if(antag_team)
antag_team.add_member(src)
A.on_gain()
@@ -185,12 +185,6 @@
objectives, uplinks, powers etc are all handled.
*/
-/datum/mind/proc/remove_objectives()
- if(objectives.len)
- for(var/datum/objective/O in objectives)
- objectives -= O
- qdel(O)
-
/datum/mind/proc/remove_changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
@@ -207,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
@@ -493,7 +490,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 +711,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 +767,44 @@
var/objective_pos
var/def_value
+
+
+ var/datum/antagonist/target_antag
+
if (href_list["obj_edit"])
objective = locate(href_list["obj_edit"])
if (!objective)
return
- objective_pos = objectives.Find(objective)
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ target_antag = A
+ objective_pos = A.objectives.Find(objective)
+ break
+
+ if(!target_antag) //Shouldn't happen
+ stack_trace("objective without antagonist found")
+ objective_pos = objectives.Find(objective)
//Text strings are easy to manipulate. Revised for simplicity.
var/temp_obj_type = "[objective.type]"//Convert path into a text string.
def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
+ else
+ switch(antag_datums.len)
+ if(0)
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ if(1)
+ target_antag = antag_datums[1]
+ else
+ var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
+ if (QDELETED(target))
+ return
+ else if(target == "(new custom antag)")
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ else
+ target_antag = target
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "late-assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -901,11 +926,15 @@
return
if (objective)
+ if(target_antag)
+ target_antag.objectives -= objective
objectives -= objective
- objectives.Insert(objective_pos, new_objective)
+ target_antag.objectives.Insert(objective_pos, new_objective)
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
else
+ if(target_antag)
+ target_antag.objectives += new_objective
objectives += new_objective
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
@@ -914,6 +943,11 @@
var/datum/objective/objective = locate(href_list["obj_delete"])
if(!istype(objective))
return
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ A.objectives -= objective
+ break
objectives -= objective
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
@@ -996,11 +1030,13 @@
message_admins("[key_name_admin(usr)] has cult'ed [current].")
log_admin("[key_name(usr)] has cult'ed [current].")
if("tome")
- if (!SSticker.mode.equip_cultist(current,1))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current,1))
to_chat(usr, "
Spawning tome failed!")
if("amulet")
- if (!SSticker.mode.equip_cultist(current))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current))
to_chat(usr, "
Spawning amulet failed!")
else if(href_list["clockcult"])
@@ -1071,36 +1107,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)
@@ -1348,50 +1362,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 +1377,11 @@
/datum/mind/proc/make_Cultist()
- if(!(src in SSticker.mode.cult))
- SSticker.mode.add_cultist(src,FALSE)
+ if(!has_antag_datum(/datum/antagonist/cult,TRUE))
+ SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
special_role = "Cultist"
to_chat(current, "
You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.")
to_chat(current, "
Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.")
- var/datum/antagonist/cult/C
- C.cult_memorization(src)
- var/mob/living/carbon/human/H = current
- if (!SSticker.mode.equip_cultist(current))
- to_chat(H, "Spawning an amulet from your Master failed.")
/datum/mind/proc/make_Rev()
var/datum/antagonist/rev/head/head = new(src)
diff --git a/code/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/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/data_huds.dm b/code/game/data_huds.dm
index 1afd2953a0..74ac93c023 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -60,6 +60,9 @@
/datum/atom_hud/data/bot_path
hud_icons = list(DIAG_PATH_HUD)
+/datum/atom_hud/abductor
+ hud_icons = list(GLAND_HUD)
+
/* MED/SEC/DIAG HUD HOOKS */
/*
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/biodegrade.dm b/code/game/gamemodes/changeling/powers/biodegrade.dm
index dbb0e3a88a..4a34de151e 100644
--- a/code/game/gamemodes/changeling/powers/biodegrade.dm
+++ b/code/game/gamemodes/changeling/powers/biodegrade.dm
@@ -55,12 +55,14 @@
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O)
if(O && user.handcuffed == O)
user.visible_message("
[O] dissolve[O.gender==PLURAL?"":"s"] into a puddle of sizzling goop.")
+ user.uncuff()
new /obj/effect/decal/cleanable/greenglow(O.drop_location())
qdel(O)
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_straightjacket(mob/living/carbon/human/user, obj/S)
if(S && user.wear_suit == S)
user.visible_message("
[S] dissolves into a puddle of sizzling goop.")
+ user.uncuff()
new /obj/effect/decal/cleanable/greenglow(S.drop_location())
qdel(S)
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_helpers/power_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
index 1935eb3e0b..c2479460c7 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
@@ -10,12 +10,15 @@
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
T.update_icon()
var/power_overwhelming = GLOB.clockwork_power
+ var/unlock_message
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
GLOB.script_scripture_unlocked = TRUE
- hierophant_message("
The Ark swells as a key power threshold is reached. Script scriptures are now available.")
+ unlock_message = "
The Ark swells as a key power threshold is reached. Script scriptures are now available."
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
GLOB.application_scripture_unlocked = TRUE
- hierophant_message("
The Ark surges as a key power threshold is reached. Application scriptures are now available.")
+ unlock_message = "
The Ark surges as a key power threshold is reached. Application scriptures are now available."
+ if(GLOB.servants_active)
+ hierophant_message(unlock_message)
return TRUE
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
index 0b94d34ab1..bfa27cefdb 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
@@ -11,6 +11,8 @@
//reports to servants when scripture is locked or unlocked
/proc/scripture_unlock_alert(list/previous_states)
+ if(!GLOB.servants_active)
+ return
. = scripture_unlock_check()
for(var/i in .)
if(.[i] != previous_states[i])
diff --git a/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm b/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
index acf6e43974..1b2b867aa5 100644
--- a/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/construct_chassis.dm
@@ -91,7 +91,8 @@
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
if(infinite_resources)
- construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar //During rounds where they can't interact with the station, let them experiment with builds
+ //During rounds where they can't interact with the station, let them experiment with builds
+ construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
if(infinite_resources) //Allow them to build stuff and recite scripture
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
index cc91feeb98..8416e4651d 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
@@ -14,16 +14,6 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/static/superheated_walls = 0
-/mob/camera/eminence/Initialize()
- if(SSticker.mode.eminence)
- return INITIALIZE_HINT_QDEL
- . = ..()
-
-/mob/camera/eminence/Destroy(force)
- if(!force && mind && SSticker.mode.eminence == mind)
- return QDEL_HINT_LETMELIVE
- return ..()
-
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
@@ -39,12 +29,20 @@
/mob/camera/eminence/Login()
..()
- add_servant_of_ratvar(src, TRUE)
+ var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(!C)
+ add_servant_of_ratvar(src, TRUE)
+ C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(C && C.clock_team)
+ if(C.clock_team.eminence)
+ remove_servant_of_ratvar(src,TRUE)
+ qdel(src)
+ else
+ C.clock_team.eminence = src
to_chat(src, "
You have been selected as the Eminence!")
to_chat(src, "
As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.")
to_chat(src, "
Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.")
to_chat(src, "
Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.")
- SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm b/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
index a1c3d211fb..562814dfeb 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
@@ -1,13 +1,13 @@
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
-#define MARAUDER_SHIELD_REGEN_TIME 100 //In deciseconds, how long it takes for shields to regenerate after breaking
+#define MARAUDER_SHIELD_REGEN_TIME 200 //In deciseconds, how long it takes for shields to regenerate after breaking
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
/mob/living/simple_animal/hostile/clockwork/marauder
name = "clockwork marauder"
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
icon_state = "clockwork_marauder"
- health = 150
- maxHealth = 150
+ health = 120
+ maxHealth = 120
force_threshold = 8
speed = 0
obj_damage = 40
@@ -39,10 +39,11 @@
speed = initial(speed) + 1 //Yes, this slows them down
else
speed = initial(speed)
- if(shield_health != max_shield_health && world.time >= shield_health_regen)
- to_chat(src, "
Your shield has recovered. [max_shield_health] blocks remaining!")
+ if(shield_health < max_shield_health && world.time >= shield_health_regen)
+ shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
+ to_chat(src, "
Your shield has recovered, [shield_health] blocks remaining!")
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
- shield_health = max_shield_health
+ shield_health++
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
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/eminence_spire.dm b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
index 8d4e936658..495bfaeaa8 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
@@ -17,7 +17,11 @@
return
if(kingmaking)
return
- if(SSticker.mode.eminence)
+
+ var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
+ if(!C || !C.clock_team)
+ return
+ if(C.clock_team.eminence)
to_chat(user, "
There's already an Eminence!")
return
if(!GLOB.servants_active)
@@ -34,7 +38,9 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
- if(SSticker.mode.eminence)
+
+ var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
+ if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "
There's already an Eminence - too late!")
return
if(!GLOB.servants_active)
diff --git a/code/game/gamemodes/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/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 8472c6c7cf..98faeae184 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
- var/is_convertable = is_convertable_to_cult(L)
+
+ var/mob/living/F = invokers[1]
+ var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+
+ var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && (is_clock || is_convertable))
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
+ var/mob/living/first_invoker = invokers[1]
+ if(!first_invoker)
+ return FALSE
+ var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C)
+ return
+
+
var/big_sac = FALSE
- if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
+ if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "
[sacrificial] is too greatly linked to the world! You need three acolytes!")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
- if(is_sacrifice_target(sacrificial.mind))
- GLOB.sac_complete = TRUE
- big_sac = TRUE
+ for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
+ if(sac_objective.target == sacrificial.mind)
+ sac_objective.sacced = TRUE
+ sac_objective.update_explanation_text()
+ big_sac = TRUE
else
GLOB.sacrificed += sacrificial
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
sleep(40)
if(src)
color = RUNE_COLOR_RED
- SSticker.mode.eldergod = FALSE
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
..()
-//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
+//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
/obj/effect/rune/raise_dead
- cultist_name = "Revive Cultist"
- cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
+ cultist_name = "Resurrect Cultist"
+ cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = TRUE
for(var/mob/living/M in T.contents)
- if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
+ if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
to_chat(user, "
There are no dead cultists on the rune!")
- log_game("Raise Dead rune failed - no cultists to revive")
+ log_game("Raise Dead rune failed - no corpses to revive")
+ fail_invoke()
+ rune_in_use = FALSE
+ return
+ if(LAZYLEN(GLOB.sacrificed) <= revives_used)
+ to_chat(user, "
You have sacrificed too few people to revive a cultist!")
fail_invoke()
rune_in_use = FALSE
return
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
else
invocation = initial(invocation)
..()
- if(mob_to_revive.stat == DEAD)
- if(LAZYLEN(GLOB.sacrificed) <= revives_used)
- to_chat(user, "
Your cult must carry out another sacrifice before it can revive a cultist!")
- fail_invoke()
- rune_in_use = FALSE
- return
- revives_used++
- mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
- mob_to_revive.grab_ghost()
- else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
- set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
- var/mob/dead/observer/theghost = null
- if(candidates.len)
- theghost = pick(candidates)
- to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
- message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
- mob_to_revive.ghostize(0)
- mob_to_revive.key = theghost.key
+ revives_used++
+ mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
+ mob_to_revive.grab_ghost()
to_chat(mob_to_revive, "
\"PASNAR SAVRAE YAM'TOTH. Arise.\"")
mob_to_revive.visible_message("
[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.", \
"
You awaken suddenly from the void. You're alive!")
diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm
index 957e261933..44f3368feb 100644
--- a/code/game/gamemodes/devil/game_mode.dm
+++ b/code/game/gamemodes/devil/game_mode.dm
@@ -3,32 +3,6 @@
var/list/datum/mind/devils = list()
var/devil_ascended = 0 // Number of arch devils on station
-/datum/game_mode/proc/auto_declare_completion_sintouched()
- var/text = ""
- if(sintouched.len)
- text += "
The sintouched were:"
- var/list/sintouchedUnique = uniqueList(sintouched)
- for(var/S in sintouchedUnique)
- var/datum/mind/sintouched_mind = S
- text += printplayer(sintouched_mind)
- text += printobjectives(sintouched_mind)
- text += "
"
- text += "
"
- to_chat(world, text)
-
-/datum/game_mode/proc/auto_declare_completion_devils()
- /var/text = ""
- if(devils.len)
- text += "
The devils were:"
- for(var/D in devils)
- var/datum/mind/devil = D
- text += printplayer(devil)
- text += printdevilinfo(devil.current)
- text += printobjectives(devil)
- text += "
"
- text += "
"
- to_chat(world, text)
-
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
for(var/i = 1 to quantity)
@@ -41,18 +15,6 @@
else
objective.find_target()
-/datum/game_mode/proc/printdevilinfo(mob/living/ply)
- var/datum/antagonist/devil/devilinfo = is_devil(ply)
- if(!devilinfo)
- return "Target is not a devil."
- var/text = "The devil's true name is: [devilinfo.truename]"
- text += "The devil's bans were:"
- text += " [GLOB.lawlorify[LORE][devilinfo.ban]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.bane]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.banish]]"
- return text
-
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
hud.join_hud(devil_mind.current)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 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/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index 9128847e16..3e7e5f01ef 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -2,6 +2,8 @@
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2
+#define MIND_DEVICE_MESSAGE 1
+#define MIND_DEVICE_CONTROL 2
//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
@@ -278,6 +280,84 @@
if(!istype(I, /obj/item/device/radio/headset))
r.broadcasting = 0 //goddamned headset hacks
+/obj/item/device/abductor/mind_device
+ name = "mental interface device"
+ desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
+ or to send a command to a test subject with a charged gland."
+ icon_state = "mind_device_message"
+ item_state = "silencer"
+ lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
+ var/mode = MIND_DEVICE_MESSAGE
+
+/obj/item/device/abductor/mind_device/attack_self(mob/user)
+ if(!ScientistCheck(user))
+ return
+
+ if(mode == MIND_DEVICE_MESSAGE)
+ mode = MIND_DEVICE_CONTROL
+ icon_state = "mind_device_control"
+ else
+ mode = MIND_DEVICE_MESSAGE
+ icon_state = "mind_device_message"
+ to_chat(user, "You switch the device to [mode==MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE")
+
+/obj/item/device/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
+ if(!ScientistCheck(user))
+ return
+
+ switch(mode)
+ if(MIND_DEVICE_CONTROL)
+ mind_control(target, user)
+ if(MIND_DEVICE_MESSAGE)
+ mind_message(target, user)
+
+/obj/item/device/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ var/obj/item/organ/heart/gland/G = C.getorganslot("heart")
+ if(!istype(G))
+ to_chat(user, "Your target does not have an experimental gland!")
+ return
+ if(!G.mind_control_uses)
+ to_chat(user, "Your target's gland is spent!")
+ return
+ if(G.active_mind_control)
+ to_chat(user, "Your target is already under a mind-controlling influence!")
+ return
+
+ var/command = stripped_input(user, "Enter the command for your target to follow.\
+ Uses Left: [G.mind_control_uses], Duration: [G.mind_control_duration / 10] seconds","Enter command")
+
+ if(!command)
+ return
+
+ if(QDELETED(user) || user.get_active_held_item() != src || loc != user)
+ return
+
+ if(QDELETED(G))
+ return
+
+ G.mind_control(command, user)
+ to_chat(user, "You send the command to your target.")
+
+/obj/item/device/abductor/mind_device/proc/mind_message(atom/target, mob/living/user)
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ to_chat(user, "Your target is dead!")
+ return
+ var/message = stripped_input(user, "Write a message to send to your target's brain.","Enter message")
+ if(!message)
+ return
+ if(QDELETED(L) || L.stat == DEAD)
+ return
+
+ to_chat(L, "You hear a voice in your head saying: [message]")
+ to_chat(user, "You send the message to your target.")
+ log_talk(user,"[key_name(user)] sent an abductor mind message to [L]/[L.ckey]: '[message]'", LOGSAY)
+
+
/obj/item/device/firing_pin/abductor
name = "alien firing pin"
icon_state = "firing_pin_ayy"
diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm
index 22edb79c80..508f4e9f13 100644
--- a/code/game/gamemodes/miniantags/abduction/gland.dm
+++ b/code/game/gamemodes/miniantags/abduction/gland.dm
@@ -12,28 +12,68 @@
var/human_only = 0
var/active = 0
+ var/mind_control_uses = 1
+ var/mind_control_duration = 1800
+ var/active_mind_control = FALSE
+
/obj/item/organ/heart/gland/proc/ownerCheck()
if(ishuman(owner))
- return 1
+ return TRUE
if(!human_only && iscarbon(owner))
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/item/organ/heart/gland/proc/Start()
active = 1
next_activation = world.time + rand(cooldown_low,cooldown_high)
+/obj/item/organ/heart/gland/proc/update_gland_hud()
+ if(!owner)
+ return
+ var/image/holder = owner.hud_list[GLAND_HUD]
+ var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
+ holder.pixel_y = I.Height() - world.icon_size
+ if(active_mind_control)
+ holder.icon_state = "hudgland_active"
+ else if(mind_control_uses)
+ holder.icon_state = "hudgland_ready"
+ else
+ holder.icon_state = "hudgland_spent"
-/obj/item/organ/heart/gland/Remove(var/mob/living/carbon/M, special = 0)
+/obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user)
+ if(!ownerCheck() || !mind_control_uses || active_mind_control)
+ return
+ mind_control_uses--
+ to_chat(owner, "You suddenly feel an irresistible compulsion to follow an order...")
+ to_chat(owner, "[command]")
+ active_mind_control = TRUE
+ log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
+ update_gland_hud()
+
+ addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
+
+/obj/item/organ/heart/gland/proc/clear_mind_control()
+ if(!ownerCheck() || !active_mind_control)
+ return
+ to_chat(owner, "You feel the compulsion fade, and you completely forget about your previous orders.")
+ active_mind_control = FALSE
+
+/obj/item/organ/heart/gland/Remove(mob/living/carbon/M, special = 0)
active = 0
if(initial(uses) == 1)
uses = initial(uses)
+ var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ hud.remove_from_hud(owner)
+ clear_mind_control()
..()
-/obj/item/organ/heart/gland/Insert(var/mob/living/carbon/M, special = 0)
+/obj/item/organ/heart/gland/Insert(mob/living/carbon/M, special = 0)
..()
if(special != 2 && uses) // Special 2 means abductor surgery
Start()
+ var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ hud.add_to_hud(owner)
+ update_gland_hud()
/obj/item/organ/heart/gland/on_life()
if(!beating)
@@ -59,6 +99,8 @@
cooldown_high = 400
uses = -1
icon_state = "health"
+ mind_control_uses = 3
+ mind_control_duration = 3000
/obj/item/organ/heart/gland/heals/activate()
to_chat(owner, "You feel curiously revitalized.")
@@ -71,6 +113,8 @@
cooldown_high = 1200
uses = -1
icon_state = "slime"
+ mind_control_uses = 1
+ mind_control_duration = 2400
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "You feel nauseous!")
@@ -86,6 +130,8 @@
cooldown_high = 300
uses = -1
icon_state = "mindshock"
+ mind_control_uses = 1
+ mind_control_duration = 6000
/obj/item/organ/heart/gland/mindshock/activate()
to_chat(owner, "You get a headache.")
@@ -103,6 +149,8 @@
uses = -1
human_only = 1
icon_state = "species"
+ mind_control_uses = 5
+ mind_control_duration = 300
/obj/item/organ/heart/gland/pop/activate()
to_chat(owner, "You feel unlike yourself.")
@@ -114,6 +162,8 @@
cooldown_high = 2400
uses = 1
icon_state = "vent"
+ mind_control_uses = 4
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "You feel very stretchy.")
@@ -125,6 +175,8 @@
cooldown_high = 2400
uses = 1
icon_state = "viral"
+ mind_control_uses = 1
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/viral/activate()
to_chat(owner, "You feel sick.")
@@ -141,6 +193,8 @@
cooldown_high = 1600
uses = 10
icon_state = "emp"
+ mind_control_uses = 1
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/emp/activate()
to_chat(owner, "You feel a spike of pain in your head.")
@@ -151,6 +205,8 @@
cooldown_high = 900
uses = 10
icon_state = "spider"
+ mind_control_uses = 2
+ mind_control_duration = 2400
/obj/item/organ/heart/gland/spiderman/activate()
to_chat(owner, "You feel something crawling in your skin.")
@@ -164,6 +220,8 @@
icon_state = "egg"
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
+ mind_control_uses = 2
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/egg/activate()
to_chat(owner, "You lay an egg!")
@@ -175,6 +233,8 @@
cooldown_low = 200
cooldown_high = 400
uses = -1
+ mind_control_uses = 1
+ mind_control_duration = 450
/obj/item/organ/heart/gland/bloody/activate()
owner.blood_volume -= 20
@@ -192,6 +252,8 @@
cooldown_high = 600
human_only = 1
uses = 1
+ mind_control_uses = 1
+ mind_control_duration = 600
/obj/item/organ/heart/gland/bodysnatch/activate()
to_chat(owner, "You feel something moving around inside you...")
@@ -233,6 +295,8 @@
cooldown_low = 1200
cooldown_high = 1800
uses = -1
+ mind_control_uses = 1
+ mind_control_duration = 800
/obj/item/organ/heart/gland/plasma/activate()
to_chat(owner, "You feel bloated.")
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
index f243f161c3..0b13c359eb 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
@@ -48,6 +48,7 @@
dat += "Agent Vest
"
dat += "Radio Silencer
"
dat += "Science Tool
"
+ dat += "Mental Interface Device
"
else
dat += "NO EXPERIMENT MACHINE DETECTED
"
@@ -109,6 +110,8 @@
Dispense(/obj/item/device/abductor/gizmo)
if("vest")
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
+ if("mind_device")
+ Dispense(/obj/item/device/abductor/mind_device,cost=2)
updateUsrDialog()
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index c3a591a278..cf1329aec9 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -151,13 +151,18 @@
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat != DEAD)
if(href_list["experiment"])
- flash = Experiment(occupant,href_list["experiment"])
+ flash = Experiment(occupant,href_list["experiment"],usr)
updateUsrDialog()
add_fingerprint(usr)
-/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
+/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
LAZYINITLIST(history)
var/mob/living/carbon/human/H = occupant
+
+ var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
+ if(!user_abductor)
+ return "Authorization failure. Contact mothership immidiately."
+
var/point_reward = 0
if(H in history)
return "Specimen already in database."
@@ -182,15 +187,8 @@
if(3)
to_chat(H, "You feel intensely watched.")
sleep(5)
- to_chat(H, "Your mind snaps!")
- H.gain_trauma_type(BRAIN_TRAUMA_MILD)
- to_chat(H, "You can't remember how you got here...")
- var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
- var/datum/objective/abductee/O = new objtype()
- SSticker.mode.abductees += H.mind
- H.mind.objectives += O
- H.mind.announce_objectives()
- SSticker.mode.update_abductor_icons_added(H.mind)
+ user_abductor.team.abductees += H.mind
+ H.mind.add_antag_datum(/datum/antagonist/abductee)
for(var/obj/item/organ/heart/gland/G in H.internal_organs)
G.Start()
diff --git a/code/game/gamemodes/miniantags/monkey/monkey.dm b/code/game/gamemodes/miniantags/monkey/monkey.dm
index 379031dce9..8e02d41441 100644
--- a/code/game/gamemodes/miniantags/monkey/monkey.dm
+++ b/code/game/gamemodes/miniantags/monkey/monkey.dm
@@ -105,13 +105,18 @@
monkey_mind.special_role = null
-/datum/game_mode/monkey/declare_completion()
+/datum/game_mode/monkey/set_round_result()
+ ..()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
- to_chat(world, "The monkeys have overthrown their captors! Eeek eeeek!!")
else
SSticker.mode_result = "loss - staff stopped the monkeys"
- to_chat(world, "The staff managed to contain the monkey infestation!")
+
+/datum/game_mode/monkey/special_report()
+ if(check_monkey_victory())
+ return "The monkeys have overthrown their captors! Eeek eeeek!!"
+ else
+ return "The staff managed to contain the monkey infestation!"
/datum/game_mode/monkey/generate_report()
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 5e1a97675b..2ebc21adac 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -227,6 +227,7 @@
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
SSticker.mode.traitors |= player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
message_admins("[key_name_admin(S)] has been made into a morph by an event.")
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index b4dc0794cc..441689fb9b 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -87,6 +87,7 @@
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
SSticker.mode.traitors |= mind //Necessary for announcing
+ mind.add_antag_datum(/datum/antagonist/auto_custom)
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
index f1f9624380..e62665f21b 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
@@ -38,6 +38,7 @@
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
SSticker.mode.traitors |= player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.")
SEND_SOUND(S, 'sound/magic/demon_dies.ogg')
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 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/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index e5bd141d05..67f79f4c52 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -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,10 +518,11 @@
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
@@ -532,7 +533,7 @@
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/dance_machine.dm b/code/game/machinery/dance_machine.dm
index ec8779b7d2..79ec733303 100644
--- a/code/game/machinery/dance_machine.dm
+++ b/code/game/machinery/dance_machine.dm
@@ -459,6 +459,8 @@
var/sound/song_played = sound(selection.song_path)
for(var/mob/M in range(10,src))
+ if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
+ continue
if(!(M in rangers))
rangers[M] = TRUE
M.playsound_local(get_turf(M), null, 100, channel = CHANNEL_JUKEBOX, S = song_played)
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/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/items.dm b/code/game/objects/items.dm
index 52933c4fbe..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.
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/defib.dm b/code/game/objects/items/defib.dm
index 22cd62a962..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)
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/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/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/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/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/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/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index b901d04815..5af62e093b 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -198,8 +198,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
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index e4485266b5..d2f1d2a31b 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -33,7 +33,7 @@
add_logs(user, M, "stunned", src, "(INTENT: [uppertext(user.a_intent)])")
/obj/item/borg/cyborghug
- name = "Hugging Module"
+ name = "hugging module"
icon_state = "hugmodule"
desc = "For when a someone really needs a hug."
var/mode = 0 //0 = Hugs 1 = "Hug" 2 = Shock 3 = CRUSH
@@ -336,6 +336,10 @@
cooldown = world.time + 600
log_game("[user.ckey]([user]) used an emagged Cyborg Harm Alarm in ([user.x],[user.y],[user.z])")
+#define DISPENSE_LOLLIPOP_MODE 1
+#define THROW_LOLLIPOP_MODE 2
+#define THROW_GUMBALL_MODE 3
+
/obj/item/borg/lollipop
name = "lollipop fabricator"
desc = "Reward good humans with this. Toggle in-module to switch between dispensing and high velocity ejection modes."
@@ -343,8 +347,9 @@
var/candy = 30
var/candymax = 30
var/charge_delay = 10
- var/charging = 0
- var/mode = 1
+ var/charging = FALSE
+ var/mode = DISPENSE_LOLLIPOP_MODE
+
var/firedelay = 0
var/hitspeed = 2
var/hitdamage = 0
@@ -379,10 +384,22 @@
var/obj/O = A
if(O.density)
return FALSE
- new /obj/item/reagent_containers/food/snacks/lollipop(T)
+
+ var/obj/item/reagent_containers/food/snacks/lollipop/L = new(T)
+
+ var/into_hands = FALSE
+ if(ismob(A))
+ var/mob/M = A
+ into_hands = M.put_in_hands(L)
+
candy--
check_amount()
- to_chat(user, "Dispensing lollipop...")
+
+ if(into_hands)
+ user.visible_message("[user] dispenses a lollipop into the hands of [A].", "You dispense a lollipop into the hands of [A].", "You hear a click.")
+ else
+ user.visible_message("[user] dispenses a lollipop.", "You dispense a lollipop.", "You hear a click.")
+
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
return TRUE
@@ -427,29 +444,33 @@
if(R.emagged)
hitdamage = emaggedhitdamage
switch(mode)
- if(1)
+ if(DISPENSE_LOLLIPOP_MODE)
if(!proximity)
return FALSE
dispense(target, user)
- if(2)
+ if(THROW_LOLLIPOP_MODE)
shootL(target, user, click_params)
- if(3)
+ if(THROW_GUMBALL_MODE)
shootG(target, user, click_params)
hitdamage = initial(hitdamage)
/obj/item/borg/lollipop/attack_self(mob/living/user)
switch(mode)
- if(1)
- mode++
+ if(DISPENSE_LOLLIPOP_MODE)
+ mode = THROW_LOLLIPOP_MODE
to_chat(user, "Module is now throwing lollipops.")
- if(2)
- mode++
+ if(THROW_LOLLIPOP_MODE)
+ mode = THROW_GUMBALL_MODE
to_chat(user, "Module is now blasting gumballs.")
- if(3)
- mode = 1
+ if(THROW_GUMBALL_MODE)
+ mode = DISPENSE_LOLLIPOP_MODE
to_chat(user, "Module is now dispensing lollipops.")
..()
+#undef DISPENSE_LOLLIPOP_MODE
+#undef THROW_LOLLIPOP_MODE
+#undef THROW_GUMBALL_MODE
+
/obj/item/ammo_casing/caseless/gumball
name = "Gumball"
desc = "Why are you seeing this?!"
@@ -616,7 +637,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\".")
@@ -626,7 +647,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)
@@ -655,7 +676,7 @@
/obj/item/borg/sight/xray
- name = "\proper x-ray Vision"
+ name = "\proper x-ray vision"
icon = 'icons/obj/decals.dmi'
icon_state = "securearea"
sight_mode = BORGXRAY
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/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/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/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/toys.dm b/code/game/objects/items/toys.dm
index e82f536dad..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", 50, 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 dc61944b4f..293ef46197 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -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/reflector.dm b/code/game/objects/structures/reflector.dm
index e47afd53d4..1ae513f847 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.Angle = 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.Angle = new_angle
return ..()
//BOX
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/sound.dm b/code/game/sound.dm
index 085c5eecd5..9cfa197738 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -182,7 +182,15 @@
if("bullet_miss")
soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg')
if("gun_dry_fire")
- soundin = pick('sound/weapons/dry_fire_1.ogg', 'sound/weapons/dry_fire_2.ogg', 'sound/weapons/dry_fire_3.ogg', 'sound/weapons/dry_fire_4.ogg')
+ soundin = pick('sound/weapons/gun_dry_fire_1.ogg', 'sound/weapons/gun_dry_fire_2.ogg', 'sound/weapons/gun_dry_fire_3.ogg', 'sound/weapons/gun_dry_fire_4.ogg')
+ if("gun_insert_empty_magazine")
+ soundin = pick('sound/weapons/gun_magazine_insert_empty_1.ogg', 'sound/weapons/gun_magazine_insert_empty_2.ogg', 'sound/weapons/gun_magazine_insert_empty_3.ogg', 'sound/weapons/gun_magazine_insert_empty_4.ogg')
+ if("gun_insert_full_magazine")
+ soundin = pick('sound/weapons/gun_magazine_insert_full_1.ogg', 'sound/weapons/gun_magazine_insert_full_2.ogg', 'sound/weapons/gun_magazine_insert_full_3.ogg', 'sound/weapons/gun_magazine_insert_full_4.ogg', 'sound/weapons/gun_magazine_insert_full_5.ogg')
+ if("gun_remove_empty_magazine")
+ soundin = pick('sound/weapons/gun_magazine_remove_empty_1.ogg', 'sound/weapons/gun_magazine_remove_empty_2.ogg', 'sound/weapons/gun_magazine_remove_empty_3.ogg', 'sound/weapons/gun_magazine_remove_empty_4.ogg')
+ if("gun_slide_lock")
+ soundin = pick('sound/weapons/gun_slide_lock_1.ogg', 'sound/weapons/gun_slide_lock_2.ogg', 'sound/weapons/gun_slide_lock_3.ogg', 'sound/weapons/gun_slide_lock_4.ogg', 'sound/weapons/gun_slide_lock_5.ogg')
if("law")
soundin = pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
if("honkbot_e")
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/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/walls.dm b/code/game/turfs/simulated/walls.dm
index 337bb051a8..00377e4f3f 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -54,7 +54,7 @@
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
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..29d95c639f 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
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/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/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..407e9aa37c 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
@@ -227,6 +227,13 @@ GLOBAL_LIST(external_rsc_urls)
message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ")
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).")
+ if(GLOB.player_details[ckey])
+ player_details = GLOB.player_details[ckey]
+ else
+ player_details = new
+ GLOB.player_details[ckey] = player_details
+
+
. = ..() //calls mob.Login()
chatOutput.start() // Starts the chat
@@ -673,6 +680,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..0469f31aba 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1596,12 +1596,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/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/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 3085f1bcce..beb3fb476f 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -10,22 +10,30 @@
var/virus_type
+ var/max_severity = 3
-/datum/round_event/disease_outbreak/announce(fake)
+
+/datum/round_event/disease_outbreak/announce()
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak7.ogg')
/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))
var/turf/T = get_turf(H)
if(!T)
continue
- if(!(T.z in GLOB.station_z_levels))
+ if(T.z != ZLEVEL_STATION_PRIMARY)
continue
if(!H.client)
continue
@@ -53,7 +61,7 @@
else
D = new virus_type()
else
- D = new virus_type()
+ D = make_virus(max_severity, max_severity)
D.carrier = TRUE
H.AddDisease(D)
break
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/events/wizard/race.dm b/code/modules/events/wizard/race.dm
index 29773d95b2..5adc4bb851 100644
--- a/code/modules/events/wizard/race.dm
+++ b/code/modules/events/wizard/race.dm
@@ -12,7 +12,7 @@
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
- if(!S.dangerous_existence)
+ if(!S.dangerous_existence && !S.blacklisted)
all_species += speciestype
var/datum/species/new_species = pick(all_species)
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/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 9f76139151..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!")
@@ -277,9 +277,9 @@
operating = FALSE // Turn it off again aferwards
icon_state = "mw"
updateUsrDialog()
+ soundloop.stop()
/obj/machinery/microwave/proc/stop()
- soundloop.stop()
abort()
/obj/machinery/microwave/proc/dispose()
@@ -293,7 +293,6 @@
icon_state = "mwbloody1" // Make it look dirty!!
/obj/machinery/microwave/proc/muck_finish()
- playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
visible_message("The microwave gets covered in muck!")
dirty = 100 // Make it dirty so it can't be used util cleaned
icon_state = "mwbloody" // Make it look dirty too
@@ -303,6 +302,7 @@
if(prob(50))
new /obj/item/reagent_containers/food/snacks/badrecipe(src)
qdel(S)
+ soundloop.stop()
/obj/machinery/microwave/proc/broke()
var/datum/effect_system/spark_spread/s = new
@@ -314,6 +314,7 @@
flags_1 = null //So you can't add condiments
operating = FALSE // Turn it off again aferwards
updateUsrDialog()
+ soundloop.stop()
/obj/machinery/microwave/Topic(href, href_list)
if(..() || panel_open)
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 4d31d082c6..c72f26a4e7 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -13,7 +13,7 @@ body {
background: #fff;
font-family: Verdana, sans-serif;
font-size: 9pt;
- line-height: 1.4;
+ line-height: 1.2;
overflow-x: hidden;
overflow-y: scroll;
word-wrap: break-word;
@@ -38,6 +38,19 @@ img.icon {
vertical-align: bottom;
}
+
+.r:before { /* "repeated" badge class for combined messages */
+ content: 'x';
+}
+.r {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ color: #f00;
+}
+
a {color: #0000ff;}
a.visited {color: #ff00ff;}
a:visited {color: #ff00ff;}
@@ -377,6 +390,7 @@ h1.alert, h2.alert {color: #000000;}
.memo {color: #638500; text-align: center;}
.memoedit {text-align: center; font-size: 16px;}
.abductor {color: #800080; font-style: italic;}
+.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;}
.slime {color: #00CED1;}
.drone {color: #848482;}
.monkey {color: #975032;}
diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html
index 7b2d3ecfe0..d40fd75f39 100644
--- a/code/modules/goonchat/browserassets/html/browserOutput.html
+++ b/code/modules/goonchat/browserassets/html/browserOutput.html
@@ -36,9 +36,12 @@
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js
index 2ef7704625..4ca135bfd7 100644
--- a/code/modules/goonchat/browserassets/js/browserOutput.js
+++ b/code/modules/goonchat/browserassets/js/browserOutput.js
@@ -22,7 +22,7 @@ window.onerror = function(msg, url, line, col, error) {
//Globals
window.status = 'Output';
-var $messages, $subOptions, $subAudio, $selectedSub, $contextMenu, $filterMessages;
+var $messages, $subOptions, $subAudio, $selectedSub, $contextMenu, $filterMessages, $last_message;
var opts = {
//General
'messageCount': 0, //A count...of messages...
@@ -68,6 +68,8 @@ var opts = {
'defaultMusicVolume': 25,
+ 'messageCombining': true,
+
};
function clamp(val, min, max) {
@@ -294,27 +296,54 @@ function output(message, flag) {
opts.messageCount--; //I guess the count should only ever equal the limit
}
- //Actually append the message
- var entry = document.createElement('div');
- entry.className = 'entry';
-
- if (filteredOut) {
- entry.className += ' hidden';
- entry.setAttribute('data-filter', filteredOut);
+ var handled = false;
+ var trimmed_message = message.trim()
+ var lastmessages = $messages.children('div.entry:last-child');
+ if (opts.messageCombining && lastmessages.length && $last_message)
+ {
+ if($last_message == trimmed_message)
+ {
+ if(lastmessages.children('span.r').length)
+ {
+ var current_value = parseInt(lastmessages.children('span.r').text())
+ lastmessages.children('span.r').text(current_value+1)
+ }
+ else
+ {
+ lastmessages.append($('
', { 'class': 'r', 'text': 2}));
+ }
+ if(parseInt(lastmessages.css("font-size")) < 24) //Completely arbitrary max size
+ lastmessages.css("font-size","+=2")
+ opts.messageCount--;
+ handled = true;
+ }
+ }
+
+ if(!handled)
+ {
+ //Actually append the message
+ var entry = document.createElement('div');
+ entry.className = 'entry';
+
+ if (filteredOut) {
+ entry.className += ' hidden';
+ entry.setAttribute('data-filter', filteredOut);
+ }
+
+ $last_message = trimmed_message;
+ entry.innerHTML = trimmed_message;
+ $messages[0].appendChild(entry);
+ $(entry).find("img.icon").error(iconError);
+ //Actually do the snap
+ //Stuff we can do after the message shows can go here, in the interests of responsiveness
+ if (opts.highlightTerms && opts.highlightTerms.length > 0) {
+ highlightTerms(entry);
+ }
}
- entry.innerHTML = message.trim();
- $messages[0].appendChild(entry);
- $(entry).find("img.icon").error(iconError);
- //Actually do the snap
if (!filteredOut && atBottom) {
$('body,html').scrollTop($messages.outerHeight());
}
-
- //Stuff we can do after the message shows can go here, in the interests of responsiveness
- if (opts.highlightTerms && opts.highlightTerms.length > 0) {
- highlightTerms(entry);
- }
}
function internalOutput(message, flag)
@@ -564,16 +593,22 @@ $(function() {
******************************************/
var savedConfig = {
'sfontSize': getCookie('fontsize'),
+ 'slineHeight': getCookie('lineheight'),
'spingDisabled': getCookie('pingdisabled'),
'shighlightTerms': getCookie('highlightterms'),
'shighlightColor': getCookie('highlightcolor'),
'smusicVolume': getCookie('musicVolume'),
+ 'smessagecombining': getCookie('messagecombining'),
};
if (savedConfig.sfontSize) {
$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;
@@ -606,7 +641,15 @@ $(function() {
opts.updatedVolume = newVolume;
sendVolumeUpdate();
internalOutput('
Loaded music volume of: '+savedConfig.smusicVolume+'', 'internal');
- } else {
+ }
+ if (savedConfig.smessagecombining) {
+ if (savedConfig.smessagecombining == 'false') {
+ opts.messageCombining = false;
+ } else {
+ opts.messageCombining = true;
+ }
+ }
+ else {
$('#adminMusic').prop('volume', opts.defaultMusicVolume / 100);
}
@@ -805,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');
@@ -922,6 +987,11 @@ $(function() {
}
});
+ $('#toggleCombine').click(function(e) {
+ opts.messageCombining = !opts.messageCombining;
+ setCookie('messagecombining', (opts.messageCombining ? 'true' : 'false'), 365);
+ });
+
$('img.icon').error(iconError);
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index 388a9d6893..85605fd2c4 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -387,9 +387,9 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
/datum/holiday/xmas
name = CHRISTMAS
- begin_day = 23
+ begin_day = 22
begin_month = DECEMBER
- end_day = 25
+ end_day = 27
/datum/holiday/xmas/greet()
return "Have a merry Christmas!"
diff --git a/code/modules/hydroponics/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/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index c8c042e30b..d655ed6e94 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -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/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index c745de747e..b01c7c09ac 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -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/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index cf8a833bd8..0760453094 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -59,6 +59,14 @@ Doesn't work on other aliens/AI.*/
return 0
return 1
+/obj/effect/proc_holder/alien/proc/check_vent_block(mob/living/user)
+ var/obj/machinery/atmospherics/components/unary/atmos_thing = locate() in user.loc
+ if(atmos_thing)
+ var/rusure = alert(user, "Laying eggs and shaping resin here would block access to [atmos_thing]. Do you want to continue?", "Blocking Atmospheric Component", "Yes", "No")
+ if(rusure != "No")
+ return FALSE
+ return TRUE
+
/obj/effect/proc_holder/alien/plant
name = "Plant Weeds"
desc = "Plants some alien weeds."
@@ -243,7 +251,7 @@ Doesn't work on other aliens/AI.*/
name = "Secrete Resin"
desc = "Secrete tough malleable resin."
plasma_cost = 55
- check_turf = 1
+ check_turf = TRUE
var/list/structures = list(
"resin wall" = /obj/structure/alien/resin/wall,
"resin membrane" = /obj/structure/alien/resin/membrane,
@@ -254,18 +262,22 @@ Doesn't work on other aliens/AI.*/
/obj/effect/proc_holder/alien/resin/fire(mob/living/carbon/user)
if(locate(/obj/structure/alien/resin) in user.loc)
to_chat(user, "There is already a resin structure there.")
- return 0
+ return FALSE
+
+ if(!check_vent_block(user))
+ return FALSE
+
var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in structures
if(!choice)
- return 0
+ return FALSE
if (!cost_check(check_turf,user))
- return 0
+ return FALSE
to_chat(user, "You shape a [choice].")
user.visible_message("[user] vomits up a thick purple substance and begins to shape it.")
choice = structures[choice]
new choice(user.loc)
- return 1
+ return TRUE
/obj/effect/proc_holder/alien/regurgitate
name = "Regurgitate"
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index 4f79ed7d25..5a48e1c6d1 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -79,16 +79,20 @@
name = "Lay Egg"
desc = "Lay an egg to produce huggers to impregnate prey with."
plasma_cost = 75
- check_turf = 1
+ check_turf = TRUE
action_icon_state = "alien_egg"
/obj/effect/proc_holder/alien/lay_egg/fire(mob/living/carbon/user)
if(locate(/obj/structure/alien/egg) in get_turf(user))
- to_chat(user, "There's already an egg here.")
- return 0
+ to_chat(user, "There's already an egg here.")
+ return FALSE
+
+ if(!check_vent_block(user))
+ return FALSE
+
user.visible_message("[user] has laid an egg!")
new /obj/structure/alien/egg(user.loc)
- return 1
+ return TRUE
//Button to let queen choose her praetorian.
/obj/effect/proc_holder/alien/royal/queen/promote
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_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 4e409391da..d601fde492 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -2,6 +2,7 @@
gender = MALE
pressure_resistance = 15
possible_a_intents = list(INTENT_HELP, INTENT_HARM)
+ hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD)
var/list/stomach_contents = list()
var/list/internal_organs = list() //List of /obj/item/organ in the mob. They don't go in the contents for some reason I don't want to know.
var/list/internal_organs_slot= list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
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/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_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index cdb714156a..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
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 8e72b26419..716373061d 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -1,5 +1,5 @@
/mob/living/carbon/human
- hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD)
+ hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD,GLAND_HUD)
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
pressure_resistance = 25
//Hair colour and style
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index d1d657652b..41875b7d91 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -91,17 +91,6 @@
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)
return FALSE
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 329e59e305..451fadab62 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1320,9 +1320,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
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
@@ -1347,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")
@@ -1369,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()
@@ -1390,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)
@@ -1514,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/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index cf03d12130..cd273ec98e 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -9,3 +9,13 @@
/datum/species/abductor/copy_properties_from(datum/species/abductor/old_species)
scientist = old_species.scientist
+
+/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ abductor_hud.add_hud_to(C)
+
+/datum/species/abductor/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ abductor_hud.remove_hud_from(C)
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 25be12a0ff..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
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/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm
index 2fe526368a..792485960e 100644
--- a/code/modules/mob/living/carbon/human/species_types/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm
@@ -25,7 +25,7 @@
limbs_id = "zombie"
mutanthands = /obj/item/zombie_hand
armor = 20 // 120 damage to KO a zombie, which kills it
- speedmod = 2
+ speedmod = 1.6
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
var/regen_cooldown = 0
@@ -34,7 +34,7 @@
/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount)
- . = min(2, amount)
+ . = min(20, amount)
/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
. = ..()
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 bd88714fd4..3e6b7f3ddd 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -121,17 +121,16 @@
if(L == src)
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/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index 74385b895c..1d5525edd9 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -59,10 +59,10 @@
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)
////////////////////////////////////////TRAUMAS/////////////////////////////////////////
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/living.dm b/code/modules/mob/living/living.dm
index bd6b00dea7..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
@@ -808,7 +815,7 @@
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))
@@ -920,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()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 4dc2b6d076..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,7 +127,7 @@
/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
@@ -135,7 +135,6 @@
if(!(status_flags & CANPUSH))
to_chat(user, "[src] can't be grabbed more aggressively!")
return FALSE
-
if(user.has_disability(PACIFISM))
to_chat(user, "You don't want to risk hurting [src]!")
return FALSE
@@ -200,13 +199,13 @@
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!")
@@ -217,13 +216,13 @@
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))
@@ -231,24 +230,24 @@
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))
@@ -260,30 +259,29 @@
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))
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..2788413ee9 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -1029,9 +1029,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..26e455106b 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -352,7 +352,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "k9"
- moduleselect_icon = "k9"
+ moduleselect_icon = "security"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -387,7 +387,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "medihound"
- moduleselect_icon = "medihound"
+ moduleselect_icon = "medical"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -409,7 +409,7 @@
/obj/item/clockwork/slab/cyborg/janitor,
/obj/item/clockwork/replica_fabricator/cyborg)
cyborg_base_icon = "scrubpup"
- moduleselect_icon = "scrubpup"
+ moduleselect_icon = "janitor"
hat_offset = INFINITY
clean_on_move = TRUE
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0e6ecf1672..8046daf55d 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -360,8 +360,14 @@
..()
/datum/action/innate/seek_master/Activate()
- if(!SSticker.mode.eldergod)
- the_construct.master = GLOB.blood_target
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult)
+ if(!C)
+ return
+ var/datum/objective/eldergod/summon_objective = locate() in C.cult_team.objectives
+
+ if(summon_objective.check_completion())
+ the_construct.master = C.cult_team.blood_target
+
if(!the_construct.master)
to_chat(the_construct, "You have no master to seek!")
the_construct.seeking = FALSE
diff --git a/code/modules/mob/living/simple_animal/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/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 b8b419087f..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))
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/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_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/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm
index 1656a43505..b26d01d880 100644
--- a/code/modules/ninja/ninja_event.dm
+++ b/code/modules/ninja/ninja_event.dm
@@ -95,7 +95,7 @@ Contents:
var/datum/mind/Mind = new /datum/mind(key)
Mind.assigned_role = "Space Ninja"
Mind.special_role = "Space Ninja"
- SSticker.mode.traitors |= Mind //Adds them to current traitor list. Which is really the extra antagonist list.
+ SSticker.mode.traitors |= Mind //Adds them to current traitor list. TODO : Remove this in admin tools refeactor.
return Mind
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index fd52d8f0ac..cde600186f 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -162,7 +162,7 @@
* Sleepypens
*/
/obj/item/pen/sleepy
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
/obj/item/pen/sleepy/attack(mob/living/M, mob/user)
diff --git a/code/modules/power/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 324470ede4..bf941108ff 100644
--- a/code/modules/projectiles/box_magazine.dm
+++ b/code/modules/projectiles/box_magazine.dm
@@ -87,7 +87,7 @@
if(num_loaded)
if(!silent)
to_chat(user, "You load [num_loaded] shell\s into \the [src]!")
- playsound(user, 'sound/weapons/bulletinsert.ogg', 60, 1)
+ playsound(src, 'sound/weapons/bulletinsert.ogg', 60, 1)
A.update_icon()
update_icon()
@@ -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(user, '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/gun.dm b/code/modules/projectiles/gun.dm
index e93f298999..8d019b842a 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", 50, 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)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index e75905b8c1..680c86ff5c 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -30,8 +30,8 @@
var/obj/item/ammo_casing/AC = chambered //Find chambered round
if(istype(AC)) //there's a chambered round
if(casing_ejector)
- AC.forceMove(get_turf(src)) //Eject casing onto ground.
- AC.SpinAnimation(10, 1) //next gen special effects
+ AC.forceMove(drop_location()) //Eject casing onto ground.
+ AC.bounce_away(TRUE)
chambered = null
else if(empty_chamber)
chambered = null
@@ -58,7 +58,13 @@
if(user.transferItemToLoc(AM, src))
magazine = AM
to_chat(user, "You load a new magazine into \the [src].")
- chamber_round()
+ if(magazine.ammo_count())
+ playsound(src, "gun_insert_full_magazine", 70, 1)
+ if(!chambered)
+ chamber_round()
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/weapons/gun_chamber_round.ogg', 100, 1), 3)
+ else
+ playsound(src, "gun_insert_empty_magazine", 70, 1)
A.update_icon()
update_icon()
return 1
@@ -110,13 +116,18 @@
magazine.forceMove(drop_location())
user.put_in_hands(magazine)
magazine.update_icon()
+ if(magazine.ammo_count())
+ playsound(src, "sound/weapons/gun_magazine_remove_full.ogg", 70, 1)
+ else
+ playsound(src, "gun_remove_empty_magazine", 70, 1)
magazine = null
to_chat(user, "You pull the magazine out of \the [src].")
else if(chambered)
AC.forceMove(drop_location())
- AC.SpinAnimation(10, 1)
+ AC.bounce_away()
chambered = null
to_chat(user, "You unload the round from \the [src]'s chamber.")
+ playsound(src, "gun_slide_lock", 70, 1)
else
to_chat(user, "There's no magazine in \the [src].")
update_icon()
@@ -162,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", 50, 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 aeceb041c6..b98bdaf957 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -40,12 +40,10 @@
CB = magazine.get_round(0)
if(CB)
CB.forceMove(drop_location())
- CB.SpinAnimation(10, 1)
- CB.update_icon()
+ CB.bounce_away(FALSE, NONE)
num_unloaded++
if (num_unloaded)
to_chat(user, "You unload [num_unloaded] shell\s from [src].")
- playsound(user, 'sound/weapons/bulletremove.ogg', 60, 1)
else
to_chat(user, "[src] is empty!")
@@ -229,7 +227,7 @@
return
user.visible_message("*click*")
- playsound(src, "gun_dry_fire", 50, 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)
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index e6e06cfd68..e702013233 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -57,7 +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(5, 1)
+ 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..ee8036bf44 100644
--- a/code/modules/projectiles/guns/beam_rifle.dm
+++ b/code/modules/projectiles/guns/beam_rifle.dm
@@ -365,7 +365,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 +416,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
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 3adadb90eb..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", 50, 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/projectile.dm b/code/modules/projectiles/projectile.dm
index 0e3bd98c68..79e2fdf903 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -168,7 +168,7 @@
/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
@@ -188,7 +188,7 @@
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)
@@ -259,7 +259,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 +267,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)
@@ -287,7 +287,7 @@
setAngle(Angle + ((rand() - 0.5) * spread))
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)
+ 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
@@ -403,7 +403,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 dc92dd3b52..7941853a91 100644
--- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm
+++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
@@ -1,3 +1,5 @@
+#define REAGENTS_BASE_VOLUME 100 // actual volume is REAGENTS_BASE_VOLUME plus REAGENTS_BASE_VOLUME * rating for each matterbin
+
/obj/machinery/smoke_machine
name = "smoke machine"
desc = "A machine with a centrifuge installed into it. It produces smoke with any reagents you put into the machine."
@@ -11,14 +13,13 @@
var/cooldown = 0
var/screen = "home"
var/useramount = 30 // Last used amount
- var/volume = 300
- var/setting = 3
- var/list/possible_settings = list(3,6,9)
+ var/setting = 1 // displayed range is 3 * setting
+ var/max_range = 3 // displayed max range is 3 * max range
-/datum/effect_system/smoke_spread/chem/smoke_machine/set_up(datum/reagents/carry, setting = 3, efficiency = 10, loc)
- amount = setting
+/datum/effect_system/smoke_spread/chem/smoke_machine/set_up(datum/reagents/carry, setting=1, efficiency=10, loc)
+ amount = setting * 3
carry.copy_to(chemholder, 20)
- carry.remove_any(setting * 16 / efficiency)
+ carry.remove_any(amount * 16 / efficiency)
location = loc
/datum/effect_system/smoke_spread/chem/smoke_machine
@@ -28,10 +29,11 @@
opaque = FALSE
alpha = 100
-
/obj/machinery/smoke_machine/Initialize()
. = ..()
- create_reagents(volume)
+ create_reagents(REAGENTS_BASE_VOLUME)
+ for(var/obj/item/stock_parts/matter_bin/B in component_parts)
+ reagents.maximum_volume += REAGENTS_BASE_VOLUME * B.rating
/obj/machinery/smoke_machine/update_icon()
if((!is_operational()) || (!on) || (reagents.total_volume == 0))
@@ -41,13 +43,22 @@
. = ..()
/obj/machinery/smoke_machine/RefreshParts()
- efficiency = 6
+ var/new_volume = REAGENTS_BASE_VOLUME
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
- efficiency += B.rating
+ 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
+ reagents.clear_reagents()
+ efficiency = 9
for(var/obj/item/stock_parts/capacitor/C in component_parts)
efficiency += C.rating
+ max_range = 1
for(var/obj/item/stock_parts/manipulator/M in component_parts)
- efficiency += M.rating
+ max_range += M.rating
+ max_range = max(3, max_range)
/obj/machinery/smoke_machine/process()
..()
@@ -78,6 +89,11 @@
return
return ..()
+/obj/machinery/smoke_machine/deconstruct()
+ reagents.reaction(loc, TOUCH)
+ reagents.clear_reagents()
+ return ..()
+
/obj/machinery/smoke_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
@@ -99,6 +115,7 @@
data["active"] = on
data["setting"] = setting
data["screen"] = screen
+ data["maxSetting"] = max_range
return data
/obj/machinery/smoke_machine/ui_act(action, params)
@@ -110,7 +127,7 @@
. = TRUE
if("setting")
var/amount = text2num(params["amount"])
- if (locate(amount) in possible_settings)
+ if(amount in 1 to max_range)
setting = amount
. = TRUE
if("power")
@@ -122,3 +139,5 @@
if("goScreen")
screen = params["screen"]
. = TRUE
+
+#undef REAGENTS_BASE_VOLUME
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/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/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 13986f5bf8..0a6288896a 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -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..0a99d9da6e 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -173,7 +173,7 @@ Borg Shaker
if(!proximity)
return
- else if(target.is_open_container() && target.reagents)
+ else if(target.is_refillable())
var/datum/reagents/R = reagent_list[mode]
if(!R.total_volume)
to_chat(user, "[src] is currently out of this ingredient! Please allow some time for the synthesizer to produce more.")
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 30aa67e91a..144db32a6c 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -6,7 +6,7 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(1, 2, 3, 4, 5)
volume = 5
- container_type = TRANSPARENT_1
+ container_type = TRANSPARENT
/obj/item/reagent_containers/dropper/afterattack(obj/target, mob/user , proximity)
if(!proximity)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index df2df7c171..06a242cca9 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -3,7 +3,7 @@
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50)
volume = 50
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = TRUE
resistance_flags = ACID_PROOF
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
else
to_chat(user, "You swallow a gulp of [src].")
var/fraction = min(5/reagents.total_volume, 1)
@@ -56,32 +56,30 @@
if((!proximity) || !check_allowed_items(target,target_self=1))
return
- else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
-
- if(target.reagents && !target.reagents.total_volume)
- to_chat(user, "[target] is empty and can't be refilled!")
- return
-
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "[src] is full.")
- return
-
- var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
- to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
-
- else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "[src] is empty!")
return
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "[target] is full.")
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
return
-
var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "You transfer [trans] unit\s of the solution to [target].")
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty and can't be refilled!")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
+
else if(reagents.total_volume)
if(user.a_intent == INTENT_HARM)
user.visible_message("[user] splashes the contents of [src] onto [target]!", \
@@ -91,15 +89,9 @@
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
var/hotness = I.is_hot()
- if(hotness)
- var/added_heat = (hotness / 100) //ishot returns a temperature
- if(reagents)
- if(reagents.chem_temp < hotness) //can't be heated to be hotter than the source
- reagents.chem_temp += added_heat
- to_chat(user, "You heat [src] with [I].")
- reagents.handle_reactions()
- else
- to_chat(user, "[src] is already hotter than [I]!")
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
if(istype(I, /obj/item/reagent_containers/food/snacks/egg)) //breaking eggs
var/obj/item/reagent_containers/food/snacks/egg/E = I
@@ -169,7 +161,6 @@
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact
name = "cryostasis beaker"
@@ -179,7 +170,6 @@
materials = list(MAT_METAL=3000)
volume = 50
amount_per_transfer_from_this = 10
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact/Initialize()
. = ..()
@@ -195,7 +185,6 @@
volume = 300
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/cryoxadone
list_reagents = list("cryoxadone" = 30)
@@ -238,7 +227,6 @@
amount_per_transfer_from_this = 20
possible_transfer_amounts = list(10,15,20,25,30,50,70)
volume = 70
- flags_1 = OPENCONTAINER_1
flags_inv = HIDEHAIR
slot_flags = SLOT_HEAD
resistance_flags = NONE
@@ -409,4 +397,4 @@
/obj/item/reagent_containers/glass/beaker/large/bromine
name = "bromine beaker"
- list_reagents = list("bromine" = 50)
\ No newline at end of file
+ list_reagents = list("bromine" = 50)
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index dff0869322..53e0c9bfb6 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -10,7 +10,7 @@
volume = 30
possible_transfer_amounts = list()
resistance_flags = ACID_PROOF
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
var/ignore_flags = 0
var/infinite = FALSE
@@ -88,7 +88,7 @@
amount_per_transfer_from_this = 10
volume = 10
ignore_flags = 1 //so you can medipen through hardsuits
- container_type = DRAWABLE_1
+ container_type = DRAWABLE
flags_1 = null
list_reagents = list("epinephrine" = 10)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 5a2e888210..4908a55911 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -46,7 +46,7 @@
"[user] forces [M] to [apply_method] [src].")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
if(reagents.total_volume)
reagents.reaction(M, apply_type)
reagents.trans_to(M, reagents.total_volume)
@@ -57,10 +57,15 @@
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
if(!proximity)
return
- if(target.is_open_container() != 0 && target.reagents)
- if(!target.reagents.total_volume)
+ if(target.is_refillable())
+ if(target.is_drainable() && !target.reagents.total_volume)
to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.")
return
+
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
+ return
+
to_chat(user, "You dissolve [src] in [target].")
for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
to_chat(O, "[user] slips something into [target]!")
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 789345ca77..2e34e39f8f 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -7,7 +7,7 @@
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
@@ -23,17 +23,17 @@
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
-/obj/item/reagent_containers/spray/afterattack(atom/A as mob|obj, mob/user)
+/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
return
- if(istype(A, /obj/structure/reagent_dispensers) && get_dist(src,A) <= 1) //this block copypasted from reagent_containers/glass, for lack of a better solution
- if(!A.reagents.total_volume && A.reagents)
- to_chat(user, "\The [A] is empty.")
+ if((A.is_drainable() && !A.is_refillable()) && get_dist(src,A) <= 1)
+ if(!A.reagents.total_volume)
+ to_chat(user, "[A] is empty.")
return
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "\The [src] is full.")
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
return
var/trans = A.reagents.trans_to(src, 50) //transfer 50u , using the spray's transfer amount would take too long to refill
@@ -41,7 +41,7 @@
return
if(reagents.total_volume < amount_per_transfer_from_this)
- to_chat(user, "\The [src] is empty!")
+ to_chat(user, "[src] is empty!")
return
spray(A)
@@ -123,6 +123,14 @@
current_range = spray_range
to_chat(user, "You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""]. You'll now use [amount_per_transfer_from_this] units per use.")
+/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, params)
+ var/hotness = I.is_hot()
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
+ return ..()
+
+
/obj/item/reagent_containers/spray/verb/empty()
set name = "Empty Spray Bottle"
set category = "Object"
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 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..0af1650d42 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -43,11 +43,49 @@ other types of metals and chemistry for reagents).
var/lathe_time_factor = 1 //How many times faster than normal is this to build on the protolathe
var/dangerous_construction = FALSE //notify and log for admin investigations if this is printed.
var/departmental_flags = ALL //bitflags for deplathes.
+ var/list/datum/techweb_node/unlocked_by = list()
+ var/icon_cache
/datum/design/Destroy()
CRASH("DESIGN DATUMS SHOULD NOT EVER BE DESTROYED AS THEY ARE ONLY MEANT TO BE IN A GLOBAL LIST AND REFERENCED FOR US.")
return ..()
+/datum/design/proc/icon_html(client/user)
+ if (!icon_cache)
+ // construct the icon and slap it into the resource cache
+ var/atom/item = build_path
+ if (!ispath(item, /atom))
+ // biogenerator outputs to beakers by default
+ if (build_type & BIOGENERATOR)
+ item = /obj/item/reagent_containers/glass/beaker/large
+ else
+ return // shouldn't happen, but just in case
+
+ // circuit boards become their resulting machines or computers
+ if (ispath(item, /obj/item/circuitboard))
+ var/obj/item/circuitboard/C = item
+ var/machine = initial(C.build_path)
+ if (machine)
+ item = machine
+ var/icon_file = initial(item.icon)
+ var/icon/I = icon(icon_file, initial(item.icon_state), SOUTH)
+
+ // computers (and snowflakes) get their screen and keyboard sprites
+ if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
+ var/obj/machinery/computer/C = item
+ var/screen = initial(C.icon_screen)
+ var/keyboard = initial(C.icon_keyboard)
+ if (screen)
+ I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
+ if (keyboard)
+ I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
+
+ // based on icon2html
+ icon_cache = "[generate_asset_name(I)].png"
+ register_asset(icon_cache, I)
+ send_asset(user, icon_cache, FALSE)
+ return "
]\")
"
+
////////////////////////////////////////
//Disks for transporting design datums//
////////////////////////////////////////
diff --git a/code/modules/research/designs/AI_module_designs.dm b/code/modules/research/designs/AI_module_designs.dm
index 13ddd2582f..eb92bb3737 100644
--- a/code/modules/research/designs/AI_module_designs.dm
+++ b/code/modules/research/designs/AI_module_designs.dm
@@ -20,8 +20,8 @@
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/board/onehuman_module
- name = "Module Design (OneCrew)"
- desc = "Allows for the construction of a OneCrew AI Module."
+ name = "Module Design (OneHuman)"
+ desc = "Allows for the construction of a OneHuman AI Module."
id = "onehuman_module"
materials = list(MAT_GLASS = 1000, MAT_DIAMOND = 100)
build_path = /obj/item/aiModule/zeroth/oneHuman
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 39fd0bf182..8542660343 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -600,14 +600,6 @@
build_path = /obj/item/device/electropack
category = list("hacked", "Tools")
-/datum/design/shock_collar
- name = "Shock Collar"
- id = "shock_collar"
- build_type = AUTOLATHE
- materials = list(MAT_METAL = 5000, MAT_GLASS = 2000)
- build_path = /obj/item/device/electropack/shockcollar
- category = list("hacked", "Security")
-
/datum/design/large_welding_tool
name = "Industrial Welding Tool"
id = "large_welding_tool"
@@ -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)
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/server_tools/st_commands.dm b/code/modules/server_tools/st_commands.dm
index 9ec87a595c..1e071550e0 100644
--- a/code/modules/server_tools/st_commands.dm
+++ b/code/modules/server_tools/st_commands.dm
@@ -51,7 +51,7 @@
/*
The MIT License
-Copyright (c) 2011 Dominic Tarr
+Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
diff --git a/code/modules/server_tools/st_interface.dm b/code/modules/server_tools/st_interface.dm
index 39bebbbb3d..b0b1b0a43c 100644
--- a/code/modules/server_tools/st_interface.dm
+++ b/code/modules/server_tools/st_interface.dm
@@ -30,7 +30,10 @@ SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
return
if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL))
CRASH("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.")
- call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(command) //trust no retval
+ var/instance = params[SERVICE_INSTANCE_PARAM]
+ if(!instance)
+ instance = "TG Station Server" //maybe just upgraded
+ call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance, command) //trust no retval
return TRUE
/world/proc/ChatBroadcast(message)
@@ -72,7 +75,7 @@ SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
switch(command)
if(SERVICE_CMD_API_COMPATIBLE)
SERVER_TOOLS_WRITE_GLOBAL(server_tools_api_compatible, TRUE)
- return "SUCCESS"
+ return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_HARD_REBOOT)
if(SERVER_TOOLS_READ_GLOBAL(reboot_mode) != REBOOT_MODE_HARD)
SERVER_TOOLS_WRITE_GLOBAL(reboot_mode, REBOOT_MODE_HARD)
@@ -88,7 +91,7 @@ SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
if(!istext(msg) || !msg)
return "No message set!"
SERVER_TOOLS_WORLD_ANNOUNCE(msg)
- return "SUCCESS"
+ return SERVICE_RETURN_SUCCESS
if(SERVICE_CMD_PLAYER_COUNT)
return "[SERVER_TOOLS_CLIENT_COUNT]"
if(SERVICE_CMD_LIST_CUSTOM)
@@ -96,13 +99,13 @@ SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE)
else
var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM])
if(custom_command_result)
- return istext(custom_command_result) ? custom_command_result : "SUCCESS"
+ return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS
return "Unknown command: [command]"
/*
The MIT License
-Copyright (c) 2011 Dominic Tarr
+Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index a4303078a5..3811fa0e4a 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
@@ -534,7 +534,7 @@
rotation = dir2angle(new_dock.dir)-dir2angle(dir)
if ((rotation % 90) != 0)
rotation += (rotation % 90) //diagonal rotations not allowed, round up
- rotation = SimplifyDegrees(rotation)
+ rotation = SIMPLIFY_DEGREES(rotation)
if(!movement_direction)
movement_direction = turn(preferred_direction, 180)
@@ -888,13 +888,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/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/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/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/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/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/changelog.html b/html/changelog.html
index 45dfe57b20..d73ebdcd62 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -1279,3 +1279,1492 @@