"
+ parts += "
You managed to survive the events on [station_name()] as [M.real_name]."
+
+ else
+ parts += "
"
+ parts += "
You did not survive the events on [station_name()]..."
+ else
+ parts += "
"
+ parts += "
"
+ if(GLOB.survivor_report)
+ parts += GLOB.survivor_report
+ else
+ parts += survivor_report()
+
+ parts += "
"
+
+ return parts.Join()
+
+/datum/controller/subsystem/ticker/proc/display_report()
+ GLOB.common_report = build_roundend_report()
+ for(var/client/C in GLOB.clients)
+ show_roundend_report(C,GLOB.common_report)
+ give_show_report_button(C)
+ CHECK_TICK
+
+/datum/controller/subsystem/ticker/proc/law_report()
+ var/list/parts = list()
+ //Silicon laws report
+ for (var/i in GLOB.ai_list)
+ var/mob/living/silicon/ai/aiPlayer = i
+ if(aiPlayer.mind)
+ parts += "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:"
+ parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
+
+ parts += "
Total law changes: [aiPlayer.law_change_counter]"
+
+ if (aiPlayer.connected_robots.len)
+ var/robolist = "
[aiPlayer.real_name]'s minions were: "
+ for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
+ if(robo.mind)
+ robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
+ parts += "[robolist]"
+
+ for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
+ if (!robo.connected_ai && robo.mind)
+ if (robo.stat != DEAD)
+ parts += "
[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:"
+ else
+ parts += "
[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:"
+
+ if(robo) //How the hell do we lose robo between here and the world messages directly above this?
+ parts += robo.laws.get_law_list(include_zeroth=TRUE)
+ if(parts.len)
+ return "
[parts.Join("
")]
"
+ else
+ return ""
+
+/datum/controller/subsystem/ticker/proc/goal_report()
+ var/list/parts = list()
+ if(mode.station_goals.len)
+ for(var/V in mode.station_goals)
+ var/datum/station_goal/G = V
+ parts += G.get_result()
+ return "
"
+
+/datum/controller/subsystem/ticker/proc/medal_report()
+ if(GLOB.commendations.len)
+ var/list/parts = list()
+ parts += ""
+ for (var/com in GLOB.commendations)
+ parts += com
+ return "
[parts.Join("
")]
"
+ return ""
+
+/datum/controller/subsystem/ticker/proc/antag_report()
+ var/list/result = list()
+ var/list/all_teams = list()
+ var/list/all_antagonists = list()
+
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ all_teams |= A.get_team()
+ all_antagonists += A
+
+ for(var/datum/team/T in all_teams)
+ result += T.roundend_report()
+ for(var/datum/antagonist/X in all_antagonists)
+ if(X.get_team() == T)
+ all_antagonists -= X
+ result += " "//newline between teams
+
+ var/currrent_category
+ var/datum/antagonist/previous_category
+
+ sortTim(all_antagonists, /proc/cmp_antag_category)
+
+ for(var/datum/antagonist/A in all_antagonists)
+ if(!A.show_in_roundend)
+ continue
+ if(A.roundend_category != currrent_category)
+ if(previous_category)
+ result += previous_category.roundend_report_footer()
+ result += "
"
+ result += "
"
+ result += A.roundend_report_header()
+ currrent_category = A.roundend_category
+ previous_category = A
+ result += A.roundend_report()
+ result += "
"
+
+ if(all_antagonists.len)
+ var/datum/antagonist/last = all_antagonists[all_antagonists.len]
+ result += last.roundend_report_footer()
+ result += "
"
+
+ return result.Join()
+
+/proc/cmp_antag_category(datum/antagonist/A,datum/antagonist/B)
+ return sorttext(B.roundend_category,A.roundend_category)
+
+
+/datum/controller/subsystem/ticker/proc/give_show_report_button(client/C)
+ var/datum/action/report/R = new
+ C.player_details.player_actions += R
+ R.Grant(C.mob)
+ to_chat(C,"
Show roundend report again")
+
+/datum/action/report
+ name = "Show roundend report"
+ button_icon_state = "vote"
+
+/datum/action/report/Trigger()
+ if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
+ SSticker.show_roundend_report(owner.client,GLOB.common_report)
+
+/datum/action/report/IsAvailable()
+ return 1
+
+/datum/action/report/Topic(href,href_list)
+ if(usr != owner)
+ return
+ if(href_list["report"])
+ Trigger()
+ return
+
+
+/proc/printplayer(datum/mind/ply, fleecheck)
+ var/text = "
[ply.key] was
[ply.name] the
[ply.assigned_role] and"
+ if(ply.current)
+ if(ply.current.stat == DEAD)
+ text += "
died"
+ else
+ text += "
survived"
+ if(fleecheck)
+ var/turf/T = get_turf(ply.current)
+ if(!T || !(T.z in GLOB.station_z_levels))
+ text += " while
fleeing the station"
+ if(ply.current.real_name != ply.name)
+ text += " as
[ply.current.real_name]"
+ else
+ text += "
had their body destroyed"
+ return text
+
+/proc/printplayerlist(list/players,fleecheck)
+ var/list/parts = list()
+
+ parts += "
"
+ for(var/datum/mind/M in players)
+ parts += "- [printplayer(M,fleecheck)]
"
+ parts += "
"
+ return parts.Join()
+
+
+/proc/printobjectives(datum/mind/ply)
+ var/list/objective_parts = list()
+ var/count = 1
+ for(var/datum/objective/objective in ply.objectives)
+ if(objective.check_completion())
+ objective_parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ objective_parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ count++
+ return objective_parts.Join("
")
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 74c565da52..68ab173ecd 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -60,7 +60,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!second)
return "0 seconds"
if(second >= 60)
- minute = round_down(second/60)
+ minute = FLOOR(second/60, 1)
second = round(second - (minute*60), 0.1)
second_rounded = TRUE
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
@@ -91,7 +91,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!minute)
return "[second]"
if(minute >= 60)
- hour = round_down(minute/60,1)
+ hour = FLOOR(minute/60, 1)
minute = (minute - (hour*60))
if(minute) //alot simpler from here since you don't have to worry about fractions
if(minute != 1)
@@ -114,7 +114,7 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(!hour)
return "[minute][second]"
if(hour >= 24)
- day = round_down(hour/24,1)
+ day = FLOOR(hour/24, 1)
hour = (hour - (day*24))
if(hour)
if(hour != 1)
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index bae773b27e..2ebe24b85b 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -117,7 +117,7 @@
//Converts an angle (degrees) into an ss13 direction
/proc/angle2dir(degree)
- degree = SimplifyDegrees(degree)
+ degree = SIMPLIFY_DEGREES(degree)
switch(degree)
if(0 to 22.5) //north requires two angle ranges
return NORTH
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 9ec23fa966..1fd60c2bd4 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -147,10 +147,10 @@ Turf and target are separate in case you want to teleport some distance from a t
var/line[] = list(locate(px,py,M.z))
var/dx=N.x-px //x distance
var/dy=N.y-py
- var/dxabs=abs(dx)//Absolute value of x distance
- var/dyabs=abs(dy)
- var/sdx=sign(dx) //Sign of x distance (+ or -)
- var/sdy=sign(dy)
+ var/dxabs = abs(dx)//Absolute value of x distance
+ var/dyabs = abs(dy)
+ var/sdx = SIGN(dx) //Sign of x distance (+ or -)
+ var/sdy = SIGN(dy)
var/x=dxabs>>1 //Counters for steps taken, setting to distance/2
var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast.
var/j //Generic integer for counting
@@ -953,8 +953,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tY = tY[1]
tX = splittext(tX[1], ":")
tX = tX[1]
- tX = Clamp(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
- tY = Clamp(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
+ tX = CLAMP(origin.x + text2num(tX) - world.view - 1, 1, world.maxx)
+ tY = CLAMP(origin.y + text2num(tY) - world.view - 1, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/screen_loc2turf(text, turf/origin)
@@ -966,8 +966,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
tX = splittext(tZ[2], "-")
tX = text2num(tX[2])
tZ = origin.z
- tX = Clamp(origin.x + 7 - tX, 1, world.maxx)
- tY = Clamp(origin.y + 7 - tY, 1, world.maxy)
+ tX = CLAMP(origin.x + 7 - tX, 1, world.maxx)
+ tY = CLAMP(origin.y + 7 - tY, 1, world.maxy)
return locate(tX, tY, tZ)
/proc/IsValidSrc(datum/D)
@@ -1272,7 +1272,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
. = 0
var/i = DS2TICKS(initial_delay)
do
- . += Ceiling(i*DELTA_CALC)
+ . += CEILING(i*DELTA_CALC, 1)
sleep(i*world.tick_lag*DELTA_CALC)
i *= 2
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
@@ -1508,9 +1508,34 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "\[[url_encode(thing.tag)]\]"
return "\ref[input]"
+// Makes a call in the context of a different usr
+// Use sparingly
+/world/proc/PushUsr(mob/M, datum/callback/CB)
+ var/temp = usr
+ usr = M
+ . = CB.Invoke()
+ usr = temp
+
//Returns a list of all servants of Ratvar and observers.
/proc/servants_and_ghosts()
. = list()
for(var/V in GLOB.player_list)
if(is_servant_of_ratvar(V) || isobserver(V))
. += V
+
+//datum may be null, but it does need to be a typed var
+#define NAMEOF(datum, X) (list(##datum.##X, #X)[2])
+
+#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
+//dupe code because dm can't handle 3 level deep macros
+#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
+
+/proc/___callbackvarset(list_or_datum, var_name, var_value)
+ if(length(list_or_datum))
+ list_or_datum[var_name] = var_value
+ return
+ var/datum/D = list_or_datum
+ if(IsAdminAdvancedProcCall())
+ D.vv_edit_var(var_name, var_value) //same result generally, unless badmemes
+ else
+ D.vars[var_name] = var_value
diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm
index 9c3af923f1..3822f7077d 100644
--- a/code/_globalvars/game_modes.dm
+++ b/code/_globalvars/game_modes.dm
@@ -1,18 +1,12 @@
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret", the secret rotation will forceably choose this mode
+GLOBAL_VAR(common_report) //Contains commmon part of roundend report
+GLOBAL_VAR(survivor_report) //Contains shared surivor report for roundend report (part of personal report)
+
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
-// Cult, needs to be global so admin cultists are functional
-GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
-GLOBAL_DATUM(blood_target_image, /image)
-GLOBAL_VAR_INIT(blood_target_reset_timer, null)
-GLOBAL_DATUM(sac_mind, /datum/mind)
-GLOBAL_VAR_INIT(sac_image, null)
-GLOBAL_VAR_INIT(cult_vote_called, FALSE)
-GLOBAL_VAR_INIT(cult_mastered, FALSE)
-GLOBAL_VAR_INIT(reckoning_complete, FALSE)
-GLOBAL_VAR_INIT(sac_complete, FALSE)
-GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
-GLOBAL_LIST_EMPTY(summon_spots)
\ No newline at end of file
+
+//TODO clear this one up too
+GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
\ No newline at end of file
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index bb86b4cbb0..8b8b817586 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -16,3 +16,5 @@ GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a perce
GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
+
+GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
\ No newline at end of file
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 0006d72d3b..2ad2eb76f5 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -302,32 +302,41 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
- if(GLOB.blood_target)
- if(!get_turf(GLOB.blood_target))
- GLOB.blood_target = null
+
+ var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!antag)
+ return
+ var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
+
+ if(antag.cult_team.blood_target)
+ if(!get_turf(antag.cult_team.blood_target))
+ antag.cult_team.blood_target = null
else
- blood_target = GLOB.blood_target
+ blood_target = antag.cult_team.blood_target
if(Cviewer && Cviewer.seeking && Cviewer.master)
blood_target = Cviewer.master
desc = "Your blood sense is leading you to [Cviewer.master]"
if(!blood_target)
- if(!GLOB.sac_complete)
+ if(sac_objective && !sac_objective.check_completion())
if(icon_state == "runed_sense0")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense0"
- desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
- add_overlay(GLOB.sac_image)
+ desc = "Nar-Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
+ add_overlay(sac_objective.sac_image)
else
+ var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
+ if(!summon_objective)
+ return
if(icon_state == "runed_sense1")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense1"
- desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
+ desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!"
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
@@ -388,11 +397,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "
CHETR
NYY
HAGEHUGF-NAQ-UBABE
RATVAR."
else
var/servants = 0
- var/list/textlist
+ var/list/textlist = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
- textlist = list("[SSticker.mode.eminence ? "There is an Eminence." : "
There is no Eminence! Get one ASAP!"]
")
+ var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(C && C.clock_team)
+ textlist += "[C.clock_team.eminence ? "There is an Eminence." : "
There is no Eminence! Get one ASAP!"]
"
textlist += "There are currently
[servants] servant[servants > 1 ? "s" : ""] of Ratvar.
"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
index ff38107bfb..e3d1af79ed 100755
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -60,8 +60,6 @@
var/pref = C.prefs.parallax
if (isnull(pref))
pref = PARALLAX_HIGH
- if (C.byond_version < 511)
- pref = PARALLAX_DISABLE
switch(C.prefs.parallax)
if (PARALLAX_INSANE)
C.parallax_throttle = FALSE
@@ -257,8 +255,8 @@
view = world.view
var/list/viewscales = getviewsize(view)
- var/countx = Ceiling((viewscales[1]/2)/(480/world.icon_size))+1
- var/county = Ceiling((viewscales[2]/2)/(480/world.icon_size))+1
+ var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
+ var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 1)+1
var/list/new_overlays = new
for(var/x in -countx to countx)
for(var/y in -county to county)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index f1ec409520..769cdb2244 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -1,277 +1,277 @@
-/obj/screen/robot
- icon = 'icons/mob/screen_cyborg.dmi'
-
-/obj/screen/robot/module
- name = "cyborg module"
- icon_state = "nomod"
-
-/obj/screen/robot/Click()
- if(isobserver(usr))
- return 1
-
-/obj/screen/robot/module/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- if(R.module.type != /obj/item/robot_module)
- R.hud_used.toggle_show_robot_modules()
- return 1
- R.pick_module()
-
-/obj/screen/robot/module1
- name = "module1"
- icon_state = "inv1"
-
-/obj/screen/robot/module1/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(1)
-
-/obj/screen/robot/module2
- name = "module2"
- icon_state = "inv2"
-
-/obj/screen/robot/module2/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(2)
-
-/obj/screen/robot/module3
- name = "module3"
- icon_state = "inv3"
-
-/obj/screen/robot/module3/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_module(3)
-
-/obj/screen/robot/radio
- name = "radio"
- icon_state = "radio"
-
-/obj/screen/robot/radio/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.radio.interact(R)
-
-/obj/screen/robot/store
- name = "store"
- icon_state = "store"
-
-/obj/screen/robot/store/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.uneq_active()
-
-/obj/screen/robot/lamp
- name = "headlamp"
- icon_state = "lamp0"
-
-/obj/screen/robot/lamp/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.control_headlamp()
-
-/obj/screen/robot/thrusters
- name = "ion thrusters"
- icon_state = "ionpulse0"
-
-/obj/screen/robot/thrusters/Click()
- if(..())
- return
- var/mob/living/silicon/robot/R = usr
- R.toggle_ionpulse()
-
-/datum/hud/robot
- ui_style_icon = 'icons/mob/screen_cyborg.dmi'
-
-/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
- ..()
- var/mob/living/silicon/robot/mymobR = mymob
- var/obj/screen/using
-
- using = new/obj/screen/language_menu
- using.screen_loc = ui_borg_language_menu
- static_inventory += using
-
-//Radio
- using = new /obj/screen/robot/radio()
- using.screen_loc = ui_borg_radio
- static_inventory += using
-
-//Module select
- using = new /obj/screen/robot/module1()
- using.screen_loc = ui_inv1
- static_inventory += using
- mymobR.inv1 = using
-
- using = new /obj/screen/robot/module2()
- using.screen_loc = ui_inv2
- static_inventory += using
- mymobR.inv2 = using
-
- using = new /obj/screen/robot/module3()
- using.screen_loc = ui_inv3
- static_inventory += using
- mymobR.inv3 = using
-
-//End of module select
-
-//Photography stuff
- using = new /obj/screen/ai/image_take()
- using.screen_loc = ui_borg_camera
- static_inventory += using
-
- using = new /obj/screen/ai/image_view()
- using.screen_loc = ui_borg_album
- static_inventory += using
-
-//Sec/Med HUDs
- using = new /obj/screen/ai/sensors()
- using.screen_loc = ui_borg_sensor
- static_inventory += using
-
-//Headlamp control
- using = new /obj/screen/robot/lamp()
- using.screen_loc = ui_borg_lamp
- static_inventory += using
- mymobR.lamp_button = using
-
-//Thrusters
- using = new /obj/screen/robot/thrusters()
- using.screen_loc = ui_borg_thrusters
- static_inventory += using
- mymobR.thruster_button = using
-
-//Intent
- action_intent = new /obj/screen/act_intent/robot()
- action_intent.icon_state = mymob.a_intent
- static_inventory += action_intent
-
-//Health
- healths = new /obj/screen/healths/robot()
- infodisplay += healths
-
-//Installed Module
- mymobR.hands = new /obj/screen/robot/module()
- mymobR.hands.screen_loc = ui_borg_module
- static_inventory += mymobR.hands
-
-//Store
- module_store_icon = new /obj/screen/robot/store()
- module_store_icon.screen_loc = ui_borg_store
-
- pull_icon = new /obj/screen/pull()
- pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
- pull_icon.update_icon(mymob)
- pull_icon.screen_loc = ui_borg_pull
- hotkeybuttons += pull_icon
-
-
- zone_select = new /obj/screen/zone_sel/robot()
- zone_select.update_icon(mymob)
- static_inventory += zone_select
-
-
-/datum/hud/proc/toggle_show_robot_modules()
- if(!iscyborg(mymob))
- return
-
- var/mob/living/silicon/robot/R = mymob
-
- R.shown_robot_modules = !R.shown_robot_modules
- update_robot_modules_display()
-
-/datum/hud/proc/update_robot_modules_display(mob/viewer)
- if(!iscyborg(mymob))
- return
-
- var/mob/living/silicon/robot/R = mymob
-
- var/mob/screenmob = viewer || R
-
- if(!R.module)
- return
-
- if(!R.client)
- return
-
- if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
- //Modules display is shown
- screenmob.client.screen += module_store_icon //"store" icon
-
- if(!R.module.modules)
- to_chat(usr, "
Selected module has no modules to select")
- return
-
- if(!R.robot_modules_background)
- return
-
- var/display_rows = Ceiling(length(R.module.get_inactive_modules()) / 8)
- R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
- screenmob.client.screen += R.robot_modules_background
-
- var/x = -4 //Start at CENTER-4,SOUTH+1
- var/y = 1
-
- for(var/atom/movable/A in R.module.get_inactive_modules())
- //Module is not currently active
- screenmob.client.screen += A
- if(x < 0)
- A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
- else
- A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
- A.layer = ABOVE_HUD_LAYER
- A.plane = ABOVE_HUD_PLANE
-
- x++
- if(x == 4)
- x = -4
- y++
-
- else
- //Modules display is hidden
- screenmob.client.screen -= module_store_icon //"store" icon
-
- for(var/atom/A in R.module.get_inactive_modules())
- //Module is not currently active
- screenmob.client.screen -= A
- R.shown_robot_modules = 0
- screenmob.client.screen -= R.robot_modules_background
-
-/mob/living/silicon/robot/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/robot(src)
-
-
-/datum/hud/robot/persistent_inventory_update(mob/viewer)
- if(!mymob)
- return
- var/mob/living/silicon/robot/R = mymob
-
- var/mob/screenmob = viewer || R
-
- if(screenmob.hud_used)
- if(screenmob.hud_used.hud_shown)
- for(var/i in 1 to R.held_items.len)
- var/obj/item/I = R.held_items[i]
- if(I)
- switch(i)
- if(1)
- I.screen_loc = ui_inv1
- if(2)
- I.screen_loc = ui_inv2
- if(3)
- I.screen_loc = ui_inv3
- else
- return
- screenmob.client.screen += I
- else
- for(var/obj/item/I in R.held_items)
- screenmob.client.screen -= I
+/obj/screen/robot
+ icon = 'icons/mob/screen_cyborg.dmi'
+
+/obj/screen/robot/module
+ name = "cyborg module"
+ icon_state = "nomod"
+
+/obj/screen/robot/Click()
+ if(isobserver(usr))
+ return 1
+
+/obj/screen/robot/module/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ if(R.module.type != /obj/item/robot_module)
+ R.hud_used.toggle_show_robot_modules()
+ return 1
+ R.pick_module()
+
+/obj/screen/robot/module1
+ name = "module1"
+ icon_state = "inv1"
+
+/obj/screen/robot/module1/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(1)
+
+/obj/screen/robot/module2
+ name = "module2"
+ icon_state = "inv2"
+
+/obj/screen/robot/module2/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(2)
+
+/obj/screen/robot/module3
+ name = "module3"
+ icon_state = "inv3"
+
+/obj/screen/robot/module3/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_module(3)
+
+/obj/screen/robot/radio
+ name = "radio"
+ icon_state = "radio"
+
+/obj/screen/robot/radio/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.radio.interact(R)
+
+/obj/screen/robot/store
+ name = "store"
+ icon_state = "store"
+
+/obj/screen/robot/store/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.uneq_active()
+
+/obj/screen/robot/lamp
+ name = "headlamp"
+ icon_state = "lamp0"
+
+/obj/screen/robot/lamp/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.control_headlamp()
+
+/obj/screen/robot/thrusters
+ name = "ion thrusters"
+ icon_state = "ionpulse0"
+
+/obj/screen/robot/thrusters/Click()
+ if(..())
+ return
+ var/mob/living/silicon/robot/R = usr
+ R.toggle_ionpulse()
+
+/datum/hud/robot
+ ui_style_icon = 'icons/mob/screen_cyborg.dmi'
+
+/datum/hud/robot/New(mob/owner, ui_style = 'icons/mob/screen_cyborg.dmi')
+ ..()
+ var/mob/living/silicon/robot/mymobR = mymob
+ var/obj/screen/using
+
+ using = new/obj/screen/language_menu
+ using.screen_loc = ui_borg_language_menu
+ static_inventory += using
+
+//Radio
+ using = new /obj/screen/robot/radio()
+ using.screen_loc = ui_borg_radio
+ static_inventory += using
+
+//Module select
+ using = new /obj/screen/robot/module1()
+ using.screen_loc = ui_inv1
+ static_inventory += using
+ mymobR.inv1 = using
+
+ using = new /obj/screen/robot/module2()
+ using.screen_loc = ui_inv2
+ static_inventory += using
+ mymobR.inv2 = using
+
+ using = new /obj/screen/robot/module3()
+ using.screen_loc = ui_inv3
+ static_inventory += using
+ mymobR.inv3 = using
+
+//End of module select
+
+//Photography stuff
+ using = new /obj/screen/ai/image_take()
+ using.screen_loc = ui_borg_camera
+ static_inventory += using
+
+ using = new /obj/screen/ai/image_view()
+ using.screen_loc = ui_borg_album
+ static_inventory += using
+
+//Sec/Med HUDs
+ using = new /obj/screen/ai/sensors()
+ using.screen_loc = ui_borg_sensor
+ static_inventory += using
+
+//Headlamp control
+ using = new /obj/screen/robot/lamp()
+ using.screen_loc = ui_borg_lamp
+ static_inventory += using
+ mymobR.lamp_button = using
+
+//Thrusters
+ using = new /obj/screen/robot/thrusters()
+ using.screen_loc = ui_borg_thrusters
+ static_inventory += using
+ mymobR.thruster_button = using
+
+//Intent
+ action_intent = new /obj/screen/act_intent/robot()
+ action_intent.icon_state = mymob.a_intent
+ static_inventory += action_intent
+
+//Health
+ healths = new /obj/screen/healths/robot()
+ infodisplay += healths
+
+//Installed Module
+ mymobR.hands = new /obj/screen/robot/module()
+ mymobR.hands.screen_loc = ui_borg_module
+ static_inventory += mymobR.hands
+
+//Store
+ module_store_icon = new /obj/screen/robot/store()
+ module_store_icon.screen_loc = ui_borg_store
+
+ pull_icon = new /obj/screen/pull()
+ pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
+ pull_icon.update_icon(mymob)
+ pull_icon.screen_loc = ui_borg_pull
+ hotkeybuttons += pull_icon
+
+
+ zone_select = new /obj/screen/zone_sel/robot()
+ zone_select.update_icon(mymob)
+ static_inventory += zone_select
+
+
+/datum/hud/proc/toggle_show_robot_modules()
+ if(!iscyborg(mymob))
+ return
+
+ var/mob/living/silicon/robot/R = mymob
+
+ R.shown_robot_modules = !R.shown_robot_modules
+ update_robot_modules_display()
+
+/datum/hud/proc/update_robot_modules_display(mob/viewer)
+ if(!iscyborg(mymob))
+ return
+
+ var/mob/living/silicon/robot/R = mymob
+
+ var/mob/screenmob = viewer || R
+
+ if(!R.module)
+ return
+
+ if(!R.client)
+ return
+
+ if(R.shown_robot_modules && screenmob.hud_used.hud_shown)
+ //Modules display is shown
+ screenmob.client.screen += module_store_icon //"store" icon
+
+ if(!R.module.modules)
+ to_chat(usr, "
Selected module has no modules to select")
+ return
+
+ if(!R.robot_modules_background)
+ return
+
+ var/display_rows = CEILING(length(R.module.get_inactive_modules()) / 8, 1)
+ R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
+ screenmob.client.screen += R.robot_modules_background
+
+ var/x = -4 //Start at CENTER-4,SOUTH+1
+ var/y = 1
+
+ for(var/atom/movable/A in R.module.get_inactive_modules())
+ //Module is not currently active
+ screenmob.client.screen += A
+ if(x < 0)
+ A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
+ else
+ A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
+ A.layer = ABOVE_HUD_LAYER
+ A.plane = ABOVE_HUD_PLANE
+
+ x++
+ if(x == 4)
+ x = -4
+ y++
+
+ else
+ //Modules display is hidden
+ screenmob.client.screen -= module_store_icon //"store" icon
+
+ for(var/atom/A in R.module.get_inactive_modules())
+ //Module is not currently active
+ screenmob.client.screen -= A
+ R.shown_robot_modules = 0
+ screenmob.client.screen -= R.robot_modules_background
+
+/mob/living/silicon/robot/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud/robot(src)
+
+
+/datum/hud/robot/persistent_inventory_update(mob/viewer)
+ if(!mymob)
+ return
+ var/mob/living/silicon/robot/R = mymob
+
+ var/mob/screenmob = viewer || R
+
+ if(screenmob.hud_used)
+ if(screenmob.hud_used.hud_shown)
+ for(var/i in 1 to R.held_items.len)
+ var/obj/item/I = R.held_items[i]
+ if(I)
+ switch(i)
+ if(1)
+ I.screen_loc = ui_inv1
+ if(2)
+ I.screen_loc = ui_inv2
+ if(3)
+ I.screen_loc = ui_inv3
+ else
+ return
+ screenmob.client.screen += I
+ else
+ for(var/obj/item/I in R.held_items)
+ screenmob.client.screen -= I
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 859c957a43..2dddce8542 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -58,6 +58,8 @@
SendSignal(COMSIG_ITEM_ATTACK, M, user)
if(flags_1 & NOBLUDGEON_1)
return
+ if(user.disabilities & PACIFISM)
+ return
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
else if(hitsound)
@@ -119,9 +121,9 @@
/obj/item/proc/get_clamped_volume()
if(w_class)
if(force)
- return Clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
+ return CLAMP((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
else
- return Clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
+ return CLAMP(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
var/message_verb = "attacked"
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 02cdfe7c13..d52a7f6fdc 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -63,6 +63,7 @@
/atom/proc/attack_animal(mob/user)
return
+
/mob/living/RestrainedClickOn(atom/A)
return
diff --git a/code/citadel/cit_arousal.dm b/code/citadel/cit_arousal.dm
index 0c03ffb399..077824fe9e 100644
--- a/code/citadel/cit_arousal.dm
+++ b/code/citadel/cit_arousal.dm
@@ -62,14 +62,14 @@
/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
- arousalloss = Clamp(arousalloss + amount, min_arousal, max_arousal)
+ arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return 0
- arousalloss = Clamp(amount, min_arousal, max_arousal)
+ arousalloss = CLAMP(amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
diff --git a/code/citadel/cit_weapons.dm b/code/citadel/cit_weapons.dm
deleted file mode 100644
index dbf0448240..0000000000
--- a/code/citadel/cit_weapons.dm
+++ /dev/null
@@ -1,240 +0,0 @@
-/obj/item/toy/sword/cx
- name = "\improper DX Non-Euplastic LightSword"
- desc = "A deluxe toy replica of an energy sword. Realistic visuals and sounds! Ages 8 and up."
- icon = 'icons/obj/cit_weapons.dmi'
- icon_state = "cxsword_hilt"
- item_state = "cxsword"
- lefthand_file = 'icons/mob/citadel/melee_lefthand.dmi'
- righthand_file = 'icons/mob/citadel/melee_righthand.dmi'
- active = FALSE
- w_class = WEIGHT_CLASS_SMALL
- attack_verb = list("poked", "jabbed", "hit")
- light_color = "#37FFF7"
- var/light_brightness = 3
- actions_types = list()
-
-/obj/item/toy/sword/cx/attack_self(mob/user)
- active = !( active )
-
- if (active)
- to_chat(user, "
You activate the holographic blade with a press of a button.")
- playsound(user, 'sound/weapons/nebon.ogg', 50, 1)
- w_class = WEIGHT_CLASS_BULKY
- attack_verb = list("slashed", "stabbed", "ravaged")
- set_light(light_brightness)
- update_icon()
-
- else
- to_chat(user, "
You deactivate the holographic blade with a press of a button.")
- playsound(user, 'sound/weapons/neboff.ogg', 50, 1)
- w_class = WEIGHT_CLASS_SMALL
- attack_verb = list("poked", "jabbed", "hit")
- set_light(0)
- update_icon()
-
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
-
- add_fingerprint(user)
-
-/obj/item/toy/sword/cx/update_icon()
- var/mutable_appearance/blade_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_blade")
- var/mutable_appearance/gem_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_gem")
-
- if(light_color)
- blade_overlay.color = light_color
- gem_overlay.color = light_color
-
- cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
-
- add_overlay(gem_overlay)
-
- if(active)
- add_overlay(blade_overlay)
-
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_hands()
-
-/obj/item/toy/sword/cx/AltClick(mob/living/user)
- if(user.incapacitated() || !istype(user))
- to_chat(user, "
You can't do that right now!")
- return
- if(!in_range(src, user))
- return
- if(user.incapacitated() || !istype(user) || !in_range(src, user))
- return
-
- if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
- var/energy_color_input = input(usr,"Choose Energy Color") as color|null
- if(energy_color_input)
- light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
- update_icon()
- update_light()
-
-/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file)
- . = ..()
- if(active)
- if(isinhands)
- var/mutable_appearance/blade_inhand = mutable_appearance(icon_file, "cxsword_blade")
- blade_inhand.color = light_color
- . += blade_inhand
-
-/obj/item/toy/sword/cx/attackby(obj/item/W, mob/living/user, params)
- if(istype(W, /obj/item/toy/sword/cx))
- if((W.flags_1 & NODROP_1) || (flags_1 & NODROP_1))
- to_chat(user, "
\the [flags_1 & NODROP_1 ? src : W] is stuck to your hand, you can't attach it to \the [flags_1 & NODROP_1 ? W : src]!")
- return
- else
- to_chat(user, "
You combine the two plastic swords, making a single supermassive toy! You're fake-cool.")
- new /obj/item/twohanded/hypereutactic/toy(user.loc)
- qdel(W)
- qdel(src)
- else
- return ..()
-
-/obj/item/toy/sword/cx/examine(mob/user)
- ..()
- to_chat(user, "
Alt-click to recolor it.")
-
-/*///autolathe memes/// I really need to stop doing this and find a proper way of adding in my toys
-
-/datum/design/toyneb
- name = "Non-Euplastic Blade"
- id = "toyneb"
- build_type = AUTOLATHE
- materials = list(MAT_METAL = 10000, MAT_GLASS = 1000)
- build_path = /obj/item/toy/sword/cx
- category = list("hacked", "Misc")
-*/ // There, I stopped doing it
-
-/datum/crafting_recipe/toyneb
- name = "Non-Euplastic Blade"
- reqs = list(/obj/item/light/bulb = 1, /obj/item/stack/cable_coil = 1, /obj/item/toy/sword = 1)
- result = /obj/item/toy/sword/cx
- category = CAT_MISC
-
-/*/////////////////////////////////////////////////////////////////////////
-///////////// The TRUE Energy Sword ///////////////////////////
-*//////////////////////////////////////////////////////////////////////////
-
-/obj/item/melee/transforming/energy/sword/cx
- name = "non-eutactic blade"
- desc = "The CX Armories Type-69 Non-Eutactic Blade utilizes a hardlight blade that is dynamically 'forged' on demand to create a deadly sharp edge that is unbreakable."
- icon_state = "cxsword_hilt"
- icon = 'icons/obj/cit_weapons.dmi'
- item_state = "cxsword"
- lefthand_file = 'icons/mob/citadel/melee_lefthand.dmi'
- righthand_file = 'icons/mob/citadel/melee_righthand.dmi'
- force = 3
- throwforce = 5
- hitsound = "swing_hit" //it starts deactivated
- hitsound_on = 'sound/weapons/nebhit.ogg'
- attack_verb_off = list("tapped", "poked")
- throw_speed = 3
- throw_range = 5
- sharpness = IS_SHARP
- embed_chance = 40
- embedded_impact_pain_multiplier = 10
- armour_penetration = 0
- block_chance = 60
- light_color = "#37FFF7"
- actions_types = list()
-
-/obj/item/melee/transforming/energy/sword/cx/transform_weapon(mob/living/user, supress_message_text)
- active = !active //I'd use a ..() here but it'd inherit from the regular esword's proc instead, so SPAGHETTI CODE
- if(active) //also I need to rip out the iconstate changing bits
- force = force_on
- throwforce = throwforce_on
- hitsound = hitsound_on
- throw_speed = 4
- if(attack_verb_on.len)
- attack_verb = attack_verb_on
- w_class = w_class_on
- START_PROCESSING(SSobj, src)
- set_light(brightness_on)
- update_icon()
- else
- force = initial(force)
- throwforce = initial(throwforce)
- hitsound = initial(hitsound)
- throw_speed = initial(throw_speed)
- if(attack_verb_off.len)
- attack_verb = attack_verb_off
- w_class = initial(w_class)
- STOP_PROCESSING(SSobj, src)
- set_light(0)
- update_icon()
- transform_messages(user, supress_message_text)
- add_fingerprint(user)
- return TRUE
-
-/obj/item/melee/transforming/energy/sword/cx/transform_messages(mob/living/user, supress_message_text)
- playsound(user, active ? 'sound/weapons/nebon.ogg' : 'sound/weapons/neboff.ogg', 65, 1)
- if(!supress_message_text)
- to_chat(user, "
[src] [active ? "is now active":"can now be concealed"].")
-
-/obj/item/melee/transforming/energy/sword/cx/update_icon()
- var/mutable_appearance/blade_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_blade")
- var/mutable_appearance/gem_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_gem")
-
- if(light_color)
- blade_overlay.color = light_color
- gem_overlay.color = light_color
-
- cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
-
- add_overlay(gem_overlay)
-
- if(active)
- add_overlay(blade_overlay)
-
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_hands()
-
-/obj/item/melee/transforming/energy/sword/cx/AltClick(mob/living/user)
- if(user.incapacitated() || !istype(user))
- to_chat(user, "
You can't do that right now!")
- return
- if(!in_range(src, user))
- return
- if(user.incapacitated() || !istype(user) || !in_range(src, user))
- return
-
- if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
- var/energy_color_input = input(usr,"Choose Energy Color") as color|null
- if(energy_color_input)
- light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
- update_icon()
- update_light()
-
-/obj/item/melee/transforming/energy/sword/cx/examine(mob/user)
- ..()
- to_chat(user, "
Alt-click to recolor it.")
-
-/obj/item/melee/transforming/energy/sword/cx/worn_overlays(isinhands, icon_file)
- . = ..()
- if(active)
- if(isinhands)
- var/mutable_appearance/blade_inhand = mutable_appearance(icon_file, "cxsword_blade")
- blade_inhand.color = light_color
- . += blade_inhand
-
-/obj/item/melee/transforming/energy/sword/cx/traitor
- name = "\improper Dragon's Tooth Sword"
- desc = "The Dragon's Tooth sword is a blackmarket modification of the CX Armouries Type-69 NEB, \
- which utilizes a hardlight blade that is dynamically 'forged' on demand to create a deadly sharp edge that is unbreakable. \
- It appears to have a wooden grip and a shaved down guard."
- icon_state = "cxsword_hilt_traitor"
- armour_penetration = 35
- embed_chance = 75
- block_chance = 50
- hitsound_on = 'sound/weapons/blade1.ogg'
- light_color = "#37F0FF"
-
-/obj/item/melee/transforming/energy/sword/cx/traitor/transform_messages(mob/living/user, supress_message_text)
- playsound(user, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 35, 1)
- if(!supress_message_text)
- to_chat(user, "
[src] [active ? "is now active":"can now be concealed"].")
\ No newline at end of file
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/input.dm b/code/controllers/subsystem/input.dm
new file mode 100644
index 0000000000..5dbb642f2e
--- /dev/null
+++ b/code/controllers/subsystem/input.dm
@@ -0,0 +1,12 @@
+SUBSYSTEM_DEF(input)
+ name = "Input"
+ wait = 1 //SS_TICKER means this runs every tick
+ flags = SS_TICKER | SS_NO_INIT
+ priority = 1000
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+
+/datum/controller/subsystem/input/fire()
+ var/list/clients = GLOB.clients // Let's sing the list cache song
+ for(var/i in 1 to clients.len)
+ var/client/C = clients[i]
+ C.keyLoop()
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index c80bc17047..35208d4137 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -307,6 +307,9 @@ SUBSYSTEM_DEF(shuttle)
return 1
/datum/controller/subsystem/shuttle/proc/autoEvac()
+ if (!SSticker.IsRoundInProgress())
+ return
+
var/callShuttle = 1
for(var/thing in GLOB.shuttle_caller_list)
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index 97d84a0d3b..ec21f3bab2 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -80,7 +80,7 @@ SUBSYSTEM_DEF(throwing)
last_move = world.time
//calculate how many tiles to move, making up for any missed ticks.
- var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
+ var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1)
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
finalize()
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 881bb7fcb7..0f06caa20d 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -398,204 +398,6 @@ SUBSYSTEM_DEF(ticker)
var/mob/living/L = I
L.notransform = FALSE
-/datum/controller/subsystem/ticker/proc/declare_completion()
- set waitfor = FALSE
- var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
- var/num_survivors = 0
- var/num_escapees = 0
- var/num_shuttle_escapees = 0
- var/list/successfulCrew = list()
- var/list/miscreants = list()
-
- to_chat(world, "
The round has ended.")
- if(LAZYLEN(GLOB.round_end_notifiees))
- send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
-
-/* var/nocredits = config.no_credits_round_end
- for(var/client/C in GLOB.clients)
- if(!C.credits && !nocredits)
- C.RollCredits()
- C.playtitlemusic(40)*/
-
- //Player status report
- for(var/i in GLOB.mob_list)
- var/mob/Player = i
- if(Player.mind && !isnewplayer(Player))
- if(Player.stat != DEAD && !isbrain(Player))
- num_survivors++
- if(station_evacuated) //If the shuttle has already left the station
- var/list/area/shuttle_areas
- if(SSshuttle && SSshuttle.emergency)
- shuttle_areas = SSshuttle.emergency.shuttle_areas
- if(!Player.onCentCom() && !Player.onSyndieBase())
- to_chat(Player, "
You managed to survive, but were marooned on [station_name()]...")
- else
- num_escapees++
- to_chat(Player, "
You managed to survive the events on [station_name()] as [Player.real_name].")
- if(shuttle_areas[get_area(Player)])
- num_shuttle_escapees++
- else
- to_chat(Player, "
You managed to survive the events on [station_name()] as [Player.real_name].")
- else
- to_chat(Player, "
You did not survive the events on [station_name()]...")
-
- CHECK_TICK
-
- //Round statistics report
- var/datum/station_state/end_state = new /datum/station_state()
- end_state.count()
- var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
-
- to_chat(world, "
[GLOB.TAB]Shift Duration:
[DisplayTimeText(world.time - SSticker.round_start_time)]")
- to_chat(world, "
[GLOB.TAB]Station Integrity:
[mode.station_was_nuked ? "Destroyed" : "[station_integrity]%"]")
- if(mode.station_was_nuked)
- SSticker.news_report = STATION_DESTROYED_NUKE
- var/total_players = GLOB.joined_player_list.len
- if(total_players)
- to_chat(world, "
[GLOB.TAB]Total Population:
[total_players]")
- if(station_evacuated)
- to_chat(world, "
[GLOB.TAB]Evacuation Rate:
[num_escapees] ([PERCENT(num_escapees/total_players)]%)")
- to_chat(world, "
[GLOB.TAB](on emergency shuttle):
[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)")
- news_report = STATION_EVACUATED
- if(SSshuttle.emergency.is_hijacked())
- news_report = SHUTTLE_HIJACK
- to_chat(world, "
[GLOB.TAB]Survival Rate:
[num_survivors] ([PERCENT(num_survivors/total_players)]%)")
- to_chat(world, "
")
-
- CHECK_TICK
-
- //Silicon laws report
- for (var/i in GLOB.ai_list)
- var/mob/living/silicon/ai/aiPlayer = i
- if (aiPlayer.stat != DEAD && aiPlayer.mind)
- to_chat(world, "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws at the end of the round were:")
- aiPlayer.show_laws(1)
- else if (aiPlayer.mind) //if the dead ai has a mind, use its key instead
- to_chat(world, "
[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws when it was deactivated were:")
- aiPlayer.show_laws(1)
-
- to_chat(world, "
Total law changes: [aiPlayer.law_change_counter]")
-
- if (aiPlayer.connected_robots.len)
- var/robolist = "
[aiPlayer.real_name]'s minions were: "
- for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
- if(robo.mind)
- robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
- to_chat(world, "[robolist]")
-
- CHECK_TICK
-
- for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
- if (!robo.connected_ai && robo.mind)
- if (robo.stat != DEAD)
- to_chat(world, "
[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:")
- else
- to_chat(world, "
[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:")
-
- if(robo) //How the hell do we lose robo between here and the world messages directly above this?
- robo.laws.show_laws(world)
-
- CHECK_TICK
-
- mode.declare_completion()//To declare normal completion.
-
- CHECK_TICK
-
- //calls auto_declare_completion_* for all modes
- for(var/handler in typesof(/datum/game_mode/proc))
- if (findtext("[handler]","auto_declare_completion_"))
- call(mode, handler)(force_ending)
-
- CHECK_TICK
-
- if(CONFIG_GET(string/cross_server_address))
- send_news_report()
-
- CHECK_TICK
-
- //Print a list of antagonists to the server log
- var/list/total_antagonists = list()
- //Look into all mobs in world, dead or alive
- for(var/datum/mind/Mind in minds)
- var/temprole = Mind.special_role
- if(temprole) //if they are an antagonist of some sort.
- if(temprole in total_antagonists) //If the role exists already, add the name to it
- total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
- else
- total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
- total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
-
- CHECK_TICK
-
- //Now print them all into the log!
- log_game("Antagonists at round end were...")
- for(var/i in total_antagonists)
- log_game("[i]s[total_antagonists[i]].")
-
- CHECK_TICK
-
- for(var/datum/mind/crewMind in minds)
- if(!crewMind.current || !crewMind.objectives.len)
- continue
- for(var/datum/objective/miscreant/MO in crewMind.objectives)
- miscreants += "
[crewMind.current.real_name] (Played by:
[crewMind.key])
Objective: [MO.explanation_text]
(Optional)"
- for(var/datum/objective/crew/CO in crewMind.objectives)
- if(CO.check_completion())
- to_chat(crewMind.current, "
Your optional objective: [CO.explanation_text]
Success!")
- successfulCrew += "
[crewMind.current.real_name] (Played by:
[crewMind.key])
Objective: [CO.explanation_text]
Success! (Optional)"
- else
- to_chat(crewMind.current, "
Your optional objective: [CO.explanation_text]
Failed.")
-
- if (successfulCrew.len)
- var/completedObjectives = "
The following crew members completed their Crew Objectives:"
- for(var/i in successfulCrew)
- completedObjectives += "[i]
"
- to_chat(world, "[completedObjectives]
")
- else
- if(CONFIG_GET(flag/allow_crew_objectives))
- to_chat(world, "
Nobody completed their Crew Objectives!")
-
- CHECK_TICK
-
- if (miscreants.len)
- var/miscreantObjectives = "
The following crew members were miscreants:"
- for(var/i in miscreants)
- miscreantObjectives += "[i]
"
- to_chat(world, "[miscreantObjectives]
")
-
- CHECK_TICK
-
- mode.declare_station_goal_completion()
-
- CHECK_TICK
- //medals, placed far down so that people can actually see the commendations.
- if(GLOB.commendations.len)
- to_chat(world, "
Medal Commendations:")
- for (var/com in GLOB.commendations)
- to_chat(world, com)
-
- CHECK_TICK
-
- //Collects persistence features
- if(mode.allow_persistence_save)
- SSpersistence.CollectData()
-
- //stop collecting feedback during grifftime
- SSblackbox.Seal()
-
- sleep(50)
- ready_for_reboot = TRUE
- standard_reboot()
-
-/datum/controller/subsystem/ticker/proc/standard_reboot()
- if(ready_for_reboot)
- if(mode.station_was_nuked)
- Reboot("Station destroyed by Nuclear Device.", "nuke")
- else
- Reboot("Round ended.", "proper completion")
- else
- CRASH("Attempted standard reboot without ticker roundend completion")
-
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
if(selected_tip)
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 37811c183f..acb873dd5b 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -206,6 +206,7 @@ SUBSYSTEM_DEF(vote)
var/datum/action/vote/V = new
if(question)
V.name = "Vote: [question]"
+ C.player_details.player_actions += V
V.Grant(C.mob)
generated_actions += V
return 1
@@ -299,6 +300,7 @@ SUBSYSTEM_DEF(vote)
for(var/v in generated_actions)
var/datum/action/vote/V = v
if(!QDELETED(V))
+ V.remove_from_client()
V.Remove(V.owner)
generated_actions = list()
@@ -318,7 +320,16 @@ SUBSYSTEM_DEF(vote)
/datum/action/vote/Trigger()
if(owner)
owner.vote()
+ remove_from_client()
Remove(owner)
/datum/action/vote/IsAvailable()
return 1
+
+/datum/action/vote/proc/remove_from_client()
+ if(owner.client)
+ owner.client.player_details.player_actions -= src
+ else if(owner.ckey)
+ var/datum/player_details/P = GLOB.player_details[owner.ckey]
+ if(P)
+ P.player_actions -= src
\ No newline at end of file
diff --git a/code/datums/action.dm b/code/datums/action.dm
index f941a00a54..ede0fa75a2 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -344,6 +344,19 @@
/datum/action/item_action/change
name = "Change"
+/datum/action/item_action/nano_picket_sign
+ name = "Retext Nano Picket Sign"
+ var/obj/item/picket_sign/S
+
+/datum/action/item_action/nano_picket_sign/New(Target)
+ ..()
+ if(istype(Target, /obj/item/picket_sign))
+ S = Target
+
+/datum/action/item_action/nano_picket_sign/Trigger()
+ if(istype(S))
+ S.retext(owner)
+
/datum/action/item_action/adjust
/datum/action/item_action/adjust/New(Target)
diff --git a/code/datums/actions/beam_rifle.dm b/code/datums/actions/beam_rifle.dm
new file mode 100644
index 0000000000..783b93fbdb
--- /dev/null
+++ b/code/datums/actions/beam_rifle.dm
@@ -0,0 +1,12 @@
+
+/datum/action/item_action/zoom_speed_action
+ name = "Toggle Zooming Speed"
+ icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon_state = "projectile"
+ background_icon_state = "bg_tech"
+
+/datum/action/item_action/zoom_lock_action
+ name = "Switch Zoom Mode"
+ icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "zoom_mode"
+ background_icon_state = "bg_tech"
diff --git a/code/datums/actions/flightsuit.dm b/code/datums/actions/flightsuit.dm
index 3e78fa5332..cf249fed31 100644
--- a/code/datums/actions/flightsuit.dm
+++ b/code/datums/actions/flightsuit.dm
@@ -1,5 +1,3 @@
-
-
/datum/action/item_action/flightsuit
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm
index 8d86507271..c12a08a792 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -373,32 +373,9 @@
ion = list()
/datum/ai_laws/proc/show_laws(who)
-
- if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
- for(var/i in devillaws)
- to_chat(who, "666. [i]")
-
- if (zeroth)
- to_chat(who, "0. [zeroth]")
-
- for (var/index = 1, index <= ion.len, index++)
- var/law = ion[index]
- var/num = ionnum()
- to_chat(who, "[num]. [law]")
-
- var/number = 1
- for (var/index = 1, index <= inherent.len, index++)
- var/law = inherent[index]
-
- if (length(law) > 0)
- to_chat(who, "[number]. [law]")
- number++
-
- for (var/index = 1, index <= supplied.len, index++)
- var/law = supplied[index]
- if (length(law) > 0)
- to_chat(who, "[number]. [law]")
- number++
+ var/list/printable_laws = get_law_list(include_zeroth = TRUE)
+ for(var/law in printable_laws)
+ to_chat(who,law)
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
if(force)
diff --git a/code/datums/antagonists/abductor.dm b/code/datums/antagonists/abductor.dm
index 8d13c48e7c..a98acf054e 100644
--- a/code/datums/antagonists/abductor.dm
+++ b/code/datums/antagonists/abductor.dm
@@ -1,7 +1,8 @@
/datum/antagonist/abductor
name = "Abductor"
+ roundend_category = "abductors"
job_rank = ROLE_ABDUCTOR
- var/datum/objective_team/abductor_team/team
+ var/datum/team/abductor_team/team
var/sub_role
var/outfit
var/landmark_type
@@ -19,7 +20,7 @@
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
-/datum/antagonist/abductor/create_team(datum/objective_team/abductor_team/new_team)
+/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -70,3 +71,65 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
+
+
+/datum/team/abductor_team
+ member_name = "abductor"
+ var/team_number
+ var/list/datum/mind/abductees = list()
+
+/datum/team/abductor_team/is_solo()
+ return FALSE
+
+/datum/team/abductor_team/proc/add_objective(datum/objective/O)
+ O.team = src
+ O.update_explanation_text()
+ objectives += O
+
+/datum/team/abductor_team/roundend_report()
+ var/list/result = list()
+
+ var/won = TRUE
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ won = FALSE
+ if(won)
+ result += "
[name] team fulfilled its mission!"
+ else
+ result += "
[name] team failed its mission."
+
+ result += ""
+ for(var/datum/mind/abductor_mind in members)
+ result += printplayer(abductor_mind)
+ result += printobjectives(abductor_mind)
+
+ return result.Join("
")
+
+
+/datum/antagonist/abductee
+ name = "Abductee"
+ roundend_category = "abductees"
+
+/datum/antagonist/abductee/on_gain()
+ give_objective()
+ . = ..()
+
+/datum/antagonist/abductee/greet()
+ to_chat(owner, "
Your mind snaps!")
+ to_chat(owner, "
You can't remember how you got here...")
+ owner.announce_objectives()
+
+/datum/antagonist/abductee/proc/give_objective()
+ var/mob/living/carbon/human/H = owner.current
+ if(istype(H))
+ H.gain_trauma_type(BRAIN_TRAUMA_MILD)
+ var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
+ var/datum/objective/abductee/O = new objtype()
+ objectives += O
+ owner.objectives += objectives
+
+/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
+ SSticker.mode.update_abductor_icons_added(mob_override ? mob_override.mind : owner)
+
+/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
+ SSticker.mode.update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
\ No newline at end of file
diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm
index 0a7b2aa22f..9b5dbb6d75 100644
--- a/code/datums/antagonists/antag_datum.dm
+++ b/code/datums/antagonists/antag_datum.dm
@@ -2,6 +2,8 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist
var/name = "Antagonist"
+ var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
+ var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
var/datum/mind/owner //Mind that owns this datum
var/silent = FALSE //Silent will prevent the gain/lose texts to show
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
@@ -9,6 +11,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/delete_on_mind_deletion = TRUE
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
+ var/list/objectives = list()
/datum/antagonist/New(datum/mind/new_owner)
GLOB.antagonists += src
@@ -46,7 +49,7 @@ GLOBAL_LIST_EMPTY(antagonists)
return
//Assign default team and creates one for one of a kind team antagonists
-/datum/antagonist/proc/create_team(datum/objective_team/team)
+/datum/antagonist/proc/create_team(datum/team/team)
return
//Proc called when the datum is given to a mind.
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(antagonists)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
farewell()
- var/datum/objective_team/team = get_team()
+ var/datum/team/team = get_team()
if(team)
team.remove_member(owner)
qdel(src)
@@ -96,9 +99,62 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/get_team()
return
+//Individual roundend report
+/datum/antagonist/proc/roundend_report()
+ var/list/report = list()
+
+ if(!owner)
+ CRASH("antagonist datum without owner")
+
+ report += printplayer(owner)
+
+ var/objectives_complete = TRUE
+ if(owner.objectives.len)
+ report += printobjectives(owner)
+ for(var/datum/objective/objective in owner.objectives)
+ if(!objective.check_completion())
+ objectives_complete = FALSE
+ break
+
+ if(owner.objectives.len == 0 || objectives_complete)
+ report += "
The [name] was successful!"
+ else
+ report += "
The [name] has failed!"
+
+ return report.Join("
")
+
+//Displayed at the start of roundend_category section, default to roundend_category header
+/datum/antagonist/proc/roundend_report_header()
+ return "
"
+
+//Displayed at the end of roundend_category section
+/datum/antagonist/proc/roundend_report_footer()
+ return
+
//Should probably be on ticker or job ss ?
/proc/get_antagonists(antag_type,specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
if(!specific && istype(A,antag_type) || specific && A.type == antag_type)
- . += A.owner
\ No newline at end of file
+ . += A.owner
+
+
+
+//This datum will autofill the name with special_role
+//Used as placeholder for minor antagonists, please create proper datums for these
+/datum/antagonist/auto_custom
+
+/datum/antagonist/auto_custom/on_gain()
+ ..()
+ name = owner.special_role
+ //Add all objectives not already owned by other datums to this one.
+ var/list/already_registered_objectives = list()
+ for(var/datum/antagonist/A in owner.antag_datums)
+ if(A == src)
+ continue
+ else
+ already_registered_objectives |= A.objectives
+ objectives = owner.objectives - already_registered_objectives
+
+//This one is created by admin tools for custom objectives
+/datum/antagonist/custom
\ No newline at end of file
diff --git a/code/datums/antagonists/brother.dm b/code/datums/antagonists/brother.dm
index 6458e6da09..b06c75e4fa 100644
--- a/code/datums/antagonists/brother.dm
+++ b/code/datums/antagonists/brother.dm
@@ -2,12 +2,12 @@
name = "Brother"
job_rank = ROLE_BROTHER
var/special_role = "blood brother"
- var/datum/objective_team/brother_team/team
+ var/datum/team/brother_team/team
/datum/antagonist/brother/New(datum/mind/new_owner)
return ..()
-/datum/antagonist/brother/create_team(datum/objective_team/brother_team/new_team)
+/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -55,3 +55,71 @@
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
+
+
+/datum/team/brother_team
+ name = "brotherhood"
+ member_name = "blood brother"
+ var/meeting_area
+
+/datum/team/brother_team/is_solo()
+ return FALSE
+
+/datum/team/brother_team/proc/update_name()
+ var/list/last_names = list()
+ for(var/datum/mind/M in members)
+ var/list/split_name = splittext(M.name," ")
+ last_names += split_name[split_name.len]
+
+ name = last_names.Join(" & ")
+
+/datum/team/brother_team/roundend_report()
+ var/list/parts = list()
+
+ parts += ""
+ for(var/datum/mind/M in members)
+ parts += printplayer(M)
+ var/win = TRUE
+ var/objective_count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[objective_count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[objective_count]: [objective.explanation_text]
Fail."
+ win = FALSE
+ objective_count++
+ if(win)
+ parts += "
The blood brothers were successful!"
+ else
+ parts += "
The blood brothers have failed!"
+
+ return "
[parts.Join("
")]
"
+
+/datum/team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
+ O.team = src
+ if(needs_target)
+ O.find_target()
+ O.update_explanation_text()
+ objectives += O
+
+/datum/team/brother_team/proc/forge_brother_objectives()
+ objectives = list()
+ var/is_hijacker = prob(10)
+ for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
+ forge_single_objective()
+ if(is_hijacker)
+ if(!locate(/datum/objective/hijack) in objectives)
+ add_objective(new/datum/objective/hijack)
+ else if(!locate(/datum/objective/escape) in objectives)
+ add_objective(new/datum/objective/escape)
+
+/datum/team/brother_team/proc/forge_single_objective()
+ if(prob(50))
+ if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
+ add_objective(new/datum/objective/destroy, TRUE)
+ else if(prob(30))
+ add_objective(new/datum/objective/maroon, TRUE)
+ else
+ add_objective(new/datum/objective/assassinate, TRUE)
+ else
+ add_objective(new/datum/objective/steal, TRUE)
\ No newline at end of file
diff --git a/code/datums/antagonists/changeling.dm b/code/datums/antagonists/changeling.dm
index e98bfed782..031e08738f 100644
--- a/code/datums/antagonists/changeling.dm
+++ b/code/datums/antagonists/changeling.dm
@@ -4,11 +4,11 @@
/datum/antagonist/changeling
name = "Changeling"
+ roundend_category = "changelings"
job_rank = ROLE_CHANGELING
var/you_are_greet = TRUE
var/give_objectives = TRUE
- var/list/objectives = list()
var/team_mode = FALSE //Should assign team objectives ?
//Changeling Stuff
@@ -223,7 +223,7 @@
if(verbose)
to_chat(user, "
[target] is not compatible with our biology.")
return
- if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
+ if((target.has_disability(NOCLONE)) || (target.has_disability(NOCLONE)))
if(verbose)
to_chat(user, "
DNA of [target] is ruined beyond usability!")
return
@@ -478,4 +478,35 @@
/datum/antagonist/changeling/xenobio
name = "Xenobio Changeling"
give_objectives = FALSE
+ show_in_roundend = FALSE //These are here for admin tracking purposes only
you_are_greet = FALSE
+
+/datum/antagonist/changeling/roundend_report()
+ var/list/parts = list()
+
+ var/changelingwin = 1
+ if(!owner.current)
+ changelingwin = 0
+
+ parts += printplayer(owner)
+
+ //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
+ parts += "
Changeling ID: [changelingID]."
+ parts += "
Genomes Extracted: [absorbedcount]"
+ parts += " "
+ if(objectives.len)
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ changelingwin = 0
+ count++
+
+ if(changelingwin)
+ parts += "
The changeling was successful!"
+ else
+ parts += "
The changeling has failed."
+
+ return parts.Join("
")
\ No newline at end of file
diff --git a/code/datums/antagonists/clockcult.dm b/code/datums/antagonists/clockcult.dm
index 8cc1c9e9a7..48f9b53425 100644
--- a/code/datums/antagonists/clockcult.dm
+++ b/code/datums/antagonists/clockcult.dm
@@ -1,8 +1,11 @@
//CLOCKCULT PROOF OF CONCEPT
/datum/antagonist/clockcult
name = "Clock Cultist"
- var/datum/action/innate/hierophant/hierophant_network = new()
+ roundend_category = "clock cultists"
job_rank = ROLE_SERVANT_OF_RATVAR
+ var/datum/action/innate/hierophant/hierophant_network = new()
+ var/datum/team/clockcult/clock_team
+ var/make_team = TRUE //This should be only false for tutorial scarabs
/datum/antagonist/clockcult/silent
silent = TRUE
@@ -11,6 +14,22 @@
qdel(hierophant_network)
return ..()
+/datum/antagonist/clockcult/get_team()
+ return clock_team
+
+/datum/antagonist/clockcult/create_team(datum/team/clockcult/new_team)
+ if(!new_team && make_team)
+ //TODO blah blah same as the others, allow multiple
+ for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
+ if(H.clock_team)
+ clock_team = H.clock_team
+ return
+ clock_team = new /datum/team/clockcult
+ return
+ if(make_team && !istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ clock_team = new_team
+
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -156,7 +175,7 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
- owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
+ owner.current.visible_message("
[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
to_chat(owner, "
A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
owner.current.log_message("
Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG)
owner.wipe_memory()
@@ -164,3 +183,35 @@
if(iscyborg(owner.current))
to_chat(owner.current, "
Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.")
. = ..()
+
+
+/datum/team/clockcult
+ name = "Clockcult"
+ var/list/objective
+ var/datum/mind/eminence
+
+/datum/team/clockcult/proc/check_clockwork_victory()
+ if(GLOB.clockwork_gateway_activated)
+ return TRUE
+ return FALSE
+
+/datum/team/clockcult/roundend_report()
+ var/list/parts = list()
+
+ if(check_clockwork_victory())
+ parts += "
Ratvar's servants defended the Ark until its activation!"
+ else
+ parts += "
The Ark was destroyed! Ratvar will rust away for all eternity!"
+ parts += " "
+ parts += "
The servants' objective was: [CLOCKCULT_OBJECTIVE]."
+ parts += "
Construction Value(CV) was:
[GLOB.clockwork_construction_value]"
+ for(var/i in SSticker.scripture_states)
+ if(i != SCRIPTURE_DRIVER)
+ parts += "
[i] scripture was:
[SSticker.scripture_states[i] ? "UN":""]LOCKED"
+ if(eminence)
+ parts += " [printplayer(eminence)]"
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members - eminence)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/cult.dm b/code/datums/antagonists/cult.dm
index c26b0f8108..916123ddff 100644
--- a/code/datums/antagonists/cult.dm
+++ b/code/datums/antagonists/cult.dm
@@ -2,84 +2,103 @@
/datum/antagonist/cult
name = "Cultist"
+ roundend_category = "cultists"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
+ var/give_equipment = FALSE
+
+ var/datum/team/cult/cult_team
+
+/datum/antagonist/cult/get_team()
+ return cult_team
+
+/datum/antagonist/cult/create_team(datum/team/cult/new_team)
+ if(!new_team)
+ //todo remove this and allow admin buttons to create more than one cult
+ for(var/datum/antagonist/cult/H in GLOB.antagonists)
+ if(H.cult_team)
+ cult_team = H.cult_team
+ return
+ cult_team = new /datum/team/cult
+ cult_team.setup_objectives()
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ cult_team = new_team
+
+/datum/antagonist/cult/proc/add_objectives()
+ objectives |= cult_team.objectives
+ owner.objectives |= objectives
+
+/datum/antagonist/cult/proc/remove_objectives()
+ owner.objectives -= objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
QDEL_NULL(vote)
return ..()
-/datum/antagonist/cult/proc/add_objectives()
- var/list/target_candidates = list()
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- if(target_candidates.len == 0)
- message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
- target_candidates += player.mind
- listclearnulls(target_candidates)
- if(LAZYLEN(target_candidates))
- GLOB.sac_mind = pick(target_candidates)
- if(!GLOB.sac_mind)
- message_admins("Cult Sacrifice: ERROR - Null target chosen!")
- else
- var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
- var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- GLOB.sac_image = reshape
- else
- message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
- GLOB.sac_complete = TRUE
- SSticker.mode.cult_objectives += "sacrifice"
- if(!GLOB.summon_spots.len)
- while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
- var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
- if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
- GLOB.summon_spots += summon
- SSticker.mode.cult_objectives += "eldergod"
-
-/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
- var/mob/living/current = cult_mind.current
- for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
- var/explanation
- switch(SSticker.mode.cult_objectives[obj_count])
- if("sacrifice")
- if(GLOB.sac_mind)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
- else
- explanation = "The veil has already been weakened here, proceed to the final objective."
- GLOB.sac_complete = TRUE
- if("eldergod")
- explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin."
- if(!silent)
- to_chat(current, "
Objective #[obj_count]: [explanation]")
- cult_mind.memory += "
Objective #[obj_count]: [explanation]
"
-
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
- . = is_convertable_to_cult(new_owner.current)
+ . = is_convertable_to_cult(new_owner.current,cult_team)
+
+/datum/antagonist/cult/greet()
+ to_chat(owner, "
You are a member of the cult!")
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
+ owner.announce_objectives()
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
- if(!LAZYLEN(SSticker.mode.cult_objectives))
- add_objectives()
+ add_objectives()
+ if(give_equipment)
+ equip_cultist()
SSticker.mode.cult += owner // Only add after they've been given objectives
- cult_memorization(owner)
SSticker.mode.update_cult_icons_added(owner)
current.log_message("
Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && current.client)
- current.client.images += GLOB.blood_target_image
+
+ if(cult_team.blood_target && cult_team.blood_target_image && current.client)
+ current.client.images += cult_team.blood_target_image
+
+
+/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
+ var/mob/living/carbon/H = owner.current
+ if(!istype(H))
+ return
+ if (owner.assigned_role == "Clown")
+ to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
+ H.dna.remove_mutation(CLOWNMUT)
+
+ if(tome)
+ . += cult_give_item(/obj/item/tome, H)
+ else
+ . += cult_give_item(/obj/item/paper/talisman/supply, H)
+ to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
+
+
+/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
+ var/list/slots = list(
+ "backpack" = slot_in_backpack,
+ "left pocket" = slot_l_store,
+ "right pocket" = slot_r_store
+ )
+
+ var/T = new item_path(mob)
+ var/item_name = initial(item_path.name)
+ var/where = mob.equip_in_one_of_slots(T, slots)
+ if(!where)
+ to_chat(mob, "
Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).")
+ return 0
+ else
+ to_chat(mob, "
You have a [item_name] in your [where].")
+ if(where == "backpack")
+ var/obj/item/storage/B = mob.back
+ B.orient2hud(mob)
+ B.show_to(mob)
+ return 1
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -89,7 +108,7 @@
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
- if(!GLOB.cult_mastered)
+ if(!cult_team.cult_mastered)
vote.Grant(current)
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
@@ -107,6 +126,7 @@
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
+ remove_objectives()
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
@@ -114,8 +134,8 @@
owner.current.visible_message("
[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!", ignored_mob = owner.current)
to_chat(owner.current, "
An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
owner.current.log_message("
Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
- if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
- owner.current.client.images -= GLOB.blood_target_image
+ if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
+ owner.current.client.images -= cult_team.blood_target_image
. = ..()
/datum/antagonist/cult/master
@@ -145,7 +165,7 @@
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
- if(!GLOB.reckoning_complete)
+ if(!cult_team.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
@@ -162,3 +182,118 @@
throwing.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
+
+/datum/team/cult
+ name = "Cult"
+
+ var/blood_target
+ var/image/blood_target_image
+ var/blood_target_reset_timer
+
+ var/cult_vote_called = FALSE
+ var/cult_mastered = FALSE
+ var/reckoning_complete = FALSE
+
+
+/datum/team/cult/proc/setup_objectives()
+ //SAC OBJECTIVE , todo: move this to objective internals
+ var/list/target_candidates = list()
+ var/datum/objective/sacrifice/sac_objective = new
+ sac_objective.team = src
+
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && player.stat != DEAD)
+ target_candidates += player.mind
+
+ if(target_candidates.len == 0)
+ message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && player.stat != DEAD)
+ target_candidates += player.mind
+ listclearnulls(target_candidates)
+ if(LAZYLEN(target_candidates))
+ sac_objective.target = pick(target_candidates)
+ sac_objective.update_explanation_text()
+
+ var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
+ var/datum/preferences/sacface = sac_objective.target.current.client.prefs
+ var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
+ reshape.Shift(SOUTH, 4)
+ reshape.Shift(EAST, 1)
+ reshape.Crop(7,4,26,31)
+ reshape.Crop(-5,-3,26,30)
+ sac_objective.sac_image = reshape
+
+ objectives += sac_objective
+ else
+ message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
+
+
+ //SUMMON OBJECTIVE
+
+ var/datum/objective/eldergod/summon_objective = new()
+ summon_objective.team = src
+ objectives += summon_objective
+
+/datum/objective/sacrifice
+ var/sacced = FALSE
+ var/sac_image
+
+/datum/objective/sacrifice/check_completion()
+ return sacced || completed
+
+/datum/objective/sacrifice/update_explanation_text()
+ if(target && !sacced)
+ explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
+ else
+ explanation_text = "The veil has already been weakened here, proceed to the final objective."
+
+/datum/objective/eldergod
+ var/summoned = FALSE
+ var/list/summon_spots = list()
+
+/datum/objective/eldergod/New()
+ ..()
+ var/sanity = 0
+ while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
+ var/area/summon = pick(GLOB.sortedAreas - summon_spots)
+ if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
+ summon_spots += summon
+ sanity++
+ update_explanation_text()
+
+/datum/objective/eldergod/update_explanation_text()
+ explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'.
The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin."
+
+/datum/objective/eldergod/check_completion()
+ return summoned || completed
+
+/datum/team/cult/proc/check_cult_victory()
+ for(var/datum/objective/O in objectives)
+ if(!O.check_completion())
+ return FALSE
+ return TRUE
+
+/datum/team/cult/roundend_report()
+ var/list/parts = list()
+
+ if(check_cult_victory())
+ parts += "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!"
+ else
+ parts += "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!"
+
+ if(objectives.len)
+ parts += "
The cultists' objectives were:"
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ count++
+
+ if(members.len)
+ parts += ""
+ parts += printplayerlist(members)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index d386c79c25..3ccdc7ddfb 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -1,5 +1,6 @@
/datum/antagonist/traitor
name = "Traitor"
+ roundend_category = "traitors"
job_rank = ROLE_TRAITOR
var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
@@ -8,7 +9,6 @@
var/employer = "The Syndicate"
var/give_objectives = TRUE
var/should_give_codewords = TRUE
- var/list/objectives_given = list()
/datum/antagonist/traitor/human
var/should_equip = TRUE
@@ -52,9 +52,9 @@
if(should_specialise)
return ..()//we never did any of this anyway
SSticker.mode.traitors -= owner
- for(var/O in objectives_given)
+ for(var/O in objectives)
owner.objectives -= O
- objectives_given = list()
+ objectives = list()
if(!silent && owner.current)
to_chat(owner.current,"
You are no longer the [special_role]! ")
owner.special_role = null
@@ -71,11 +71,11 @@
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
owner.objectives += O
- objectives_given += O
+ objectives += O
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
owner.objectives -= O
- objectives_given -= O
+ objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
@@ -294,3 +294,53 @@
where = "In your [equipped_slot]"
to_chat(mob, "
[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.")
+//TODO Collate
+/datum/antagonist/traitor/roundend_report()
+ var/list/result = list()
+
+ var/traitorwin = TRUE
+
+ result += printplayer(owner)
+
+ var/TC_uses = 0
+ var/uplink_true = FALSE
+ var/purchases = ""
+ for(var/datum/component/uplink/H in GLOB.uplinks)
+ if(H && H.owner && H.owner == owner.key)
+ TC_uses += H.spent_telecrystals
+ uplink_true = TRUE
+ purchases += H.purchase_log.generate_render(FALSE)
+
+ var/objectives_text = ""
+ if(objectives.len)//If the traitor had no objectives, don't need to process this.
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ objectives_text += "
Objective #[count]: [objective.explanation_text]
Fail."
+ traitorwin = FALSE
+ count++
+
+ if(uplink_true)
+ var/uplink_text = "(used [TC_uses] TC) [purchases]"
+ if(TC_uses==0 && traitorwin)
+ var/static/icon/badass = icon('icons/badass.dmi', "badass")
+ uplink_text += "
[icon2html(badass, world)]"
+ result += uplink_text
+
+ result += objectives_text
+
+ var/special_role_text = lowertext(name)
+
+ if(traitorwin)
+ result += "
The [special_role_text] was successful!"
+ else
+ result += "
The [special_role_text] has failed!"
+ SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
+
+ return result.Join("
")
+
+/datum/antagonist/traitor/roundend_report_footer()
+ return "
The code phrases were: [GLOB.syndicate_code_phrase]\
+
The code responses were: [GLOB.syndicate_code_response]"
\ No newline at end of file
diff --git a/code/datums/antagonists/devil.dm b/code/datums/antagonists/devil.dm
index 416a8f3752..97e0d8c18a 100644
--- a/code/datums/antagonists/devil.dm
+++ b/code/datums/antagonists/devil.dm
@@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon",
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
name = "Devil"
+ roundend_category = "devils"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
@@ -508,6 +509,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
owner.RemoveSpell(S)
.=..()
+/datum/antagonist/devil/proc/printdevilinfo()
+ var/list/parts = list()
+ parts += "The devil's true name is: [truename]"
+ parts += "The devil's bans were:"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
+ parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report()
+ var/list/parts = list()
+ parts += printplayer(owner)
+ parts += printdevilinfo()
+ parts += printobjectives(owner)
+ return parts.Join("
")
+
+/datum/antagonist/devil/roundend_report_footer()
+ //sintouched go here for now as a hack , TODO proper antag datum for these
+ var/list/parts = list()
+ if(SSticker.mode.sintouched.len)
+ parts += ""
+ var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
+ for(var/S in sintouchedUnique)
+ var/datum/mind/sintouched_mind = S
+ parts += printplayer(sintouched_mind)
+ parts += printobjectives(sintouched_mind)
+ return parts.Join("
")
+
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm
index ab4822dd79..8201cd879d 100644
--- a/code/datums/antagonists/ninja.dm
+++ b/code/datums/antagonists/ninja.dm
@@ -37,19 +37,20 @@
else if(M.assigned_role in GLOB.command_positions)
possible_targets[M] = 1 //good-guy
- var/list/objectives = list(1,2,3,4)
- while(owner.objectives.len < quantity)
- switch(pick_n_take(objectives))
+ var/list/possible_objectives = list(1,2,3,4)
+
+ while(objectives.len < quantity)
+ switch(pick_n_take(possible_objectives))
if(1) //research
var/datum/objective/download/O = new /datum/objective/download()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
if(2) //steal
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
O.owner = owner
- owner.objectives += O
+ objectives += O
if(3) //protect/kill
if(!possible_targets.len) continue
@@ -63,13 +64,13 @@
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
- owner.objectives += O
+ objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
O.owner = owner
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
- owner.objectives += O
+ objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
@@ -82,17 +83,17 @@
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
- owner.objectives += O
+ objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
O.owner = owner
O.gen_amount_goal()
- owner.objectives += O
+ objectives += O
else
break
var/datum/objective/O = new /datum/objective/survive()
O.owner = owner
- owner.objectives += O
+ owner.objectives |= objectives
/proc/remove_ninja(mob/living/L)
diff --git a/code/datums/antagonists/nukeop.dm b/code/datums/antagonists/nukeop.dm
new file mode 100644
index 0000000000..8b7fc7826f
--- /dev/null
+++ b/code/datums/antagonists/nukeop.dm
@@ -0,0 +1,322 @@
+#define NUKE_RESULT_FLUKE 0
+#define NUKE_RESULT_NUKE_WIN 1
+#define NUKE_RESULT_CREW_WIN 2
+#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
+#define NUKE_RESULT_DISK_LOST 4
+#define NUKE_RESULT_DISK_STOLEN 5
+#define NUKE_RESULT_NOSURVIVORS 6
+#define NUKE_RESULT_WRONG_STATION 7
+#define NUKE_RESULT_WRONG_STATION_DEAD 8
+
+/datum/antagonist/nukeop
+ name = "Nuclear Operative"
+ roundend_category = "syndicate operatives" //just in case
+ job_rank = ROLE_OPERATIVE
+ var/datum/team/nuclear/nuke_team
+ var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
+ var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
+ var/nukeop_outfit = /datum/outfit/syndicate
+
+/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
+ var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
+ opshud.join_hud(M)
+ set_antag_hud(M, "synd")
+
+/datum/antagonist/nukeop/proc/update_synd_icons_removed(mob/living/M)
+ var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
+ opshud.leave_hud(M)
+ set_antag_hud(M, null)
+
+/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_synd_icons_added(M)
+
+/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_synd_icons_removed(M)
+
+/datum/antagonist/nukeop/proc/equip_op()
+ if(!ishuman(owner.current))
+ return
+ var/mob/living/carbon/human/H = owner.current
+
+ H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
+
+ H.equipOutfit(nukeop_outfit)
+ return TRUE
+
+/datum/antagonist/nukeop/greet()
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
+ to_chat(owner, "
You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!")
+ owner.announce_objectives()
+ return
+
+/datum/antagonist/nukeop/on_gain()
+ give_alias()
+ forge_objectives()
+ . = ..()
+ equip_op()
+ memorize_code()
+ if(send_to_spawnpoint)
+ move_to_spawnpoint()
+
+/datum/antagonist/nukeop/get_team()
+ return nuke_team
+
+/datum/antagonist/nukeop/proc/assign_nuke()
+ if(nuke_team && !nuke_team.tracked_nuke)
+ nuke_team.memorized_code = random_nukecode()
+ var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
+ if(nuke)
+ nuke_team.tracked_nuke = nuke
+ if(nuke.r_code == "ADMIN")
+ nuke.r_code = nuke_team.memorized_code
+ else //Already set by admins/something else?
+ nuke_team.memorized_code = nuke.r_code
+ else
+ stack_trace("Syndicate nuke not found during nuke team creation.")
+ nuke_team.memorized_code = null
+
+/datum/antagonist/nukeop/proc/give_alias()
+ if(nuke_team && nuke_team.syndicate_name)
+ var/number = 1
+ number = nuke_team.members.Find(owner)
+ owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
+
+/datum/antagonist/nukeop/proc/memorize_code()
+ if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
+ owner.store_memory("
[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]", 0, 0)
+ to_chat(owner, "The nuclear authorization code is:
[nuke_team.memorized_code]")
+ else
+ to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
+
+/datum/antagonist/nukeop/proc/forge_objectives()
+ if(nuke_team)
+ owner.objectives |= nuke_team.objectives
+
+/datum/antagonist/nukeop/proc/move_to_spawnpoint()
+ var/team_number = 1
+ if(nuke_team)
+ team_number = nuke_team.members.Find(owner)
+ owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
+
+/datum/antagonist/nukeop/leader/move_to_spawnpoint()
+ owner.current.forceMove(pick(GLOB.nukeop_leader_start))
+
+/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
+ if(!new_team)
+ if(!always_new_team)
+ for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
+ if(N.nuke_team)
+ nuke_team = N.nuke_team
+ return
+ nuke_team = new /datum/team/nuclear
+ nuke_team.update_objectives()
+ assign_nuke() //This is bit ugly
+ return
+ if(!istype(new_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ nuke_team = new_team
+
+/datum/antagonist/nukeop/leader
+ name = "Nuclear Operative Leader"
+ nukeop_outfit = /datum/outfit/syndicate/leader
+ always_new_team = TRUE
+ var/title
+
+/datum/antagonist/nukeop/leader/memorize_code()
+ ..()
+ if(nuke_team && nuke_team.memorized_code)
+ var/obj/item/paper/P = new
+ P.info = "The nuclear authorization code is:
[nuke_team.memorized_code]"
+ P.name = "nuclear bomb code"
+ var/mob/living/carbon/human/H = owner.current
+ if(!istype(H))
+ P.forceMove(get_turf(H))
+ else
+ H.put_in_hands(P, TRUE)
+ H.update_icons()
+
+/datum/antagonist/nukeop/leader/give_alias()
+ title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
+ if(nuke_team && nuke_team.syndicate_name)
+ owner.current.real_name = "[nuke_team.syndicate_name] [title]"
+ else
+ owner.current.real_name = "Syndicate [title]"
+
+/datum/antagonist/nukeop/leader/greet()
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
+ to_chat(owner, "
You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.")
+ to_chat(owner, "
If you feel you are not up to this task, give your ID to another operative.")
+ to_chat(owner, "
In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.")
+ owner.announce_objectives()
+ addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1)
+
+
+/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
+ if(!nuke_team)
+ return
+ nuke_team.rename_team(ask_name())
+
+/datum/team/nuclear/proc/rename_team(new_name)
+ syndicate_name = new_name
+ name = "[syndicate_name] Team"
+ for(var/I in members)
+ var/datum/mind/synd_mind = I
+ var/mob/living/carbon/human/H = synd_mind.current
+ if(!istype(H))
+ continue
+ var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
+ H.fully_replace_character_name(H.real_name,chosen_name)
+
+/datum/antagonist/nukeop/leader/proc/ask_name()
+ var/randomname = pick(GLOB.last_names)
+ var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
+ if (!newname)
+ newname = randomname
+ else
+ newname = reject_bad_name(newname)
+ if(!newname)
+ newname = randomname
+
+ return capitalize(newname)
+
+/datum/antagonist/nukeop/lone
+ name = "Lone Operative"
+ always_new_team = TRUE
+ send_to_spawnpoint = FALSE //Handled by event
+ nukeop_outfit = /datum/outfit/syndicate/full
+
+/datum/antagonist/nukeop/lone/assign_nuke()
+ if(nuke_team && !nuke_team.tracked_nuke)
+ nuke_team.memorized_code = random_nukecode()
+ var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
+ if(nuke)
+ nuke_team.tracked_nuke = nuke
+ if(nuke.r_code == "ADMIN")
+ nuke.r_code = nuke_team.memorized_code
+ else //Already set by admins/something else?
+ nuke_team.memorized_code = nuke.r_code
+ else
+ stack_trace("Station self destruct ot found during lone op team creation.")
+ nuke_team.memorized_code = null
+
+/datum/team/nuclear
+ var/syndicate_name
+ var/obj/machinery/nuclearbomb/tracked_nuke
+ var/core_objective = /datum/objective/nuclear
+ var/memorized_code
+
+/datum/team/nuclear/New()
+ ..()
+ syndicate_name = syndicate_name()
+
+/datum/team/nuclear/proc/update_objectives()
+ if(core_objective)
+ var/datum/objective/O = new core_objective
+ O.team = src
+ objectives += O
+
+/datum/team/nuclear/proc/disk_rescued()
+ for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
+ if(!D.onCentCom())
+ return FALSE
+ return TRUE
+
+/datum/team/nuclear/proc/operatives_dead()
+ for(var/I in members)
+ var/datum/mind/operative_mind = I
+ if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
+ return FALSE
+ return TRUE
+
+/datum/team/nuclear/proc/syndies_escaped()
+ var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
+ return (S && (S.z == ZLEVEL_CENTCOM || S.z == ZLEVEL_TRANSIT))
+
+/datum/team/nuclear/proc/get_result()
+ var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
+ var/disk_rescued = disk_rescued()
+ var/syndies_didnt_escape = !syndies_escaped()
+ var/station_was_nuked = SSticker.mode.station_was_nuked
+ var/nuke_off_station = SSticker.mode.nuke_off_station
+
+ if(nuke_off_station == NUKE_SYNDICATE_BASE)
+ return NUKE_RESULT_FLUKE
+ else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
+ return NUKE_RESULT_NUKE_WIN
+ else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
+ return NUKE_RESULT_NOSURVIVORS
+ else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
+ return NUKE_RESULT_WRONG_STATION
+ else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
+ return NUKE_RESULT_WRONG_STATION_DEAD
+ else if ((disk_rescued || evacuation) && operatives_dead())
+ return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
+ else if (disk_rescued)
+ return NUKE_RESULT_CREW_WIN
+ else if (!disk_rescued && operatives_dead())
+ return NUKE_RESULT_DISK_LOST
+ else if (!disk_rescued && evacuation)
+ return NUKE_RESULT_DISK_STOLEN
+ else
+ return //Undefined result
+
+/datum/team/nuclear/roundend_report()
+ var/list/parts = list()
+ parts += ""
+
+ switch(get_result())
+ if(NUKE_RESULT_FLUKE)
+ parts += "
Humiliating Syndicate Defeat"
+ parts += "
The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed! Next time, don't lose the nuke!"
+ if(NUKE_RESULT_NUKE_WIN)
+ parts += "
Syndicate Major Victory!"
+ parts += "
[syndicate_name] operatives have destroyed [station_name()]!"
+ if(NUKE_RESULT_NOSURVIVORS)
+ parts += "
Total Annihilation"
+ parts += "
[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!"
+ if(NUKE_RESULT_WRONG_STATION)
+ parts += "
Crew Minor Victory"
+ parts += "
[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't do that!"
+ if(NUKE_RESULT_WRONG_STATION_DEAD)
+ parts += "
[syndicate_name] operatives have earned Darwin Award!"
+ parts += "
[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't do that!"
+ if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
+ parts += "
Crew Major Victory!"
+ parts += "
The Research Staff has saved the disk and killed the [syndicate_name] Operatives"
+ if(NUKE_RESULT_CREW_WIN)
+ parts += "
Crew Major Victory"
+ parts += "
The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!"
+ if(NUKE_RESULT_DISK_LOST)
+ parts += "
Neutral Victory!"
+ parts += "
The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!"
+ if(NUKE_RESULT_DISK_STOLEN)
+ parts += "
Syndicate Minor Victory!"
+ parts += "
[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()]. Next time, don't lose the disk!"
+ else
+ parts += "
Neutral Victory"
+ parts += "
Mission aborted!"
+
+ var/text = "
"
+ var/purchases = ""
+ var/TC_uses = 0
+ for(var/I in members)
+ var/datum/mind/syndicate = I
+ for(var/U in GLOB.uplinks)
+ var/datum/component/uplink/H = U
+ if(H.owner == syndicate.key)
+ TC_uses += H.purchase_log.total_spent
+ if(H.purchase_log)
+ purchases += H.purchase_log.generate_render(show_key = FALSE)
+ else
+ stack_trace("WARNING: Nuke Op uplink with no purchase_log Owner: [H.owner]")
+ text += printplayerlist(members)
+ text += "
"
+ text += "(Syndicates used [TC_uses] TC) [purchases]"
+ if(TC_uses == 0 && SSticker.mode.station_was_nuked && !operatives_dead())
+ text += "
[icon2html('icons/badass.dmi', world, "badass")]"
+
+ parts += text
+
+ return "
[parts.Join("
")]
"
diff --git a/code/datums/antagonists/pirate.dm b/code/datums/antagonists/pirate.dm
index ad32e09151..9bf20a4bf5 100644
--- a/code/datums/antagonists/pirate.dm
+++ b/code/datums/antagonists/pirate.dm
@@ -1,7 +1,8 @@
/datum/antagonist/pirate
name = "Space Pirate"
job_rank = ROLE_TRAITOR
- var/datum/objective_team/pirate/crew
+ roundend_category = "space pirates"
+ var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
to_chat(owner, "
You are a Space Pirate!")
@@ -11,15 +12,16 @@
/datum/antagonist/pirate/get_team()
return crew
-/datum/antagonist/pirate/create_team(datum/objective_team/pirate/new_team)
+/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
if(!new_team)
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
if(P.crew)
- new_team = P.crew
+ crew = P.crew
+ return
if(!new_team)
- crew = new /datum/objective_team/pirate
+ crew = new /datum/team/pirate
crew.forge_objectives()
- return
+ return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
crew = new_team
@@ -34,11 +36,10 @@
owner.objectives -= crew.objectives
. = ..()
-/datum/objective_team/pirate
+/datum/team/pirate
name = "Pirate crew"
- var/list/objectives = list()
-/datum/objective_team/pirate/proc/forge_objectives()
+/datum/team/pirate/proc/forge_objectives()
var/datum/objective/loot/getbooty = new()
getbooty.team = src
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
@@ -84,11 +85,11 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
loot_table[lootname] = count
else
loot_table[lootname] += count
- var/text = ""
+ var/list/loot_texts = list()
for(var/key in loot_table)
var/amount = loot_table[key]
- text += "[amount] [key][amount > 1 ? "s":""], "
- return text
+ loot_texts += "[amount] [key][amount > 1 ? "s":""]"
+ return loot_texts.Join(", ")
/datum/objective/loot/proc/get_loot_value()
if(!storage_area)
@@ -104,32 +105,25 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
/datum/objective/loot/check_completion()
return ..() || get_loot_value() >= target_value
+/datum/team/pirate/roundend_report()
+ var/list/parts = list()
-//These need removal ASAP as everything is converted to datum antags.
-/datum/game_mode/proc/auto_declare_completion_pirates()
- var/list/datum/mind/pirates = get_antagonists(/datum/antagonist/pirate)
- var/datum/objective_team/pirate/crew
- var/text = ""
- if(pirates.len)
- text += "
Space Pirates were:"
- for(var/datum/mind/M in pirates)
- text += printplayer(M)
- if(!crew)
- var/datum/antagonist/pirate/P = M.has_antag_datum(/datum/antagonist/pirate)
- crew = P.crew
- if(crew)
- text += "
Loot stolen: "
- var/datum/objective/loot/L = locate() in crew.objectives
- text += L.loot_listing()
- text += "
Total loot value : [L.get_loot_value()]/[L.target_value] credits"
+ parts += ""
- var/all_dead = TRUE
- for(var/datum/mind/M in crew.members)
- if(considered_alive(M))
- all_dead = FALSE
- break
- if(L.check_completion() && !all_dead)
- text += "
The pirate crew was successful!"
- else
- text += "
The pirate crew has failed."
- to_chat(world, text)
\ No newline at end of file
+ var/all_dead = TRUE
+ for(var/datum/mind/M in members)
+ if(considered_alive(M))
+ all_dead = FALSE
+ parts += printplayerlist(members)
+
+ parts += "Loot stolen: "
+ var/datum/objective/loot/L = locate() in objectives
+ parts += L.loot_listing()
+ parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits"
+
+ if(L.check_completion() && !all_dead)
+ parts += "
The pirate crew was successful!"
+ else
+ parts += "
The pirate crew has failed."
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/antagonists/revolution.dm b/code/datums/antagonists/revolution.dm
index 9db86bdf08..3209b9221c 100644
--- a/code/datums/antagonists/revolution.dm
+++ b/code/datums/antagonists/revolution.dm
@@ -3,9 +3,10 @@
/datum/antagonist/rev
name = "Revolutionary"
+ roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
job_rank = ROLE_REV
var/hud_type = "rev"
- var/datum/objective_team/revolution/rev_team
+ var/datum/team/revolution/rev_team
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
@@ -39,17 +40,17 @@
. = ..()
/datum/antagonist/rev/greet()
- to_chat(owner, "
You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!")
+ to_chat(owner, "
You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!")
owner.announce_objectives()
-/datum/antagonist/rev/create_team(datum/objective_team/revolution/new_team)
+/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
if(!new_team)
//For now only one revolution at a time
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
if(H.rev_team)
rev_team = H.rev_team
return
- rev_team = new /datum/objective_team/revolution
+ rev_team = new /datum/team/revolution
rev_team.update_objectives()
rev_team.update_heads()
return
@@ -77,7 +78,7 @@
old_owner.add_antag_datum(new_revhead,old_team)
new_revhead.silent = FALSE
to_chat(old_owner, "
You have proved your devotion to revolution! You are a head revolutionary now!")
-
+
/datum/antagonist/rev/head
name = "Head Revolutionary"
@@ -131,14 +132,14 @@
old_owner.add_antag_datum(new_rev,old_team)
new_rev.silent = FALSE
to_chat(old_owner, "
Revolution has been disappointed of your leader traits! You are a regular revolutionary now!")
-
+
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
- owner.current.visible_message("[owner.current] looks like they just remembered their real allegiance!")
- to_chat(owner, "
You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...")
+ owner.current.visible_message("
[owner.current] looks like they just remembered their real allegiance!", ignored_mob = owner.current)
+ to_chat(owner, "
You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...")
else if(issilicon(owner.current))
- owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.")
- to_chat(owner, "
The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.")
+ owner.current.visible_message("
The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.", ignored_mob = owner.current)
+ to_chat(owner, "
The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.")
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
@@ -163,7 +164,7 @@
if(remove_clumsy && owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
-
+
if(give_flash)
var/obj/item/device/assembly/flash/T = new(H)
var/list/slots = list (
@@ -176,18 +177,17 @@
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
else
to_chat(H, "The flash in your [where] will help you to persuade the crew to join your cause.")
-
+
if(give_hud)
var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(H)
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
-/datum/objective_team/revolution
+/datum/team/revolution
name = "Revolution"
- var/list/objectives = list()
var/max_headrevs = 3
-/datum/objective_team/revolution/proc/update_objectives(initial = FALSE)
+/datum/team/revolution/proc/update_objectives(initial = FALSE)
var/untracked_heads = SSjob.get_all_heads()
for(var/datum/objective/mutiny/O in objectives)
untracked_heads -= O.target
@@ -199,16 +199,16 @@
objectives += new_target
for(var/datum/mind/M in members)
M.objectives |= objectives
-
+
addtimer(CALLBACK(src,.proc/update_objectives),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
-/datum/objective_team/revolution/proc/head_revolutionaries()
+/datum/team/revolution/proc/head_revolutionaries()
. = list()
for(var/datum/mind/M in members)
if(M.has_antag_datum(/datum/antagonist/rev/head))
. += M
-/datum/objective_team/revolution/proc/update_heads()
+/datum/team/revolution/proc/update_heads()
if(SSticker.HasRoundStarted())
var/list/datum/mind/head_revolutionaries = head_revolutionaries()
var/list/datum/mind/heads = SSjob.get_all_heads()
@@ -227,3 +227,56 @@
rev.promote()
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
+
+
+/datum/team/revolution/roundend_report()
+ if(!members.len)
+ return
+
+ var/list/result = list()
+
+ result += "
"
+
+ var/num_revs = 0
+ var/num_survivors = 0
+ for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
+ if(survivor.ckey)
+ num_survivors++
+ if(survivor.mind)
+ if(is_revolutionary(survivor))
+ num_revs++
+ if(num_survivors)
+ result += "Command's Approval Rating:
[100 - round((num_revs/num_survivors)*100, 0.1)]%"
+
+
+ var/list/targets = list()
+ var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
+ var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
+ if(headrevs.len)
+ var/list/headrev_part = list()
+ headrev_part += ""
+ headrev_part += printplayerlist(headrevs,TRUE)
+ result += headrev_part.Join("
")
+
+ if(revs.len)
+ var/list/rev_part = list()
+ rev_part += ""
+ rev_part += printplayerlist(revs,TRUE)
+ result += rev_part.Join("
")
+
+ var/list/heads = SSjob.get_all_heads()
+ if(heads.len)
+ var/head_text = ""
+ head_text += "
"
+ for(var/datum/mind/head in heads)
+ var/target = (head in targets)
+ head_text += "- "
+ if(target)
+ head_text += "Target"
+ head_text += "[printplayer(head, 1)]
"
+ head_text += "
"
+ result += head_text
+
+ result += "
"
+
+ return result.Join()
\ No newline at end of file
diff --git a/code/datums/antagonists/wizard.dm b/code/datums/antagonists/wizard.dm
index e1e6dc09c8..e856a6642f 100644
--- a/code/datums/antagonists/wizard.dm
+++ b/code/datums/antagonists/wizard.dm
@@ -5,13 +5,13 @@
/datum/antagonist/wizard
name = "Space Wizard"
+ roundend_category = "wizards/witches"
job_rank = ROLE_WIZARD
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
var/allow_rename = TRUE
var/hud_version = "wizard"
- var/datum/objective_team/wizard/wiz_team //Only created if wizard summons apprentices
- var/list/objectives = list() //this should be base datum antag proc and list, todo make lazy
+ var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
@@ -33,7 +33,7 @@
/datum/antagonist/wizard/proc/unregister()
SSticker.mode.wizards -= src
-/datum/antagonist/wizard/create_team(datum/objective_team/wizard/new_team)
+/datum/antagonist/wizard/create_team(datum/team/wizard/new_team)
if(!new_team)
return
if(!istype(new_team))
@@ -43,12 +43,14 @@
/datum/antagonist/wizard/get_team()
return wiz_team
-/datum/objective_team/wizard
+/datum/team/wizard
name = "wizard team"
+ var/datum/antagonist/wizard/master_wizard
/datum/antagonist/wizard/proc/create_wiz_team()
wiz_team = new(owner)
wiz_team.name = "[owner.current.real_name] team"
+ wiz_team.master_wizard = src
update_wiz_icons_added(owner.current)
/datum/antagonist/wizard/proc/send_to_lair()
@@ -283,4 +285,46 @@
var/datum/objective/new_objective = new("Protect Wizard Academy from the intruders")
new_objective.owner = owner
owner.objectives += new_objective
- objectives += new_objective
\ No newline at end of file
+ objectives += new_objective
+
+//Solo wizard report
+/datum/antagonist/wizard/roundend_report()
+ var/list/parts = list()
+
+ parts += printplayer(owner)
+
+ var/count = 1
+ var/wizardwin = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ parts += "
Objective #[count]: [objective.explanation_text]
Success!"
+ else
+ parts += "
Objective #[count]: [objective.explanation_text]
Fail."
+ wizardwin = 0
+ count++
+
+ if(wizardwin)
+ parts += "
The wizard was successful!"
+ else
+ parts += "
The wizard has failed!"
+
+ if(owner.spell_list.len>0)
+ parts += "
[owner.name] used the following spells: "
+ var/list/spell_names = list()
+ for(var/obj/effect/proc_holder/spell/S in owner.spell_list)
+ spell_names += S.name
+ parts += spell_names.Join(", ")
+
+ return parts.Join("
")
+
+//Wizard with apprentices report
+/datum/team/wizard/roundend_report()
+ var/list/parts = list()
+
+ parts += ""
+ parts += master_wizard.roundend_report()
+ parts += " "
+ parts += ""
+ parts += printplayerlist(members - master_wizard.owner)
+
+ return "
[parts.Join("
")]
"
\ No newline at end of file
diff --git a/code/datums/beam.dm b/code/datums/beam.dm
index c1a75c8b7e..dc68de933a 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -128,11 +128,11 @@
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
- a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
+ a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
- a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
+ a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
X.y += a
Pixel_y %= 32
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
new file mode 100644
index 0000000000..ea01a87506
--- /dev/null
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -0,0 +1,157 @@
+/datum/brain_trauma/special/imaginary_friend
+ name = "Imaginary Friend"
+ desc = "Patient can see and hear an imaginary person."
+ scan_desc = "partial schizophrenia"
+ gain_text = "
You feel in good company, for some reason."
+ lose_text = "
You feel lonely again."
+ var/mob/camera/imaginary_friend/friend
+ var/friend_initialized = FALSE
+
+/datum/brain_trauma/special/imaginary_friend/on_gain()
+ ..()
+ make_friend()
+ get_ghost()
+
+/datum/brain_trauma/special/imaginary_friend/on_life()
+ if(get_dist(owner, friend) > 9)
+ friend.yank()
+ if(!friend)
+ qdel(src)
+ return
+ if(!friend.client && friend_initialized)
+ addtimer(CALLBACK(src, .proc/reroll_friend), 600)
+
+/datum/brain_trauma/special/imaginary_friend/on_lose()
+ ..()
+ QDEL_NULL(friend)
+
+//If the friend goes afk, make a brand new friend. Plenty of fish in the sea of imagination.
+/datum/brain_trauma/special/imaginary_friend/proc/reroll_friend()
+ if(friend.client) //reconnected
+ return
+ friend_initialized = FALSE
+ QDEL_NULL(friend)
+ make_friend()
+ get_ghost()
+
+/datum/brain_trauma/special/imaginary_friend/proc/make_friend()
+ friend = new(get_turf(src), src)
+
+/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
+ set waitfor = FALSE
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend)
+ if(LAZYLEN(candidates))
+ var/client/C = pick(candidates)
+ friend.key = C.key
+ friend_initialized = TRUE
+ else
+ qdel(src)
+
+/mob/camera/imaginary_friend
+ name = "imaginary friend"
+ real_name = "imaginary friend"
+ move_on_shuttle = TRUE
+ desc = "A wonderful yet fake friend."
+ see_in_dark = 0
+ lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
+ sight = NONE
+ see_invisible = SEE_INVISIBLE_LIVING
+ var/icon/human_image
+ var/image/current_image
+ var/mob/living/carbon/owner
+ var/datum/brain_trauma/special/imaginary_friend/trauma
+
+/mob/camera/imaginary_friend/Login()
+ ..()
+ to_chat(src, "
You are the imaginary friend of [owner]!")
+ to_chat(src, "
You are absolutely loyal to your friend, no matter what.")
+ to_chat(src, "
You cannot directly influence the world around you, but you can see what [owner] cannot.")
+
+/mob/camera/imaginary_friend/Initialize(mapload, _trauma)
+ . = ..()
+ var/gender = pick(MALE, FEMALE)
+ real_name = random_unique_name(gender)
+ name = real_name
+ trauma = _trauma
+ owner = trauma.owner
+ human_image = get_flat_human_icon(null, pick(SSjob.occupations))
+ Show()
+
+/mob/camera/imaginary_friend/proc/Show()
+ if(!client) //nobody home
+ return
+
+ //Remove old image from owner and friend
+ if(owner.client)
+ owner.client.images.Remove(current_image)
+
+ client.images.Remove(current_image)
+
+ //Generate image from the static icon and the current dir
+ current_image = image(human_image, src, , MOB_LAYER, dir=src.dir)
+ current_image.override = TRUE
+ current_image.name = name
+
+ //Add new image to owner and friend
+ if(owner.client)
+ owner.client.images |= current_image
+
+ client.images |= current_image
+
+/mob/camera/imaginary_friend/Destroy()
+ if(owner.client)
+ owner.client.images.Remove(human_image)
+ if(client)
+ client.images.Remove(human_image)
+ return ..()
+
+/mob/camera/imaginary_friend/proc/yank()
+ if(!client) //don't bother if the friend is braindead
+ return
+ forceMove(get_turf(owner))
+ Show()
+
+/mob/camera/imaginary_friend/say(message)
+ if (!message)
+ return
+
+ if (src.client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+ if (src.client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ friend_talk(message)
+
+/mob/camera/imaginary_friend/proc/friend_talk(message)
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ if(!message)
+ return
+
+ log_talk(src,"[key_name(src)] : [message]",LOGSAY)
+
+ var/rendered = "
[name] [say_quote(message)]"
+ var/dead_rendered = "
[name] (Imaginary friend of [owner]) [say_quote(message)]"
+
+ to_chat(owner, "[rendered]")
+ to_chat(src, "[rendered]")
+
+ for(var/mob/M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, owner)
+ to_chat(M, "[link] [dead_rendered]")
+
+/mob/camera/imaginary_friend/emote(act,m_type=1,message = null)
+ return
+
+/mob/camera/imaginary_friend/forceMove(atom/destination)
+ dir = get_dir(get_turf(src), destination)
+ loc = destination
+ if(get_dist(src, owner) > 9)
+ yank()
+ return
+ Show()
+
+/mob/camera/imaginary_friend/movement_delay()
+ return 2
diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm
index 6bfa149aa7..d5ccc71ef9 100644
--- a/code/datums/brain_damage/mild.dm
+++ b/code/datums/brain_damage/mild.dm
@@ -42,7 +42,7 @@
lose_text = "
You feel smart again."
/datum/brain_trauma/mild/dumbness/on_gain()
- owner.disabilities |= DUMB
+ owner.add_disability(DUMB, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/mild/dumbness/on_life()
@@ -54,7 +54,7 @@
..()
/datum/brain_trauma/mild/dumbness/on_lose()
- owner.disabilities &= ~DUMB
+ owner.remove_disability(DUMB, TRAUMA_DISABILITY)
owner.derpspeech = 0
..()
@@ -107,6 +107,26 @@
..()
+/datum/brain_trauma/mild/healthy
+ name = "Anosognosia"
+ desc = "Patient always feels healthy, regardless of their condition."
+ scan_desc = "self-awareness deficit"
+ gain_text = "
You feel great!"
+ lose_text = "
You no longer feel perfectly healthy."
+
+/datum/brain_trauma/mild/healthy/on_gain()
+ owner.set_screwyhud(SCREWYHUD_HEALTHY)
+ ..()
+
+/datum/brain_trauma/mild/healthy/on_life()
+ owner.set_screwyhud(SCREWYHUD_HEALTHY) //just in case of hallucinations
+ owner.adjustStaminaLoss(-5) //no pain, no fatigue
+ ..()
+
+/datum/brain_trauma/mild/healthy/on_lose()
+ owner.set_screwyhud(SCREWYHUD_NONE)
+ ..()
+
/datum/brain_trauma/mild/muscle_weakness
name = "Muscle Weakness"
desc = "Patient experiences occasional bouts of muscle weakness."
@@ -133,3 +153,62 @@
to_chat(owner, "
You feel a sudden weakness in your muscles!")
owner.adjustStaminaLoss(50)
..()
+
+/datum/brain_trauma/mild/muscle_spasms
+ name = "Muscle Spasms"
+ desc = "Patient has occasional muscle spasms, causing them to move unintentionally."
+ scan_desc = "nervous fits"
+ gain_text = "
Your muscles feel oddly faint."
+ lose_text = "
You feel in control of your muscles again."
+
+/datum/brain_trauma/mild/muscle_spasms/on_life()
+ if(prob(7))
+ switch(rand(1,5))
+ if(1)
+ if(owner.canmove && !isspaceturf(owner.loc))
+ to_chat(owner, "
Your leg spasms!")
+ step(owner, pick(GLOB.cardinals))
+ if(2)
+ if(owner.incapacitated())
+ return
+ var/obj/item/I = owner.get_active_held_item()
+ if(I)
+ to_chat(owner, "
Your fingers spasm!")
+ log_attack("[key_name(owner)] used [I] due to a Muscle Spasm.")
+ I.attack_self(owner)
+ if(3)
+ var/prev_intent = owner.a_intent
+ owner.a_intent = INTENT_HARM
+
+ var/range = 1
+ if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
+ range = 7
+
+ var/list/mob/living/targets = list()
+ for(var/mob/M in oview(owner, range))
+ if(isliving(M))
+ targets += M
+ if(LAZYLEN(targets))
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] attacked someone due to a Muscle Spasm.") //the following attack will log itself
+ owner.ClickOn(pick(targets))
+ owner.a_intent = prev_intent
+ if(4)
+ var/prev_intent = owner.a_intent
+ owner.a_intent = INTENT_HARM
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] attacked himself to a Muscle Spasm.")
+ owner.ClickOn(owner)
+ owner.a_intent = prev_intent
+ if(5)
+ if(owner.incapacitated())
+ return
+ var/obj/item/I = owner.get_active_held_item()
+ var/list/turf/targets = list()
+ for(var/turf/T in oview(owner, 3))
+ targets += T
+ if(LAZYLEN(targets) && I)
+ to_chat(owner, "
Your arm spasms!")
+ log_attack("[key_name(owner)] threw [I] due to a Muscle Spasm.")
+ owner.throw_item(pick(targets))
+ ..()
\ No newline at end of file
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index 08cee65085..a138073040 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -7,22 +7,39 @@
/datum/brain_trauma/severe/mute
name = "Mutism"
desc = "Patient is completely unable to speak."
- scan_desc = "extensive damage to the brain's language center"
+ scan_desc = "extensive damage to the brain's speech center"
gain_text = "
You forget how to speak!"
lose_text = "
You suddenly remember how to speak."
/datum/brain_trauma/severe/mute/on_gain()
- owner.disabilities |= MUTE
- ..()
-
-//no fiddling with genetics to get out of this one
-/datum/brain_trauma/severe/mute/on_life()
- if(!(owner.disabilities & MUTE))
- on_gain()
+ owner.add_disability(MUTE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/mute/on_lose()
- owner.disabilities &= ~MUTE
+ owner.remove_disability(MUTE, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/aphasia
+ name = "Aphasia"
+ desc = "Patient is unable to speak or understand any language."
+ scan_desc = "extensive damage to the brain's language center"
+ gain_text = "
You have trouble forming words in your head..."
+ lose_text = "
You suddenly remember how languages work."
+ var/datum/language_holder/prev_language
+ var/datum/language_holder/mob_language
+
+/datum/brain_trauma/severe/aphasia/on_gain()
+ mob_language = owner.get_language_holder()
+ prev_language = mob_language.copy()
+ mob_language.remove_all_languages()
+ mob_language.grant_language(/datum/language/aphasia)
+ ..()
+
+/datum/brain_trauma/severe/aphasia/on_lose()
+ mob_language.remove_language(/datum/language/aphasia)
+ mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
+ QDEL_NULL(prev_language)
+ mob_language = null
..()
/datum/brain_trauma/severe/blindness
@@ -33,17 +50,11 @@
lose_text = "
Your vision returns."
/datum/brain_trauma/severe/blindness/on_gain()
- owner.become_blind()
- ..()
-
-//no fiddling with genetics to get out of this one
-/datum/brain_trauma/severe/blindness/on_life()
- if(!(owner.disabilities & BLIND))
- on_gain()
+ owner.become_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/blindness/on_lose()
- owner.cure_blind()
+ owner.cure_blind(TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/paralysis
@@ -109,7 +120,7 @@
stress -= 4
/datum/brain_trauma/severe/monophobia/proc/check_alone()
- if(owner.disabilities & BLIND)
+ if(owner.has_disability(BLIND))
return TRUE
for(var/mob/M in oview(owner, 7))
if(!isliving(M)) //ghosts ain't people
@@ -171,9 +182,39 @@
lose_text = "
You feel in control of your hands again."
/datum/brain_trauma/severe/discoordination/on_gain()
- owner.disabilities |= MONKEYLIKE
+ owner.add_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
/datum/brain_trauma/severe/discoordination/on_lose()
- owner.disabilities &= ~MONKEYLIKE
+ owner.remove_disability(MONKEYLIKE, TRAUMA_DISABILITY)
..()
+
+/datum/brain_trauma/severe/pacifism
+ name = "Traumatic Non-Violence"
+ desc = "Patient is extremely unwilling to harm others in violent ways."
+ scan_desc = "pacific syndrome"
+ gain_text = "
You feel oddly peaceful."
+ lose_text = "
You no longer feel compelled to not harm."
+
+/datum/brain_trauma/severe/pacifism/on_gain()
+ owner.add_disability(PACIFISM, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/pacifism/on_lose()
+ owner.remove_disability(PACIFISM, TRAUMA_DISABILITY)
+ ..()
+
+/datum/brain_trauma/severe/pacifism
+ name = "Traumatic Non-Violence"
+ desc = "Patient is extremely unwilling to harm others in violent ways."
+ scan_desc = "pacific syndrome"
+ gain_text = "
You feel oddly peaceful."
+ lose_text = "
You no longer feel compelled to not harm."
+
+/datum/brain_trauma/severe/pacifism/on_gain()
+ owner.disabilities |= PACIFISM
+ ..()
+
+/datum/brain_trauma/severe/pacifism/on_lose()
+ owner.disabilities &= ~PACIFISM
+ ..()
\ No newline at end of file
diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm
index ddb8f8e6e6..db0ca60801 100644
--- a/code/datums/brain_damage/special.dm
+++ b/code/datums/brain_damage/special.dm
@@ -9,25 +9,35 @@
scan_desc = "god delusion"
gain_text = "
You feel a higher power inside your mind..."
lose_text = "
The divine presence leaves your head, no longer interested."
- var/next_speech = 0
- var/inspiration = FALSE
/datum/brain_trauma/special/godwoken/on_life()
..()
- if(!inspiration && world.time > next_speech && prob(4))
- to_chat(owner, "
[pick("You feel inspired!","You feel power course through you...","You feel something within you itching to speak...")]")
- inspiration = TRUE
+ if(prob(4))
+ if(prob(33) && (owner.IsStun() || owner.IsKnockdown() || owner.IsUnconscious()))
+ speak("unstun", TRUE)
+ else if(prob(60) && owner.health <= HEALTH_THRESHOLD_CRIT)
+ speak("heal", TRUE)
+ else if(prob(30) && owner.a_intent == INTENT_HARM)
+ speak("aggressive")
+ else
+ speak("neutral", prob(25))
-/datum/brain_trauma/special/godwoken/on_say(message)
- if(world.time > next_speech && inspiration)
- playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5)
- var/cooldown = voice_of_god(message, owner, list("colossus","yell"), 2)
- cooldown *= 0.33
- next_speech = world.time + cooldown
- inspiration = FALSE
- return ""
- else
- return message
+/datum/brain_trauma/special/godwoken/proc/speak(type, include_owner = FALSE)
+ var/message
+ switch(type)
+ if("unstun")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_unstun")
+ if("heal")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_heal")
+ if("neutral")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
+ if("aggressive")
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_aggressive")
+ else
+ message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
+
+ playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5)
+ voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE)
/datum/brain_trauma/special/bluespace_prophet
name = "Bluespace Prophecy"
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index c726b2ecb5..deed1c8406 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -23,7 +23,7 @@
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", null, null, null, 75, stranger_backseat)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
stranger_backseat.key = C.key
@@ -136,6 +136,7 @@
/mob/living/split_personality/Login()
..()
to_chat(src, "
As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.")
+ to_chat(src, "
Do not commit suicide or put the body in a deadly position. Behave like you care about it as much as the owner.")
/mob/living/split_personality/say(message)
to_chat(src, "
You cannot speak, your other self is controlling your body!")
diff --git a/code/datums/callback.dm b/code/datums/callback.dm
index 88d9427301..5566137189 100644
--- a/code/datums/callback.dm
+++ b/code/datums/callback.dm
@@ -48,6 +48,7 @@
var/datum/object = GLOBAL_PROC
var/delegate
var/list/arguments
+ var/datum/weakref/user
/datum/callback/New(thingtocall, proctocall, ...)
if (thingtocall)
@@ -55,6 +56,8 @@
delegate = proctocall
if (length(args) > 2)
arguments = args.Copy(3)
+ if(usr)
+ user = WEAKREF(usr)
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
@@ -70,8 +73,16 @@
call(thingtocall, proctocall)(arglist(calling_arguments))
/datum/callback/proc/Invoke(...)
+ if(!usr)
+ var/datum/weakref/W = user
+ if(W)
+ var/mob/M = W.resolve()
+ if(M)
+ return world.PushUsr(M, src)
+
if (!object)
return
+
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
@@ -87,8 +98,17 @@
//copy and pasted because fuck proc overhead
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
+
+ if(!usr)
+ var/datum/weakref/W = user
+ if(W)
+ var/mob/M = W.resolve()
+ if(M)
+ return world.PushUsr(M, src)
+
if (!object)
return
+
var/list/calling_arguments = arguments
if (length(args))
if (length(arguments))
diff --git a/code/datums/components/README.md b/code/datums/components/README.md
index 574e628741..026b387e27 100644
--- a/code/datums/components/README.md
+++ b/code/datums/components/README.md
@@ -40,6 +40,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
+ * `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
1. `/datum/component/var/dupe_type` (protected, type)
* Definition of a duplicate component type
* `null` means exact match on `type` (default)
@@ -66,6 +67,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* All components a datum owns are deleted with the datum
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
+ * Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
@@ -104,9 +106,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
* Clears `parent` and removes the component from it's component list
-1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final)
+1. `/datum/component/proc/_JoinParent` (private, final)
* Tries to add the component to it's `parent`s `datum_components` list
- * Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index c54376d787..fcd4651459 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -6,54 +6,16 @@
var/datum/parent
/datum/component/New(datum/P, ...)
- if(type == /datum/component)
- qdel(src)
- CRASH("[type] instantiated!")
-
- //check for common mishaps
- if(!isnum(dupe_mode))
- qdel(src)
- CRASH("[type]: Invalid dupe_mode!")
- var/dt = dupe_type
- if(dt && !ispath(dt))
- qdel(src)
- CRASH("[type]: Invalid dupe_type!")
-
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
return
- _CheckDupesAndJoinParent(P)
+ _JoinParent(P)
-/datum/component/proc/_CheckDupesAndJoinParent()
+/datum/component/proc/_JoinParent()
var/datum/P = parent
- var/dm = dupe_mode
-
- var/datum/component/old
- if(dm != COMPONENT_DUPE_ALLOWED)
- var/dt = dupe_type
- if(!dt)
- old = P.GetExactComponent(type)
- else
- old = P.GetComponent(dt)
- if(old)
- //One or the other has to die
- switch(dm)
- if(COMPONENT_DUPE_UNIQUE)
- old.InheritComponent(src, TRUE)
- qdel(src, TRUE, TRUE)
- return
- if(COMPONENT_DUPE_HIGHLANDER)
- InheritComponent(old, FALSE)
- qdel(old, FALSE, TRUE)
-
- //provided we didn't eat someone
- if(!old)
- //let the others know
- P.SendSignal(COMSIG_COMPONENT_ADDED, src)
-
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
@@ -212,10 +174,59 @@
return list(.)
/datum/proc/AddComponent(new_type, ...)
- var/nt = new_type
+ var/datum/component/nt = new_type
+ var/dm = initial(nt.dupe_mode)
+ var/dt = initial(nt.dupe_type)
+
+ var/datum/component/old_comp
+ var/datum/component/new_comp
+
+ if(ispath(nt))
+ if(nt == /datum/component)
+ CRASH("[nt] attempted instantiation!")
+ if(!isnum(dm))
+ CRASH("[nt]: Invalid dupe_mode ([dm])!")
+ if(dt && !ispath(dt))
+ CRASH("[nt]: Invalid dupe_type ([dt])!")
+ else
+ new_comp = nt
+
args[1] = src
- var/datum/component/C = new nt(arglist(args))
- return QDELING(C) ? GetExactComponent(new_type) : C
+
+ if(dm != COMPONENT_DUPE_ALLOWED)
+ if(!dt)
+ old_comp = GetExactComponent(nt)
+ else
+ old_comp = GetComponent(dt)
+ if(old_comp)
+ switch(dm)
+ if(COMPONENT_DUPE_UNIQUE)
+ if(!new_comp)
+ new_comp = new nt(arglist(args))
+ if(!QDELETED(new_comp))
+ old_comp.InheritComponent(new_comp, TRUE)
+ qdel(new_comp)
+ if(COMPONENT_DUPE_HIGHLANDER)
+ if(!new_comp)
+ new_comp = new nt(arglist(args))
+ if(!QDELETED(new_comp))
+ new_comp.InheritComponent(old_comp, FALSE)
+ qdel(old_comp)
+ if(COMPONENT_DUPE_UNIQUE_PASSARGS)
+ if(!new_comp)
+ var/list/arguments = args.Copy(2)
+ old_comp.InheritComponent(null, TRUE, arguments)
+ else
+ old_comp.InheritComponent(new_comp, TRUE)
+ else if(!new_comp)
+ new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
+ else if(!new_comp)
+ new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
+
+ if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
+ SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
+ return new_comp
+ return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
@@ -235,7 +246,8 @@
C._RemoveFromParent()
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
C.parent = src
- C._CheckDupesAndJoinParent()
+ if(C == AddComponent(C))
+ C._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
diff --git a/code/datums/components/archaeology.dm b/code/datums/components/archaeology.dm
index 6fb2b67051..30bf107ad0 100644
--- a/code/datums/components/archaeology.dm
+++ b/code/datums/components/archaeology.dm
@@ -6,7 +6,7 @@
var/datum/callback/callback
/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list(), datum/callback/_callback)
- prob2drop = Clamp(_prob2drop, 0, 100)
+ prob2drop = CLAMP(_prob2drop, 0, 100)
archdrops = _archdrops
callback = _callback
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
diff --git a/code/datums/components/cleaning.dm b/code/datums/components/cleaning.dm
new file mode 100644
index 0000000000..5d9d5992e2
--- /dev/null
+++ b/code/datums/components/cleaning.dm
@@ -0,0 +1,40 @@
+/datum/component/cleaning
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+
+/datum/component/cleaning/Initialize()
+ if(!ismovableatom(parent))
+ . = COMPONENT_INCOMPATIBLE
+ CRASH("[type] added to a [parent.type]")
+ RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
+
+/datum/component/cleaning/proc/Clean()
+ var/atom/movable/AM = parent
+ var/turf/tile = AM.loc
+ if(!isturf(tile))
+ return
+
+ tile.clean_blood()
+ for(var/A in tile)
+ if(is_cleanable(A))
+ qdel(A)
+ else if(istype(A, /obj/item))
+ var/obj/item/cleaned_item = A
+ cleaned_item.clean_blood()
+ else if(ishuman(A))
+ var/mob/living/carbon/human/cleaned_human = A
+ if(cleaned_human.lying)
+ if(cleaned_human.head)
+ cleaned_human.head.clean_blood()
+ cleaned_human.update_inv_head()
+ if(cleaned_human.wear_suit)
+ cleaned_human.wear_suit.clean_blood()
+ cleaned_human.update_inv_wear_suit()
+ else if(cleaned_human.w_uniform)
+ cleaned_human.w_uniform.clean_blood()
+ cleaned_human.update_inv_w_uniform()
+ if(cleaned_human.shoes)
+ cleaned_human.shoes.clean_blood()
+ cleaned_human.update_inv_shoes()
+ cleaned_human.clean_blood()
+ cleaned_human.wash_cream()
+ to_chat(cleaned_human, "
[AM] cleans your face!")
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index a28213b0b5..a79de32898 100644
--- a/code/datums/components/decal.dm
+++ b/code/datums/components/decal.dm
@@ -48,8 +48,7 @@
if(old_dir == new_dir)
return
remove()
- var/rotation = SimplifyDegrees(dir2angle(new_dir)-dir2angle(old_dir))
- pic.dir = turn(pic.dir, rotation)
+ pic.dir = turn(pic.dir, dir2angle(old_dir) - dir2angle(new_dir))
apply()
/datum/component/decal/proc/clean_react(strength)
@@ -57,4 +56,4 @@
qdel(src)
/datum/component/decal/proc/examine(mob/user)
- to_chat(user, description)
\ No newline at end of file
+ to_chat(user, description)
diff --git a/code/datums/components/jousting.dm b/code/datums/components/jousting.dm
new file mode 100644
index 0000000000..68621e60ec
--- /dev/null
+++ b/code/datums/components/jousting.dm
@@ -0,0 +1,81 @@
+/datum/component/jousting
+ var/current_direction = NONE
+ var/max_tile_charge = 5
+ var/min_tile_charge = 2 //tiles before this code gets into effect.
+ var/current_tile_charge = 0
+ var/movement_reset_tolerance = 2 //deciseconds
+ var/unmounted_damage_boost_per_tile = 0
+ var/unmounted_knockdown_chance_per_tile = 0
+ var/unmounted_knockdown_time = 0
+ var/mounted_damage_boost_per_tile = 2
+ var/mounted_knockdown_chance_per_tile = 20
+ var/mounted_knockdown_time = 20
+ var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
+ var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
+ var/mob/current_holder
+ var/datum/component/redirect/listener
+ var/current_timerid
+
+/datum/component/jousting/Initialize()
+ if(!isitem(parent))
+ . = COMPONENT_INCOMPATIBLE
+ stack_trace("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
+ RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
+ RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
+ RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
+
+/datum/component/jousting/Destroy()
+ QDEL_NULL(listener)
+ return ..()
+
+/datum/component/jousting/proc/on_equip(mob/user, slot)
+ QDEL_NULL(listener)
+ current_holder = user
+ listener = new(user, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/mob_move))
+
+/datum/component/jousting/proc/on_drop(mob/user)
+ QDEL_NULL(listener)
+ current_holder = null
+ current_direction = NONE
+ current_tile_charge = 0
+
+/datum/component/jousting/proc/on_attack(mob/living/target, mob/user)
+ if(user != current_holder)
+ return
+ var/current = current_tile_charge
+ var/obj/item/I = parent
+ var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
+ if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
+ return
+ var/turf/target_turf = get_step(user, current_direction)
+ if(target in range(1, target_turf))
+ var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
+ var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
+ var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
+ var/sharp = I.is_sharp()
+ var/msg
+ if(damage)
+ msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
+ target.apply_damage(damage, BRUTE, user.zone_selected, 0)
+ if(prob(knockdown_chance))
+ msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
+ if(target_buckled)
+ target.buckled.unbuckle_mob(target)
+ target.Knockdown(knockdown_time)
+ if(length(msg))
+ user.visible_message("
[msg]!")
+
+/datum/component/jousting/proc/mob_move(newloc, dir)
+ if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
+ return
+ if(dir != current_direction)
+ current_tile_charge = 0
+ current_direction = dir
+ if(current_tile_charge < max_tile_charge)
+ current_tile_charge++
+ if(current_timerid)
+ deltimer(current_timerid)
+ current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
+
+/datum/component/jousting/proc/reset_charge()
+ current_tile_charge = 0
diff --git a/code/datums/components/knockoff.dm b/code/datums/components/knockoff.dm
new file mode 100644
index 0000000000..35d1e5423e
--- /dev/null
+++ b/code/datums/components/knockoff.dm
@@ -0,0 +1,53 @@
+//Items with these will have a chance to get knocked off when disarming
+/datum/component/knockoff
+ var/knockoff_chance = 100 //Chance to knockoff
+ var/list/target_zones //Aiming for these zones will cause the knockoff, null means all zones allowed
+ var/list/slots_knockoffable //Can be only knocked off from these slots, null means all slots allowed
+ var/datum/component/redirect/disarm_redirect
+
+/datum/component/knockoff/Initialize(knockoff_chance,zone_override,slots_knockoffable)
+ if(!isitem(parent))
+ . = COMPONENT_INCOMPATIBLE
+ CRASH("Knockoff component misuse")
+ RegisterSignal(COMSIG_ITEM_EQUIPPED,.proc/OnEquipped)
+ RegisterSignal(COMSIG_ITEM_DROPPED,.proc/OnDropped)
+
+ src.knockoff_chance = knockoff_chance
+
+ if(zone_override)
+ target_zones = zone_override
+
+ if(slots_knockoffable)
+ src.slots_knockoffable = slots_knockoffable
+
+/datum/component/knockoff/proc/Knockoff(mob/living/attacker,zone)
+ var/obj/item/I = parent
+ var/mob/living/carbon/human/wearer = I.loc
+ if(!istype(wearer))
+ return
+ if(target_zones && !(zone in target_zones))
+ return
+ if(!prob(knockoff_chance))
+ return
+ if(!wearer.dropItemToGround(I))
+ return
+
+ wearer.visible_message("
[attacker] knocks off [wearer]'s [I.name]!","
[attacker] knocks off your [I.name]!")
+
+/datum/component/knockoff/proc/OnEquipped(mob/living/carbon/human/H,slot)
+ if(!istype(H))
+ return
+ if(slots_knockoffable && !(slot in slots_knockoffable))
+ if(disarm_redirect)
+ QDEL_NULL(disarm_redirect)
+ return
+ if(!disarm_redirect)
+ disarm_redirect = H.AddComponent(/datum/component/redirect,list(COMSIG_HUMAN_DISARM_HIT),CALLBACK(src,.proc/Knockoff))
+
+/datum/component/knockoff/proc/OnDropped(mob/living/M)
+ if(disarm_redirect)
+ QDEL_NULL(disarm_redirect)
+
+/datum/component/knockoff/Destroy()
+ QDEL_NULL(disarm_redirect)
+ . = ..()
\ No newline at end of file
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
index c149fd8492..fc0456ad10 100644
--- a/code/datums/components/radioactive.dm
+++ b/code/datums/components/radioactive.dm
@@ -4,7 +4,7 @@
#define RAD_AMOUNT_EXTREME 1000
/datum/component/radioactive
- dupe_mode = COMPONENT_DUPE_UNIQUE
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/source
@@ -47,13 +47,16 @@
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
-/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original)
+/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments)
if(!i_am_original)
return
if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
return
- var/datum/component/radioactive/other = C
- strength = max(strength, other.strength)
+ if(C)
+ var/datum/component/radioactive/other = C
+ strength = max(strength, other.strength)
+ else
+ strength = max(strength, arguments[1])
/datum/component/radioactive/proc/rad_examine(mob/user, atom/thing)
var/atom/master = parent
diff --git a/code/datums/components/thermite.dm b/code/datums/components/thermite.dm
index f76178213d..11611cadfb 100644
--- a/code/datums/components/thermite.dm
+++ b/code/datums/components/thermite.dm
@@ -1,5 +1,5 @@
/datum/component/thermite
- dupe_mode = COMPONENT_DUPE_UNIQUE
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/amount
var/overlay
@@ -46,10 +46,13 @@
master.cut_overlay(overlay)
return ..()
-/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original)
+/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments)
if(!i_am_original)
return
- amount += newC.amount
+ if(newC)
+ amount += newC.amount
+ else
+ amount += arguments[1]
/datum/component/thermite/proc/thermite_melt(mob/user)
var/turf/master = parent
diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm
index 1637655d18..03badb2069 100644
--- a/code/datums/dash_weapon.dm
+++ b/code/datums/dash_weapon.dm
@@ -43,7 +43,7 @@
addtimer(CALLBACK(src, .proc/charge), charge_rate)
/datum/action/innate/dash/proc/charge()
- current_charges = Clamp(current_charges + 1, 0, max_charges)
+ current_charges = CLAMP(current_charges + 1, 0, max_charges)
holder.update_action_buttons_icon()
if(recharge_sound)
playsound(dashing_item, recharge_sound, 50, 1)
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 0c1058a287..60f90d61ad 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -185,10 +185,10 @@
if(properties["stealth"] >= 2)
visibility_flags = HIDDEN_SCANNER
- SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
+ SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
- permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
- cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
+ permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
+ cure_chance = 15 - CLAMP(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
@@ -243,7 +243,7 @@
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure()
if(properties && properties.len)
- var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
+ var/res = CLAMP(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
cures = list(advance_cures[res])
// Get the cure name from the cure_id
diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm
index 728dfa01d0..39d853a758 100644
--- a/code/datums/diseases/advance/symptoms/vision.dm
+++ b/code/datums/diseases/advance/symptoms/vision.dm
@@ -58,11 +58,12 @@ Bonus
M.blur_eyes(20)
M.adjust_eye_damage(5)
if(eyes.eye_damage >= 10)
- M.become_nearsighted()
+ M.become_nearsighted(EYE_DAMAGE)
if(prob(eyes.eye_damage - 10 + 1))
if(!remove_eyes)
- if(M.become_blind())
+ if(!M.has_disability(BLIND))
to_chat(M, "
You go blind!")
+ M.become_blind(EYE_DAMAGE)
else
M.visible_message("
[M]'s eyes fall off their sockets!", "
Your eyes fall off their sockets!")
eyes.Remove(M)
@@ -111,16 +112,16 @@ Bonus
return
switch(A.stage)
if(4, 5) //basically oculine
- if(M.disabilities & BLIND)
+ if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "
Your vision slowly returns...")
- M.cure_blind()
- M.cure_nearsighted()
+ M.cure_blind(EYE_DAMAGE)
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
- else if(M.disabilities & NEARSIGHT)
+ else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "
The blackness in your peripheral vision fades.")
- M.cure_nearsighted()
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm
index 71e4064676..6d77acd3ae 100644
--- a/code/datums/diseases/gbs.dm
+++ b/code/datums/diseases/gbs.dm
@@ -1,6 +1,6 @@
/datum/disease/gbs
name = "GBS"
- max_stages = 5
+ max_stages = 4
spread_text = "On contact"
spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
@@ -16,25 +16,15 @@
..()
switch(stage)
if(2)
- if(prob(45))
- affected_mob.adjustToxLoss(5)
- affected_mob.updatehealth()
- if(prob(1))
- affected_mob.emote("sneeze")
- if(3)
if(prob(5))
affected_mob.emote("cough")
- else if(prob(5))
+ if(3)
+ if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
- to_chat(affected_mob, "
You're starting to feel very weak...")
+ to_chat(affected_mob, "
Your body hurts all over!")
if(4)
- if(prob(10))
- affected_mob.emote("cough")
- affected_mob.adjustToxLoss(5)
- affected_mob.updatehealth()
- if(5)
- to_chat(affected_mob, "
Your body feels as if it's trying to rip itself open...")
+ to_chat(affected_mob, "
Your body feels as if it's trying to rip itself apart!")
if(prob(50))
affected_mob.gib()
else
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 2e5bd580bf..b452eff382 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -16,8 +16,9 @@
var/emote_type = EMOTE_VISIBLE //Whether the emote is visible or audible
var/restraint_check = FALSE //Checks if the mob is restrained before performing the emote
var/muzzle_ignore = FALSE //Will only work if the emote is EMOTE_AUDIBLE
- var/list/mob_type_allowed_typecache //Types that are allowed to use that emote
+ var/list/mob_type_allowed_typecache = list(/mob) //Types that are allowed to use that emote
var/list/mob_type_blacklist_typecache //Types that are NOT allowed to use that emote
+ var/list/mob_type_ignore_stat_typecache
var/stat_allowed = CONSCIOUS
var/static/list/emote_list = list()
@@ -26,6 +27,7 @@
emote_list[key_third_person] = src
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
+ mob_type_ignore_stat_typecache = typecacheof(mob_type_ignore_stat_typecache)
/datum/emote/proc/run_emote(mob/user, params, type_override)
. = TRUE
@@ -37,9 +39,10 @@
msg = replace_pronoun(user, msg)
- var/mob/living/L = user
- for(var/obj/item/implant/I in L.implants)
- I.trigger(key, L)
+ if(isliving(user))
+ var/mob/living/L = user
+ for(var/obj/item/implant/I in L.implants)
+ I.trigger(key, L)
if(!msg)
return
@@ -97,7 +100,7 @@
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
- if(status_check)
+ if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
if(user.stat > stat_allowed || (user.status_flags & FAKEDEATH))
to_chat(user, "
You cannot [key] while unconscious.")
return FALSE
diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm
index b71c560193..73b76a9155 100644
--- a/code/datums/explosion.dm
+++ b/code/datums/explosion.dm
@@ -121,7 +121,7 @@ GLOBAL_LIST_EMPTY(explosions)
M.playsound_local(epicenter, null, 100, 1, frequency, falloff = 5, S = explosion_sound)
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
- var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
+ var/far_volume = CLAMP(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
EX_PREPROCESS_CHECK_TICK
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index ec39bcec67..c4ccc4c1fb 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -45,6 +45,8 @@
set name = "Show Server Revision"
set desc = "Check the current server code revision"
+ if(GLOB.round_id)
+ to_chat(src, "
Round ID: [GLOB.round_id]")
if(GLOB.revdata.originmastercommit)
to_chat(src, "
Server revision compiled on: [GLOB.revdata.date]")
var/prefix = ""
diff --git a/code/datums/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/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index f3a1f53dd2..0a4309e708 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -197,7 +197,7 @@
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
- if((CLUMSY in user.disabilities) && prob(50))
+ if((user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "
You club yourself over the head with [src].")
user.Knockdown(60)
if(ishuman(user))
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index e35837a7d2..f7f3ef8825 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -149,7 +149,7 @@
return
LAZYADD(antag_datums, A)
A.create_team(team)
- var/datum/objective_team/antag_team = A.get_team()
+ var/datum/team/antag_team = A.get_team()
if(antag_team)
antag_team.add_member(src)
A.on_gain()
@@ -185,12 +185,6 @@
objectives, uplinks, powers etc are all handled.
*/
-/datum/mind/proc/remove_objectives()
- if(objectives.len)
- for(var/datum/objective/O in objectives)
- objectives -= O
- qdel(O)
-
/datum/mind/proc/remove_changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
@@ -207,13 +201,12 @@
remove_antag_datum(ANTAG_DATUM_BROTHER)
SSticker.mode.update_brother_icons_removed(src)
+
/datum/mind/proc/remove_nukeop()
- if(src in SSticker.mode.syndicates)
- SSticker.mode.syndicates -= src
- SSticker.mode.update_synd_icons_removed(src)
- special_role = null
- remove_objectives()
- remove_antag_equip()
+ var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ if(nuke)
+ remove_antag_datum(nuke.type)
+ special_role = null
/datum/mind/proc/remove_wizard()
remove_antag_datum(/datum/antagonist/wizard)
@@ -223,7 +216,6 @@
if(src in SSticker.mode.cult)
SSticker.mode.remove_cultist(src, 0, 0)
special_role = null
- remove_objectives()
remove_antag_equip()
/datum/mind/proc/remove_rev()
@@ -329,14 +321,19 @@
SSticker.mode.add_cultist(src)
else if(is_revolutionary(creator))
- var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev)
+ var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
converter.add_revolutionary(src,FALSE)
else if(is_servant_of_ratvar(creator))
add_servant_of_ratvar(current)
else if(is_nuclear_operative(creator))
- make_Nuke(null, null, 0, FALSE)
+ var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ var/datum/antagonist/nukeop/N = new(src)
+ N.send_to_spawnpoint = FALSE
+ N.nukeop_outfit = null
+ add_antag_datum(N,converter.nuke_team)
+
enslaved_to = creator
@@ -500,7 +497,8 @@
if (SSticker.mode.config_tag=="nuclear")
text = uppertext(text)
text = "
[text]: "
- if (src in SSticker.mode.syndicates)
+ var/datum/antagonist/nukeop/N = has_antag_datum(/datum/antagonist/nukeop,TRUE)
+ if(N)
text += "
OPERATIVE |
nanotrasen"
text += "
To shuttle,
undress,
dress up."
var/code
@@ -720,7 +718,7 @@
out += sections[i]+"
"
- if(((src in SSticker.mode.traitors) || (src in SSticker.mode.syndicates)) && ishuman(current))
+ if(((src in SSticker.mode.traitors) || is_nuclear_operative(current)) && ishuman(current))
text = "Uplink:
give"
var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
@@ -776,17 +774,44 @@
var/objective_pos
var/def_value
+
+
+ var/datum/antagonist/target_antag
+
if (href_list["obj_edit"])
objective = locate(href_list["obj_edit"])
if (!objective)
return
- objective_pos = objectives.Find(objective)
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ target_antag = A
+ objective_pos = A.objectives.Find(objective)
+ break
+
+ if(!target_antag) //Shouldn't happen
+ stack_trace("objective without antagonist found")
+ objective_pos = objectives.Find(objective)
//Text strings are easy to manipulate. Revised for simplicity.
var/temp_obj_type = "[objective.type]"//Convert path into a text string.
def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
+ else
+ switch(antag_datums.len)
+ if(0)
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ if(1)
+ target_antag = antag_datums[1]
+ else
+ var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
+ if (QDELETED(target))
+ return
+ else if(target == "(new custom antag)")
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ else
+ target_antag = target
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "late-assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -908,11 +933,15 @@
return
if (objective)
+ if(target_antag)
+ target_antag.objectives -= objective
objectives -= objective
- objectives.Insert(objective_pos, new_objective)
+ target_antag.objectives.Insert(objective_pos, new_objective)
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
else
+ if(target_antag)
+ target_antag.objectives += new_objective
objectives += new_objective
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
@@ -921,6 +950,11 @@
var/datum/objective/objective = locate(href_list["obj_delete"])
if(!istype(objective))
return
+
+ for(var/datum/antagonist/A in antag_datums)
+ if(objective in A.objectives)
+ A.objectives -= objective
+ break
objectives -= objective
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
@@ -1003,11 +1037,13 @@
message_admins("[key_name_admin(usr)] has cult'ed [current].")
log_admin("[key_name(usr)] has cult'ed [current].")
if("tome")
- if (!SSticker.mode.equip_cultist(current,1))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current,1))
to_chat(usr, "
Spawning tome failed!")
if("amulet")
- if (!SSticker.mode.equip_cultist(current))
+ var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
+ if (C.equip_cultist(current))
to_chat(usr, "
Spawning amulet failed!")
else if(href_list["clockcult"])
@@ -1078,36 +1114,14 @@
message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
log_admin("[key_name(usr)] has de-nuke op'ed [current].")
if("nuclear")
- if(!(src in SSticker.mode.syndicates))
- SSticker.mode.syndicates += src
- SSticker.mode.update_synd_icons_added(src)
- if (SSticker.mode.syndicates.len==1)
- SSticker.mode.prepare_syndicate_leader(src)
- else
- current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
+ if(!has_antag_datum(/datum/antagonist/nukeop,TRUE))
+ add_antag_datum(/datum/antagonist/nukeop)
special_role = "Syndicate"
assigned_role = "Syndicate"
- to_chat(current, "
You are a [syndicate_name()] agent!")
- SSticker.mode.forge_syndicate_objectives(src)
- SSticker.mode.greet_syndicate(src)
message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
log_admin("[key_name(usr)] has nuke op'ed [current].")
if("lair")
current.forceMove(pick(GLOB.nukeop_start))
- if("dressup")
- var/mob/living/carbon/human/H = current
- qdel(H.belt)
- qdel(H.back)
- qdel(H.ears)
- qdel(H.gloves)
- qdel(H.head)
- qdel(H.shoes)
- qdel(H.wear_id)
- qdel(H.wear_suit)
- qdel(H.w_uniform)
-
- if (!SSticker.mode.equip_syndicate(current))
- to_chat(usr, "
Equipping a syndicate failed!")
if("tellcode")
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
@@ -1362,50 +1376,6 @@
T.should_specialise = TRUE
add_antag_datum(T)
-
-/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
- if(!(src in SSticker.mode.syndicates))
- SSticker.mode.syndicates += src
- SSticker.mode.update_synd_icons_added(src)
- assigned_role = "Syndicate"
- special_role = "Syndicate"
- SSticker.mode.forge_syndicate_objectives(src)
- SSticker.mode.greet_syndicate(src)
- current.faction |= "syndicate"
-
- if(spawnloc)
- current.forceMove(spawnloc)
-
- if(ishuman(current))
- var/mob/living/carbon/human/H = current
- qdel(H.belt)
- qdel(H.back)
- qdel(H.ears)
- qdel(H.gloves)
- qdel(H.head)
- qdel(H.shoes)
- qdel(H.wear_id)
- qdel(H.wear_suit)
- qdel(H.w_uniform)
-
- SSticker.mode.equip_syndicate(current, telecrystals)
-
- if (nuke_code)
- store_memory("
Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
- to_chat(current, "The nuclear authorization code is:
[nuke_code]")
- else
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
- if(nuke)
- store_memory("
Syndicate Nuclear Bomb Code: [nuke.r_code]", 0, 0)
- to_chat(current, "The nuclear authorization code is:
nuke.r_code")
- else
- to_chat(current, "You were not provided with a nuclear code. Trying asking your team leader or contacting syndicate command.")
-
- if (leader)
- SSticker.mode.prepare_syndicate_leader(src,nuke_code)
- else
- current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
-
/datum/mind/proc/make_Changling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(!C)
@@ -1421,16 +1391,11 @@
/datum/mind/proc/make_Cultist()
- if(!(src in SSticker.mode.cult))
- SSticker.mode.add_cultist(src,FALSE)
+ if(!has_antag_datum(/datum/antagonist/cult,TRUE))
+ SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
special_role = "Cultist"
to_chat(current, "
You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.")
to_chat(current, "
Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.")
- var/datum/antagonist/cult/C
- C.cult_memorization(src)
- var/mob/living/carbon/human/H = current
- if (!SSticker.mode.equip_cultist(current))
- to_chat(H, "Spawning an amulet from your Master failed.")
/datum/mind/proc/make_Rev()
var/datum/antagonist/rev/head/head = new(src)
diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm
index 170c0a2a7f..a171cf91da 100644
--- a/code/datums/mutations.dm
+++ b/code/datums/mutations.dm
@@ -8,7 +8,6 @@ GLOBAL_LIST_EMPTY(mutations_list)
GLOB.mutations_list[name] = src
/datum/mutation/human
-
var/dna_block
var/quality
var/get_chance = 100
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 23b91add58..015004eef6 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -85,12 +85,12 @@
/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= CLUMSY
+ owner.add_disability(CLUMSY, GENETIC_MUTATION)
/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~CLUMSY
+ owner.remove_disability(CLUMSY, GENETIC_MUTATION)
//Tourettes causes you to randomly stand in place and shout.
@@ -124,12 +124,12 @@
/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= DEAF
+ owner.add_disability(DEAF, GENETIC_MUTATION)
/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~DEAF
+ owner.remove_disability(DEAF, GENETIC_MUTATION)
//Monified turns you into a monkey.
diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm
index dee26166dd..60f5d75c5e 100644
--- a/code/datums/mutations/sight.dm
+++ b/code/datums/mutations/sight.dm
@@ -7,12 +7,12 @@
/datum/mutation/human/nearsight/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.become_nearsighted()
+ owner.become_nearsighted(GENETIC_MUTATION)
/datum/mutation/human/nearsight/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.cure_nearsighted()
+ owner.cure_nearsighted(GENETIC_MUTATION)
//Blind makes you blind. Who knew?
@@ -24,12 +24,12 @@
/datum/mutation/human/blind/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.become_blind()
+ owner.become_blind(GENETIC_MUTATION)
/datum/mutation/human/blind/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.cure_blind()
+ owner.cure_blind(GENETIC_MUTATION)
//X-Ray Vision lets you see through walls.
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index 3b4b38bbcc..dc1333024a 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -30,12 +30,12 @@
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities |= MUTE
+ owner.add_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.disabilities &= ~MUTE
+ owner.remove_disability(MUTE, GENETIC_MUTATION)
/datum/mutation/human/smile
diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm
new file mode 100644
index 0000000000..635ae0bbec
--- /dev/null
+++ b/code/datums/position_point_vector.dm
@@ -0,0 +1,239 @@
+//Designed for things that need precision trajectories like projectiles.
+//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
+
+#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
+#define RETURN_PRECISE_POINT(A) new /datum/point(A)
+
+/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
+ var/x = 0
+ var/y = 0
+ var/z = 0
+ var/pixel_x = 0
+ var/pixel_y = 0
+
+/datum/position/proc/valid()
+ return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
+
+/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
+ if(istype(_x, /datum/point))
+ var/datum/point/P = _x
+ var/turf/T = P.return_turf()
+ _x = T.x
+ _y = T.y
+ _z = T.z
+ _pixel_x = P.return_px()
+ _pixel_y = P.return_py()
+ else if(isatom(_x))
+ var/atom/A = _x
+ _x = A.x
+ _y = A.y
+ _z = A.z
+ _pixel_x = A.pixel_x
+ _pixel_y = A.pixel_y
+ x = _x
+ y = _y
+ z = _z
+ pixel_x = _pixel_x
+ pixel_y = _pixel_y
+
+/datum/position/proc/return_turf()
+ return locate(x, y, z)
+
+/datum/position/proc/return_px()
+ return pixel_x
+
+/datum/position/proc/return_py()
+ return pixel_y
+
+/datum/position/proc/return_point()
+ return new /datum/point(src)
+
+/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
+ var/datum/point/P = new
+ P.x = round(a.x + (b.x - a.x) / 2, 1)
+ P.y = round(a.y + (b.y - a.y) / 2, 1)
+ P.z = a.z
+ return P
+
+/proc/pixel_length_between_points(datum/point/a, datum/point/b)
+ return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
+
+/proc/angle_between_points(datum/point/a, datum/point/b)
+ return ATAN2((b.y - a.y), (b.x - a.x))
+
+/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
+ var/x = 0
+ var/y = 0
+ var/z = 0
+
+/datum/point/proc/valid()
+ return x && y && z
+
+/datum/point/proc/copy_to(datum/point/p = new)
+ p.x = x
+ p.y = y
+ p.z = z
+ return p
+
+/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
+ if(istype(_x, /datum/position))
+ var/datum/position/P = _x
+ _x = P.x
+ _y = P.y
+ _z = P.z
+ _pixel_x = P.pixel_x
+ _pixel_y = P.pixel_y
+ else if(istype(_x, /atom))
+ var/atom/A = _x
+ _x = A.x
+ _y = A.y
+ _z = A.z
+ _pixel_x = A.pixel_x
+ _pixel_y = A.pixel_y
+ initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
+
+/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
+ if(!isnull(tile_x))
+ x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x
+ if(!isnull(tile_y))
+ y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
+ if(!isnull(tile_z))
+ z = tile_z
+
+/datum/point/proc/return_turf()
+ return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
+
+/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
+ return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
+
+/datum/point/proc/return_position()
+ return new /datum/position(src)
+
+/datum/point/proc/return_px()
+ return MODULUS(x, world.icon_size) - 16
+
+/datum/point/proc/return_py()
+ return MODULUS(y, world.icon_size) - 16
+
+/datum/point/proc/mapcheck()
+ . = FALSE
+ var/maxx = world.icon_size * world.maxx
+ var/maxy = world.icon_size * world.maxy
+ var/move_zx = 0
+ var/move_zy = 0
+ if(x < 0)
+ x += maxx
+ move_zx -= 1
+ if(y < 0)
+ y += maxy
+ move_zy -= 1
+ if(x > maxx)
+ x -= maxx
+ move_zx += 1
+ if(y > maxy)
+ y -= maxy
+ move_zy += 1
+ var/datum/space_level/S = GLOB.z_levels_list["[z]"]
+ if(move_zx != 0)
+ var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
+ z = L.z_value
+ . = TRUE
+ if(move_zy != 0)
+ var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
+ z = L.z_value
+ . = TRUE
+
+/datum/point/vector
+ var/speed = 32 //pixels per iteration
+ var/iteration = 0
+ var/angle = 0
+ var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
+ var/mpy = 0
+ var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
+ var/starting_y = 0
+ var/starting_z = 0
+
+/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
+ ..()
+ initialize_trajectory(_speed, _angle)
+
+/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
+ . = ..()
+ starting_x = x
+ starting_y = y
+ starting_z = z
+
+/datum/point/vector/copy_to(datum/point/vector/v = new)
+ ..(v)
+ v.speed = speed
+ v.iteration = iteration
+ v.angle = angle
+ v.mpx = mpx
+ v.mpy = mpy
+ v.starting_x = starting_x
+ v.starting_y = starting_y
+ v.starting_z = starting_z
+ return v
+
+/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
+ if(!isnull(pixel_speed))
+ speed = pixel_speed
+ set_angle(new_angle)
+
+/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
+ if(isnull(angle))
+ return
+ angle = new_angle
+ update_offsets()
+
+/datum/point/vector/proc/update_offsets()
+ mpx = sin(angle) * speed
+ mpy = cos(angle) * speed
+
+/datum/point/vector/proc/set_speed(new_speed)
+ if(isnull(new_speed) || speed == new_speed)
+ return
+ speed = new_speed
+ update_offsets()
+
+/datum/point/vector/proc/increment(multiplier = 1)
+ iteration++
+ x += mpx * 1
+ y += mpy * 1
+ if(mapcheck())
+ on_z_change()
+
+/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
+ var/datum/point/vector/v = copy_to()
+ if(force_simulate)
+ for(var/i in 1 to amount)
+ v.increment(multiplier)
+ else
+ v.increment(multiplier * amount)
+ return v
+
+/datum/point/vector/proc/on_z_change()
+ return
+
+/datum/point/vector/processed //pixel_speed is per decisecond.
+ var/last_process = 0
+ var/last_move = 0
+ var/paused = FALSE
+
+/datum/point/vector/processed/Destroy()
+ STOP_PROCESSING(SSprojectiles, src)
+
+/datum/point/vector/processed/proc/start()
+ last_process = world.time
+ last_move = world.time
+ START_PROCESSING(SSprojectiles, src)
+
+/datum/point/vector/processed/process()
+ if(paused)
+ last_move += world.time - last_process
+ last_process = world.time
+ return
+ var/needed_time = world.time - last_move
+ last_process = world.time
+ last_move = world.time
+ increment(needed_time)
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index f9883cfe50..3599c60f89 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -38,7 +38,7 @@
if (user.client)
user.client.images += bar
- progress = Clamp(progress, 0, goal)
+ progress = CLAMP(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if (!shown)
user.client.images += bar
diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm
index f065ccfeab..68d8ebc31f 100644
--- a/code/datums/radiation_wave.dm
+++ b/code/datums/radiation_wave.dm
@@ -34,7 +34,7 @@
var/strength
if(steps>1)
- strength = InverseSquareLaw(intensity, max(range_modifier*steps, 1), 1)
+ strength = INVERSE_SQUARE(intensity, max(range_modifier*steps, 1), 1)
else
strength = intensity
@@ -42,7 +42,7 @@
qdel(src)
return
- radiate(atoms, Floor(strength))
+ radiate(atoms, FLOOR(strength, 1))
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
diff --git a/code/datums/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 3e0f0112ff..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)
@@ -414,7 +382,7 @@
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
if(!buckled_mob.Move(newloc, direct))
- loc = buckled_mob.loc
+ forceMove(buckled_mob.loc)
last_move = buckled_mob.last_move
inertia_dir = last_move
buckled_mob.inertia_dir = last_move
@@ -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 4f26563da1..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)
@@ -215,12 +215,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(placed)
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
if(B)
- loc = NewLoc
+ forceMove(NewLoc)
else
return 0
else
var/area/A = get_area(NewLoc)
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
return 0
- loc = NewLoc
+ forceMove(NewLoc)
return 1
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index aa1a3e7046..2ef047506f 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -42,7 +42,7 @@
return 0
else if(placement_override == 1)
var/turf/T = pick(GLOB.blobstart)
- loc = T //got overrided? you're somewhere random, motherfucker
+ forceMove(T) //got overrided? you're somewhere random, motherfucker
if(placed && blob_core)
blob_core.forceMove(loc)
else
@@ -74,7 +74,7 @@
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
- loc = chosen_node.loc
+ forceMove(chosen_node.loc)
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
if(!T)
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/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
index 4fdd84040e..e3f486a2f1 100644
--- a/code/game/gamemodes/changeling/powers/tiny_prick.dm
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -20,7 +20,7 @@
to_chat(user, "
We prepare our sting, use alt+click or middle mouse button on target to sting them.")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = src
-
+
user.hud_used.lingstingdisplay.icon_state = sting_icon
user.hud_used.lingstingdisplay.invisibility = 0
@@ -28,7 +28,7 @@
to_chat(user, "
We retract our sting, we can't sting anyone for now.")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = null
-
+
user.hud_used.lingstingdisplay.icon_state = null
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
@@ -90,7 +90,7 @@
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
if(!..())
return
- if((target.disabilities & HUSK) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
+ if((target.has_disability(HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
to_chat(user, "
Our sting appears ineffective against its DNA.")
return 0
return 1
@@ -129,9 +129,11 @@
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
if(!..())
return
- if((target.disabilities & HUSK) || !target.has_dna())
- to_chat(user, "
Our sting appears ineffective against its DNA.")
- return 0
+ if(isliving(target))
+ var/mob/living/L = target
+ if((L.has_disability(HUSK)) || !L.has_dna())
+ to_chat(user, "
Our sting appears ineffective against its DNA.")
+ return 0
return 1
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
@@ -207,7 +209,7 @@
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
add_logs(user, target, "stung", "blind sting")
to_chat(target, "
Your eyes burn horrifically!")
- target.become_nearsighted()
+ target.become_nearsighted(EYE_DAMAGE)
target.blind_eyes(20)
target.blur_eyes(40)
return TRUE
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 61bd9bb496..e4f75ea563 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -65,13 +65,16 @@ Credit where due:
return TRUE
return FALSE
-/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
+/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
if(!L || !L.mind)
return
var/update_type = ANTAG_DATUM_CLOCKCULT
if(silent)
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
- . = L.mind.add_antag_datum(update_type)
+ var/datum/antagonist/clockcult/C = new update_type(L.mind)
+ C.make_team = create_team
+ C.show_in_roundend = create_team //tutorial scarabs begone
+ . = L.mind.add_antag_datum(C)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
@@ -88,7 +91,6 @@ Credit where due:
///////////////
/datum/game_mode
- var/datum/mind/eminence //The clockwork Eminence
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
@@ -111,6 +113,8 @@ Credit where due:
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
+ var/datum/team/clockcult/main_clockcult
+
/datum/game_mode/clockwork_cult/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -185,22 +189,21 @@ Credit where due:
return FALSE
/datum/game_mode/clockwork_cult/check_finished()
- var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
- if(G && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
+ if(GLOB.ark_of_the_clockwork_justiciar && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
return FALSE
- . = ..()
+ return ..()
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
+ return main_clockcult.check_clockwork_victory()
+
+/datum/game_mode/clock_cult/set_round_result()
+ ..()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_SUMMON
- return TRUE
+ SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
SSticker.news_report = CULT_FAILURE
- return FALSE
-
-/datum/game_mode/clockwork_cult/declare_completion()
- ..()
- return //Doesn't end until the round does
+ SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
/datum/game_mode/clockwork_cult/generate_report()
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
@@ -210,30 +213,6 @@ Credit where due:
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
your crew to dispatch it in a timely manner."
-/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
- var/text = ""
- if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
- var/datum/game_mode/clockwork_cult/C = SSticker.mode
- if(C.check_clockwork_victory())
- text += "
Ratvar's servants defended the Ark until its activation!"
- SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
- else
- text += "
The Ark was destroyed! Ratvar will rust away for all eternity!"
- SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
- text += "
The servants' objective was: [CLOCKCULT_OBJECTIVE]."
- text += "
Ratvar's servants had
[GLOB.clockwork_caches] Tinkerer's Caches."
- text += "
Construction Value(CV) was:
[GLOB.clockwork_construction_value]"
- for(var/i in SSticker.scripture_states)
- if(i != SCRIPTURE_DRIVER)
- text += "
[i] scripture was:
[SSticker.scripture_states[i] ? "UN":""]LOCKED"
- if(SSticker.mode.eminence)
- text += "
The Eminence was: [printplayer(SSticker.mode.eminence)]"
- if(servants_of_ratvar.len)
- text += "
Ratvar's servants were:"
- for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
- text += printplayer(M)
- to_chat(world, text)
-
/datum/game_mode/proc/update_servant_icons_added(datum/mind/M)
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
A.join_hud(M.current)
diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
index e5a8c9b6f3..29655a0ac9 100644
--- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
+++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
@@ -207,7 +207,7 @@
to_chat(cyborg, "
You start to charge from the [sigil_name]...")
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
return
- var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
+ var/giving_power = min(FLOOR(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
if(adjust_clockwork_power(-giving_power))
cyborg.visible_message("
[cyborg] glows a brilliant orange!")
var/previous_color = cyborg.color
@@ -275,7 +275,6 @@
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
return
- visible_message("
[src] begins to glow bright blue!")
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
sleep(10)
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
@@ -355,5 +354,4 @@
if(sigil_active)
animation_number = initial(animation_number)
sigil_active = FALSE
- visible_message("
[src] slowly stops glowing!")
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
index a5af47ff05..74f7119193 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm
@@ -90,7 +90,7 @@
if(amount_temp < 2)
to_chat(user, "
You need at least 2 floor tiles to convert into power.")
return TRUE
- if(IsOdd(amount_temp))
+ if(ISODD(amount_temp))
amount_temp--
no_delete = TRUE
use(amount_temp)
@@ -239,7 +239,7 @@
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
break
- obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
+ obj_integrity = CLAMP(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
adjust_clockwork_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
diff --git a/code/game/gamemodes/clock_cult/clock_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_items/wraith_spectacles.dm b/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
index fc734ac426..b579326fcc 100644
--- a/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/wraith_spectacles.dm
@@ -32,7 +32,7 @@
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(src == H.glasses && !up)
- if(H.disabilities & BLIND)
+ if(H.has_disability(BLIND))
to_chat(H, "
\"You're blind, idiot. Stop embarrassing yourself.\"")
return
if(blind_cultist(H))
@@ -51,7 +51,7 @@
to_chat(victim, "
\"It looks like Nar-Sie's dogs really don't value their eyes.\"")
to_chat(victim, "
Your eyes explode with horrific pain!")
victim.emote("scream")
- victim.become_blind()
+ victim.become_blind(EYE_DAMAGE)
victim.adjust_blurriness(30)
victim.adjust_blindness(30)
return TRUE
@@ -76,7 +76,7 @@
..()
if(slot != slot_glasses || up)
return
- if(user.disabilities & BLIND)
+ if(user.has_disability(BLIND))
to_chat(user, "
\"You're blind, idiot. Stop embarrassing yourself.\"" )
return
if(blind_cultist(user)) //Cultists instantly go blind
@@ -115,11 +115,11 @@
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
desc = "[glasses_right && !WS.up ? "
":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!":"."]
\
You have taken
[W.eye_damage_done] eye damage from them.
"
- if(L.disabilities & NEARSIGHT)
+ if(L.has_disability(NEARSIGHT))
desc += "
You are nearsighted!"
else if(glasses_right && !WS.up)
desc += "You will become nearsighted at
[W.nearsight_breakpoint] eye damage.
"
- if(L.disabilities & BLIND)
+ if(L.has_disability(BLIND))
desc += "
You are blind!"
else if(glasses_right && !WS.up)
desc += "You will become blind at
[W.blind_breakpoint] eye damage."
@@ -142,8 +142,8 @@
apply_eye_damage(H)
else
if(GLOB.ratvar_awakens)
- H.cure_nearsighted()
- H.cure_blind()
+ H.cure_nearsighted(list(EYE_DAMAGE))
+ H.cure_blind(list(EYE_DAMAGE))
H.adjust_eye_damage(-eye_damage_done)
eye_damage_done = 0
else if(prob(50) && eye_damage_done)
@@ -153,17 +153,20 @@
qdel(src)
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
- if(H.disabilities & BLIND)
+ if(H.has_disability(BLIND))
return
H.adjust_eye_damage(0.5)
eye_damage_done += 0.5
if(eye_damage_done >= 20)
H.adjust_blurriness(2)
if(eye_damage_done >= nearsight_breakpoint)
- if(H.become_nearsighted())
- to_chat(H, "
Your vision doubles, then trebles. Darkness begins to close in. You can't keep this up!")
+ if(!H.has_disability(NEARSIGHT))
+ to_chat(H, "
Your vision doubles, then trembles. Darkness begins to close in. You can't keep this up!")
+ H.become_nearsighted(EYE_DAMAGE)
if(eye_damage_done >= blind_breakpoint)
- if(H.become_blind())
+ if(!H.has_disability(BLIND))
to_chat(H, "
A piercing white light floods your vision. Suddenly, all goes dark!")
+ H.become_blind(EYE_DAMAGE)
+
if(prob(min(20, 5 + eye_damage_done)))
to_chat(H, "
Your eyes continue to burn.")
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
index cc91feeb98..5a8a40a544 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/_eminence.dm
@@ -1,3 +1,7 @@
+//Helper proc to get an Eminence mob if it exists
+/proc/get_eminence()
+ return locate(/mob/camera/eminence) in servants_and_ghosts()
+
//The Eminence is a unique mob that functions like the leader of the cult. It's incorporeal but can interact with the world in several ways.
/mob/camera/eminence
name = "\the Emininence"
@@ -12,39 +16,50 @@
layer = FLY_LAYER
faction = list("ratvar")
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ var/turf/last_failed_turf
var/static/superheated_walls = 0
-/mob/camera/eminence/Initialize()
- if(SSticker.mode.eminence)
- return INITIALIZE_HINT_QDEL
- . = ..()
-
-/mob/camera/eminence/Destroy(force)
- if(!force && mind && SSticker.mode.eminence == mind)
- return QDEL_HINT_LETMELIVE
- return ..()
-
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
/mob/camera/eminence/Move(NewLoc, direct)
var/OldLoc = loc
if(NewLoc && !istype(NewLoc, /turf/open/indestructible/reebe_void))
- forceMove(get_turf(NewLoc))
+ var/turf/T = get_turf(NewLoc)
+ if(T.flags_1 & NOJAUNT_1)
+ if(last_failed_turf != T)
+ T.visible_message("
[T] suddenly emits a ringing sound!", ignore_mob = src)
+ playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
+ last_failed_turf = T
+ to_chat(src, "
This turf is consecrated and can't be crossed!")
+ return
+ if(istype(get_area(T), /area/chapel))
+ to_chat(src, "
The Chapel is hallowed ground under a heretical deity, and can't be accessed!")
+ return
+ forceMove(T)
Moved(OldLoc, direct)
if(GLOB.ratvar_awakens)
for(var/turf/T in range(5, src))
if(prob(166 - (get_dist(src, T) * 33)))
T.ratvar_act() //Causes moving to leave a swath of proselytized area behind the Eminence
+/mob/camera/eminence/Process_Spacemove(movement_dir = 0)
+ return TRUE
+
/mob/camera/eminence/Login()
..()
- add_servant_of_ratvar(src, TRUE)
+ var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
+ if(C && C.clock_team)
+ if(C.clock_team.eminence && C.clock_team.eminence != src)
+ remove_servant_of_ratvar(src,TRUE)
+ qdel(src)
+ return
+ else
+ C.clock_team.eminence = src
to_chat(src, "
You have been selected as the Eminence!")
to_chat(src, "
As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.")
to_chat(src, "
Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.")
to_chat(src, "
Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.")
- SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
@@ -55,6 +70,12 @@
E.Grant(src)
/mob/camera/eminence/say(message)
+ if(client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+ if(client.handle_spam_prevention(message,MUTE_IC))
+ return
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message)
return
@@ -62,7 +83,13 @@
if(GLOB.ratvar_awakens)
visible_message("
You feel light slam into your mind and form words: \"[capitalize(message)]\"")
playsound(src, 'sound/machines/clockcult/ark_scream.ogg', 50, FALSE)
- hierophant_message("
The Eminence: \"[message]\"")
+ message = "
The [GLOB.ratvar_awakens ? "Radiance" : "Eminence"]: \"[message]\""
+ for(var/mob/M in servants_and_ghosts())
+ if(isobserver(M))
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [message]")
+ else
+ to_chat(M, message)
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(z == ZLEVEL_CITYOFCOGS || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
diff --git a/code/game/gamemodes/clock_cult/clock_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/ark_of_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
index 63fea1eeb6..21d1159541 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -113,7 +113,7 @@
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/mass_recall()
for(var/V in SSticker.mode.servants_of_ratvar)
var/datum/mind/M = V
- if(!M.current.stat)
+ if(M.current.stat != DEAD)
M.current.forceMove(get_turf(src))
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
index 8d4e936658..2edaba3b23 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
@@ -17,7 +17,11 @@
return
if(kingmaking)
return
- if(SSticker.mode.eminence)
+
+ var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
+ if(!C || !C.clock_team)
+ return
+ if(C.clock_team.eminence)
to_chat(user, "
There's already an Eminence!")
return
if(!GLOB.servants_active)
@@ -34,7 +38,8 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
- if(SSticker.mode.eminence)
+ var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
+ if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "
There's already an Eminence - too late!")
return
if(!GLOB.servants_active)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
index b95d9cc0db..447b077d87 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm
@@ -60,4 +60,4 @@
break
if(!M)
M = H.apply_status_effect(STATUS_EFFECT_MANIAMOTOR, src)
- M.severity = Clamp(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
+ M.severity = CLAMP(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
index c7aea3df7e..76e942037c 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
@@ -110,7 +110,7 @@
if(!(BI.resistance_flags & ON_FIRE))
BI.fire_act()
continue
- if(is_servant_of_ratvar(L) || (L.disabilities & BLIND) || L.null_rod_check())
+ if(is_servant_of_ratvar(L) || (L.has_disability(BLIND)) || L.null_rod_check())
continue
if(L.stat || L.restrained() || L.buckled || L.lying)
continue
diff --git a/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm b/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
index 9d4667ee9f..e417cbbc32 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/taunting_trail.dm
@@ -57,5 +57,5 @@
L.confused = min(L.confused + 15, 50)
L.dizziness = min(L.dizziness + 15, 50)
if(L.confused >= 25)
- L.Knockdown(Floor(L.confused * 0.8))
+ L.Knockdown(FLOOR(L.confused * 0.8, 1))
take_damage(max_integrity)
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index f20dd25802..697a5c8eba 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -2,24 +2,23 @@
/datum/game_mode
var/list/datum/mind/cult = list()
- var/list/cult_objectives = list()
- var/eldergod = 1 //for the summon god objective
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
-/proc/is_sacrifice_target(datum/mind/mind)
- if(mind == GLOB.sac_mind)
- return TRUE
+/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
+ for(var/datum/objective/sacrifice/sac_objective in objectives)
+ if(mind == sac_objective.target)
+ return TRUE
return FALSE
-/proc/is_convertable_to_cult(mob/living/M)
+/proc/is_convertable_to_cult(mob/living/M,datum/team/cult/specific_cult)
if(!istype(M))
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return FALSE
- if(is_sacrifice_target(M.mind))
+ if(specific_cult && specific_cult.is_sacrifice_target(M.mind))
return FALSE
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return FALSE
@@ -55,10 +54,10 @@
var/list/cultists_to_cult = list() //the cultists we'll convert
+ var/datum/team/cult/main_cult
+
/datum/game_mode/cult/pre_setup()
- cult_objectives += "sacrifice"
-
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -86,82 +85,19 @@
/datum/game_mode/cult/post_setup()
- if("sacrifice" in cult_objectives)
- var/list/possible_targets = get_unconvertables()
- if(!possible_targets.len)
- message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !(player.mind in cultists_to_cult))
- possible_targets += player.mind
- if(possible_targets.len > 0)
- GLOB.sac_mind = pick(possible_targets)
- if(!GLOB.sac_mind)
- message_admins("Cult Sacrifice: ERROR - Null target chosen!")
- else
- var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
- var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- GLOB.sac_image = reshape
- else
- message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
- if(!GLOB.summon_spots.len)
- while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
- var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
- if((summon.z in GLOB.station_z_levels) && summon.valid_territory)
- GLOB.summon_spots += summon
- cult_objectives += "eldergod"
-
for(var/datum/mind/cult_mind in cultists_to_cult)
- equip_cultist(cult_mind.current)
- update_cult_icons_added(cult_mind)
- to_chat(cult_mind.current, "
You are a member of the cult!")
- cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
- add_cultist(cult_mind, 0)
+ add_cultist(cult_mind, 0, equip=TRUE)
..()
-/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob,tome = 0)
- if(!istype(mob))
- return
- if (mob.mind)
- if (mob.mind.assigned_role == "Clown")
- to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
- mob.dna.remove_mutation(CLOWNMUT)
- if(tome)
- . += cult_give_item(/obj/item/tome, mob)
- else
- . += cult_give_item(/obj/item/paper/talisman/supply, mob)
- to_chat(mob, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
-
-/datum/game_mode/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
- var/list/slots = list(
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store
- )
-
- var/T = new item_path(mob)
- var/item_name = initial(item_path.name)
- var/where = mob.equip_in_one_of_slots(T, slots)
- if(!where)
- to_chat(mob, "
Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).")
- return 0
- else
- to_chat(mob, "
You have a [item_name] in your [where].")
- if(where == "backpack")
- var/obj/item/storage/B = mob.back
- B.orient2hud(mob)
- B.show_to(mob)
- return 1
-
-/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
+/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun , equip = FALSE) //BASE
if (!istype(cult_mind))
return 0
- if(cult_mind.add_antag_datum(ANTAG_DATUM_CULT))
+
+ var/datum/antagonist/cult/new_cultist = new(cult_mind)
+ new_cultist.give_equipment = equip
+
+ if(cult_mind.add_antag_datum(new_cultist))
if(stun)
cult_mind.current.Unconscious(100)
return 1
@@ -187,25 +123,19 @@
culthud.leave_hud(cult_mind.current)
set_antag_hud(cult_mind.current, null)
-/datum/game_mode/cult/proc/get_unconvertables()
- var/list/ucs = list()
- for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
- ucs += player.mind
- return ucs
-
/datum/game_mode/cult/proc/check_cult_victory()
- var/cult_fail = 0
- if(cult_objectives.Find("survive"))
- cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise
- if(cult_objectives.Find("eldergod"))
- cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
- if(cult_objectives.Find("sacrifice"))
- if(GLOB.sac_mind && !GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
- cult_fail++
- return cult_fail //if any objectives aren't met, failure
+ return main_cult.check_cult_victory()
+/datum/game_mode/cult/set_round_result()
+ ..()
+ if(check_cult_victory())
+ SSticker.mode_result = "win - cult win"
+ SSticker.news_report = CULT_SUMMON
+ else
+ SSticker.mode_result = "loss - staff stopped the cult"
+ SSticker.news_report = CULT_FAILURE
+
/datum/game_mode/cult/proc/check_survive()
var/acolytes_survived = 0
for(var/datum/mind/cult_mind in cult)
@@ -218,57 +148,6 @@
return 1
-/datum/game_mode/cult/declare_completion()
-
- if(!check_cult_victory())
- SSticker.mode_result = "win - cult win"
- to_chat(world, "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!")
- else
- SSticker.mode_result = "loss - staff stopped the cult"
- to_chat(world, "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!")
-
- var/text = ""
-
- if(cult_objectives.len)
- text += "
The cultists' objectives were:"
- for(var/obj_count=1, obj_count <= cult_objectives.len, obj_count++)
- var/explanation
- switch(cult_objectives[obj_count])
- if("survive")
- if(!check_survive())
- explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped)
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "SUCCESS"))
- SSticker.news_report = CULT_ESCAPE
- else
- explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped)
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "FAIL"))
- SSticker.news_report = CULT_FAILURE
- if("sacrifice")
- if(GLOB.sac_complete)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
- else
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
- if("eldergod")
- if(!eldergod)
- explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
- SSticker.news_report = CULT_SUMMON
- else
- explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)]
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
- SSticker.news_report = CULT_FAILURE
-
- text += "
Objective #[obj_count]: [explanation]"
- if(cult.len)
- text += "
The cultists were:"
- for(var/datum/mind/M in cult)
- text += printplayer(M)
- to_chat(world, text)
- ..()
- return 1
-
/datum/game_mode/cult/generate_report()
return "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
@@ -276,41 +155,4 @@
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
altogether."
-/datum/game_mode/proc/datum_cult_completion()
- var/text = ""
- var/cult_fail = 0
- cult_fail += eldergod
- if(!GLOB.sac_complete)
- cult_fail++
- if(!cult_fail)
- SSticker.mode_result = "win - cult win"
- to_chat(world, "
The cult has succeeded! Nar-sie has snuffed out another torch in the void!")
- else
- SSticker.mode_result = "loss - staff stopped the cult"
- to_chat(world, "
The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!")
- if(cult_objectives.len)
- text += "
The cultists' objectives were:"
- for(var/obj_count in 1 to 2)
- var/explanation
- switch(cult_objectives[obj_count])
- if("sacrifice")
- if(GLOB.sac_mind)
- if(GLOB.sac_complete)
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
- else
- explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role].
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
- if("eldergod")
- if(!eldergod)
- explanation = "Summon Nar-Sie.
Success!"
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
- SSticker.news_report = CULT_SUMMON
- else
- explanation = "Summon Nar-Sie.
Fail."
- SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
- SSticker.news_report = CULT_FAILURE
- text += "
Objective #[obj_count]: [explanation]"
- to_chat(world, text)
-
#undef CULT_SCALING_COEFFICIENT
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index 530b6ebb20..b809f2419c 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -30,7 +30,7 @@
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
var/title = "Acolyte"
- var/span = "cultitalic"
+ var/span = "cult italic"
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
span = "cultlarge"
if(ishuman(user))
@@ -88,19 +88,21 @@
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
- if(GLOB.cult_vote_called || !ishuman(owner))
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
/datum/action/innate/cult/mastervote/Activate()
- pollCultists(owner)
+ var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ pollCultists(owner,C.cult_team)
-/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
+/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
if(world.time < CULT_POLL_WAIT)
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
return
- GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
@@ -108,39 +110,39 @@
to_chat(B.current, "
Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.")
sleep(100)
var/list/asked_cultists = list()
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in team.members)
if(B.current && B.current != Nominee && !B.current.incapacitated())
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
asked_cultists += B.current
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
if(QDELETED(Nominee) || Nominee.incapacitated())
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"
[Nominee] has died in the process of attempting to win the cult's support!")
return FALSE
if(!Nominee.mind)
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"
[Nominee] has gone catatonic in the process of attempting to win the cult's support!")
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
- GLOB.cult_vote_called = FALSE
- for(var/datum/mind/B in SSticker.mode.cult)
+ team.cult_vote_called = FALSE
+ for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current, "
[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
return FALSE
- GLOB.cult_mastered = TRUE
+ team.cult_mastered = TRUE
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in team.members)
if(B.current)
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
vote.Remove(B.current)
@@ -159,6 +161,9 @@
button_icon_state = "sintouch"
/datum/action/innate/cult/master/finalreck/Activate()
+ var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!antag)
+ return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -169,7 +174,7 @@
to_chat(owner, "
You need more space to summon the cult!")
return
if(do_after(owner, 30, target = owner))
- for(var/datum/mind/B in SSticker.mode.cult)
+ for(var/datum/mind/B in antag.cult_team.members)
if(B.current && B.current.stat != DEAD)
var/turf/mobloc = get_turf(B.current)
switch(i)
@@ -194,7 +199,7 @@
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
- GLOB.reckoning_complete = TRUE
+ antag.cult_team.reckoning_complete = TRUE
Remove(owner)
/mob/proc/reckon(turf/final)
@@ -269,34 +274,37 @@
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
+
+ var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+
if(target in view(7, get_turf(ranged_ability_user)))
- GLOB.blood_target = target
+ C.cult_team.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
- GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
- GLOB.blood_target_image.appearance_flags = RESET_COLOR
- GLOB.blood_target_image.pixel_x = -target.pixel_x
- GLOB.blood_target_image.pixel_y = -target.pixel_y
+ C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
+ C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
+ C.cult_team.blood_target_image.pixel_x = -target.pixel_x
+ C.cult_team.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
- to_chat(B.current, "
Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
+ to_chat(B.current, "
Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
- B.current.client.images += GLOB.blood_target_image
+ B.current.client.images += C.cult_team.blood_target_image
attached_action.owner.update_action_buttons_icon()
remove_ranged_ability("
The marking rite is complete! It will last for 90 seconds.")
- GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE)
+ C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
return TRUE
return FALSE
-/proc/reset_blood_target()
- for(var/datum/mind/B in SSticker.mode.cult)
+/proc/reset_blood_target(datum/team/cult/team)
+ for(var/datum/mind/B in team.members)
if(B.current && B.current.stat != DEAD && B.current.client)
- if(GLOB.blood_target)
+ if(team.blood_target)
to_chat(B.current,"
The blood mark has expired!")
- B.current.client.images -= GLOB.blood_target_image
- QDEL_NULL(GLOB.blood_target_image)
- GLOB.blood_target = null
+ B.current.client.images -= team.blood_target_image
+ QDEL_NULL(team.blood_target_image)
+ team.blood_target = null
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 2adaa57a2f..f0934b524f 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -179,6 +179,13 @@ This file contains the arcane tome files.
var/list/shields = list()
var/area/A = get_area(src)
+ var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!user_antag)
+ return
+
+ var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
+ var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
+
if(!check_rune_turf(Turf, user))
return
entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types
@@ -196,18 +203,20 @@ This file contains the arcane tome files.
A = get_area(src)
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
return
+
+ //AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
- if(!("eldergod" in SSticker.mode.cult_objectives))
+ if(!summon_objective)
to_chat(user, "
Nar-Sie does not wish to be summoned!")
return
- if(!GLOB.sac_complete)
+ if(sac_objective && !sac_objective.check_completion())
to_chat(user, "
The sacrifice is not complete. The portal would lack the power to open if you tried!")
return
- if(!SSticker.mode.eldergod)
+ if(summon_objective.check_completion())
to_chat(user, "
\"I am already here. There is no need to try to summon me now.\"")
return
- if(!(A in GLOB.summon_spots))
- to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
+ if(!(A in summon_objective.summon_spots))
+ to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
@@ -215,8 +224,8 @@ This file contains the arcane tome files.
return
Turf = get_turf(user)
A = get_area(src)
- if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
- to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
+ if(!(A in summon_objective.summon_spots)) // Check again to make sure they didn't move
+ to_chat(user, "
The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!")
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/ai/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index 33d5f49661..98faeae184 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -115,7 +115,7 @@ structure_check() searches for nearby cultist structures required for the invoca
continue
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if((H.disabilities & MUTE) || H.silent)
+ if((H.has_disability(MUTE)) || H.silent)
continue
if(L.stat)
continue
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
- var/is_convertable = is_convertable_to_cult(L)
+
+ var/mob/living/F = invokers[1]
+ var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+
+ var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && (is_clock || is_convertable))
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
+ var/mob/living/first_invoker = invokers[1]
+ if(!first_invoker)
+ return FALSE
+ var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C)
+ return
+
+
var/big_sac = FALSE
- if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
+ if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "
[sacrificial] is too greatly linked to the world! You need three acolytes!")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
- if(is_sacrifice_target(sacrificial.mind))
- GLOB.sac_complete = TRUE
- big_sac = TRUE
+ for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
+ if(sac_objective.target == sacrificial.mind)
+ sac_objective.sacced = TRUE
+ sac_objective.update_explanation_text()
+ big_sac = TRUE
else
GLOB.sacrificed += sacrificial
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
sleep(40)
if(src)
color = RUNE_COLOR_RED
- SSticker.mode.eldergod = FALSE
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
..()
-//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
+//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
/obj/effect/rune/raise_dead
- cultist_name = "Revive Cultist"
- cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
+ cultist_name = "Resurrect Cultist"
+ cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = TRUE
for(var/mob/living/M in T.contents)
- if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
+ if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
to_chat(user, "
There are no dead cultists on the rune!")
- log_game("Raise Dead rune failed - no cultists to revive")
+ log_game("Raise Dead rune failed - no corpses to revive")
+ fail_invoke()
+ rune_in_use = FALSE
+ return
+ if(LAZYLEN(GLOB.sacrificed) <= revives_used)
+ to_chat(user, "
You have sacrificed too few people to revive a cultist!")
fail_invoke()
rune_in_use = FALSE
return
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
else
invocation = initial(invocation)
..()
- if(mob_to_revive.stat == DEAD)
- if(LAZYLEN(GLOB.sacrificed) <= revives_used)
- to_chat(user, "
Your cult must carry out another sacrifice before it can revive a cultist!")
- fail_invoke()
- rune_in_use = FALSE
- return
- revives_used++
- mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
- mob_to_revive.grab_ghost()
- else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
- set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
- var/mob/dead/observer/theghost = null
- if(candidates.len)
- theghost = pick(candidates)
- to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
- message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
- mob_to_revive.ghostize(0)
- mob_to_revive.key = theghost.key
+ revives_used++
+ mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
+ mob_to_revive.grab_ghost()
to_chat(mob_to_revive, "
\"PASNAR SAVRAE YAM'TOTH. Arise.\"")
mob_to_revive.visible_message("
[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.", \
"
You awaken suddenly from the void. You're alive!")
diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm
index 957e261933..44f3368feb 100644
--- a/code/game/gamemodes/devil/game_mode.dm
+++ b/code/game/gamemodes/devil/game_mode.dm
@@ -3,32 +3,6 @@
var/list/datum/mind/devils = list()
var/devil_ascended = 0 // Number of arch devils on station
-/datum/game_mode/proc/auto_declare_completion_sintouched()
- var/text = ""
- if(sintouched.len)
- text += "
The sintouched were:"
- var/list/sintouchedUnique = uniqueList(sintouched)
- for(var/S in sintouchedUnique)
- var/datum/mind/sintouched_mind = S
- text += printplayer(sintouched_mind)
- text += printobjectives(sintouched_mind)
- text += "
"
- text += "
"
- to_chat(world, text)
-
-/datum/game_mode/proc/auto_declare_completion_devils()
- /var/text = ""
- if(devils.len)
- text += "
The devils were:"
- for(var/D in devils)
- var/datum/mind/devil = D
- text += printplayer(devil)
- text += printdevilinfo(devil.current)
- text += printobjectives(devil)
- text += "
"
- text += "
"
- to_chat(world, text)
-
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
for(var/i = 1 to quantity)
@@ -41,18 +15,6 @@
else
objective.find_target()
-/datum/game_mode/proc/printdevilinfo(mob/living/ply)
- var/datum/antagonist/devil/devilinfo = is_devil(ply)
- if(!devilinfo)
- return "Target is not a devil."
- var/text = "The devil's true name is: [devilinfo.truename]"
- text += "The devil's bans were:"
- text += " [GLOB.lawlorify[LORE][devilinfo.ban]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.bane]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]"
- text += " [GLOB.lawlorify[LORE][devilinfo.banish]]"
- return text
-
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
hud.join_hud(devil_mind.current)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 803e73b9e0..a0e5a9f147 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -19,6 +19,7 @@
var/probability = 0
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
+ var/nuke_off_station = 0 //Used for tracking where the nuke hit
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
@@ -73,7 +74,6 @@
/datum/game_mode/proc/pre_setup()
return 1
-
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
@@ -241,55 +241,9 @@
return 0
-/datum/game_mode/proc/declare_completion()
- var/clients = 0
- var/surviving_humans = 0
- var/surviving_total = 0
- var/ghosts = 0
- var/escaped_humans = 0
- var/escaped_total = 0
-
- for(var/mob/M in GLOB.player_list)
- if(M.client)
- clients++
- if(ishuman(M))
- if(!M.stat)
- surviving_humans++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_humans++
- if(!M.stat)
- surviving_total++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_total++
-
-
- if(isobserver(M))
- ghosts++
-
- if(clients)
- SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
- if(ghosts)
- SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
- if(surviving_humans)
- SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
- if(surviving_total)
- SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
- if(escaped_humans)
- SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
- if(escaped_total)
- SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
-
- send2irc("Server", "Round just ended.")
- if(cult.len && !istype(SSticker.mode, /datum/game_mode/cult))
- datum_cult_completion()
-
- return 0
-
-
/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
return 0
-
/datum/game_mode/proc/send_intercept()
var/intercepttext = "
Central Command Status Summary
"
intercepttext += "
Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
@@ -451,34 +405,6 @@
for (var/C in GLOB.admins)
to_chat(C, msg)
-/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
- var/text = "
[ply.key] was [ply.name] the [ply.assigned_role] and"
- if(ply.current)
- if(ply.current.stat == DEAD)
- text += " died"
- else
- text += " survived"
- if(fleecheck)
- var/turf/T = get_turf(ply.current)
- if(!T || !(T.z in GLOB.station_z_levels))
- text += " while fleeing the station"
- if(ply.current.real_name != ply.name)
- text += " as [ply.current.real_name]"
- else
- text += " had their body destroyed"
- return text
-
-/datum/game_mode/proc/printobjectives(datum/mind/ply)
- var/text = ""
- var/count = 1
- for(var/datum/objective/objective in ply.objectives)
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- count++
- return text
-
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/game_mode/proc/age_check(client/C)
if(get_remaining_days(C) == 0)
@@ -518,15 +444,25 @@
station_goals += new picked
-/datum/game_mode/proc/declare_station_goal_completion()
- for(var/V in station_goals)
- var/datum/station_goal/G = V
- G.print_result()
-
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
return "Gamemode report for [name] not set. Contact a coder."
//By default nuke just ends the round
/datum/game_mode/proc/OnNukeExplosion(off_station)
+ nuke_off_station = off_station
if(off_station < 2)
station_was_nuked = TRUE //Will end the round on next check.
+
+//Additional report section in roundend report
+/datum/game_mode/proc/special_report()
+ return
+
+//Set result and news report here
+/datum/game_mode/proc/set_round_result()
+ SSticker.mode_result = "undefined"
+ if(station_was_nuked)
+ SSticker.news_report = STATION_DESTROYED_NUKE
+ if(EMERGENCY_ESCAPED_OR_ENDGAMED)
+ SSticker.news_report = STATION_EVACUATED
+ if(SSshuttle.emergency.is_hijacked())
+ SSticker.news_report = SHUTTLE_HIJACK
\ No newline at end of file
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 1c17893a28..9e2e889047 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -304,7 +304,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(30)
if(!owner || QDELETED(owner))
return
- priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/AI/aimalf.ogg')
+ priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/ai/aimalf.ogg')
set_security_level("delta")
var/obj/machinery/doomsday_device/DOOM = new(owner_AI)
owner_AI.nuking = TRUE
diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm
index b7a6580570..efe6dc69e9 100644
--- a/code/game/gamemodes/meteor/meteor.dm
+++ b/code/game/gamemodes/meteor/meteor.dm
@@ -25,35 +25,34 @@
if (prob(meteorminutes/2))
wavetype = GLOB.meteors_catastrophic
- var/ramp_up_final = Clamp(round(meteorminutes/rampupdelta), 1, 10)
+ var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
spawn_meteors(ramp_up_final, wavetype)
-/datum/game_mode/meteor/declare_completion()
- var/text
+/datum/game_mode/meteor/special_report()
var/survivors = 0
+ var/list/survivor_list = list()
for(var/mob/living/player in GLOB.player_list)
if(player.stat != DEAD)
++survivors
if(player.onCentCom())
- text += "
[player.real_name] escaped to the safety of CentCom."
+ survivor_list += "[player.real_name] escaped to the safety of CentCom."
else if(player.onSyndieBase())
- text += "
[player.real_name] escaped to the (relative) safety of Syndicate Space."
+ survivor_list += "[player.real_name] escaped to the (relative) safety of Syndicate Space."
else
- text += "
[player.real_name] survived but is stranded without any hope of rescue."
-
+ survivor_list += "[player.real_name] survived but is stranded without any hope of rescue."
if(survivors)
- to_chat(world, "The following survived the meteor storm:[text]")
+ return "
[survivor_list.Join("
")]"
else
- to_chat(world, "Nobody survived the meteor storm!")
+ return "Nobody survived the meteor storm!"
- SSticker.mode_result = "end - evacuation"
+/datum/game_mode/meteor/set_round_result()
..()
- return 1
+ SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/generate_report()
return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \
diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm
index 4eb8642c02..f9e8f8d752 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction.dm
@@ -1,19 +1,5 @@
-/datum/objective_team/abductor_team
- member_name = "abductor"
- var/list/objectives = list()
- var/team_number
-
-/datum/objective_team/abductor_team/is_solo()
- return FALSE
-
-/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
- O.team = src
- O.update_explanation_text()
- objectives += O
-
/datum/game_mode
var/list/datum/mind/abductors = list()
- var/list/datum/mind/abductees = list()
/datum/game_mode/abduction
name = "abduction"
@@ -24,7 +10,7 @@
required_players = 15
maximum_players = 50
var/max_teams = 4
- var/list/datum/objective_team/abductor_team/abductor_teams = list()
+ var/list/datum/team/abductor_team/abductor_teams = list()
var/finished = FALSE
var/static/team_count = 0
@@ -51,7 +37,7 @@
if(team_number > max_teams)
return //or should it try to stuff them in anway ?
- var/datum/objective_team/abductor_team/team = new
+ var/datum/team/abductor_team/team = new
team.team_number = team_number
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
team.add_objective(new/datum/objective/experiment)
@@ -64,6 +50,7 @@
antag_candidates -= scientist
team.members |= scientist
scientist.assigned_role = "Abductor Scientist"
+ scientist.special_role = "Abductor Scientist"
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
if(!agent)
@@ -71,18 +58,19 @@
antag_candidates -= agent
team.members |= agent
agent.assigned_role = "Abductor Agent"
+ agent.special_role = "Abductor Agent"
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
abductor_teams += team
return team
/datum/game_mode/abduction/post_setup()
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ for(var/datum/team/abductor_team/team in abductor_teams)
post_setup_team(team)
return ..()
//Used for create antag buttons
-/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
+/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
for(var/datum/mind/M in team.members)
if(M.assigned_role == "Abductor Scientist")
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
@@ -91,7 +79,7 @@
/datum/game_mode/abduction/check_finished()
if(!finished)
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ for(var/datum/team/abductor_team/team in abductor_teams)
for(var/datum/objective/O in team.objectives)
if(O.check_completion())
SSshuttle.emergency.request(null, set_coefficient = 0.5)
@@ -99,35 +87,6 @@
return ..()
return ..()
-/datum/game_mode/abduction/declare_completion()
- for(var/datum/objective_team/abductor_team/team in abductor_teams)
- var/won = TRUE
- for(var/datum/objective/O in team.objectives)
- if(!O.check_completion())
- won = FALSE
- if(won)
- to_chat(world, "[team.name] team fulfilled its mission!")
- else
- to_chat(world, "[team.name] team failed its mission.")
- ..()
- return TRUE
-
-/datum/game_mode/proc/auto_declare_completion_abduction()
- var/text = ""
- if(abductors.len)
- text += "
The abductors were:"
- for(var/datum/mind/abductor_mind in abductors)
- text += printplayer(abductor_mind)
- text += printobjectives(abductor_mind)
- text += "
"
- if(abductees.len)
- text += "
The abductees were:"
- for(var/datum/mind/abductee_mind in abductees)
- text += printplayer(abductee_mind)
- text += printobjectives(abductee_mind)
- text += "
"
- to_chat(world, text)
-
// LANDMARKS
/obj/effect/landmark/abductor
var/team_number = 1
@@ -144,9 +103,9 @@
/datum/objective/experiment/check_completion()
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
- if(!istype(team, /datum/objective_team/abductor_team))
+ if(!istype(team, /datum/team/abductor_team))
return FALSE
- var/datum/objective_team/abductor_team/T = team
+ var/datum/team/abductor_team/T = team
if(E.team_number == T.team_number)
return E.points >= target_amount
return FALSE
diff --git a/code/game/gamemodes/miniantags/abduction/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 9050d03686..682552e2d1 100644
--- a/code/game/gamemodes/miniantags/monkey/monkey.dm
+++ b/code/game/gamemodes/miniantags/monkey/monkey.dm
@@ -89,13 +89,18 @@
return FALSE
-/datum/game_mode/monkey/declare_completion()
+/datum/game_mode/monkey/set_round_result()
+ ..()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
- to_chat(world, "The monkeys have overthrown their captors! Eeek eeeek!!")
else
SSticker.mode_result = "loss - staff stopped the monkeys"
- to_chat(world, "The staff managed to contain the monkey infestation!")
+
+/datum/game_mode/monkey/special_report()
+ if(check_monkey_victory())
+ return "The monkeys have overthrown their captors! Eeek eeeek!!"
+ else
+ return "The staff managed to contain the monkey infestation!"
/datum/game_mode/monkey/generate_report()
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
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 727203b150..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))
@@ -374,7 +375,7 @@
return
var/key_of_revenant
message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
- loc = get_turf(src) //In case it's in a backpack or someone's hand
+ forceMove(drop_location()) //In case it's in a backpack or someone's hand
revenant.forceMove(loc)
if(client_to_revive)
for(var/mob/M in GLOB.dead_mob_list)
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/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index c59ad05cd5..21de0fc2f9 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -213,7 +213,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
var/mob/living/carbon/human/target = null
var/list/mob/living/carbon/human/possible = list()
- var/obj/item/link = null
+ var/obj/item/linked_item = null
var/cooldown_time = 30 //3s
var/cooldown = 0
max_integrity = 10
@@ -237,10 +237,10 @@
cooldown = world.time +cooldown_time
return
- if(!link)
+ if(!linked_item)
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
if (user.transferItemToLoc(I,src))
- link = I
+ linked_item = I
to_chat(user, "You attach [I] to the doll.")
update_targets()
@@ -255,11 +255,11 @@
return
if(user.zone_selected == "chest")
- if(link)
+ if(linked_item)
target = null
- link.loc = get_turf(src)
- to_chat(user, "You remove the [link] from the doll.")
- link = null
+ linked_item.forceMove(drop_location())
+ to_chat(user, "You remove the [linked_item] from the doll.")
+ linked_item = null
update_targets()
return
@@ -291,10 +291,10 @@
/obj/item/voodoo/proc/update_targets()
possible = list()
- if(!link)
+ if(!linked_item)
return
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- if(md5(H.dna.uni_identity) in link.fingerprints)
+ if(md5(H.dna.uni_identity) in linked_item.fingerprints)
possible |= H
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
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/PDApainter.dm b/code/game/machinery/PDApainter.dm
index 61d5627354..6156ee1d86 100644
--- a/code/game/machinery/PDApainter.dm
+++ b/code/game/machinery/PDApainter.dm
@@ -134,7 +134,7 @@
return
if(storedpda)
- storedpda.loc = get_turf(src.loc)
+ storedpda.forceMove(drop_location())
storedpda = null
update_icon()
else
diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm
index cbdc28883f..e9390a3cf5 100644
--- a/code/game/machinery/computer/apc_control.dm
+++ b/code/game/machinery/computer/apc_control.dm
@@ -161,7 +161,7 @@
return
log_activity("changed greater than charge filter to \"[new_filter]\"")
if(new_filter)
- new_filter = Clamp(new_filter, 0, 100)
+ new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Above"] = new_filter
if(href_list["below_filter"])
@@ -171,7 +171,7 @@
return
log_activity("changed lesser than charge filter to \"[new_filter]\"")
if(new_filter)
- new_filter = Clamp(new_filter, 0, 100)
+ new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Below"] = new_filter
if(href_list["access_filter"])
diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm
index 2d1d771203..a4881546cf 100644
--- a/code/game/machinery/computer/atmos_control.dm
+++ b/code/game/machinery/computer/atmos_control.dm
@@ -211,7 +211,7 @@
if("pressure")
var/target = input("New target pressure:", name, output_info ? output_info["internal"] : 0) as num|null
if(!isnull(target) && !..())
- target = Clamp(target, 0, 50 * ONE_ATMOSPHERE)
+ target = CLAMP(target, 0, 50 * ONE_ATMOSPHERE)
signal.data += list("tag" = output_tag, "set_internal_pressure" = target)
. = TRUE
radio_connection.post_signal(src, signal, filter = GLOB.RADIO_ATMOSIA)
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 44d6d5abe4..786deaa56a 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -300,6 +300,9 @@
else if(isspaceturf(T))
to_chat(user, "[prob(1) ? "Servant cannot into space." : "You can't teleport into space."]")
return
+ else if(T.flags_1 & NOJAUNT_1)
+ to_chat(user, "This tile is blessed by holy water and deflects the warp.")
+ return
var/area/AR = get_area(T)
if(!AR.clockwork_warp_allowed)
to_chat(user, "[AR.clockwork_warp_fail]")
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 7814e05138..c4a4d118b3 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -449,7 +449,7 @@
scantemp = "Subject's brain is not responding to scanning stimuli."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
+ if((mob_occupant.has_disability(NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 9fa196bd46..67f79f4c52 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -81,7 +81,7 @@
if(connected && connected.is_operational())
if(connected.occupant) //set occupant_status message
viable_occupant = connected.occupant
- if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.disabilities & NOCLONE) || (connected.scan_level == 3))) //occupant is viable for dna modification
+ if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.has_disability(NOCLONE)) || (connected.scan_level == 3))) //occupant is viable for dna modification
occupant_status += "[viable_occupant.name] => "
switch(viable_occupant.stat)
if(CONSCIOUS)
@@ -337,12 +337,12 @@
if(!num)
num = round(input(usr, "Choose pulse duration:", "Input an Integer", null) as num|null)
if(num)
- radduration = Wrap(num, 1, RADIATION_DURATION_MAX+1)
+ radduration = WRAP(num, 1, RADIATION_DURATION_MAX+1)
if("setstrength")
if(!num)
num = round(input(usr, "Choose pulse strength:", "Input an Integer", null) as num|null)
if(num)
- radstrength = Wrap(num, 1, RADIATION_STRENGTH_MAX+1)
+ radstrength = WRAP(num, 1, RADIATION_STRENGTH_MAX+1)
if("screen")
current_screen = href_list["text"]
if("rejuv")
@@ -353,13 +353,13 @@
if("setbufferlabel")
var/text = sanitize(input(usr, "Input a new label:", "Input an Text", null) as text|null)
if(num && text)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot["label"] = text
if("setbuffer")
if(num && viable_occupant)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = list(
"label"="Buffer[num]:[viable_occupant.real_name]",
"UI"=viable_occupant.dna.uni_identity,
@@ -370,7 +370,7 @@
)
if("clearbuffer")
if(num)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot.Cut()
@@ -387,7 +387,7 @@
apply_buffer(SCANNER_ACTION_MIXED,num)
if("injector")
if(num && injectorready < world.time)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
var/obj/item/dnainjector/timed/I
@@ -436,11 +436,11 @@
injectorready = world.time + INJECTOR_TIMEOUT
if("loaddisk")
if(num && diskette && diskette.fields)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = diskette.fields.Copy()
if("savedisk")
if(num && diskette && !diskette.read_only)
- num = Clamp(num, 1, NUMBER_OF_BUFFERS)
+ num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
diskette.name = "data disk \[[buffer_slot["label"]]\]"
@@ -454,8 +454,8 @@
delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num)
if("pulseui","pulsese")
if(num && viable_occupant && connected)
- radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1)
- radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1)
+ radduration = WRAP(radduration, 1, RADIATION_DURATION_MAX+1)
+ radstrength = WRAP(radstrength, 1, RADIATION_STRENGTH_MAX+1)
var/locked_state = connected.locked
connected.locked = TRUE
@@ -471,7 +471,7 @@
switch(href_list["task"]) //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage
if("pulseui")
var/len = length(viable_occupant.dna.uni_identity)
- num = Wrap(num, 1, len+1)
+ num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
//Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -487,7 +487,7 @@
viable_occupant.updateappearance(mutations_overlay_update=1)
if("pulsese")
var/len = length(viable_occupant.dna.struc_enzymes)
- num = Wrap(num, 1, len+1)
+ num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len)
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -518,21 +518,22 @@
ran = round(ran) //negative, so floor it
else
ran = -round(-ran) //positive, so ceiling it
- return num2hex(Wrap(hex2num(input)+ran, 0, 16**length), length)
+ return num2hex(WRAP(hex2num(input)+ran, 0, 16**length), length)
-/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks)
- return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1)
+/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position, radduration, number_of_blocks)
+ var/val = round(gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration) + position, 1)
+ return WRAP(val, 1, number_of_blocks+1)
/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant()
var/mob/living/carbon/viable_occupant = null
if(connected)
viable_occupant = connected.occupant
- if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE))
+ if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.has_disability(NOCLONE)))
viable_occupant = null
return viable_occupant
/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num)
- buffer_num = Clamp(buffer_num, 1, NUMBER_OF_BUFFERS)
+ buffer_num = CLAMP(buffer_num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[buffer_num]
var/mob/living/carbon/viable_occupant = get_viable_occupant()
if(istype(buffer_slot))
diff --git a/code/game/machinery/computer/gulag_teleporter.dm b/code/game/machinery/computer/gulag_teleporter.dm
index 36da1288a9..2419dd2299 100644
--- a/code/game/machinery/computer/gulag_teleporter.dm
+++ b/code/game/machinery/computer/gulag_teleporter.dm
@@ -106,7 +106,7 @@
return
if(!new_goal)
new_goal = default_goal
- id.goal = Clamp(new_goal, 0, 1000) //maximum 1000 points
+ id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points
if("toggle_open")
if(teleporter.locked)
to_chat(usr, "The teleporter is locked")
diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm
index 959253036b..8679652a10 100644
--- a/code/game/machinery/computer/telecrystalconsoles.dm
+++ b/code/game/machinery/computer/telecrystalconsoles.dm
@@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/ejectuplink()
if(uplinkholder)
- uplinkholder.loc = get_turf(src.loc)
+ uplinkholder.forceMove(drop_location())
uplinkholder = null
update_icon()
@@ -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/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 99cbded13a..4328a22222 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -157,15 +157,15 @@
if(istype(P, /obj/item/crowbar))
playsound(src.loc, P.usesound, 50, 1)
state = 2
- circuit.loc = src.loc
+ circuit.forceMove(drop_location())
components.Remove(circuit)
circuit = null
if(components.len == 0)
to_chat(user, "You remove the circuit board.")
else
to_chat(user, "You remove the circuit board and other components.")
- for(var/atom/movable/A in components)
- A.loc = src.loc
+ for(var/atom/movable/AM in components)
+ AM.forceMove(drop_location())
desc = initial(desc)
req_components = null
components = null
@@ -186,9 +186,9 @@
qdel(O)
new_machine.component_parts = list()
for(var/obj/O in src)
- O.loc = null
+ O.moveToNullspace()
new_machine.component_parts += O
- circuit.loc = null
+ circuit.moveToNullspace()
new_machine.RefreshParts()
qdel(src)
return
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/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index d1189ff8b8..29df5e4949 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -100,7 +100,7 @@
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
if(istype(mob_occupant))
if(locate_computer(/obj/machinery/computer/cloning))
- if(!mob_occupant.suiciding && !(mob_occupant.disabilities & NOCLONE) && !mob_occupant.hellbound)
+ if(!mob_occupant.suiciding && !(mob_occupant.has_disability(NOCLONE)) && !mob_occupant.hellbound)
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
// DNA manipulators cannot operate on severed heads or brains
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index d30554d258..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
@@ -1036,7 +1033,7 @@
panel_open = TRUE
update_icon(AIRLOCK_OPENING)
visible_message("[src]'s panel is blown off in a spray of deadly shrapnel!")
- charge.loc = get_turf(src)
+ charge.forceMove(drop_location())
charge.ex_act(EXPLODE_DEVASTATE)
detonated = 1
charge = null
@@ -1340,7 +1337,7 @@
else
ae = electronics
electronics = null
- ae.loc = src.loc
+ ae.forceMove(drop_location())
qdel(src)
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
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/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 2313afec3b..dce884b794 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -275,7 +275,7 @@
else
ae = electronics
electronics = null
- ae.loc = src.loc
+ ae.forceMove(drop_location())
qdel(src)
return
@@ -495,4 +495,4 @@
/obj/machinery/door/window/brigdoor/security/holding/southright
dir = SOUTH
icon_state = "rightsecure"
- base_state = "rightsecure"
\ No newline at end of file
+ base_state = "rightsecure"
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index d6d8c93ed1..10a552564b 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -75,7 +75,7 @@ Possible to do for anyone motivated enough:
replay_stop()
if(record_mode)
record_stop()
-
+
QDEL_NULL(disk)
holopads -= src
@@ -256,12 +256,12 @@ Possible to do for anyone motivated enough:
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
-
+
else if(href_list["disk_eject"])
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
-
+
else if(href_list["replay_stop"])
replay_stop()
else if(href_list["replay_start"])
@@ -424,7 +424,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(masters[user])
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
step_to(H, new_turf)
- H.loc = new_turf
+ H.forceMove(new_turf)
var/area/holo_area = get_area(src)
var/area/eye_area = new_turf.loc
@@ -505,7 +505,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
current_delay += entry[2]
var/time_delta = world.time - record_start - current_delay
-
+
if(time_delta >= 1)
disk.record.entries += list(list(HOLORECORD_DELAY,time_delta))
disk.record.entries += list(list(HOLORECORD_SAY,message))
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/newscaster.dm b/code/game/machinery/newscaster.dm
index 18acd9ece7..ee9b1ff31a 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -780,7 +780,7 @@ GLOBAL_LIST_EMPTY(allCasters)
/obj/machinery/newscaster/proc/AttachPhoto(mob/user)
if(photo)
if(!photo.sillynewscastervar)
- photo.loc = loc
+ photo.forceMove(drop_location())
if(!issilicon(user))
user.put_in_inactive_hand(photo)
else
@@ -856,7 +856,7 @@ GLOBAL_LIST_EMPTY(allCasters)
NEWSPAPER.wantedBody = GLOB.news_network.wanted_issue.body
if(GLOB.news_network.wanted_issue.img)
NEWSPAPER.wantedPhoto = GLOB.news_network.wanted_issue.img
- NEWSPAPER.loc = get_turf(src)
+ NEWSPAPER.forceMove(drop_location())
NEWSPAPER.creationTime = GLOB.news_network.lastAction
paper_remaining--
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/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
index 606f64c7f3..c01c72d7a8 100644
--- a/code/game/machinery/robot_fabricator.dm
+++ b/code/game/machinery/robot_fabricator.dm
@@ -137,7 +137,7 @@ Please wait until completion...
spawn (build_time)
if (!isnull(src.being_built))
- src.being_built.loc = get_turf(src)
+ src.being_built.forceMove(drop_location())
src.being_built = null
src.use_power = IDLE_POWER_USE
operating = FALSE
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 b45b393ab2..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,12 +223,12 @@
target= text2num(target) + T0C
. = TRUE
if(.)
- targetTemperature = Clamp(round(target),
+ targetTemperature = CLAMP(round(target),
max(settableTemperatureMedian - settableTemperatureRange, TCMB),
settableTemperatureMedian + settableTemperatureRange)
if("eject")
if(panel_open && cell)
- cell.loc = get_turf(src)
+ cell.forceMove(drop_location())
cell = null
. = TRUE
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/transformer.dm b/code/game/machinery/transformer.dm
index fe18365a9c..7624312f84 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -57,7 +57,7 @@
var/move_dir = get_dir(loc, AM.loc)
var/mob/living/carbon/human/H = AM
if((transform_standing || H.lying) && move_dir == EAST)// || move_dir == WEST)
- AM.loc = src.loc
+ AM.forceMove(drop_location())
do_transform(AM)
/obj/machinery/transformer/CanPass(atom/movable/mover, turf/target)
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/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm
index e2a35ac591..54530d368c 100644
--- a/code/game/mecha/equipment/mecha_equipment.dm
+++ b/code/game/mecha/equipment/mecha_equipment.dm
@@ -104,7 +104,7 @@
/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/mecha/M)
M.equipment += src
chassis = M
- src.loc = M
+ forceMove(M)
M.log_message("[src] initialized.")
if(!M.selected && selectable)
M.selected = src
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/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index d456642633..f076b723ae 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -39,7 +39,7 @@
O.anchored = TRUE
if(do_after_cooldown(target))
cargo_holder.cargo += O
- O.loc = chassis
+ O.forceMove(chassis)
O.anchored = FALSE
occupant_message("[target] successfully loaded.")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
@@ -91,7 +91,7 @@
O.anchored = TRUE
if(do_after_cooldown(target))
cargo_holder.cargo += O
- O.loc = chassis
+ O.forceMove(chassis)
O.anchored = FALSE
occupant_message("[target] successfully loaded.")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
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 e50da70c5d..2d148b4ff4 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -24,7 +24,7 @@
infra_luminosity = 15 //byond implementation is bugged.
force = 5
flags_1 = HEAR_1
- var/can_move = 1
+ var/can_move = 0 //time of next allowed movement
var/mob/living/carbon/occupant = null
var/step_in = 10 //make a step in step_in/10 sec.
var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South.
@@ -502,7 +502,7 @@
return domove(direction)
/obj/mecha/proc/domove(direction)
- if(!can_move)
+ if(can_move >= world.time)
return 0
if(!Process_Spacemove(direction))
return 0
@@ -520,21 +520,19 @@
return 0
var/move_result = 0
+ var/oldloc = loc
if(internal_damage & MECHA_INT_CONTROL_LOST)
move_result = mechsteprand()
else if(dir != direction && !strafe)
move_result = mechturn(direction)
else
move_result = mechstep(direction)
- if(move_result)
+ if(move_result || loc != oldloc)// halfway done diagonal move still returns false
use_power(step_energy_drain)
- can_move = 0
- spawn(step_in)
- can_move = 1
+ can_move = world.time + step_in
return 1
return 0
-
/obj/mecha/proc/mechturn(direction)
setDir(direction)
if(turnsound)
@@ -573,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/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 272d3530a6..de50d6f86f 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -542,7 +542,7 @@
else
user.visible_message("[user] removes the capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "gygax12"
if(9)
if(diff==FORWARD)
@@ -1155,7 +1155,7 @@
else
user.visible_message("[user] removes the scanner module from the [holder].", "You remove the scanner module from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "durand10"
if(11)
if(diff==FORWARD)
@@ -1173,7 +1173,7 @@
else
user.visible_message("[user] removes the super capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "durand12"
if(9)
if(diff==FORWARD)
@@ -1480,7 +1480,7 @@
else
user.visible_message("[user] removes the phasic scanner module from the [holder].", "You remove the scanner module from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "phazon10"
if(15)
if(diff==FORWARD)
@@ -1498,7 +1498,7 @@
else
user.visible_message("[user] removes the super capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "phazon12"
if(13)
if(diff==FORWARD)
diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm
index 67e5c1dbd1..de8f8ecb3a 100644
--- a/code/game/mecha/mecha_wreckage.dm
+++ b/code/game/mecha/mecha_wreckage.dm
@@ -68,7 +68,7 @@
if(crowbar_salvage && crowbar_salvage.len)
var/obj/S = pick(crowbar_salvage)
if(S)
- S.loc = get_turf(user)
+ S.forceMove(user.drop_location())
crowbar_salvage -= S
user.visible_message("[user] pries [S] from [src].", "You pry [S] from [src].")
return
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 5688214044..a7115abd1d 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -94,7 +94,7 @@
/obj/mecha/working/ripley/mining/Initialize()
. = ..()
if(cell)
- cell.charge = Floor(cell.charge * 0.25) //Starts at very low charge
+ cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge
if(prob(70)) //Maybe add a drill
if(prob(15)) //Possible diamond drill... Feeling lucky?
var/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill/D = new
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 04737f2e4c..76fd5e5cbf 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -26,9 +26,8 @@
aSignal = new(src)
aSignal.name = "[name] core"
aSignal.code = rand(1,100)
-
- aSignal.frequency = rand(1200, 1599)
- if(IsMultiple(aSignal.frequency, 2))//signaller frequencies are always uneven!
+ aSignal.frequency = rand(MIN_FREE_FREQ, MAX_FREE_FREQ)
+ if(ISMULTIPLE(aSignal.frequency, 2))//signaller frequencies are always uneven!
aSignal.frequency++
if(new_lifespan)
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index 0e0c7c606e..f06525863d 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -47,10 +47,8 @@
return
else
var/hotness = W.is_hot()
- var/added_heat = (hotness / 100)
- src.reagents.chem_temp = min(src.reagents.chem_temp + added_heat, hotness)
- src.reagents.handle_reactions()
- to_chat(user, "You heat [src] with [W]!")
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [W]!")
else
return ..()
@@ -62,8 +60,7 @@
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
if(reagents)
- reagents.chem_temp += 30
- reagents.handle_reactions()
+ reagents.expose_temperature(exposed_temperature)
..()
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 3de8432ee9..4dc985c9a1 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -169,7 +169,7 @@
qdel(H)
var/list/G_gases = G.gases
if(G_gases[/datum/gas/plasma])
- ASSERT_GAS(/datum/gas/nitrogen, G)
+ G.assert_gas(/datum/gas/nitrogen)
G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES])
G_gases[/datum/gas/plasma][MOLES] = 0
G.garbage_collect()
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index caeb1f168c..2708e78535 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -16,7 +16,7 @@
/obj/effect/landmark/start
name = "start"
- icon = 'icons/mob/screen_gen.dmi'
+ icon = 'icons/mob/landmarks.dmi'
icon_state = "x"
anchored = TRUE
var/jobspawn_override = FALSE
@@ -40,9 +40,9 @@
// START LANDMARKS FOLLOW. Don't change the names unless
// you are refactoring shitty landmark code.
-
/obj/effect/landmark/start/assistant
name = "Assistant"
+ icon_state = "Assistant"
/obj/effect/landmark/start/assistant/override
jobspawn_override = TRUE
@@ -50,102 +50,135 @@
/obj/effect/landmark/start/janitor
name = "Janitor"
+ icon_state = "Janitor"
/obj/effect/landmark/start/cargo_technician
name = "Cargo Technician"
+ icon_state = "Cargo Technician"
/obj/effect/landmark/start/bartender
name = "Bartender"
+ icon_state = "Bartender"
/obj/effect/landmark/start/clown
name = "Clown"
+ icon_state = "Clown"
/obj/effect/landmark/start/mime
name = "Mime"
+ icon_state = "Mime"
/obj/effect/landmark/start/quartermaster
name = "Quartermaster"
+ icon_state = "Quartermaster"
/obj/effect/landmark/start/atmospheric_technician
name = "Atmospheric Technician"
+ icon_state = "Atmospheric Technician"
/obj/effect/landmark/start/cook
name = "Cook"
+ icon_state = "Cook"
/obj/effect/landmark/start/shaft_miner
name = "Shaft Miner"
+ icon_state = "Shaft Miner"
/obj/effect/landmark/start/security_officer
name = "Security Officer"
+ icon_state = "Security Officer"
/obj/effect/landmark/start/botanist
name = "Botanist"
+ icon_state = "Botanist"
/obj/effect/landmark/start/head_of_security
name = "Head of Security"
-
-/obj/effect/landmark/start/ai
- name = "AI"
- delete_after_roundstart = FALSE
+ icon_state = "Head of Security"
/obj/effect/landmark/start/captain
name = "Captain"
+ icon_state = "Captain"
/obj/effect/landmark/start/detective
name = "Detective"
+ icon_state = "Detective"
/obj/effect/landmark/start/warden
name = "Warden"
+ icon_state = "Warden"
/obj/effect/landmark/start/chief_engineer
name = "Chief Engineer"
-
-/obj/effect/landmark/start/cyborg
- name = "Cyborg"
+ icon_state = "Chief Engineer"
/obj/effect/landmark/start/head_of_personnel
name = "Head of Personnel"
+ icon_state = "Head of Personnel"
/obj/effect/landmark/start/librarian
name = "Curator"
+ icon_state = "Curator"
/obj/effect/landmark/start/lawyer
name = "Lawyer"
+ icon_state = "Lawyer"
/obj/effect/landmark/start/station_engineer
name = "Station Engineer"
+ icon_state = "Station Engineer"
/obj/effect/landmark/start/medical_doctor
name = "Medical Doctor"
+ icon_state = "Medical Doctor"
/obj/effect/landmark/start/scientist
name = "Scientist"
+ icon_state = "Scientist"
/obj/effect/landmark/start/chemist
name = "Chemist"
+ icon_state = "Chemist"
/obj/effect/landmark/start/roboticist
name = "Roboticist"
+ icon_state = "Roboticist"
/obj/effect/landmark/start/research_director
name = "Research Director"
+ icon_state = "Research Director"
/obj/effect/landmark/start/geneticist
name = "Geneticist"
+ icon_state = "Geneticist"
/obj/effect/landmark/start/chief_medical_officer
name = "Chief Medical Officer"
+ icon_state = "Chief Medical Officer"
/obj/effect/landmark/start/virologist
name = "Virologist"
+ icon_state = "Virologist"
/obj/effect/landmark/start/chaplain
name = "Chaplain"
+ icon_state = "Chaplain"
+
+/obj/effect/landmark/start/cyborg
+ name = "Cyborg"
+ icon_state = "Cyborg"
+
+/obj/effect/landmark/start/ai
+ name = "AI"
+ icon_state = "AI"
+ delete_after_roundstart = FALSE
+
//Department Security spawns
/obj/effect/landmark/start/depsec
name = "department_sec"
+ icon_state = "Security Officer"
/obj/effect/landmark/start/depsec/New()
..()
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 89a5ce7353..4ecba7c982 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -150,7 +150,7 @@
spawn(travel_time)
if(!exit_vent || exit_vent.welded)
- loc = entry_vent
+ forceMove(entry_vent)
entry_vent = null
return
@@ -162,7 +162,7 @@
forceMove(entry_vent)
entry_vent = null
return
- loc = exit_vent.loc
+ forceMove(exit_vent.loc)
entry_vent = null
var/area/new_area = get_area(loc)
if(new_area)
diff --git a/code/game/objects/effects/temporary_visuals/projectile_beam.dm b/code/game/objects/effects/temporary_visuals/projectile_beam.dm
new file mode 100644
index 0000000000..8918dc8e27
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/projectile_beam.dm
@@ -0,0 +1,70 @@
+/proc/generate_projectile_beam_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
+ if(!istype(starting) || !istype(ending) || !ispath(beam_type))
+ return
+ var/datum/point/midpoint = point_midpoint_points(starting, ending)
+ var/obj/effect/projectile_beam/PB = new beam_type
+ PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
+ . = PB
+ if(qdel_in)
+ QDEL_IN(PB, qdel_in)
+
+/obj/effect/projectile_beam
+ icon = 'icons/obj/projectiles.dmi'
+ layer = ABOVE_MOB_LAYER
+ anchored = TRUE
+ light_power = 1
+ light_range = 2
+ light_color = "#00ffff"
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ flags_1 = ABSTRACT_1
+ appearance_flags = 0
+
+/obj/effect/projectile_beam/singularity_pull()
+ return
+
+/obj/effect/projectile_beam/singularity_act()
+ return
+
+/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
+ var/matrix/M
+ if(!override)
+ M = transform
+ else
+ M = new
+ M.Scale(nx,ny)
+ transform = M
+
+/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
+ var/matrix/M
+ if(!override)
+ M = transform
+ else
+ M = new
+ M.Turn(angle)
+ transform = M
+
+/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
+ if(angle_override && p_x && p_y && color_override && scaling)
+ apply_vars(angle_override, p_x, p_y, color_override, scaling)
+ return ..()
+
+/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
+ var/mutable_appearance/look = new(src)
+ look.pixel_x = p_x
+ look.pixel_y = p_y
+ if(color_override)
+ look.color = color_override
+ appearance = look
+ scale_to(1,scaling, FALSE)
+ turn_to(angle_override, FALSE)
+ if(!isnull(new_loc)) //If you want to null it just delete it...
+ forceMove(new_loc)
+ for(var/i in 1 to increment)
+ pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
+ pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
+
+/obj/effect/projectile_beam/tracer
+ icon_state = "tracer_beam"
+
+/obj/effect/projectile_beam/tracer/aiming
+ icon_state = "gbeam"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f4dd741695..1cca673778 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -119,6 +119,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/icon_override = null
+ //Grinder vars
+ var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
+ var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
+
/obj/item/Initialize()
if (!materials)
materials = list()
@@ -282,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
@@ -396,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)
@@ -427,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.
@@ -532,9 +539,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.adjust_blurriness(15)
if(M.stat != DEAD)
to_chat(M, "Your eyes start to bleed profusely!")
- if(!(M.disabilities & (NEARSIGHT | BLIND)))
- if(M.become_nearsighted())
- to_chat(M, "You become nearsighted!")
+ if(!(M.has_disability(BLIND) || M.has_disability(NEARSIGHT)))
+ to_chat(M, "You become nearsighted!")
+ M.become_nearsighted(EYE_DAMAGE)
if(prob(50))
if(M.stat != DEAD)
if(M.drop_all_held_items())
@@ -543,8 +550,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.Unconscious(20)
M.Knockdown(40)
if (prob(eyes.eye_damage - 10 + 1))
- if(M.become_blind())
- to_chat(M, "You go blind!")
+ M.become_blind(EYE_DAMAGE)
+ to_chat(M, "You go blind!")
/obj/item/clean_blood()
. = ..()
@@ -678,6 +685,15 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/proc/on_mob_death(mob/living/L, gibbed)
+/obj/item/proc/grind_requirements(obj/machinery/reagentgrinder/R) //Used to check for extra requirements for grinding an object
+ return TRUE
+
+ //Called BEFORE the object is ground up - use this to change grind results based on conditions
+ //Use "return -1" to prevent the grinding from occurring
+/obj/item/proc/on_grind()
+
+/obj/item/proc/on_juice()
+
/obj/item/proc/set_force_string()
switch(force)
if(0 to 4)
@@ -713,4 +729,3 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/MouseExited()
deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes
closeToolTip(usr)
-
diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm
index 4c8d342c16..5048f6ed2d 100644
--- a/code/game/objects/items/apc_frame.dm
+++ b/code/game/objects/items/apc_frame.dm
@@ -120,4 +120,5 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=50, MAT_GLASS=50)
\ No newline at end of file
+ materials = list(MAT_METAL=50, MAT_GLASS=50)
+ grind_results = list("iron" = 10, "silicon" = 10)
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 8ac9643c39..7533718c17 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -163,7 +163,7 @@
/obj/effect/chrono_field/New(loc, var/mob/living/target, var/obj/item/gun/energy/chrono_gun/G)
if(target && isliving(target) && G)
- target.loc = src
+ target.forceMove(src)
src.captured = target
var/icon/mob_snapshot = getFlatIcon(target)
var/icon/cached_icon = new()
@@ -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]"
@@ -198,7 +198,7 @@
if(captured)
if(tickstokill > initial(tickstokill))
for(var/atom/movable/AM in contents)
- AM.loc = loc
+ AM.forceMove(drop_location())
qdel(src)
else if(tickstokill <= 0)
to_chat(captured, "As the last essence of your being is erased from time, you begin to re-experience your most enjoyable memory. You feel happy...")
@@ -213,7 +213,7 @@
else
captured.Unconscious(80)
if(captured.loc != src)
- captured.loc = src
+ captured.forceMove(src)
update_icon()
if(gun)
if(gun.field_check(src))
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 491feb91ce..372eb56bfe 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -25,6 +25,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/smoketime = 5
w_class = WEIGHT_CLASS_TINY
heat = 1000
+ grind_results = list("phosphorus" = 2)
/obj/item/match/process()
smoketime--
@@ -101,9 +102,10 @@ 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()
var/lit = FALSE
var/starts_lit = FALSE
var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
@@ -127,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)
@@ -363,6 +366,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "cigbutt"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
+ grind_results = list("carbon" = 2)
/obj/item/cigbutt/cigarbutt
name = "cigar butt"
@@ -484,6 +488,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
heat = 1500
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
+ grind_results = list("iron" = 1, "welding_fuel" = 5, "oil" = 5)
/obj/item/lighter/update_icon()
if(lit)
@@ -655,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/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm
index 82350e37f9..12b54a3751 100644
--- a/code/game/objects/items/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/circuitboards/circuitboard.dm
@@ -12,6 +12,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
materials = list(MAT_GLASS=1000)
w_class = WEIGHT_CLASS_SMALL
+ grind_results = list("silicon" = 20, "sacid" = 0.5) //Retrieving acid this way is extremely inefficient
var/build_path = null
/obj/item/circuitboard/proc/apply_default_parts(obj/machinery/M)
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index c96ec4167a..f2a804e9e9 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -21,6 +21,7 @@
throwforce = 0
throw_speed = 3
throw_range = 7
+ grind_results = list("lye" = 10)
var/cleanspeed = 50 //slower than mop
force_string = "robust... against germs"
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index a3ad685406..0277ec5371 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -8,7 +8,6 @@
var/colour = "red"
var/open = FALSE
-
/obj/item/lipstick/purple
name = "purple lipstick"
colour = "purple"
@@ -22,7 +21,6 @@
name = "black lipstick"
colour = "black"
-
/obj/item/lipstick/random
name = "lipstick"
icon_state = "random_lipstick"
@@ -33,8 +31,6 @@
colour = pick("red","purple","lime","black","green","blue","white")
name = "[colour] lipstick"
-
-
/obj/item/lipstick/attack_self(mob/user)
cut_overlays()
to_chat(user, "You twist \the [src] [open ? "closed" : "open"].")
@@ -103,7 +99,6 @@
else
..()
-
/obj/item/razor
name = "electric razor"
desc = "The latest and greatest power razor born from the science of shaving."
@@ -112,7 +107,6 @@
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_TINY
-
/obj/item/razor/proc/shave(mob/living/carbon/human/H, location = "mouth")
if(location == "mouth")
H.facial_hair_style = "Shaved"
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 7b2d730daf..56bad47963 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -26,6 +26,7 @@
item_color = "red"
w_class = WEIGHT_CLASS_TINY
attack_verb = list("attacked", "coloured")
+ grind_results = list()
var/paint_color = "#FF0000" //RGB
var/drawtype
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index bbeed24168..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)
@@ -328,7 +328,7 @@
O.unwield()
to_chat(user, "The paddles snap back into the main unit.")
defib.on = 0
- loc = defib
+ forceMove(defib)
defib.update_icon()
return unwield(user)
@@ -393,7 +393,7 @@
/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/human/H)
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
- return (!H.suiciding && !(H.disabilities & NOCLONE) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
+ return (!H.suiciding && !(H.has_disability(NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
if(isliving(H.pulledby)) //CLEAR!
@@ -514,7 +514,7 @@
shock_touching(30, H)
var/failed
- if (H.suiciding || (H.disabilities & NOCLONE))
+ if (H.suiciding || (H.has_disability(NOCLONE)))
failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile."
else if (H.hellbound)
failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile."
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 1f7fd77c4a..f2bc8b5686 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -543,7 +543,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if("2") // Eject pAI device
var/turf/T = get_turf(src.loc)
if(T)
- pai.loc = T
+ pai.forceMove(T)
//LINK FUNCTIONS===================================
@@ -578,7 +578,7 @@ GLOBAL_LIST_EMPTY(PDAs)
M.put_in_hands(id)
to_chat(usr, "You remove the ID from the [name].")
else
- id.loc = get_turf(src)
+ id.forceMove(drop_location())
id = null
update_icon()
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/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index b405e21ca6..a07d8d8d60 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -85,7 +85,7 @@
/obj/item/device/chameleon/proc/eject_all()
for(var/atom/movable/A in active_dummy)
- A.loc = active_dummy.loc
+ A.forceMove(active_dummy.loc)
if(ismob(A))
var/mob/M = A
M.reset_perspective(null)
@@ -106,7 +106,7 @@
VRD.force_dismount(M)
else
V.unbuckle_mob(M, force = TRUE)
- M.loc = src
+ M.forceMove(src)
master = C
master.active_dummy = src
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 08c570a786..7a40d8f3a2 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -48,7 +48,7 @@
add_fingerprint(user)
if(istype(M) && on && user.zone_selected in list("eyes", "mouth"))
- if((user.disabilities & (CLUMSY | DUMB)) && prob(50)) //too dumb to use flashlight properly
+ if((user.has_disability(CLUMSY) || user.has_disability(DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!user.IsAdvancedToolUser())
@@ -82,7 +82,7 @@
else
user.visible_message("[user] directs [src] to [M]'s eyes.", \
"You direct [src] to [M]'s eyes.")
- if(M.stat == DEAD || (M.disabilities & BLIND) || !M.flash_act(visual = 1)) //mob is dead or fully blind
+ if(M.stat == DEAD || (M.has_disability(BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
to_chat(user, "[M]'s pupils don't react to the light!")
else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-RAY vision
to_chat(user, "[M]'s pupils give an eerie glow!")
@@ -256,6 +256,7 @@
var/produce_heat = 1500
heat = 1000
light_color = LIGHT_COLOR_FLARE
+ grind_results = list("sulfur" = 15)
/obj/item/device/flashlight/flare/New()
fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
@@ -404,6 +405,7 @@
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
item_state = "glowstick"
+ grind_results = list("phenol" = 15, "hydrogen" = 10, "oxygen" = 5) //Meth-in-a-stick
var/fuel = 0
/obj/item/device/flashlight/glowstick/Initialize()
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index b1b200f489..eb1ccd15f4 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -50,7 +50,7 @@
else if(istype(W, /obj/item/screwdriver))
if(diode)
to_chat(user, "You remove the [diode.name] from \the [src].")
- diode.loc = get_turf(src.loc)
+ diode.forceMove(drop_location())
diode = null
else
return ..()
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/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 9ff19ba57c..750e1f0511 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -227,7 +227,7 @@
if(keyslot)
var/turf/T = get_turf(user)
if(T)
- keyslot.loc = T
+ keyslot.forceMove(T)
keyslot = null
@@ -235,7 +235,7 @@
if(keyslot2)
var/turf/T = get_turf(user)
if(T)
- keyslot2.loc = T
+ keyslot2.forceMove(T)
keyslot2 = null
recalculateChannels()
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 236f3df93e..8227d75069 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -569,7 +569,7 @@
if(keyslot)
var/turf/T = get_turf(user)
if(T)
- keyslot.loc = T
+ keyslot.forceMove(T)
keyslot = null
recalculateChannels()
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 3f17485550..6e67ca886b 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -85,7 +85,7 @@ GAS ANALYZER
/obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
// Clumsiness/brain damage check
- if ((user.disabilities & (CLUMSY | DUMB)) && prob(50))
+ if ((user.has_disability(CLUMSY) || user.has_disability(DUMB)) && prob(50))
to_chat(user, "You stupidly try to analyze the floor's vitals!")
user.visible_message("[user] has analyzed the floor's vitals!")
to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy")
@@ -181,9 +181,12 @@ GAS ANALYZER
to_chat(user, "\t==EAR STATUS==")
if(istype(ears))
var/healthy = TRUE
- if(C.disabilities & DEAF)
+ if(C.has_disability(DEAF, GENETIC_MUTATION))
healthy = FALSE
to_chat(user, "\tSubject is genetically deaf.")
+ else if(C.has_disability(DEAF))
+ healthy = FALSE
+ to_chat(user, "\tSubject is deaf.")
else
if(ears.ear_damage)
to_chat(user, "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.")
@@ -199,10 +202,10 @@ GAS ANALYZER
to_chat(user, "\t==EYE STATUS==")
if(istype(eyes))
var/healthy = TRUE
- if(C.disabilities & BLIND)
+ if(C.has_disability(BLIND))
to_chat(user, "\tSubject is blind.")
healthy = FALSE
- if(C.disabilities & NEARSIGHT)
+ if(C.has_disability(NEARSIGHT))
to_chat(user, "\tSubject is nearsighted.")
healthy = FALSE
if(eyes.eye_damage > 30)
@@ -335,6 +338,7 @@ GAS ANALYZER
throw_speed = 3
throw_range = 7
materials = list(MAT_METAL=30, MAT_GLASS=20)
+ grind_results = list("mercury" = 5, "iron" = 5, "silicon" = 5)
/obj/item/device/analyzer/attack_self(mob/user)
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index 338f113afb..5afc8602ff 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -228,7 +228,7 @@ effective or pretty fucking useless.
charge = max(0,charge - 25)//Quick decrease in light
else
charge = min(max_charge,charge + 50) //Charge in the dark
- animate(user,alpha = Clamp(255 - charge,0,255),time = 10)
+ animate(user,alpha = CLAMP(255 - charge,0,255),time = 10)
/obj/item/device/jammer
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index 334be4a645..e14363a1c1 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -166,7 +166,7 @@
/obj/item/dice/proc/diceroll(mob/user)
result = rand(1, sides)
if(rigged && result != rigged)
- if(prob(Clamp(1/(sides - 1) * 100, 25, 80)))
+ if(prob(CLAMP(1/(sides - 1) * 100, 25, 80)))
result = rigged
var/fake_result = rand(1, sides)//Daredevil isn't as good as he used to be
var/comment = ""
diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index 9644d827ea..19008b43a6 100644
--- a/code/game/objects/items/dna_injector.dm
+++ b/code/game/objects/items/dna_injector.dm
@@ -31,7 +31,7 @@
/obj/item/dnainjector/proc/inject(mob/living/carbon/M, mob/user)
prepare()
- if(M.has_dna() && !(RADIMMUNE in M.dna.species.species_traits) && !(M.disabilities & NOCLONE))
+ if(M.has_dna() && !(RADIMMUNE in M.dna.species.species_traits) && !(M.has_disability(NOCLONE)))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
for(var/datum/mutation/human/HM in remove_mutations)
@@ -313,7 +313,7 @@
to_chat(user, "You can't modify [M]'s DNA while [M.p_theyre()] dead.")
return FALSE
- if(M.has_dna() && !(M.disabilities & NOCLONE))
+ if(M.has_dna() && !(M.has_disability(NOCLONE)))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
var/endtime = world.time+duration
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index d334d12193..5f582b9e15 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -16,6 +16,7 @@
attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
dog_fashion = /datum/dog_fashion/back
resistance_flags = FIRE_PROOF
+ container_type = AMOUNT_VISIBLE
var/max_water = 50
var/last_use = 1
var/safety = TRUE
@@ -48,7 +49,6 @@
/obj/item/extinguisher/attack_self(mob/user)
safety = !safety
src.icon_state = "[sprite_name][!safety]"
- src.desc = "The safety is [safety ? "on" : "off"]."
to_chat(user, "The safety is [safety ? "on" : "off"].")
return
@@ -67,11 +67,10 @@
/obj/item/extinguisher/examine(mob/user)
..()
+ to_chat(user, "The safety is [safety ? "on" : "off"].")
+
if(reagents.total_volume)
- to_chat(user, "It contains [round(reagents.total_volume)] unit\s.")
to_chat(user, "Alt-click to empty it.")
- else
- to_chat(user, "It is empty.")
/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
if(istype(target, /obj/structure/reagent_dispensers/watertank) && target.Adjacent(user))
diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm
index 1e3e9ccd73..0fe53f293c 100644
--- a/code/game/objects/items/gift.dm
+++ b/code/game/objects/items/gift.dm
@@ -7,6 +7,9 @@
/*
* Gifts
*/
+
+GLOBAL_LIST_EMPTY(possible_gifts)
+
/obj/item/a_gift
name = "gift"
desc = "PRESENTS!!!! eek!"
@@ -30,6 +33,14 @@
to_chat(M, "You're supposed to be spreading gifts, not opening them yourself!")
return
+ var/gift_type = get_gift_type()
+
+ qdel(src)
+ var/obj/item/I = new gift_type(M)
+ M.put_in_hands(I)
+ I.add_fingerprint(M)
+
+/obj/item/a_gift/proc/get_gift_type()
var/gift_type_list = list(/obj/item/sord,
/obj/item/storage/wallet,
/obj/item/storage/photo_album,
@@ -72,10 +83,21 @@
var/gift_type = pick(gift_type_list)
- if(!ispath(gift_type, /obj/item))
- return
+ return gift_type
- qdel(src)
- var/obj/item/I = new gift_type(M)
- M.put_in_hands(I)
- I.add_fingerprint(M)
+
+/obj/item/a_gift/anything
+ name = "christmas gift"
+ desc = "It could be anything!"
+
+/obj/item/a_gift/anything/get_gift_type()
+ if(!GLOB.possible_gifts.len)
+ var/list/gift_types_list = subtypesof(/obj/item)
+ for(var/V in gift_types_list)
+ var/obj/item/I = V
+ if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.flags_1) & ABSTRACT_1))
+ gift_types_list -= V
+ GLOB.possible_gifts = gift_types_list
+ var/gift_type = pick(GLOB.possible_gifts)
+
+ return gift_type
diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index e791a74541..8698594555 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -110,12 +110,12 @@
else if(stage == WIRED && istype(I, /obj/item/wrench))
if(beakers.len)
for(var/obj/O in beakers)
- O.loc = get_turf(src)
+ O.forceMove(drop_location())
beakers = list()
to_chat(user, "You open the [initial(name)] assembly and remove the payload.")
return // First use of the wrench remove beakers, then use the wrench to remove the activation mechanism.
if(nadeassembly)
- nadeassembly.loc = get_turf(src)
+ nadeassembly.forceMove(drop_location())
nadeassembly.master = null
nadeassembly = null
else // If "nadeassembly = null && stage == WIRED", then it most have been cable_coil that was used.
@@ -167,7 +167,7 @@
playsound(loc, 'sound/items/screwdriver2.ogg', 50, 1)
if(beakers.len)
for(var/obj/O in beakers)
- O.loc = get_turf(src)
+ O.forceMove(drop_location())
beakers = list()
stage_change(EMPTY)
return
diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index e444ecce25..257007aba9 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -24,7 +24,7 @@
qdel(src)
/obj/item/grenade/proc/clown_check(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "Huh? How does this thing work?")
preprime(user, 5, FALSE)
return FALSE
diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm
index dd0d397e81..0375e5529e 100644
--- a/code/game/objects/items/grenades/plastic.dm
+++ b/code/game/objects/items/grenades/plastic.dm
@@ -87,7 +87,7 @@
return
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
- newtime = Clamp(newtime, 10, 60000)
+ newtime = CLAMP(newtime, 10, 60000)
det_time = newtime
to_chat(user, "Timer set for [det_time] seconds.")
@@ -204,7 +204,7 @@
/obj/item/grenade/plastic/c4/attack_self(mob/user)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
- newtime = Clamp(newtime, 10, 60000)
+ newtime = CLAMP(newtime, 10, 60000)
timer = newtime
to_chat(user, "Timer set for [timer] seconds.")
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 886a248c8c..1dd2b1b1de 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -26,7 +26,7 @@
/obj/item/restraints/handcuffs/attack(mob/living/carbon/C, mob/living/carbon/human/user)
if(!istype(C))
return
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "Uh... how do those things work?!")
apply_cuffs(user,user)
return
diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm
index 98121f7772..d13d6cc1dd 100644
--- a/code/game/objects/items/his_grace.dm
+++ b/code/game/objects/items/his_grace.dm
@@ -75,7 +75,7 @@
drowse()
return
if(bloodthirst < HIS_GRACE_CONSUME_OWNER)
- adjust_bloodthirst(1 + Floor(LAZYLEN(contents) * 0.5)) //Maybe adjust this?
+ adjust_bloodthirst(1 + FLOOR(LAZYLEN(contents) * 0.5, 1)) //Maybe adjust this?
else
adjust_bloodthirst(1) //don't cool off rapidly once we're at the point where His Grace consumes all.
var/mob/living/master = get_atom_on_turf(src, /mob/living)
@@ -164,9 +164,9 @@
/obj/item/his_grace/proc/adjust_bloodthirst(amt)
prev_bloodthirst = bloodthirst
if(prev_bloodthirst < HIS_GRACE_CONSUME_OWNER)
- bloodthirst = Clamp(bloodthirst + amt, HIS_GRACE_SATIATED, HIS_GRACE_CONSUME_OWNER)
+ bloodthirst = CLAMP(bloodthirst + amt, HIS_GRACE_SATIATED, HIS_GRACE_CONSUME_OWNER)
else
- bloodthirst = Clamp(bloodthirst + amt, HIS_GRACE_CONSUME_OWNER, HIS_GRACE_FALL_ASLEEP)
+ bloodthirst = CLAMP(bloodthirst + amt, HIS_GRACE_CONSUME_OWNER, HIS_GRACE_FALL_ASLEEP)
update_stats()
/obj/item/his_grace/proc/update_stats()
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index 7ca82c1236..f5b50542d0 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -14,6 +14,9 @@
/obj/item/implant/proc/trigger(emote, mob/living/carbon/source)
return
+/obj/item/implant/proc/on_death(emote, mob/living/carbon/source)
+ return
+
/obj/item/implant/proc/activate()
return
diff --git a/code/game/objects/items/implants/implant_chem.dm b/code/game/objects/items/implants/implant_chem.dm
index 509784a699..e266f3ab09 100644
--- a/code/game/objects/items/implants/implant_chem.dm
+++ b/code/game/objects/items/implants/implant_chem.dm
@@ -2,7 +2,7 @@
name = "chem implant"
desc = "Injects things."
icon_state = "reagents"
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
/obj/item/implant/chem/get_data()
var/dat = {"Implant Specifications:
diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm
index 8b19bb9d96..0dc22c3d83 100644
--- a/code/game/objects/items/implants/implant_explosive.dm
+++ b/code/game/objects/items/implants/implant_explosive.dm
@@ -3,7 +3,7 @@
desc = "And boom goes the weasel."
icon_state = "explosive"
actions_types = list(/datum/action/item_action/explosive_implant)
- // Explosive implant action is always availible.
+ // Explosive implant action is always available.
var/weak = 2
var/medium = 0.8
var/heavy = 0.4
@@ -11,6 +11,9 @@
var/popup = FALSE // is the DOUWANNABLOWUP window open?
var/active = FALSE
+/obj/item/implant/explosive/on_mob_death(mob/living/L, gibbed)
+ activate("death")
+
/obj/item/implant/explosive/get_data()
var/dat = {"Implant Specifications:
Name: Robust Corp RX-78 Employee Management Implant
@@ -23,10 +26,6 @@
"}
return dat
-/obj/item/implant/explosive/trigger(emote, mob/source)
- if(emote == "deathgasp")
- activate("death")
-
/obj/item/implant/explosive/activate(cause)
if(!cause || !imp_in || active)
return 0
diff --git a/code/game/objects/items/implants/implantcase.dm b/code/game/objects/items/implants/implantcase.dm
index 7c363fe052..00bda4dadb 100644
--- a/code/game/objects/items/implants/implantcase.dm
+++ b/code/game/objects/items/implants/implantcase.dm
@@ -1,79 +1,80 @@
-/obj/item/implantcase
- name = "implant case"
- desc = "A glass case containing an implant."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "implantcase-0"
- item_state = "implantcase"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- throw_speed = 2
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- materials = list(MAT_GLASS=500)
- var/obj/item/implant/imp = null
- var/imp_type
-
-/obj/item/implantcase/update_icon()
- if(imp)
- icon_state = "implantcase-[imp.item_color]"
- reagents = imp.reagents
- else
- icon_state = "implantcase-0"
- reagents = null
-
-
-/obj/item/implantcase/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/pen))
- var/t = stripped_input(user, "What would you like the label to be?", name, null)
- if(user.get_active_held_item() != W)
- return
- if(!in_range(src, user) && loc != user)
- return
- if(t)
- name = "implant case - '[t]'"
- else
- name = "implant case"
- else if(istype(W, /obj/item/implanter))
- var/obj/item/implanter/I = W
- if(I.imp)
- if(imp || I.imp.imp_in)
- return
- I.imp.loc = src
- imp = I.imp
- I.imp = null
- update_icon()
- I.update_icon()
- else
- if(imp)
- if(I.imp)
- return
- imp.loc = I
- I.imp = imp
- imp = null
- update_icon()
- I.update_icon()
-
- else
- return ..()
-
-/obj/item/implantcase/Initialize(mapload)
- . = ..()
- if(imp_type)
- imp = new imp_type(src)
- update_icon()
-
-
-/obj/item/implantcase/tracking
- name = "implant case - 'Tracking'"
- desc = "A glass case containing a tracking implant."
- imp_type = /obj/item/implant/tracking
-
-/obj/item/implantcase/weapons_auth
- name = "implant case - 'Firearms Authentication'"
- desc = "A glass case containing a firearms authentication implant."
- imp_type = /obj/item/implant/weapons_auth
-
-/obj/item/implantcase/adrenaline
- name = "implant case - 'Adrenaline'"
- desc = "A glass case containing an adrenaline implant."
- imp_type = /obj/item/implant/adrenalin
+/obj/item/implantcase
+ name = "implant case"
+ desc = "A glass case containing an implant."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "implantcase-0"
+ item_state = "implantcase"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ throw_speed = 2
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ materials = list(MAT_GLASS=500)
+ var/obj/item/implant/imp = null
+ var/imp_type
+
+
+/obj/item/implantcase/update_icon()
+ if(imp)
+ icon_state = "implantcase-[imp.item_color]"
+ reagents = imp.reagents
+ else
+ icon_state = "implantcase-0"
+ reagents = null
+
+
+/obj/item/implantcase/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/pen))
+ var/t = stripped_input(user, "What would you like the label to be?", name, null)
+ if(user.get_active_held_item() != W)
+ return
+ if(!in_range(src, user) && loc != user)
+ return
+ if(t)
+ name = "implant case - '[t]'"
+ else
+ name = "implant case"
+ else if(istype(W, /obj/item/implanter))
+ var/obj/item/implanter/I = W
+ if(I.imp)
+ if(imp || I.imp.imp_in)
+ return
+ I.imp.forceMove(src)
+ imp = I.imp
+ I.imp = null
+ update_icon()
+ I.update_icon()
+ else
+ if(imp)
+ if(I.imp)
+ return
+ imp.forceMove(I)
+ I.imp = imp
+ imp = null
+ update_icon()
+ I.update_icon()
+
+ else
+ return ..()
+
+/obj/item/implantcase/Initialize(mapload)
+ . = ..()
+ if(imp_type)
+ imp = new imp_type(src)
+ update_icon()
+
+
+/obj/item/implantcase/tracking
+ name = "implant case - 'Tracking'"
+ desc = "A glass case containing a tracking implant."
+ imp_type = /obj/item/implant/tracking
+
+/obj/item/implantcase/weapons_auth
+ name = "implant case - 'Firearms Authentication'"
+ desc = "A glass case containing a firearms authentication implant."
+ imp_type = /obj/item/implant/weapons_auth
+
+/obj/item/implantcase/adrenaline
+ name = "implant case - 'Adrenaline'"
+ desc = "A glass case containing an adrenaline implant."
+ imp_type = /obj/item/implant/adrenalin
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 5a8fcda09b..0a9e356014 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -44,7 +44,7 @@
forkload = null
else if(user.zone_selected == "eyes")
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
else
@@ -70,7 +70,7 @@
/obj/item/kitchen/knife/attack(mob/living/carbon/M, mob/living/carbon/user)
if(user.zone_selected == "eyes")
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
else
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 6e21251b6e..6fb173b905 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -99,7 +99,7 @@
return ..()
add_fingerprint(user)
- if((CLUMSY in user.disabilities) && prob(50))
+ if((user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "You club yourself over the head.")
user.Knockdown(60 * force)
if(ishuman(user))
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index b63c5bcefa..94f7de09bc 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -72,6 +72,6 @@
to_chat(user, "[src] [active ? "is now active":"can now be concealed"].")
/obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
user.take_bodypart_damage(5,5)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index 9bf0b949c0..dc0a2fe286 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -125,14 +125,14 @@
loadedWeightClass += I.w_class
return TRUE
-/obj/item/pneumatic_cannon/afterattack(atom/target, mob/living/carbon/human/user, flag, params)
+/obj/item/pneumatic_cannon/afterattack(atom/target, mob/living/user, flag, params)
if(flag && user.a_intent == INTENT_HARM) //melee attack
return
if(!istype(user))
return
Fire(user, target)
-/obj/item/pneumatic_cannon/proc/Fire(mob/living/carbon/human/user, var/atom/target)
+/obj/item/pneumatic_cannon/proc/Fire(mob/living/user, var/atom/target)
if(!istype(user) && !target)
return
var/discharge = 0
@@ -147,9 +147,10 @@
if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
return
- if(user.disabilities & CLUMSY && prob(75) && clumsyCheck)
- user.visible_message("[user] loses their grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
- user.dropItemToGround(src, TRUE)
+ if(user.has_disability(CLUMSY) && prob(75) && clumsyCheck && iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.visible_message("[C] loses their grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
+ C.dropItemToGround(src, TRUE)
if(prob(10))
target = get_turf(user)
else
@@ -163,9 +164,10 @@
var/turf/T = get_target(target, get_turf(src))
playsound(src.loc, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
fire_items(T, user)
- if(pressureSetting >= 3 && user)
- user.visible_message("[user] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
- user.Knockdown(60)
+ if(pressureSetting >= 3 && iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.visible_message("[C] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
+ C.Knockdown(60)
/obj/item/pneumatic_cannon/proc/fire_items(turf/target, mob/user)
if(fire_mode == PCANNON_FIREALL)
@@ -198,8 +200,8 @@
return target
var/x_o = (target.x - starting.x)
var/y_o = (target.y - starting.y)
- var/new_x = Clamp((starting.x + (x_o * range_multiplier)), 0, world.maxx)
- var/new_y = Clamp((starting.y + (y_o * range_multiplier)), 0, world.maxy)
+ var/new_x = CLAMP((starting.x + (x_o * range_multiplier)), 0, world.maxx)
+ var/new_y = CLAMP((starting.y + (y_o * range_multiplier)), 0, world.maxy)
var/turf/newtarget = locate(new_x, new_y, starting.z)
return newtarget
@@ -271,3 +273,10 @@
selfcharge = TRUE
charge_type = /obj/item/reagent_containers/food/snacks/pie/cream
maxWeightClass = 60 //20 pies.
+
+/obj/item/pneumatic_cannon/pie/selfcharge/cyborg
+ name = "low velocity pie cannon"
+ automatic = FALSE
+ charge_type = /obj/item/reagent_containers/food/snacks/pie/cream/nostun
+ maxWeightClass = 6 //2 pies
+ charge_ticks = 2 //4 second/pie
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index e4485266b5..6c1cf93295 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,13 +347,17 @@
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
var/emaggedhitdamage = 3
+/obj/item/borg/lollipop/clown
+ emaggedhitdamage = 0
+
/obj/item/borg/lollipop/equipped()
check_amount()
@@ -379,10 +387,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 +447,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 +640,7 @@
continue
usage += projectile_tick_speed_ecost
usage += (tracked[I] * projectile_damage_tick_ecost_coefficient)
- energy = Clamp(energy - usage, 0, maxenergy)
+ energy = CLAMP(energy - usage, 0, maxenergy)
if(energy <= 0)
deactivate_field()
visible_message("[src] blinks \"ENERGY DEPLETED\".")
@@ -626,7 +650,7 @@
if(iscyborg(host.loc))
host = host.loc
else
- energy = Clamp(energy + energy_recharge, 0, maxenergy)
+ energy = CLAMP(energy + energy_recharge, 0, maxenergy)
return
if((host.cell.charge >= (host.cell.maxcharge * cyborg_cell_critical_percentage)) && (energy < maxenergy))
host.cell.use(energy_recharge*energy_recharge_cyborg_drain_coefficient)
@@ -655,7 +679,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/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 09e3ccdeb0..339b7fbf4b 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -69,7 +69,7 @@
if(!l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
if (M.use(1))
var/obj/item/ed209_assembly/B = new /obj/item/ed209_assembly
- B.loc = get_turf(src)
+ B.forceMove(drop_location())
to_chat(user, "You arm the robot frame.")
var/holding_this = user.get_inactive_held_item()==src
qdel(src)
@@ -227,7 +227,7 @@
O.job = "Cyborg"
O.cell = chest.cell
- chest.cell.loc = O
+ chest.cell.forceMove(O)
chest.cell = null
W.forceMove(O)//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
if(O.mmi) //we delete the mmi created by robot/New()
@@ -271,7 +271,7 @@
O.cell = chest.cell
- chest.cell.loc = O
+ chest.cell.forceMove(O)
chest.cell = null
O.locked = panel_locked
O.job = "Cyborg"
diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm
index fb25cb1d76..93056adc99 100644
--- a/code/game/objects/items/sharpener.dm
+++ b/code/game/objects/items/sharpener.dm
@@ -35,14 +35,14 @@
if(TH.force_wielded > initial(TH.force_wielded))
to_chat(user, "[TH] has already been refined before. It cannot be sharpened further!")
return
- TH.force_wielded = Clamp(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
+ TH.force_wielded = CLAMP(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
if(I.force > initial(I.force))
to_chat(user, "[I] has already been refined before. It cannot be sharpened further!")
return
user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.")
I.sharpness = IS_SHARP_ACCURATE
- I.force = Clamp(I.force + increment, 0, max)
- I.throwforce = Clamp(I.throwforce + increment, 0, max)
+ I.force = CLAMP(I.force + increment, 0, max)
+ I.throwforce = CLAMP(I.throwforce + increment, 0, max)
I.name = "[prefix] [I.name]"
name = "worn out [name]"
desc = "[desc] At least, it used to."
diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm
index 57306f498c..113bc9755c 100644
--- a/code/game/objects/items/shields.dm
+++ b/code/game/objects/items/shields.dm
@@ -1,142 +1,142 @@
-/obj/item/shield
- name = "shield"
- block_chance = 50
- armor = list(melee = 50, bullet = 50, laser = 50, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 80, acid = 70)
-
-/obj/item/shield/riot
- name = "riot shield"
- desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "riot"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- slot_flags = SLOT_BACK
- force = 10
- throwforce = 5
- throw_speed = 2
- throw_range = 3
- w_class = WEIGHT_CLASS_BULKY
- materials = list(MAT_GLASS=7500, MAT_METAL=1000)
- attack_verb = list("shoved", "bashed")
- var/cooldown = 0 //shield bash cooldown. based on world.time
-
-
-/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/melee/baton))
- if(cooldown < world.time - 25)
- user.visible_message("[user] bashes [src] with [W]!")
- playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
- cooldown = world.time
- else
- return ..()
-
-/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(attack_type == THROWN_PROJECTILE_ATTACK)
- final_block_chance += 30
- if(attack_type == LEAP_ATTACK)
- final_block_chance = 100
- return ..()
-
-/obj/item/shield/riot/roman
- name = "roman shield"
- desc = "Bears an inscription on the inside: \"Romanes venio domus\"."
- icon_state = "roman_shield"
- item_state = "roman_shield"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
-
-/obj/item/shield/riot/buckler
- name = "wooden buckler"
- desc = "A medieval wooden buckler."
- icon_state = "buckler"
- item_state = "buckler"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- materials = list()
- resistance_flags = FLAMMABLE
- block_chance = 30
-
-/obj/item/shield/energy
- name = "energy combat shield"
- desc = "A shield capable of stopping most melee attacks. Protects user from almost all energy projectiles. It can be retracted, expanded, and stored anywhere."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "eshield0" // eshield1 for expanded
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- force = 3
- throwforce = 3
- throw_speed = 3
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- attack_verb = list("shoved", "bashed")
- var/active = 0
-
-/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- return 0
-
-/obj/item/shield/energy/IsReflect()
- return (active)
-
-/obj/item/shield/energy/attack_self(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
- to_chat(user, "You beat yourself in the head with [src].")
- user.take_bodypart_damage(5)
- active = !active
- icon_state = "eshield[active]"
-
- if(active)
- force = 10
- throwforce = 8
- throw_speed = 2
- w_class = WEIGHT_CLASS_BULKY
- playsound(user, 'sound/weapons/saberon.ogg', 35, 1)
- to_chat(user, "[src] is now active.")
- else
- force = 3
- throwforce = 3
- throw_speed = 3
- w_class = WEIGHT_CLASS_TINY
- playsound(user, 'sound/weapons/saberoff.ogg', 35, 1)
- to_chat(user, "[src] can now be concealed.")
- add_fingerprint(user)
-
-/obj/item/shield/riot/tele
- name = "telescopic shield"
- desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "teleriot0"
- lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
- slot_flags = null
- force = 3
- throwforce = 3
- throw_speed = 3
- throw_range = 4
- w_class = WEIGHT_CLASS_NORMAL
- var/active = 0
-
-/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(active)
- return ..()
- return 0
-
-/obj/item/shield/riot/tele/attack_self(mob/living/user)
- active = !active
- icon_state = "teleriot[active]"
- playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
-
- if(active)
- force = 8
- throwforce = 5
- throw_speed = 2
- w_class = WEIGHT_CLASS_BULKY
- slot_flags = SLOT_BACK
- to_chat(user, "You extend \the [src].")
- else
- force = 3
- throwforce = 3
- throw_speed = 3
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = null
- to_chat(user, "[src] can now be concealed.")
- add_fingerprint(user)
+/obj/item/shield
+ name = "shield"
+ block_chance = 50
+ armor = list(melee = 50, bullet = 50, laser = 50, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 80, acid = 70)
+
+/obj/item/shield/riot
+ name = "riot shield"
+ desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "riot"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ slot_flags = SLOT_BACK
+ force = 10
+ throwforce = 5
+ throw_speed = 2
+ throw_range = 3
+ w_class = WEIGHT_CLASS_BULKY
+ materials = list(MAT_GLASS=7500, MAT_METAL=1000)
+ attack_verb = list("shoved", "bashed")
+ var/cooldown = 0 //shield bash cooldown. based on world.time
+
+
+/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/melee/baton))
+ if(cooldown < world.time - 25)
+ user.visible_message("[user] bashes [src] with [W]!")
+ playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
+ cooldown = world.time
+ else
+ return ..()
+
+/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(attack_type == THROWN_PROJECTILE_ATTACK)
+ final_block_chance += 30
+ if(attack_type == LEAP_ATTACK)
+ final_block_chance = 100
+ return ..()
+
+/obj/item/shield/riot/roman
+ name = "roman shield"
+ desc = "Bears an inscription on the inside: \"Romanes venio domus\"."
+ icon_state = "roman_shield"
+ item_state = "roman_shield"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+
+/obj/item/shield/riot/buckler
+ name = "wooden buckler"
+ desc = "A medieval wooden buckler."
+ icon_state = "buckler"
+ item_state = "buckler"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ materials = list()
+ resistance_flags = FLAMMABLE
+ block_chance = 30
+
+/obj/item/shield/energy
+ name = "energy combat shield"
+ desc = "A shield capable of stopping most melee attacks. Protects user from almost all energy projectiles. It can be retracted, expanded, and stored anywhere."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "eshield0" // eshield1 for expanded
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ attack_verb = list("shoved", "bashed")
+ var/active = 0
+
+/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ return 0
+
+/obj/item/shield/energy/IsReflect()
+ return (active)
+
+/obj/item/shield/energy/attack_self(mob/living/carbon/human/user)
+ if(user.has_disability(CLUMSY) && prob(50))
+ to_chat(user, "You beat yourself in the head with [src].")
+ user.take_bodypart_damage(5)
+ active = !active
+ icon_state = "eshield[active]"
+
+ if(active)
+ force = 10
+ throwforce = 8
+ throw_speed = 2
+ w_class = WEIGHT_CLASS_BULKY
+ playsound(user, 'sound/weapons/saberon.ogg', 35, 1)
+ to_chat(user, "[src] is now active.")
+ else
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ w_class = WEIGHT_CLASS_TINY
+ playsound(user, 'sound/weapons/saberoff.ogg', 35, 1)
+ to_chat(user, "[src] can now be concealed.")
+ add_fingerprint(user)
+
+/obj/item/shield/riot/tele
+ name = "telescopic shield"
+ desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "teleriot0"
+ lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
+ slot_flags = null
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ throw_range = 4
+ w_class = WEIGHT_CLASS_NORMAL
+ var/active = 0
+
+/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(active)
+ return ..()
+ return 0
+
+/obj/item/shield/riot/tele/attack_self(mob/living/user)
+ active = !active
+ icon_state = "teleriot[active]"
+ playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
+
+ if(active)
+ force = 8
+ throwforce = 5
+ throw_speed = 2
+ w_class = WEIGHT_CLASS_BULKY
+ slot_flags = SLOT_BACK
+ to_chat(user, "You extend \the [src].")
+ else
+ force = 3
+ throwforce = 3
+ throw_speed = 3
+ w_class = WEIGHT_CLASS_NORMAL
+ slot_flags = null
+ to_chat(user, "[src] can now be concealed.")
+ add_fingerprint(user)
diff --git a/code/game/objects/items/signs.dm b/code/game/objects/items/signs.dm
index 350daa0fc3..65716f2f30 100644
--- a/code/game/objects/items/signs.dm
+++ b/code/game/objects/items/signs.dm
@@ -10,13 +10,23 @@
var/label = ""
var/last_wave = 0
+/obj/item/picket_sign/cyborg
+ name = "metallic nano-sign"
+ desc = "A high tech picket sign used by silicons that can reprogram its surface at will. Probably hurts to get hit by, too."
+ force = 13
+ resistance_flags = NONE
+ actions_types = list(/datum/action/item_action/nano_picket_sign)
+
+/obj/item/picket_sign/proc/retext(mob/user)
+ var/txt = stripped_input(user, "What would you like to write on the sign?", "Sign Label", null , 30)
+ if(txt && Adjacent(user))
+ label = txt
+ name = "[label] sign"
+ desc = "It reads: [label]"
+
/obj/item/picket_sign/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen) || istype(W, /obj/item/toy/crayon))
- var/txt = stripped_input(user, "What would you like to write on the sign?", "Sign Label", null , 30)
- if(txt)
- label = txt
- src.name = "[label] sign"
- desc = "It reads: [label]"
+ retext(user)
else
return ..()
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 5276050b03..978966706e 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -9,6 +9,7 @@
points = 50
var/blink_range = 8 // The teleport range when crushed/thrown at someone.
refined_type = /obj/item/stack/sheet/bluespace_crystal
+ grind_results = list("bluespace" = 2)
/obj/item/ore/bluespace_crystal/refined
name = "refined bluespace crystal"
@@ -48,6 +49,7 @@
blink_range = 4 // Not as good as the organic stuff!
points = 0 //nice try
refined_type = null
+ grind_results = list("bluespace" = 1, "silicon" = 2)
//Polycrystals, aka stacks
/obj/item/stack/sheet/bluespace_crystal
@@ -58,6 +60,7 @@
materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
novariants = TRUE
+ grind_results = list("bluespace" = 2)
var/crystal_type = /obj/item/ore/bluespace_crystal/refined
/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 560182d9c7..7a0f85a8f2 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -111,6 +111,7 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_brute = 40
self_delay = 20
+ grind_results = list("styptic_powder" = 1)
/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -147,3 +148,4 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_burn = 40
self_delay = 20
+ grind_results = list("silver_sulfadiazine" = 1)
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 0544598246..8cc6a60efa 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -22,6 +22,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/glass
+ grind_results = list("silicon" = 1)
/obj/item/stack/sheet/glass/cyborg
materials = list()
@@ -79,6 +80,7 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 75, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmaglass
+ grind_results = list("silicon" = 1, "plasma" = 1)
/obj/item/stack/sheet/plasmaglass/fifty
amount = 50
@@ -128,6 +130,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/rglass
+ grind_results = list("silicon" = 1, "iron" = 1)
/obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -168,6 +171,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmarglass
+ grind_results = list("silicon" = 1, "plasma" = 1, "iron" = 1)
/obj/item/stack/sheet/plasmarglass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.prglass_recipes
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index a02d182f1c..051d8326b8 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -1,37 +1,38 @@
-/obj/item/stack/light_w
- name = "wired glass tile"
- singular_name = "wired glass floor tile"
- desc = "A glass tile, which is wired, somehow."
- icon = 'icons/obj/tiles.dmi'
- icon_state = "glass_wire"
- w_class = WEIGHT_CLASS_NORMAL
- force = 3
- throwforce = 5
- throw_speed = 3
- throw_range = 7
+/obj/item/stack/light_w
+ name = "wired glass tile"
+ singular_name = "wired glass floor tile"
+ desc = "A glass tile, which is wired, somehow."
+ icon = 'icons/obj/tiles.dmi'
+ icon_state = "glass_wire"
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 3
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 7
flags_1 = CONDUCT_1
- max_amount = 60
-
-/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
-
+ max_amount = 60
+ grind_results = list("silicon" = 1, "copper" = 1)
+
+/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
+
if(istype(O, /obj/item/wirecutters))
- var/obj/item/stack/cable_coil/CC = new (user.loc)
- CC.amount = 5
- CC.add_fingerprint(user)
- amount--
- var/obj/item/stack/sheet/glass/G = new (user.loc)
- G.add_fingerprint(user)
- if(amount <= 0)
- qdel(src)
-
- else if(istype(O, /obj/item/stack/sheet/metal))
- var/obj/item/stack/sheet/metal/M = O
- if (M.use(1))
- use(1)
- var/obj/item/L = new /obj/item/stack/tile/light(user.loc)
- to_chat(user, "You make a light tile.")
- L.add_fingerprint(user)
- else
- to_chat(user, "You need one metal sheet to finish the light tile!")
- else
- return ..()
+ var/obj/item/stack/cable_coil/CC = new (user.loc)
+ CC.amount = 5
+ CC.add_fingerprint(user)
+ amount--
+ var/obj/item/stack/sheet/glass/G = new (user.loc)
+ G.add_fingerprint(user)
+ if(amount <= 0)
+ qdel(src)
+
+ else if(istype(O, /obj/item/stack/sheet/metal))
+ var/obj/item/stack/sheet/metal/M = O
+ if (M.use(1))
+ use(1)
+ var/obj/item/L = new /obj/item/stack/tile/light(user.loc)
+ to_chat(user, "You make a light tile.")
+ L.add_fingerprint(user)
+ else
+ to_chat(user, "You need one metal sheet to finish the light tile!")
+ else
+ return ..()
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index e2ae00d06c..e44366daec 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -126,6 +126,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
sheettype = "uranium"
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
+ grind_results = list("uranium" = 20)
GLOBAL_LIST_INIT(uranium_recipes, list ( \
new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, one_per_turf = 1, on_floor = 1), \
@@ -149,6 +150,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
resistance_flags = FLAMMABLE
max_integrity = 100
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("plasma" = 20)
GLOBAL_LIST_INIT(plasma_recipes, list ( \
new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, one_per_turf = 1, on_floor = 1), \
@@ -182,6 +184,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
singular_name = "gold bar"
sheettype = "gold"
materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("gold" = 20)
GLOBAL_LIST_INIT(gold_recipes, list ( \
new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, one_per_turf = 1, on_floor = 1), \
@@ -207,6 +210,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
singular_name = "silver bar"
sheettype = "silver"
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("silver" = 20)
GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
@@ -232,6 +236,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
sheettype = "clown"
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
+ grind_results = list("banana" = 20)
GLOBAL_LIST_INIT(clown_recipes, list ( \
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
@@ -302,6 +307,7 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
singular_name = "snow block"
force = 1
throwforce = 2
+ grind_results = list("ice" = 20)
GLOBAL_LIST_INIT(snow_recipes, list ( \
new/datum/stack_recipe("Snow Wall", /turf/closed/wall/mineral/snow, 5, one_per_turf = 1, on_floor = 1), \
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index d8019d98a3..36b9cf210a 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -99,6 +99,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
flags_1 = CONDUCT_1
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/metal
+ grind_results = list("iron" = 20)
/obj/item/stack/sheet/metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -151,6 +152,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 80)
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/plasteel
+ grind_results = list("iron" = 20, "plasma" = 20)
/obj/item/stack/sheet/plasteel/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.plasteel_recipes
@@ -202,6 +204,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/mineral/wood
novariants = TRUE
+ grind_results = list("carbon" = 20)
/obj/item/stack/sheet/mineral/wood/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.wood_recipes
@@ -322,6 +325,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
+ grind_results = list("iron" = 0.5, "blood" = 1.5)
/obj/item/stack/sheet/runed_metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -385,6 +389,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
throw_range = 3
turf_type = /turf/open/floor/clockwork
novariants = FALSE
+ grind_results = list("iron" = 0.5, "teslium" = 1.5)
/obj/item/stack/tile/brass/narsie_act()
new /obj/item/stack/sheet/runed_metal(loc, amount)
@@ -435,6 +440,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 1
throw_range = 3
+ grind_results = list("carbon" = 1)
GLOBAL_LIST_INIT(plastic_recipes, list(
new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_floor = TRUE, time = 40), \
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 1faad3462b..cef25a0a36 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -21,6 +21,17 @@
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount
var/novariants = TRUE //Determines whether the item should update it's sprites based on amount.
+ //NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
+
+/obj/item/stack/on_grind()
+ for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
+ grind_results[grind_results[i]] *= amount //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size
+
+/obj/item/stack/grind_requirements()
+ if(is_cyborg)
+ to_chat(usr, "[src] is electronically synthesized in your chassis and can't be ground up!")
+ return
+ return TRUE
/obj/item/stack/Initialize(mapload, new_amount=null , merge = TRUE)
. = ..()
@@ -37,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
@@ -98,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))
@@ -150,8 +161,8 @@
if (href_list["sublist"] && !href_list["make"])
interact(usr, text2num(href_list["sublist"]))
if (href_list["make"])
- if (get_amount() < 1)
- qdel(src) //Never should happen
+ if (get_amount() < 1 && !is_cyborg)
+ qdel(src)
var/list/recipes_list = recipes
if (href_list["sublist"])
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 14529b4078..533858b748 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -419,7 +419,7 @@
name = "suspicious looking duffel bag"
desc = "A large duffel bag for holding extra tactical supplies."
icon_state = "duffel-syndie"
- item_state = "duffel-syndie"
+ item_state = "duffel-syndieammo"
silent = 1
slowdown = 0
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index ef04fc48f5..a06d1a509e 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -94,7 +94,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
to_chat(user, "You don't have the dexterity to do this!")
return
- if (user.disabilities & CLUMSY && prob(50))
+ if (user.has_disability(CLUMSY) && prob(50))
to_chat(user, "[src] slips out of your hand and hits your head.")
user.take_bodypart_damage(10)
user.Unconscious(400)
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index ab82f92c2d..128a313525 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -108,7 +108,7 @@
add_fingerprint(user)
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
- if(status && user.disabilities & CLUMSY && prob(50))
+ if(status && user.has_disability(CLUMSY) && prob(50))
user.visible_message("[user] accidentally hits themself with [src]!", \
"You accidentally hit yourself with [src]!")
user.Knockdown(stunforce*3)
diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm
index f1644f0b1a..6466696b98 100644
--- a/code/game/objects/items/tanks/jetpack.dm
+++ b/code/game/objects/items/tanks/jetpack.dm
@@ -17,7 +17,7 @@
/obj/item/tank/jetpack/New()
..()
if(gas_type)
- ASSERT_GAS(gas_type,air_contents)
+ air_contents.assert_gas(gas_type)
air_contents.gases[gas_type][MOLES] = (6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)
ion_trail = new
diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm
index 7a1fa569a3..4a687b458d 100644
--- a/code/game/objects/items/tanks/tank_types.dm
+++ b/code/game/objects/items/tanks/tank_types.dm
@@ -21,7 +21,7 @@
/obj/item/tank/internals/oxygen/New()
..()
- ASSERT_GAS(/datum/gas/oxygen, air_contents)
+ air_contents.assert_gas(/datum/gas/oxygen)
air_contents.gases[/datum/gas/oxygen][MOLES] = (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -87,7 +87,7 @@
/obj/item/tank/internals/plasma/New()
..()
- ASSERT_GAS(/datum/gas/plasma, air_contents)
+ air_contents.assert_gas(/datum/gas/plasma)
air_contents.gases[/datum/gas/plasma][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -124,7 +124,7 @@
/obj/item/tank/internals/plasmaman/New()
..()
- ASSERT_GAS(/datum/gas/plasma, air_contents)
+ air_contents.assert_gas(/datum/gas/plasma)
air_contents.gases[/datum/gas/plasma][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
@@ -166,7 +166,7 @@
/obj/item/tank/internals/emergency_oxygen/New()
..()
- ASSERT_GAS(/datum/gas/oxygen, air_contents)
+ air_contents.assert_gas(/datum/gas/oxygen)
air_contents.gases[/datum/gas/oxygen][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 3d1c091a2b..0109b67b00 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -194,7 +194,7 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- distribute_pressure = Clamp(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
+ distribute_pressure = CLAMP(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
/obj/item/tank/remove_air(amount)
return air_contents.remove(amount)
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 58aadadce0..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
@@ -131,7 +131,7 @@
..()
to_chat(user, "The mister snaps back onto the watertank.")
tank.on = 0
- loc = tank
+ forceMove(tank)
/obj/item/reagent_containers/spray/mister/attack_self()
return
@@ -236,13 +236,13 @@
tank = parent_tank
reagents = tank.reagents
max_water = tank.volume
- loc = tank
+ forceMove(tank)
/obj/item/extinguisher/mini/nozzle/Move()
..()
if(loc != tank.loc)
- loc = tank
+ forceMove(tank)
return
/obj/item/extinguisher/mini/nozzle/attack_self(mob/user)
@@ -268,7 +268,7 @@
..()
to_chat(user, "The nozzle snaps back onto the tank!")
tank.on = 0
- loc = tank
+ forceMove(tank)
/obj/item/extinguisher/mini/nozzle/afterattack(atom/target, mob/user)
if(nozzle_mode == EXTINGUISHER)
@@ -351,7 +351,7 @@
var/usage_ratio = 5 //5 unit added per 1 removed
var/injection_amount = 1
amount_per_transfer_from_this = 5
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = FALSE
possible_transfer_amounts = list(5,10,15)
diff --git a/code/game/objects/items/teleprod.dm b/code/game/objects/items/teleprod.dm
index 92e7a8e9ba..c780d32917 100644
--- a/code/game/objects/items/teleprod.dm
+++ b/code/game/objects/items/teleprod.dm
@@ -8,7 +8,7 @@
/obj/item/melee/baton/cattleprod/teleprod/attack(mob/living/carbon/M, mob/living/carbon/user)//handles making things teleport when hit
..()
- if(status && user.disabilities & CLUMSY && prob(50))
+ if(status && user.has_disability(CLUMSY) && prob(50))
user.visible_message("[user] accidentally hits themself with [src]!", \
"You accidentally hit yourself with [src]!")
if(do_teleport(user, get_turf(user), 50))//honk honk
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index 08f22b7e46..8fd37a3b38 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -75,7 +75,7 @@
return ..()
if(user.zone_selected != "eyes" && user.zone_selected != "head")
return ..()
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
M = user
return eyestab(M,user)
@@ -105,7 +105,7 @@
item_state = "drill"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
//done for balance reasons, making them high value for research, but harder to get
+ materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) //done for balance reasons, making them high value for research, but harder to get
force = 8 //might or might not be too high, subject to change
w_class = WEIGHT_CLASS_SMALL
throwforce = 8
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 1c20c95e93..12c056c9af 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -21,7 +21,7 @@
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30)
resistance_flags = FIRE_PROOF
- materials = list(MAT_METAL=70, MAT_GLASS=30)
+ materials = list(MAT_METAL=70, MAT_GLASS=30)
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower)
var/max_fuel = 20 //The max amount of fuel the welder can hold
@@ -51,7 +51,7 @@
cut_overlays()
if(change_icons)
var/ratio = get_fuel() / max_fuel
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
add_overlay("[initial(icon_state)][ratio]")
update_torch()
return
@@ -89,18 +89,15 @@
flamethrower_screwdriver(I, user)
else if(istype(I, /obj/item/stack/rods))
flamethrower_rods(I, user)
- else if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
- var/amountNeeded = max_fuel - get_fuel()
- var/obj/item/reagent_containers/container = I
- if(length(container.reagents.reagent_list) > 1)
- to_chat(user, "[container] has too many chemicals mixed into it. You wouldn't want to put the wrong chemicals into [src].")
- return ..()
- if(amountNeeded > 0 && container.reagents.has_reagent("welding_fuel"))
- container.reagents.trans_id_to(src, "welding_fuel", amountNeeded)
- to_chat(user, "You transfer some fuel from [container] to [src].")
else
- return ..()
+ . = ..()
+ update_icon()
+/obj/item/weldingtool/proc/explode()
+ var/turf/T = get_turf(loc)
+ var/plasmaAmount = reagents.get_reagent_amount("plasma")
+ dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
+ qdel(src)
/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user)
if(!istype(H))
@@ -123,7 +120,10 @@
/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity)
if(!proximity)
return
-
+ if(!status && O.is_refillable())
+ reagents.trans_to(O, reagents.total_volume)
+ to_chat(user, "You empty [src]'s fuel tank into [O].")
+ update_icon()
if(welding)
remove_fuel(1)
var/turf/location = get_turf(user)
@@ -139,6 +139,9 @@
/obj/item/weldingtool/attack_self(mob/user)
+ if(src.reagents.has_reagent("plasma"))
+ message_admins("[key_name_admin(user)] activated a rigged welder.")
+ explode()
switched_on(user)
if(welding)
set_light(light_intensity)
@@ -234,9 +237,11 @@
return
status = !status
if(status)
- to_chat(user, "You resecure [src].")
+ to_chat(user, "You resecure [src] and close the fuel tank.")
+ container_type = NONE
else
- to_chat(user, "[src] can now be attached and modified.")
+ to_chat(user, "[src] can now be attached, modified, and refuelled.")
+ container_type = OPENCONTAINER
add_fingerprint(user)
/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user)
@@ -264,7 +269,7 @@
desc = "A slightly larger welder with a larger tank."
icon_state = "indwelder"
max_fuel = 40
- materials = list(MAT_GLASS=60)
+ materials = list(MAT_GLASS=60)
/obj/item/weldingtool/largetank/cyborg
name = "integrated welding tool"
@@ -294,7 +299,7 @@
icon_state = "welder"
toolspeed = 0.1
light_intensity = 0
- change_icons = 0
+ change_icons = 0
/obj/item/weldingtool/abductor/process()
if(get_fuel() <= max_fuel)
@@ -307,7 +312,7 @@
icon_state = "upindwelder"
item_state = "upindwelder"
max_fuel = 80
- materials = list(MAT_METAL=70, MAT_GLASS=120)
+ materials = list(MAT_METAL=70, MAT_GLASS=120)
/obj/item/weldingtool/experimental
name = "experimental welding tool"
@@ -315,7 +320,7 @@
icon_state = "exwelder"
item_state = "exwelder"
max_fuel = 40
- materials = list(MAT_METAL=70, MAT_GLASS=120)
+ materials = list(MAT_METAL=70, MAT_GLASS=120)
var/last_gen = 0
change_icons = 0
can_off_process = 1
@@ -336,4 +341,5 @@
if(get_fuel() < max_fuel && nextrefueltick < world.time)
nextrefueltick = world.time + 10
reagents.add_reagent("welding_fuel", 1)
-#undef WELDER_FUEL_BURN_INTERVAL
\ No newline at end of file
+
+#undef WELDER_FUEL_BURN_INTERVAL
diff --git a/code/game/objects/items/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/trash.dm b/code/game/objects/items/trash.dm
index c9552a3d39..b1313ef84f 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -66,6 +66,7 @@
name = "crushed can"
icon_state = "cola"
resistance_flags = NONE
+ grind_results = list("aluminum" = 10)
/obj/item/trash/attack(mob/M, mob/living/user)
return
@@ -75,6 +76,7 @@
icon = 'icons/obj/mining.dmi'
icon_state = "slag"
desc = "Someone's gotten on the naughty list."
+ grind_results = list("carbon" = 20)
/obj/item/trash/coal/burn()
visible_message("[src] fuses into a diamond! Someone wasn't so naughty after all...")
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 9058e837ab..293ef46197 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -302,7 +302,7 @@
unwield()
return
..()
- if(user.disabilities & CLUMSY && (wielded) && prob(40))
+ if(user.has_disability(CLUMSY) && (wielded) && prob(40))
impale(user)
return
if((wielded) && prob(50))
@@ -429,6 +429,10 @@
var/obj/item/grenade/explosive = null
var/war_cry = "AAAAARGH!!!"
+/obj/item/twohanded/spear/Initialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
/obj/item/twohanded/spear/examine(mob/user)
..()
if(explosive)
@@ -447,7 +451,7 @@
return
if(explosive && wielded)
user.say("[war_cry]")
- explosive.loc = AM
+ explosive.forceMove(AM)
explosive.prime()
qdel(src)
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/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 39fbbe3335..aabbba6b2f 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -20,7 +20,7 @@
var/obj/item/canvas/C = I
user.dropItemToGround(C)
painting = C
- C.loc = get_turf(src)
+ C.forceMove(get_turf(src))
C.layer = layer+0.1
user.visible_message("[user] puts \the [C] on \the [src].","You place \the [C] on \the [src].")
else
@@ -32,7 +32,7 @@
var/turf/T = get_turf(src)
..()
if(painting && painting.loc == T) //Only move if it's near us.
- painting.loc = get_turf(src)
+ painting.forceMove(get_turf(src))
else
painting = null
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 241d7ea41c..30384d2da9 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -224,7 +224,7 @@
G.use(10)
var/obj/structure/displaycase/display = new(src.loc)
if(electronics)
- electronics.loc = display
+ electronics.forceMove(display)
display.electronics = electronics
if(electronics.one_access)
display.req_one_access = electronics.accesses
diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm
index 81c9e9cc63..f2b0efb6b7 100644
--- a/code/game/objects/structures/electricchair.dm
+++ b/code/game/objects/structures/electricchair.dm
@@ -15,7 +15,7 @@
var/obj/structure/chair/C = new /obj/structure/chair(loc)
playsound(loc, W.usesound, 50, 1)
C.setDir(dir)
- part.loc = loc
+ part.forceMove(loc)
part.master = null
part = null
qdel(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/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index 5f1fa2ebb7..d6b50d0b1a 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -81,7 +81,7 @@
return
playsound(src.loc, 'sound/effects/splat.ogg', 25, 1)
L.visible_message("[user] slams [L] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.")
- L.loc = src.loc
+ L.forceMove(drop_location())
L.emote("scream")
L.add_splatter_floor()
L.adjustBruteLoss(30)
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/noticeboard.dm b/code/game/objects/structures/noticeboard.dm
index aeca1453e3..f667832843 100644
--- a/code/game/objects/structures/noticeboard.dm
+++ b/code/game/objects/structures/noticeboard.dm
@@ -18,7 +18,7 @@
if(notices > 4)
break
if(istype(I, /obj/item/paper))
- I.loc = src
+ I.forceMove(src)
notices++
icon_state = "nboard0[notices]"
@@ -58,7 +58,7 @@
return
var/obj/item/I = locate(href_list["remove"]) in contents
if(istype(I) && I.loc == src)
- I.loc = usr.loc
+ I.forceMove(usr.loc)
usr.put_in_hands(I)
notices--
icon_state = "nboard0[notices]"
diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm
index 36233bc155..d2bee1af36 100644
--- a/code/game/objects/structures/petrified_statue.dm
+++ b/code/game/objects/structures/petrified_statue.dm
@@ -17,7 +17,7 @@
L.buckled.unbuckle_mob(L,force=1)
L.visible_message("[L]'s skin rapidly turns to marble!", "Your body freezes up! Can't... move... can't... think...")
L.forceMove(src)
- L.disabilities |= MUTE
+ L.add_disability(MUTE, STATUE_MUTE)
L.faction += "mimic" //Stops mimics from instaqdeling people in statues
L.status_flags |= GODMODE
obj_integrity = L.health + 100 //stoning damaged mobs will result in easier to shatter statues
@@ -59,7 +59,7 @@
if(petrified_mob)
petrified_mob.status_flags &= ~GODMODE
petrified_mob.forceMove(loc)
- petrified_mob.disabilities &= ~MUTE
+ petrified_mob.remove_disability(MUTE, STATUE_MUTE)
petrified_mob.take_overall_damage((petrified_mob.health - obj_integrity + 100)) //any new damage the statue incurred is transfered to the mob
petrified_mob.faction -= "mimic"
petrified_mob = null
diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm
index e47afd53d4..a8ca42bff5 100644
--- a/code/game/objects/structures/reflector.dm
+++ b/code/game/objects/structures/reflector.dm
@@ -165,7 +165,7 @@
to_chat(user, "You can't do that right now!")
return
if(!isnull(new_angle))
- setAngle(NORM_ROT(new_angle))
+ setAngle(SIMPLIFY_DEGREES(new_angle))
return TRUE
/obj/structure/reflector/AltClick(mob/user)
@@ -197,16 +197,12 @@
anchored = TRUE
/obj/structure/reflector/single/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
- var/incidence = get_angle_of_incidence(rotation_angle, P.Angle)
- var/incidence_norm = get_angle_of_incidence(rotation_angle, P.Angle, FALSE)
- if((incidence_norm > -90) && (incidence_norm < 90))
+ var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, P.Angle)
+ var/norm_inc = WRAP(incidence, -90, 90)
+ var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
+ if(ISINRANGE_EX(norm_inc, -90, 90))
return FALSE
- var/new_angle_s = rotation_angle + incidence
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- while(new_angle_s < -180)
- new_angle_s += 360
- P.Angle = new_angle_s
+ P.setAngle(new_angle)
return ..()
//DOUBLE
@@ -228,17 +224,12 @@
anchored = TRUE
/obj/structure/reflector/double/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
- var/incidence = get_angle_of_incidence(rotation_angle, P.Angle)
- var/incidence_norm = get_angle_of_incidence(rotation_angle, P.Angle, FALSE)
- var/invert = ((incidence_norm > -90) && (incidence_norm < 90))
- var/new_angle_s = rotation_angle + incidence
- if(invert)
- new_angle_s += 180
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- while(new_angle_s < -180)
- new_angle_s += 360
- P.Angle = new_angle_s
+ var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, P.Angle)
+ var/norm_inc = WRAP(incidence, -90, 90)
+ var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
+ if(ISINRANGE_EX(norm_inc, -90, 90))
+ new_angle += 180
+ P.setAngle(new_angle)
return ..()
//BOX
@@ -260,7 +251,7 @@
anchored = TRUE
/obj/structure/reflector/box/auto_reflect(obj/item/projectile/P)
- P.Angle = rotation_angle
+ P.setAngle(rotation_angle)
return ..()
/obj/structure/reflector/ex_act()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 26582515f8..95c2380802 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -121,7 +121,7 @@
T.quick_empty()
for(var/obj/item/C in oldContents)
- C.loc = src.loc
+ C.forceMove(drop_location())
user.visible_message("[user] empties [I] on [src].")
return
@@ -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/target_stake.dm b/code/game/objects/structures/target_stake.dm
index c3496678c2..58b4186ad5 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -18,7 +18,7 @@
/obj/structure/target_stake/Move()
..()
if(pinned_target)
- pinned_target.loc = loc
+ pinned_target.forceMove(loc)
/obj/structure/target_stake/attackby(obj/item/target/T, mob/user)
if(pinned_target)
@@ -36,7 +36,7 @@
/obj/structure/target_stake/proc/removeTarget(mob/user)
pinned_target.layer = OBJ_LAYER
- pinned_target.loc = user.loc
+ pinned_target.forceMove(user.loc)
pinned_target.nullPinnedLoc()
nullPinnedTarget()
if(ishuman(user))
@@ -44,7 +44,7 @@
user.put_in_hands(pinned_target)
to_chat(user, "You take the target out of the stake.")
else
- pinned_target.loc = get_turf(user)
+ pinned_target.forceMove(user.drop_location())
to_chat(user, "You take the target out of the stake.")
/obj/structure/target_stake/bullet_act(obj/item/projectile/P)
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/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index b29df0aaf4..bb5be3a501 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -216,13 +216,13 @@
if(do_after(user, 40, target = src))
if(!src || electronics)
- W.loc = src.loc
+ W.forceMove(drop_location())
return
to_chat(user, "You install the airlock electronics.")
name = "near finished windoor assembly"
electronics = W
else
- W.loc = loc
+ W.forceMove(drop_location())
//Screwdriver to remove airlock electronics. Step 6 undone.
else if(istype(W, /obj/item/screwdriver))
@@ -240,7 +240,7 @@
var/obj/item/electronics/airlock/ae
ae = electronics
electronics = null
- ae.loc = loc
+ ae.forceMove(drop_location())
else if(istype(W, /obj/item/pen))
var/t = stripped_input(user, "Enter the name for the door.", name, created_name,MAX_NAME_LEN)
@@ -285,7 +285,7 @@
else
windoor.req_access = electronics.accesses
windoor.electronics = electronics
- electronics.loc = windoor
+ electronics.forceMove(windoor)
if(created_name)
windoor.name = created_name
qdel(src)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 2b9494c535..f5aec5c274 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -283,11 +283,10 @@
return
if(!disassembled)
playsound(src, breaksound, 70, 1)
- var/turf/T = loc
if(!(flags_1 & NODECONSTRUCT_1))
for(var/i in debris)
var/obj/item/I = i
- I.loc = T
+ I.forceMove(drop_location())
transfer_fingerprints_to(I)
qdel(src)
update_nearby_icons()
@@ -380,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/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm
index 3e7540cdf6..634767c98b 100644
--- a/code/game/turfs/simulated/floor/misc_floor.dm
+++ b/code/game/turfs/simulated/floor/misc_floor.dm
@@ -146,6 +146,9 @@
var/uses_overlay = TRUE
var/obj/effect/clockwork/overlay/floor/realappearence
+/turf/open/floor/clockwork/Bless() //Who needs holy blessings when you have DADDY RATVAR?
+ return
+
/turf/open/floor/clockwork/Initialize()
. = ..()
if(uses_overlay)
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index b2ab28dcae..1419036d07 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -188,7 +188,7 @@
break
var/list/L = list(45)
- if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
+ if(ISODD(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
L += -45
// Expand the edges of our tunnel
diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm
index ecc389af88..0dab10ff92 100644
--- a/code/game/turfs/simulated/wall/misc_walls.dm
+++ b/code/game/turfs/simulated/wall/misc_walls.dm
@@ -70,6 +70,10 @@
if(realappearence)
qdel(realappearence)
realappearence = null
+ if(heated)
+ var/mob/camera/eminence/E = get_eminence()
+ if(E)
+ E.superheated_walls--
return ..()
/turf/closed/wall/clockwork/ReplaceWithLattice()
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 337bb051a8..14b7ef74b5 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -54,14 +54,14 @@
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
- var/incidence_s = get_angle_of_incidence(face_angle, P.Angle)
+ var/incidence_s = WRAP(GET_ANGLE_OF_INCIDENCE(face_angle, P.Angle), -90, 90)
var/new_angle = face_angle + incidence_s
var/new_angle_s = new_angle
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
while(new_angle_s < -180)
new_angle_s += 360
- P.Angle = new_angle_s
+ P.setAngle(new_angle_s)
return TRUE
/turf/closed/wall/proc/dismantle_wall(devastated=0, explode=0)
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 1d7b32e3a2..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.loc = 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
@@ -202,4 +204,3 @@
destination_x = dest_x
destination_y = dest_y
destination_z = dest_z
-
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 22365c4584..43651cebef 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -705,56 +705,60 @@
/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.")
/datum/admins/proc/manage_free_slots()
if(!check_rights())
return
- var/dat = "Manage Free Slots"
+ var/datum/browser/browser = new(usr, "jobmanagement", "Manage Free Slots", 520)
+ var/list/dat = list()
var/count = 0
- if(!SSticker.HasRoundStarted())
- alert(usr, "You cannot manage jobs before the round starts!")
+ if(!SSjob.initialized)
+ alert(usr, "You cannot manage jobs before the job subsystem is initialized!")
return
- for(var/datum/job/job in SSjob.occupations)
+ dat += ""
+
+ for(var/j in SSjob.occupations)
+ var/datum/job/job = j
count++
var/J_title = html_encode(job.title)
var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions))
var/J_totPos = html_encode(job.total_positions)
- if(job.total_positions < 0)
- dat += "[J_title]: [J_opPos] (unlimited)"
- else
- dat += "[J_title]: [J_opPos]/[J_totPos]"
+ dat += "| [J_title]: | [J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]"
if(job.title == "AI" || job.title == "Cyborg")
- dat += " (Cannot Late Join) "
+ dat += " (Cannot Late Join) | "
continue
- if(job.total_positions >= 0)
- dat += " Add | "
- if(job.total_positions > job.current_positions)
- dat += "Remove | "
- else
- dat += "Remove | "
- dat += "Unlimit"
else
- dat += " Limit"
- dat += "
"
+ dat += ""
+ dat += ""
+ if(job.total_positions >= 0)
+ dat += "Add | "
+ if(job.total_positions > job.current_positions)
+ dat += "Remove | "
+ else
+ dat += "Remove | "
+ dat += "Unlimit | "
+ else
+ dat += "Limit"
- dat += ""
- var/winheight = 100 + (count * 20)
- winheight = min(winheight, 690)
- usr << browse(dat, "window=players;size=375x[winheight]")
+ browser.height = min(100 + count * 20, 650)
+ browser.set_content(dat.Join())
+ browser.open()
/datum/admins/proc/create_or_modify_area()
set category = "Debug"
diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm
index 6e327db6b5..f259e9b1e9 100644
--- a/code/modules/admin/admin_investigate.dm
+++ b/code/modules/admin/admin_investigate.dm
@@ -11,6 +11,8 @@
return
switch(subject)
if("notes, memos, watchlist")
+ if(!check_rights(R_ADMIN))
+ return
browse_messages()
else
var/F = file("[GLOB.log_directory]/[subject].html")
diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm
index 9a54d094e5..bc41b489c0 100644
--- a/code/modules/admin/chat_commands.dm
+++ b/code/modules/admin/chat_commands.dm
@@ -47,7 +47,9 @@
target = AH.initiator_ckey
else
return "Ticket #[id] not found!"
- return IrcPm(target, all_params.Join(" "), sender)
+ var/res = IrcPm(target, all_params.Join(" "), sender)
+ if(res != "Message Successful")
+ return res
/datum/server_tools_command/namecheck
name = "namecheck"
@@ -92,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/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index 3336f3d0a8..480ba20b4d 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -95,7 +95,7 @@
var/obj/docking_port/stationary/SM = S
if(SM.id == "emergency_home")
var/new_dir = turn(SM.dir, 180)
- SM.loc = get_ranged_target_turf(SM, new_dir, rand(3,15))
+ SM.forceMove(get_ranged_target_turf(SM, new_dir, rand(3,15)))
break
qdel(src)
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 de8dff1518..91769ac55a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -58,6 +58,8 @@
toggle_exempt_status(C)
else if(href_list["makeAntag"])
+ if(!check_rights(R_ADMIN))
+ return
if (!SSticker.mode)
to_chat(usr, "Not until the round starts!")
return
@@ -201,7 +203,8 @@
return
else if(href_list["dbbanaddtype"])
-
+ if(!check_rights(R_BAN))
+ return
var/bantype = text2num(href_list["dbbanaddtype"])
var/banckey = href_list["dbbanaddckey"]
var/banip = href_list["dbbanaddip"]
@@ -599,6 +602,8 @@
return
else if(href_list["jobban2"])
+ if(!check_rights(R_BAN))
+ return
var/mob/M = locate(href_list["jobban2"])
if(!ismob(M))
to_chat(usr, "This can only be used on instances of type /mob.")
@@ -1029,6 +1034,8 @@
return 0 //we didn't do anything!
else if(href_list["boot2"])
+ if(!check_rights(R_ADMIN))
+ return
var/mob/M = locate(href_list["boot2"])
if (ismob(M))
if(!check_if_greater_rights_than(M.client))
@@ -1041,72 +1048,110 @@
qdel(M.client)
else if(href_list["addmessage"])
+ if(!check_rights(R_ADMIN))
+ return
var/target_ckey = href_list["addmessage"]
create_message("message", target_ckey, secret = 0)
else if(href_list["addnote"])
+ if(!check_rights(R_ADMIN))
+ return
var/target_ckey = href_list["addnote"]
create_message("note", target_ckey)
else if(href_list["addwatch"])
+ if(!check_rights(R_ADMIN))
+ return
var/target_ckey = href_list["addwatch"]
create_message("watchlist entry", target_ckey, secret = 1)
else if(href_list["addmemo"])
+ if(!check_rights(R_ADMIN))
+ return
create_message("memo", secret = 0, browse = 1)
else if(href_list["addmessageempty"])
+ if(!check_rights(R_ADMIN))
+ return
create_message("message", secret = 0)
else if(href_list["addnoteempty"])
+ if(!check_rights(R_ADMIN))
+ return
create_message("note")
else if(href_list["addwatchempty"])
+ if(!check_rights(R_ADMIN))
+ return
create_message("watchlist entry", secret = 1)
else if(href_list["deletemessage"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = href_list["deletemessage"]
delete_message(message_id)
else if(href_list["deletemessageempty"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = href_list["deletemessageempty"]
delete_message(message_id, browse = 1)
else if(href_list["editmessage"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = href_list["editmessage"]
edit_message(message_id)
else if(href_list["editmessageempty"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = href_list["editmessageempty"]
edit_message(message_id, browse = 1)
else if(href_list["secretmessage"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = href_list["secretmessage"]
toggle_message_secrecy(message_id)
else if(href_list["searchmessages"])
+ if(!check_rights(R_ADMIN))
+ return
var/target = href_list["searchmessages"]
browse_messages(index = target)
else if(href_list["nonalpha"])
+ if(!check_rights(R_ADMIN))
+ return
var/target = href_list["nonalpha"]
target = text2num(target)
browse_messages(index = target)
else if(href_list["showmessages"])
+ if(!check_rights(R_ADMIN))
+ return
var/target = href_list["showmessages"]
browse_messages(index = target)
else if(href_list["showmemo"])
+ if(!check_rights(R_ADMIN))
+ return
browse_messages("memo")
else if(href_list["showwatch"])
+ if(!check_rights(R_ADMIN))
+ return
browse_messages("watchlist entry")
else if(href_list["showwatchfilter"])
+ if(!check_rights(R_ADMIN))
+ return
browse_messages("watchlist entry", filter = 1)
else if(href_list["showmessageckey"])
+ if(!check_rights(R_ADMIN))
+ return
var/target = href_list["showmessageckey"]
var/agegate = TRUE
if (href_list["showall"])
@@ -1118,6 +1163,8 @@
browse_messages(target_ckey = target, linkless = 1)
else if(href_list["messageedits"])
+ if(!check_rights(R_ADMIN))
+ return
var/message_id = sanitizeSQL("[href_list["messageedits"]]")
var/datum/DBQuery/query_get_message_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("messages")] WHERE id = '[message_id]'")
if(!query_get_message_edits.warn_execute())
@@ -1307,7 +1354,7 @@
if(alert(usr, "Send [key_name(M)] to Prison?", "Message", "Yes", "No") != "Yes")
return
- M.loc = pick(GLOB.prisonwarp)
+ M.forceMove(pick(GLOB.prisonwarp))
to_chat(M, "You have been sent to Prison!")
log_admin("[key_name(usr)] has sent [key_name(M)] to Prison!")
@@ -1543,7 +1590,7 @@
C.admin_ghost()
var/mob/dead/observer/A = C.mob
A.ManualFollow(AM)
-
+
else if(href_list["admingetmovable"])
if(!check_rights(R_ADMIN))
return
@@ -1568,9 +1615,13 @@
C.jumptocoord(x,y,z)
else if(href_list["adminchecklaws"])
+ if(!check_rights(R_ADMIN))
+ return
output_ai_laws()
else if(href_list["admincheckdevilinfo"])
+ if(!check_rights(R_ADMIN))
+ return
var/mob/M = locate(href_list["admincheckdevilinfo"])
output_devil_info(M)
@@ -1892,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
@@ -1979,20 +2030,28 @@
Secrets_topic(href_list["secrets"],href_list)
else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster.
src.access_news_network()
else if(href_list["ac_set_channel_name"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_feed_channel.channel_name = stripped_input(usr, "Provide a Feed Channel Name.", "Network Channel Handler", "")
while (findtext(src.admincaster_feed_channel.channel_name," ") == 1)
src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,lentext(src.admincaster_feed_channel.channel_name)+1)
src.access_news_network()
else if(href_list["ac_set_channel_lock"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked
src.access_news_network()
else if(href_list["ac_submit_new_channel"])
+ if(!check_rights(R_ADMIN))
+ return
var/check = 0
for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels)
if(FC.channel_name == src.admincaster_feed_channel.channel_name)
@@ -2010,6 +2069,8 @@
src.access_news_network()
else if(href_list["ac_set_channel_receiving"])
+ if(!check_rights(R_ADMIN))
+ return
var/list/available_channels = list()
for(var/datum/newscaster/feed_channel/F in GLOB.news_network.network_channels)
available_channels += F.channel_name
@@ -2017,12 +2078,16 @@
src.access_news_network()
else if(href_list["ac_set_new_message"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_feed_message.body = adminscrub(input(usr, "Write your Feed story.", "Network Channel Handler", ""))
while (findtext(src.admincaster_feed_message.returnBody(-1)," ") == 1)
src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.returnBody(-1),2,lentext(src.admincaster_feed_message.returnBody(-1))+1)
src.access_news_network()
else if(href_list["ac_submit_new_message"])
+ if(!check_rights(R_ADMIN))
+ return
if(src.admincaster_feed_message.returnBody(-1) =="" || src.admincaster_feed_message.returnBody(-1) =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" )
src.admincaster_screen = 6
else
@@ -2037,22 +2102,32 @@
src.access_news_network()
else if(href_list["ac_create_channel"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen=2
src.access_news_network()
else if(href_list["ac_create_feed_story"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen=3
src.access_news_network()
else if(href_list["ac_menu_censor_story"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen=10
src.access_news_network()
else if(href_list["ac_menu_censor_channel"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen=11
src.access_news_network()
else if(href_list["ac_menu_wanted"])
+ if(!check_rights(R_ADMIN))
+ return
var/already_wanted = 0
if(GLOB.news_network.wanted_issue.active)
already_wanted = 1
@@ -2064,18 +2139,24 @@
src.access_news_network()
else if(href_list["ac_set_wanted_name"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_wanted_message.criminal = adminscrub(input(usr, "Provide the name of the Wanted person.", "Network Security Handler", ""))
while(findtext(src.admincaster_wanted_message.criminal," ") == 1)
src.admincaster_wanted_message.criminal = copytext(admincaster_wanted_message.criminal,2,lentext(admincaster_wanted_message.criminal)+1)
src.access_news_network()
else if(href_list["ac_set_wanted_desc"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_wanted_message.body = adminscrub(input(usr, "Provide the a description of the Wanted person and any other details you deem important.", "Network Security Handler", ""))
while (findtext(src.admincaster_wanted_message.body," ") == 1)
src.admincaster_wanted_message.body = copytext(src.admincaster_wanted_message.body,2,lentext(src.admincaster_wanted_message.body)+1)
src.access_news_network()
else if(href_list["ac_submit_wanted"])
+ if(!check_rights(R_ADMIN))
+ return
var/input_param = text2num(href_list["ac_submit_wanted"])
if(src.admincaster_wanted_message.criminal == "" || src.admincaster_wanted_message.body == "")
src.admincaster_screen = 16
@@ -2092,6 +2173,8 @@
src.access_news_network()
else if(href_list["ac_cancel_wanted"])
+ if(!check_rights(R_ADMIN))
+ return
var/choice = alert("Please confirm Wanted Issue removal.","Network Security Handler","Confirm","Cancel")
if(choice=="Confirm")
GLOB.news_network.deleteWanted()
@@ -2099,36 +2182,50 @@
src.access_news_network()
else if(href_list["ac_censor_channel_author"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_channel/FC = locate(href_list["ac_censor_channel_author"])
FC.toggleCensorAuthor()
src.access_news_network()
else if(href_list["ac_censor_channel_story_author"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"])
MSG.toggleCensorAuthor()
src.access_news_network()
else if(href_list["ac_censor_channel_story_body"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"])
MSG.toggleCensorBody()
src.access_news_network()
else if(href_list["ac_pick_d_notice"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_d_notice"])
src.admincaster_feed_channel = FC
src.admincaster_screen=13
src.access_news_network()
else if(href_list["ac_toggle_d_notice"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_channel/FC = locate(href_list["ac_toggle_d_notice"])
FC.toggleCensorDclass()
src.access_news_network()
else if(href_list["ac_view"])
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen=1
src.access_news_network()
else if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~
+ if(!check_rights(R_ADMIN))
+ return
src.admincaster_screen = text2num(href_list["ac_setScreen"])
if (src.admincaster_screen == 0)
if(src.admincaster_feed_channel)
@@ -2140,25 +2237,35 @@
src.access_news_network()
else if(href_list["ac_show_channel"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_channel/FC = locate(href_list["ac_show_channel"])
src.admincaster_feed_channel = FC
src.admincaster_screen = 9
src.access_news_network()
else if(href_list["ac_pick_censor_channel"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_censor_channel"])
src.admincaster_feed_channel = FC
src.admincaster_screen = 12
src.access_news_network()
else if(href_list["ac_refresh"])
+ if(!check_rights(R_ADMIN))
+ return
src.access_news_network()
else if(href_list["ac_set_signature"])
+ if(!check_rights(R_ADMIN))
+ return
src.admin_signature = adminscrub(input(usr, "Provide your desired signature.", "Network Identity Handler", ""))
src.access_news_network()
else if(href_list["ac_del_comment"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_comment/FC = locate(href_list["ac_del_comment"])
var/datum/newscaster/feed_message/FM = locate(href_list["ac_del_comment_msg"])
FM.comments -= FC
@@ -2166,6 +2273,8 @@
src.access_news_network()
else if(href_list["ac_lock_comment"])
+ if(!check_rights(R_ADMIN))
+ return
var/datum/newscaster/feed_message/FM = locate(href_list["ac_lock_comment"])
FM.locked ^= 1
src.access_news_network()
@@ -2262,6 +2371,8 @@
error_viewer.show_to(owner, null, href_list["viewruntime_linear"])
else if(href_list["showrelatedacc"])
+ if(!check_rights(R_ADMIN))
+ return
var/client/C = locate(href_list["client"]) in GLOB.clients
var/thing_to_check
if(href_list["showrelatedacc"] == "cid")
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/adminjump.dm b/code/modules/admin/verbs/adminjump.dm
index 1e7f89fc8d..779ea64640 100644
--- a/code/modules/admin/verbs/adminjump.dm
+++ b/code/modules/admin/verbs/adminjump.dm
@@ -34,7 +34,7 @@
log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]")
message_admins("[key_name_admin(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]")
- usr.loc = T
+ usr.forceMove(T)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Turf") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
@@ -137,7 +137,7 @@
admin_ticket_log(M, msg)
if(M)
M.forceMove(get_turf(usr))
- usr.loc = M.loc
+ usr.forceMove(M.loc)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/sendmob(mob/M in sortmobs())
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index b96c8f4bdc..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,11 +742,11 @@ 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
- Plasma.loc = Rad
+ Plasma.forceMove(Rad)
if(!Rad.active)
Rad.toggle_power()
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/assembly/flash.dm b/code/modules/assembly/flash.dm
index 81f2c75660..8feff99df4 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -30,7 +30,7 @@
holder.update_icon()
/obj/item/device/assembly/flash/proc/clown_check(mob/living/carbon/human/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
flash_carbon(user, user, 15, 0)
return 0
return 1
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index b929e83ada..6ac1ef093d 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -88,10 +88,10 @@
return 0
if(a_left)
a_left.holder = null
- a_left.loc = T
+ a_left.forceMove(T)
if(a_right)
a_right.holder = null
- a_right.loc = T
+ a_right.forceMove(T)
qdel(src)
else
..()
diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm
index e8ee742e56..d1b88e68e1 100644
--- a/code/modules/assembly/mousetrap.dm
+++ b/code/modules/assembly/mousetrap.dm
@@ -1,142 +1,142 @@
-/obj/item/device/assembly/mousetrap
- name = "mousetrap"
- desc = "A handy little spring-loaded trap for catching pesty rodents."
- icon_state = "mousetrap"
- materials = list(MAT_METAL=100)
- attachable = 1
- var/armed = 0
-
-
-/obj/item/device/assembly/mousetrap/examine(mob/user)
- ..()
- if(armed)
- to_chat(user, "The mousetrap is armed!")
- else
- to_chat(user, "The mousetrap is not armed.")
-
-/obj/item/device/assembly/mousetrap/activate()
- if(..())
- armed = !armed
- if(!armed)
- if(ishuman(usr))
- var/mob/living/carbon/human/user = usr
- if((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY && prob(50))
- to_chat(user, "Your hand slips, setting off the trigger!")
- pulse(0)
- update_icon()
- if(usr)
- playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
-
-/obj/item/device/assembly/mousetrap/describe()
- return "The pressure switch is [armed?"primed":"safe"]."
-
-/obj/item/device/assembly/mousetrap/update_icon()
- if(armed)
- icon_state = "mousetraparmed"
- else
- icon_state = "mousetrap"
- if(holder)
- holder.update_icon()
-
-/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
- if(!armed)
- return
- var/obj/item/bodypart/affecting = null
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- if(PIERCEIMMUNE in H.dna.species.species_traits)
- playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
- armed = 0
- update_icon()
- pulse(0)
- return 0
- switch(type)
- if("feet")
- if(!H.shoes)
- affecting = H.get_bodypart(pick("l_leg", "r_leg"))
- H.Knockdown(60)
- if("l_hand", "r_hand")
- if(!H.gloves)
- affecting = H.get_bodypart(type)
- H.Stun(60)
- if(affecting)
- if(affecting.receive_damage(1, 0))
- H.update_damage_overlays()
- else if(ismouse(target))
- var/mob/living/simple_animal/mouse/M = target
- visible_message("SPLAT!")
- M.splat()
- playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
- armed = 0
- update_icon()
- pulse(0)
-
-
-/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
- if(!armed)
- to_chat(user, "You arm [src].")
- else
- if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
- var/which_hand = "l_hand"
- if(!(user.active_hand_index % 2))
- which_hand = "r_hand"
- triggered(user, which_hand)
- user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- return
- to_chat(user, "You disarm [src].")
- armed = !armed
- update_icon()
- playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
-
-
-/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
- if(armed)
- if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
- var/which_hand = "l_hand"
- if(!(user.active_hand_index % 2))
- which_hand = "r_hand"
- triggered(user, which_hand)
- user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- return
- ..()
-
-
-/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
- if(armed)
- if(ismob(AM))
- var/mob/MM = AM
- if(!(MM.movement_type & FLYING))
- if(ishuman(AM))
- var/mob/living/carbon/H = AM
- if(H.m_intent == MOVE_INTENT_RUN)
- triggered(H)
- H.visible_message("[H] accidentally steps on [src].", \
- "You accidentally step on [src]")
- else if(ismouse(MM))
- triggered(MM)
- else if(AM.density) // For mousetrap grenades, set off by anything heavy
- triggered(AM)
- ..()
-
-
-/obj/item/device/assembly/mousetrap/on_found(mob/finder)
- if(armed)
- finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \
- "You accidentally trigger [src]!")
- triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
- return 1 //end the search!
- return 0
-
-
-/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
- if(!armed)
- return ..()
- visible_message("[src] is triggered by [A].")
- triggered(null)
-
-
-/obj/item/device/assembly/mousetrap/armed
- icon_state = "mousetraparmed"
- armed = TRUE
+/obj/item/device/assembly/mousetrap
+ name = "mousetrap"
+ desc = "A handy little spring-loaded trap for catching pesty rodents."
+ icon_state = "mousetrap"
+ materials = list(MAT_METAL=100)
+ attachable = 1
+ var/armed = 0
+
+
+/obj/item/device/assembly/mousetrap/examine(mob/user)
+ ..()
+ if(armed)
+ to_chat(user, "The mousetrap is armed!")
+ else
+ to_chat(user, "The mousetrap is not armed.")
+
+/obj/item/device/assembly/mousetrap/activate()
+ if(..())
+ armed = !armed
+ if(!armed)
+ if(ishuman(usr))
+ var/mob/living/carbon/human/user = usr
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ to_chat(user, "Your hand slips, setting off the trigger!")
+ pulse(0)
+ update_icon()
+ if(usr)
+ playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
+
+/obj/item/device/assembly/mousetrap/describe()
+ return "The pressure switch is [armed?"primed":"safe"]."
+
+/obj/item/device/assembly/mousetrap/update_icon()
+ if(armed)
+ icon_state = "mousetraparmed"
+ else
+ icon_state = "mousetrap"
+ if(holder)
+ holder.update_icon()
+
+/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
+ if(!armed)
+ return
+ var/obj/item/bodypart/affecting = null
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(PIERCEIMMUNE in H.dna.species.species_traits)
+ playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
+ armed = 0
+ update_icon()
+ pulse(0)
+ return 0
+ switch(type)
+ if("feet")
+ if(!H.shoes)
+ affecting = H.get_bodypart(pick("l_leg", "r_leg"))
+ H.Knockdown(60)
+ if("l_hand", "r_hand")
+ if(!H.gloves)
+ affecting = H.get_bodypart(type)
+ H.Stun(60)
+ if(affecting)
+ if(affecting.receive_damage(1, 0))
+ H.update_damage_overlays()
+ else if(ismouse(target))
+ var/mob/living/simple_animal/mouse/M = target
+ visible_message("SPLAT!")
+ M.splat()
+ playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
+ armed = 0
+ update_icon()
+ pulse(0)
+
+
+/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
+ if(!armed)
+ to_chat(user, "You arm [src].")
+ else
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ triggered(user, which_hand)
+ user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ return
+ to_chat(user, "You disarm [src].")
+ armed = !armed
+ update_icon()
+ playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
+
+
+/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
+ if(armed)
+ if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ triggered(user, which_hand)
+ user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ return
+ ..()
+
+
+/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
+ if(armed)
+ if(ismob(AM))
+ var/mob/MM = AM
+ if(!(MM.movement_type & FLYING))
+ if(ishuman(AM))
+ var/mob/living/carbon/H = AM
+ if(H.m_intent == MOVE_INTENT_RUN)
+ triggered(H)
+ H.visible_message("[H] accidentally steps on [src].", \
+ "You accidentally step on [src]")
+ else if(ismouse(MM))
+ triggered(MM)
+ else if(AM.density) // For mousetrap grenades, set off by anything heavy
+ triggered(AM)
+ ..()
+
+
+/obj/item/device/assembly/mousetrap/on_found(mob/finder)
+ if(armed)
+ finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \
+ "You accidentally trigger [src]!")
+ triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
+ return 1 //end the search!
+ return 0
+
+
+/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
+ if(!armed)
+ return ..()
+ visible_message("[src] is triggered by [A].")
+ triggered(null)
+
+
+/obj/item/device/assembly/mousetrap/armed
+ icon_state = "mousetraparmed"
+ armed = 1
diff --git a/code/modules/assembly/shock_kit.dm b/code/modules/assembly/shock_kit.dm
index 1b21738391..174312df1e 100644
--- a/code/modules/assembly/shock_kit.dm
+++ b/code/modules/assembly/shock_kit.dm
@@ -1,42 +1,39 @@
-/obj/item/assembly/shock_kit
- name = "electrohelmet assembly"
- desc = "This appears to be made from both an electropack and a helmet."
- icon = 'icons/obj/assemblies.dmi'
- icon_state = "shock_kit"
- var/obj/item/clothing/head/helmet/part1 = null
- var/obj/item/device/electropack/part2 = null
- w_class = WEIGHT_CLASS_HUGE
+/obj/item/assembly/shock_kit
+ name = "electrohelmet assembly"
+ desc = "This appears to be made from both an electropack and a helmet."
+ icon = 'icons/obj/assemblies.dmi'
+ icon_state = "shock_kit"
+ var/obj/item/clothing/head/helmet/part1 = null
+ var/obj/item/device/electropack/part2 = null
+ w_class = WEIGHT_CLASS_HUGE
flags_1 = CONDUCT_1
-
-/obj/item/assembly/shock_kit/Destroy()
- qdel(part1)
- qdel(part2)
- return ..()
-
-/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/wrench))
- var/turf/T = loc
- if(ismob(T))
- T = T.loc
- part1.loc = T
- part2.loc = T
- part1.master = null
- part2.master = null
- part1 = null
- part2 = null
- qdel(src)
- return
- add_fingerprint(user)
- return
-
-/obj/item/assembly/shock_kit/attack_self(mob/user)
- part1.attack_self(user)
- part2.attack_self(user)
- add_fingerprint(user)
- return
-
-/obj/item/assembly/shock_kit/receive_signal()
- if(istype(loc, /obj/structure/chair/e_chair))
- var/obj/structure/chair/e_chair/C = loc
- C.shock()
- return
+
+/obj/item/assembly/shock_kit/Destroy()
+ qdel(part1)
+ qdel(part2)
+ return ..()
+
+/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/wrench))
+ part1.forceMove(drop_location())
+ part2.forceMove(drop_location())
+ part1.master = null
+ part2.master = null
+ part1 = null
+ part2 = null
+ qdel(src)
+ return
+ add_fingerprint(user)
+ return
+
+/obj/item/assembly/shock_kit/attack_self(mob/user)
+ part1.attack_self(user)
+ part2.attack_self(user)
+ add_fingerprint(user)
+ return
+
+/obj/item/assembly/shock_kit/receive_signal()
+ if(istype(loc, /obj/structure/chair/e_chair))
+ var/obj/structure/chair/e_chair/C = loc
+ C.shock()
+ return
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 3f2bceaa04..36dd30731e 100644
--- a/code/modules/atmospherics/machinery/portable/pump.dm
+++ b/code/modules/atmospherics/machinery/portable/pump.dm
@@ -131,11 +131,11 @@
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)
- holding.loc = get_turf(src)
+ holding.forceMove(drop_location())
holding = null
. = TRUE
update_icon()
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index 564e6d294f..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.
@@ -96,7 +96,7 @@
. = TRUE
if("eject")
if(holding)
- holding.loc = get_turf(src)
+ holding.forceMove(drop_location())
holding = null
. = TRUE
if("toggle_filter")
diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm
index 15c5deb4cb..90b2e3a02e 100644
--- a/code/modules/awaymissions/gateway.dm
+++ b/code/modules/awaymissions/gateway.dm
@@ -199,9 +199,9 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
active = 1
update_icon()
-/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C)
- for(var/obj/item/implant/exile/E in C.implants)//Checking that there is an exile implant
- to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.")
+/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/L)
+ for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant
+ to_chat(L, "\black The station gate has detected your exile implant and is blocking your entry.")
return TRUE
return FALSE
@@ -212,17 +212,17 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
return
if(!stationgate || QDELETED(stationgate))
return
- if(istype(AM, /mob/living/carbon))
+ if(isliving(AM))
if(check_exile_implant(AM))
return
else
- for(var/mob/living/carbon/C in AM.contents)
- if(check_exile_implant(C))
+ for(var/mob/living/L in AM.contents)
+ if(check_exile_implant(L))
say("Rejecting [AM]: Exile implant detected in contained lifeform.")
return
if(AM.has_buckled_mobs())
- for(var/mob/living/carbon/C in AM.buckled_mobs)
- if(check_exile_implant(C))
+ for(var/mob/living/L in AM.buckled_mobs)
+ if(check_exile_implant(L))
say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
return
AM.forceMove(get_step(stationgate.loc, SOUTH))
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index 5af834955f..bf256fecbd 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -207,7 +207,7 @@
//Swarm of creatures
for(var/direction in GLOB.alldirs)
var/turf/T = get_turf(src)
- new /mob/living/simple_animal/hostile/creature(get_step(T,direction))
+ new /mob/living/simple_animal/hostile/netherworld(get_step(T,direction))
if(4)
//Destroy Equipment
for (var/obj/item/I in user)
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..4c5d8e7a4c 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -152,7 +152,7 @@ GLOBAL_LIST(external_rsc_urls)
#if (PRELOAD_RSC == 0)
var/static/next_external_rsc = 0
if(external_rsc_urls && external_rsc_urls.len)
- next_external_rsc = Wrap(next_external_rsc+1, 1, external_rsc_urls.len+1)
+ next_external_rsc = WRAP(next_external_rsc+1, 1, external_rsc_urls.len+1)
preload_rsc = external_rsc_urls[next_external_rsc]
#endif
@@ -199,9 +199,7 @@ GLOBAL_LIST(external_rsc_urls)
prefs.parent = src
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
- if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps)
- vars["fps"] = prefs.clientfps
- sethotkeys(1) //set hoykeys from preferences (from_pref = 1)
+ fps = prefs.clientfps
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[byond_version]")
var/alert_mob_dupe_login = FALSE
@@ -227,6 +225,13 @@ GLOBAL_LIST(external_rsc_urls)
message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ")
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).")
+ if(GLOB.player_details[ckey])
+ player_details = GLOB.player_details[ckey]
+ else
+ player_details = new
+ GLOB.player_details[ckey] = player_details
+
+
. = ..() //calls mob.Login()
chatOutput.start() // Starts the chat
@@ -673,6 +678,13 @@ GLOBAL_LIST(external_rsc_urls)
return TRUE
. = ..()
+/client/proc/rescale_view(change, min, max)
+ var/viewscale = getviewsize(view)
+ var/x = viewscale[1]
+ var/y = viewscale[2]
+ x = CLAMP(x+change, min, max)
+ y = CLAMP(y+change, min,max)
+ change_view("[x]x[y]")
/client/proc/change_view(new_size)
if (isnull(new_size))
diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm
new file mode 100644
index 0000000000..a842607235
--- /dev/null
+++ b/code/modules/client/player_details.dm
@@ -0,0 +1,2 @@
+/datum/player_details
+ var/list/player_actions = list()
\ No newline at end of file
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 175a23c91e..730b98ede5 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1282,16 +1282,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
preferred_map = maplist[pickedmap]
if ("clientfps")
- var/version_message
- if (user.client && user.client.byond_version < 511)
- version_message = "\nYou need to be using byond version 511 or later to take advantage of this feature, your version of [user.client.byond_version] is too low"
- if (world.byond_version < 511)
- version_message += "\nThis server does not currently support client side fps. You can set now for when it does."
- var/desiredfps = input(user, "Choose your desired fps.[version_message]\n(0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
+ var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
if (!isnull(desiredfps))
clientfps = desiredfps
- if (world.byond_version >= 511 && user.client && user.client.byond_version >= 511)
- user.client.vars["fps"] = clientfps
+ parent.fps = desiredfps
if("ui")
var/pickedui = input(user, "Choose your UI style.", "Character Preference") as null|anything in list("Midnight", "Plasmafire", "Retro", "Slimecore", "Operative", "Clockwork")
if(pickedui)
@@ -1596,12 +1590,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
toggles ^= MIDROUND_ANTAG
if("parallaxup")
- parallax = Wrap(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
if (parent && parent.mob && parent.mob.hud_used)
parent.mob.hud_used.update_parallax_pref(parent.mob)
if("parallaxdown")
- parallax = Wrap(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
if (parent && parent.mob && parent.mob.hud_used)
parent.mob.hud_used.update_parallax_pref(parent.mob)
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 29990a299b..ddb1cf5545 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -41,7 +41,7 @@
/obj/item/clothing/glasses/proc/thermal_overload()
if(ishuman(src.loc))
var/mob/living/carbon/human/H = src.loc
- if(!(H.disabilities & BLIND))
+ if(!(H.has_disability(BLIND)))
if(H.glasses == src)
to_chat(H, "[src] overloads and blinds you!")
H.flash_act(visual = 1)
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 5691dbb782..15d4579d33 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -283,7 +283,7 @@
for(var/obj/item/device/flashlight/seclite/S in src)
to_chat(user, "You unscrew the seclite from [src].")
F = null
- S.loc = get_turf(user)
+ S.forceMove(user.drop_location())
update_helmlight(user)
S.update_brightness(user)
update_icon()
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 1715636b57..2b25188b80 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -98,7 +98,7 @@
I.flags_1 &= ~NODROP_1
if(camera)
camera.remove_target_ui()
- camera.loc = user
+ camera.forceMove(user)
teleport_now.UpdateButtonIcon()
/obj/item/clothing/suit/space/chronos/proc/chronowalk(atom/location)
@@ -278,19 +278,19 @@
if(loc == user)
forceMove(get_turf(user))
if(user.client && user.client.eye != src)
- src.loc = get_turf(user)
+ src.forceMove(user.drop_location())
user.reset_perspective(src)
user.set_machine(src)
var/atom/step = get_step(src, direction)
if(step)
if((step.x <= TRANSITIONEDGE) || (step.x >= (world.maxx - TRANSITIONEDGE - 1)) || (step.y <= TRANSITIONEDGE) || (step.y >= (world.maxy - TRANSITIONEDGE - 1)))
if(!src.Move(step))
- src.loc = step
+ src.forceMove(step)
else
- src.loc = step
+ src.forceMove(step)
if((x == holder.x) && (y == holder.y) && (z == holder.z))
remove_target_ui()
- loc = user
+ forceMove(user)
else if(!target_ui)
create_target_ui()
phase_time = world.time + phase_time_length
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 cc1df785b5..58eac96f78 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -136,7 +136,7 @@
return
jetpack.turn_off()
- jetpack.loc = get_turf(src)
+ jetpack.forceMove(drop_location())
jetpack = null
to_chat(user, "You successfully remove the jetpack from [src].")
@@ -654,7 +654,7 @@
/obj/item/clothing/suit/space/hardsuit/shielded/process()
if(world.time > recharge_cooldown && current_charges < max_charges)
- current_charges = Clamp((current_charges + recharge_rate), 0, max_charges)
+ current_charges = CLAMP((current_charges + recharge_rate), 0, max_charges)
playsound(loc, 'sound/magic/charge.ogg', 50, 1)
if(current_charges == max_charges)
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index f50f6eaf6a..7c7599af3d 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -1,48 +1,49 @@
-/obj/item/clothing/suit/toggle/labcoat
- name = "labcoat"
- desc = "A suit that protects against minor chemical spills."
- icon_state = "labcoat"
- item_state = "labcoat"
- blood_overlay_type = "coat"
- body_parts_covered = CHEST|ARMS
- allowed = list(/obj/item/device/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/device/healthanalyzer, /obj/item/device/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/soap, /obj/item/device/sensor_device, /obj/item/tank/internals/emergency_oxygen)
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0, fire = 50, acid = 50)
- togglename = "buttons"
-
-/obj/item/clothing/suit/toggle/labcoat/cmo
- name = "chief medical officer's labcoat"
- desc = "Bluer than the standard model."
- icon_state = "labcoat_cmo"
- item_state = "labcoat_cmo"
-
-/obj/item/clothing/suit/toggle/labcoat/emt
- name = "EMT's jacket"
- desc = "A dark blue jacket with reflective strips for emergency medical technicians."
- icon_state = "labcoat_emt"
- item_state = "labcoat_cmo"
-
-/obj/item/clothing/suit/toggle/labcoat/mad
- name = "\improper The Mad's labcoat"
- desc = "It makes you look capable of konking someone on the noggin and shooting them into space."
- icon_state = "labgreen"
- item_state = "labgreen"
-
-/obj/item/clothing/suit/toggle/labcoat/genetics
- name = "geneticist labcoat"
- desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
- icon_state = "labcoat_gen"
-
-/obj/item/clothing/suit/toggle/labcoat/chemist
- name = "chemist labcoat"
- desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder."
- icon_state = "labcoat_chem"
-
-/obj/item/clothing/suit/toggle/labcoat/virologist
- name = "virologist labcoat"
- desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
- icon_state = "labcoat_vir"
-
-/obj/item/clothing/suit/toggle/labcoat/science
- name = "scientist labcoat"
- desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
- icon_state = "labcoat_tox"
\ No newline at end of file
+/obj/item/clothing/suit/toggle/labcoat
+ name = "labcoat"
+ desc = "A suit that protects against minor chemical spills."
+ icon_state = "labcoat"
+ item_state = "labcoat"
+ blood_overlay_type = "coat"
+ body_parts_covered = CHEST|ARMS
+ allowed = list(/obj/item/device/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/device/healthanalyzer, /obj/item/device/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/soap, /obj/item/device/sensor_device, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0, fire = 50, acid = 50)
+ togglename = "buttons"
+ species_exception = list(/datum/species/golem)
+
+/obj/item/clothing/suit/toggle/labcoat/cmo
+ name = "chief medical officer's labcoat"
+ desc = "Bluer than the standard model."
+ icon_state = "labcoat_cmo"
+ item_state = "labcoat_cmo"
+
+/obj/item/clothing/suit/toggle/labcoat/emt
+ name = "EMT's jacket"
+ desc = "A dark blue jacket with reflective strips for emergency medical technicians."
+ icon_state = "labcoat_emt"
+ item_state = "labcoat_cmo"
+
+/obj/item/clothing/suit/toggle/labcoat/mad
+ name = "\improper The Mad's labcoat"
+ desc = "It makes you look capable of konking someone on the noggin and shooting them into space."
+ icon_state = "labgreen"
+ item_state = "labgreen"
+
+/obj/item/clothing/suit/toggle/labcoat/genetics
+ name = "geneticist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
+ icon_state = "labcoat_gen"
+
+/obj/item/clothing/suit/toggle/labcoat/chemist
+ name = "chemist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder."
+ icon_state = "labcoat_chem"
+
+/obj/item/clothing/suit/toggle/labcoat/virologist
+ name = "virologist labcoat"
+ desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
+ icon_state = "labcoat_vir"
+
+/obj/item/clothing/suit/toggle/labcoat/science
+ name = "scientist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
+ icon_state = "labcoat_tox"
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index f983ca2563..49364e76d9 100644
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -15,11 +15,11 @@
if(U.pockets) // storage items conflict
return FALSE
- pockets.loc = U
+ pockets.forceMove(U)
U.pockets = pockets
U.attached_accessory = src
- loc = U
+ forceMove(U)
layer = FLOAT_LAYER
plane = FLOAT_PLANE
if(minimize_when_attached)
@@ -39,7 +39,7 @@
/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user)
if(pockets && pockets == U.pockets)
- pockets.loc = src
+ pockets.forceMove(src)
U.pockets = null
for(var/armor_type in armor)
@@ -135,7 +135,7 @@
"You pin \the [src] on [M]'s chest.")
if(input)
SSblackbox.record_feedback("associative", "commendation", 1, list("commender" = "[user.real_name]", "commendee" = "[M.real_name]", "medal" = "[src]", "reason" = input))
- GLOB.commendations += "[user.real_name] awarded [M.real_name] the [name]! \n- [input]"
+ GLOB.commendations += "[user.real_name] awarded [M.real_name] the [name]! \n- [input]"
commended = TRUE
log_game("[key_name(M)] was given the following commendation by [key_name(user)]: [input]")
message_admins("[key_name(M)] was given the following commendation by [key_name(user)]: [input]")
diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm
index 3e4e93ca4c..85ae7c3b18 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -98,7 +98,7 @@
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
- if(RC.container_type & OPENCONTAINER_1)
+ if(RC.is_drainable())
for(var/datum/reagent/A in RC.reagents.reagent_list)
.[A.type] += A.volume
.[I.type] += 1
diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm
index 9415bef33d..793805977c 100644
--- a/code/modules/detectivework/footprints_and_rag.dm
+++ b/code/modules/detectivework/footprints_and_rag.dm
@@ -13,7 +13,7 @@
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
amount_per_transfer_from_this = 5
possible_transfer_amounts = list()
volume = 5
diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm
index a5b23623f2..471dad12d7 100644
--- a/code/modules/events/_event.dm
+++ b/code/modules/events/_event.dm
@@ -29,8 +29,8 @@
/datum/round_event_control/New()
if(config && !wizardevent) // Magic is unaffected by configs
- earliest_start = Ceiling(earliest_start * CONFIG_GET(number/events_min_time_mul))
- min_players = Ceiling(min_players * CONFIG_GET(number/events_min_players_mul))
+ earliest_start = CEILING(earliest_start * CONFIG_GET(number/events_min_time_mul), 1)
+ min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1)
/datum/round_event_control/wizard
wizardevent = 1
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index e898729f2d..c2f98be8d5 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -67,12 +67,12 @@
kill()
return
- if(IsMultiple(activeFor, 4))
+ if(ISMULTIPLE(activeFor, 4))
var/obj/machinery/vending/rebel = pick(vendingMachines)
vendingMachines.Remove(rebel)
infectedMachines.Add(rebel)
rebel.shut_up = 0
rebel.shoot_inventory = 1
- if(IsMultiple(activeFor, 8))
+ if(ISMULTIPLE(activeFor, 8))
originMachine.speak(pick(rampant_speeches))
\ No newline at end of file
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index eb7625e08c..5c28632c89 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -10,6 +10,8 @@
var/virus_type
+ var/max_severity = 3
+
/datum/round_event/disease_outbreak/announce(fake)
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak7.ogg')
@@ -17,8 +19,14 @@
/datum/round_event/disease_outbreak/setup()
announceWhen = rand(15, 30)
+
/datum/round_event/disease_outbreak/start()
- if(!virus_type)
+ var/advanced_virus = FALSE
+ max_severity = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes
+ if(prob(20 + (10 * max_severity)))
+ advanced_virus = TRUE
+
+ if(!virus_type && !advanced_virus)
virus_type = pick(/datum/disease/dnaspread, /datum/disease/advance/flu, /datum/disease/advance/cold, /datum/disease/brainrot, /datum/disease/magnitis)
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
@@ -41,16 +49,48 @@
continue
var/datum/disease/D
- if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
- if(!H.dna || (H.disabilities & BLIND)) //A blindness disease would be the worst.
- continue
- D = new virus_type()
- var/datum/disease/dnaspread/DS = D
- DS.strain_data["name"] = H.real_name
- DS.strain_data["UI"] = H.dna.uni_identity
- DS.strain_data["SE"] = H.dna.struc_enzymes
+ if(!advanced_virus)
+ if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
+ if(!H.dna || (H.has_disability(BLIND))) //A blindness disease would be the worst.
+ continue
+ D = new virus_type()
+ var/datum/disease/dnaspread/DS = D
+ DS.strain_data["name"] = H.real_name
+ DS.strain_data["UI"] = H.dna.uni_identity
+ DS.strain_data["SE"] = H.dna.struc_enzymes
+ else
+ D = new virus_type()
else
- D = new virus_type()
+ D = make_virus(max_severity, max_severity)
D.carrier = TRUE
H.AddDisease(D)
- break
\ No newline at end of file
+
+ if(advanced_virus)
+ var/datum/disease/advance/A = D
+ var/list/name_symptoms = list() //for feedback
+ for(var/datum/symptom/S in A.symptoms)
+ name_symptoms += S.name
+ message_admins("An event has triggered a random advanced virus outbreak on [key_name_admin(H)]! It has these symptoms: [english_list(name_symptoms)]")
+ log_game("An event has triggered a random advanced virus outbreak on [key_name(H)]! It has these symptoms: [english_list(name_symptoms)]")
+ break
+
+/datum/round_event/disease_outbreak/proc/make_virus(max_symptoms, max_level)
+ if(max_symptoms > SYMPTOM_LIMIT)
+ max_symptoms = SYMPTOM_LIMIT
+ var/datum/disease/advance/A = new(FALSE, null)
+ A.symptoms = list()
+ var/list/datum/symptom/possible_symptoms = list()
+ for(var/symptom in subtypesof(/datum/symptom))
+ var/datum/symptom/S = symptom
+ if(initial(S.level) > max_level)
+ continue
+ if(initial(S.level) <= 0) //unobtainable symptoms
+ continue
+ possible_symptoms += S
+ for(var/i in 1 to max_symptoms)
+ var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
+ if(chosen_symptom)
+ var/datum/symptom/S = new chosen_symptom
+ A.symptoms += S
+ A.Refresh() //just in case someone already made and named the same disease
+ return A
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index 41ff90407d..abb5a0639d 100644
--- a/code/modules/events/holiday/vday.dm
+++ b/code/modules/events/holiday/vday.dm
@@ -45,19 +45,26 @@
to_chat(L, "You didn't get a date! They're all having fun without you! you'll show them though...")
var/datum/objective/martyr/normiesgetout = new
normiesgetout.owner = L.mind
+ L.mind.special_role = "heartbreaker"
SSticker.mode.traitors |= L.mind
L.mind.objectives += normiesgetout
+ L.mind.add_antag_datum(/datum/antagonist/auto_custom)
+
/proc/forge_valentines_objective(mob/living/lover,mob/living/date)
SSticker.mode.traitors |= lover.mind
lover.mind.special_role = "valentine"
+
var/datum/objective/protect/protect_objective = new /datum/objective/protect
protect_objective.owner = lover.mind
protect_objective.target = date.mind
protect_objective.explanation_text = "Protect [date.real_name], your date."
lover.mind.objectives += protect_objective
+
+ lover.mind.add_antag_datum(/datum/antagonist/auto_custom)
+
to_chat(lover, "You're on a date with [date]! Protect them at all costs. This takes priority over all other loyalties.")
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index 2f5618714d..956a214009 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -1,19 +1,3 @@
-/datum/round_event_control/treevenge
- name = "Treevenge (Christmas)"
- holidayID = CHRISTMAS
- typepath = /datum/round_event/treevenge
- max_occurrences = 1
- weight = 20
-
-/datum/round_event/treevenge/start()
- for(var/obj/structure/flora/tree/pine/xmas in world)
- var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc)
- evil_tree.icon_state = xmas.icon_state
- evil_tree.icon_living = evil_tree.icon_state
- evil_tree.icon_dead = evil_tree.icon_state
- evil_tree.icon_gib = evil_tree.icon_state
- qdel(xmas) //b-but I don't want to delete xmas...
-
//this is an example of a possible round-start event
/datum/round_event_control/presents
name = "Presents under Trees (Christmas)"
@@ -24,12 +8,11 @@
earliest_start = 0
/datum/round_event/presents/start()
- for(var/obj/structure/flora/tree/pine/xmas in world)
+ for(var/obj/structure/flora/tree/pine/xmas/xmas in world)
if(!(xmas.z in GLOB.station_z_levels))
continue
- for(var/turf/open/floor/T in orange(1,xmas))
- for(var/i=1,i<=rand(1,5),i++)
- new /obj/item/a_gift(T)
+ xmas.icon_state = "pinepresents"
+ xmas.gifts_under_tree = TRUE
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/Ian in GLOB.mob_living_list)
Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
for(var/obj/machinery/computer/security/telescreen/entertainment/Monitor in GLOB.machines)
@@ -98,7 +81,7 @@
name = "Santa is coming to town! (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/santa
- weight = 150
+ weight = 20
max_occurrences = 1
earliest_start = 20000
diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm
index b933e566be..9612fd8018 100644
--- a/code/modules/events/immovable_rod.dm
+++ b/code/modules/events/immovable_rod.dm
@@ -12,6 +12,16 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
typepath = /datum/round_event/immovable_rod
min_players = 15
max_occurrences = 5
+ var/atom/special_target
+
+
+/datum/round_event_control/immovable_rod/admin_setup()
+ if(!check_rights(R_FUN))
+ return
+
+ var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No")
+ if(aimed == "Yes")
+ special_target = get_turf(usr)
/datum/round_event/immovable_rod
announceWhen = 5
@@ -20,10 +30,11 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
priority_announce("What the fuck was that?!", "General Alert")
/datum/round_event/immovable_rod/start()
+ var/datum/round_event_control/immovable_rod/C = control
var/startside = pick(GLOB.cardinals)
var/turf/startT = spaceDebrisStartLoc(startside, ZLEVEL_STATION_PRIMARY)
var/turf/endT = spaceDebrisFinishLoc(startside, ZLEVEL_STATION_PRIMARY)
- new /obj/effect/immovablerod(startT, endT)
+ new /obj/effect/immovablerod(startT, endT, C.special_target)
/obj/effect/immovablerod
name = "immovable rod"
@@ -36,18 +47,28 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
var/z_original = 0
var/destination
var/notify = TRUE
+ var/atom/special_target
-/obj/effect/immovablerod/New(atom/start, atom/end)
+/obj/effect/immovablerod/New(atom/start, atom/end, aimed_at)
..()
SSaugury.register_doom(src, 2000)
z_original = z
destination = end
+ special_target = aimed_at
if(notify)
notify_ghosts("\A [src] is inbound!",
enter_link="(Click to orbit)",
source=src, action=NOTIFY_ORBIT)
GLOB.poi_list += src
- if(end && end.z==z_original)
+
+ var/special_target_valid = FALSE
+ if(special_target)
+ var/turf/T = get_turf(special_target)
+ if(T.z == z_original)
+ special_target_valid = TRUE
+ if(special_target_valid)
+ walk_towards(src, special_target, 1)
+ else if(end && end.z==z_original)
walk_towards(src, destination, 1)
/obj/effect/immovablerod/Topic(href, href_list)
@@ -60,11 +81,20 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
GLOB.poi_list -= src
. = ..()
-/obj/effect/immovablerod/Move()
+/obj/effect/immovablerod/Moved()
if((z != z_original) || (loc == destination))
qdel(src)
+ if(special_target && loc == get_turf(special_target))
+ complete_trajectory()
return ..()
+/obj/effect/immovablerod/proc/complete_trajectory()
+ //We hit what we wanted to hit, time to go
+ special_target = null
+ destination = get_edge_target_turf(src, dir)
+ walk(src,0)
+ walk_towards(src, destination, 1)
+
/obj/effect/immovablerod/ex_act(severity, target)
return 0
@@ -83,6 +113,9 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
x = clong.x
y = clong.y
+ if(special_target && clong == special_target)
+ complete_trajectory()
+
if(isturf(clong) || isobj(clong))
if(clong.density)
clong.ex_act(EXPLODE_HEAVY)
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index 35eb02f082..798bcf82dd 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -49,7 +49,7 @@
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
- if(IsMultiple(activeFor, 3))
+ if(ISMULTIPLE(activeFor, 3))
spawn_meteors(5, wave_type) //meteor list types defined in gamemode/meteor/meteors.dm
/datum/round_event_control/meteor_wave/threatening
diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm
index 073ef8aea3..76188cb5b7 100644
--- a/code/modules/events/nightmare.dm
+++ b/code/modules/events/nightmare.dm
@@ -35,6 +35,7 @@
player_mind.assigned_role = "Nightmare"
player_mind.special_role = "Nightmare"
SSticker.mode.traitors += player_mind
+ player_mind.add_antag_datum(/datum/antagonist/auto_custom)
S.set_species(/datum/species/shadow/nightmare)
playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
message_admins("[key_name_admin(S)] has been made into a Nightmare by an event.")
diff --git a/code/modules/events/operative.dm b/code/modules/events/operative.dm
index 47130ff924..894ad7e995 100644
--- a/code/modules/events/operative.dm
+++ b/code/modules/events/operative.dm
@@ -27,31 +27,13 @@
A.copy_to(operative)
operative.dna.update_dna_identity()
- operative.equipOutfit(/datum/outfit/syndicate/full)
-
var/datum/mind/Mind = new /datum/mind(selected.key)
Mind.assigned_role = "Lone Operative"
Mind.special_role = "Lone Operative"
- SSticker.mode.traitors |= Mind
Mind.active = 1
- var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.machines
- if(nuke)
- var/nuke_code
- if(!nuke.r_code || nuke.r_code == "ADMIN")
- nuke_code = random_nukecode()
- nuke.r_code = nuke_code
- else
- nuke_code = nuke.r_code
-
- Mind.store_memory("Station Self-Destruct Device Code: [nuke_code]", 0, 0)
- to_chat(Mind.current, "The nuclear authorization code is: [nuke_code]")
-
- var/datum/objective/nuclear/O = new()
- O.owner = Mind
- Mind.objectives += O
-
Mind.transfer_to(operative)
+ Mind.add_antag_datum(/datum/antagonist/nukeop/lone)
message_admins("[key_name_admin(operative)] has been made into lone operative by an event.")
log_game("[key_name(operative)] was spawned as a lone operative by an event.")
diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm
index 7e17124d59..55d9e69f71 100644
--- a/code/modules/events/portal_storm.dm
+++ b/code/modules/events/portal_storm.dm
@@ -64,7 +64,7 @@
T = safepick(get_area_turfs(pick(station_areas)))
hostiles_spawn += T
- next_boss_spawn = startWhen + Ceiling(2 * number_of_hostiles / number_of_bosses)
+ next_boss_spawn = startWhen + CEILING(2 * number_of_hostiles / number_of_bosses, 1)
/datum/round_event/portal_storm/announce(fake)
set waitfor = 0
@@ -117,14 +117,14 @@
/datum/round_event/portal_storm/proc/spawn_hostile()
if(!hostile_types || !hostile_types.len)
return 0
- return IsMultiple(activeFor, 2)
+ return ISMULTIPLE(activeFor, 2)
/datum/round_event/portal_storm/proc/spawn_boss()
if(!boss_types || !boss_types.len)
return 0
if(activeFor == next_boss_spawn)
- next_boss_spawn += Ceiling(number_of_hostiles / number_of_bosses)
+ next_boss_spawn += CEILING(number_of_hostiles / number_of_bosses, 1)
return 1
/datum/round_event/portal_storm/proc/time_to_end()
diff --git a/code/modules/events/wizard/departmentrevolt.dm b/code/modules/events/wizard/departmentrevolt.dm
index 618c746a65..3227f81d58 100644
--- a/code/modules/events/wizard/departmentrevolt.dm
+++ b/code/modules/events/wizard/departmentrevolt.dm
@@ -44,6 +44,7 @@
citizens += H
SSticker.mode.traitors += M
M.special_role = "separatist"
+ M.add_antag_datum(/datum/antagonist/auto_custom)
H.log_message("Was made into a separatist, long live [nation]!", INDIVIDUAL_ATTACK_LOG)
to_chat(H, "You are a separatist! [nation] forever! Protect the sovereignty of your newfound land with your comrades in arms!")
if(citizens.len)
diff --git a/code/modules/events/wizard/greentext.dm b/code/modules/events/wizard/greentext.dm
index 6ee000249b..1cf4858ce7 100644
--- a/code/modules/events/wizard/greentext.dm
+++ b/code/modules/events/wizard/greentext.dm
@@ -67,6 +67,7 @@
O.completed = 1 //YES!
O.owner = new_holder.mind
new_holder.mind.objectives += O
+ new_holder.mind.add_antag_datum(/datum/antagonist/auto_custom)
new_holder.log_message("Won with greentext!!!", INDIVIDUAL_ATTACK_LOG)
color_altered_mobs -= new_holder
resistance_flags |= ON_FIRE
diff --git a/code/modules/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 7217fe0b28..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
@@ -393,6 +394,7 @@
container_type = NONE
spillable = FALSE
isGlass = FALSE
+ grind_results = list("aluminum" = 10)
/obj/item/reagent_containers/food/drinks/soda_cans/attack(mob/M, mob/user)
if(M == user && !src.reagents.total_volume && user.a_intent == INTENT_HARM && user.zone_selected == "head")
@@ -405,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 49f85a882d..08b09124d5 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -6,6 +6,7 @@
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
unique_rename = 1
+ grind_results = list() //To let them be ground up to transfer their reagents
var/bitesize = 2
var/bitecount = 0
var/trash = null
@@ -93,7 +94,7 @@
if(!do_mob(user, M))
return
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
M.visible_message("[user] forces [M] to eat [src].", \
"[user] forces [M] to eat [src].")
diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm
index bfe181b419..10039f7a8b 100644
--- a/code/modules/food_and_drinks/food/snacks_egg.dm
+++ b/code/modules/food_and_drinks/food/snacks_egg.dm
@@ -20,6 +20,7 @@
filling_color = "#F0E68C"
tastes = list("egg" = 1)
foodtype = MEAT
+ grind_results = list("eggyolk" = 5)
/obj/item/reagent_containers/food/snacks/egg/throw_impact(atom/hit_atom)
if(!..()) //was it caught by a mob?
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index c32ebfb765..c7681fe807 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -28,6 +28,7 @@
filling_color = "#FF1493"
tastes = list("watermelon" = 1)
foodtype = FRUIT
+ juice_results = list("watermelonjuice" = 5)
/obj/item/reagent_containers/food/snacks/candy_corn
name = "candy corn"
diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm
index 977bd60da1..1ec5bb3499 100644
--- a/code/modules/food_and_drinks/food/snacks_pie.dm
+++ b/code/modules/food_and_drinks/food/snacks_pie.dm
@@ -27,6 +27,7 @@
list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2)
tastes = list("pie" = 1)
foodtype = GRAIN | DAIRY | SUGAR
+ var/stunning = TRUE
/obj/item/reagent_containers/food/snacks/pie/cream/throw_impact(atom/hit_atom)
. = ..()
@@ -46,15 +47,18 @@
creamoverlay.icon_state = "creampie_lizard"
else
creamoverlay.icon_state = "creampie_human"
- H.Knockdown(20) //splat!
+ if(stunning)
+ H.Knockdown(20) //splat!
H.adjust_blurriness(1)
H.visible_message("[H] is creamed by [src]!", "You've been creamed by [src]!")
playsound(H, "desceration", 50, TRUE)
- if (!H.creamed) // one layer at a time
+ if(!H.creamed) // one layer at a time
H.add_overlay(creamoverlay)
H.creamed = TRUE
qdel(src)
+/obj/item/reagent_containers/food/snacks/pie/cream/nostun
+ stunning = FALSE
/obj/item/reagent_containers/food/snacks/pie/berryclafoutis
name = "berry clafoutis"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index a336d77404..40eae1b570 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -29,7 +29,7 @@ God bless America.
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
var/obj/item/reagent_containers/food/snacks/deepfryholder/frying //What's being fried RIGHT NOW?
var/cook_time = 0
var/oil_use = 0.05 //How much cooking oil is used per tick
diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
index 8573a84c9b..40f99b363a 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
@@ -15,7 +15,7 @@
var/portion = 10
var/selected_drink
var/list/stored_food = list()
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
var/obj/item/reagent_containers/mixer
/obj/machinery/food_cart/Initialize()
@@ -100,7 +100,7 @@
stored_food[sanitize(S.name)]++
else
stored_food[sanitize(S.name)] = 1
- else if(O.is_open_container())
+ else if(O.is_drainable())
return
else
. = ..()
@@ -123,7 +123,7 @@
break
if(href_list["portion"])
- portion = Clamp(input("How much drink do you want to dispense per glass?") as num, 0, 50)
+ portion = CLAMP(input("How much drink do you want to dispense per glass?") as num, 0, 50)
if(href_list["pour"] || href_list["m_pour"])
if(glasses-- <= 0)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index 372c085adb..99a3de90e1 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -1,4 +1,3 @@
-
/obj/machinery/gibber
name = "gibber"
desc = "The name isn't descriptive enough?"
@@ -12,10 +11,10 @@
circuit = /obj/item/circuitboard/machine/gibber
var/operating = FALSE //Is it on?
- var/dirty = 0 // Does it need cleaning?
+ var/dirty = FALSE // Does it need cleaning?
var/gibtime = 40 // Time from starting until meat appears
var/meat_produced = 0
- var/ignore_clothing = 0
+ var/ignore_clothing = FALSE
/obj/machinery/gibber/Initialize()
@@ -30,7 +29,7 @@
gib_time -= 5 * M.rating
gibtime = gib_time
if(M.rating >= 2)
- ignore_clothing = 1
+ ignore_clothing = TRUE
/obj/machinery/gibber/update_icon()
cut_overlays()
@@ -61,6 +60,10 @@
to_chat(user, "It's locked and running.")
return
+ if(!anchored)
+ to_chat(user, "[src] cannot be used unless bolted to the ground.")
+ return
+
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(!iscarbon(L))
@@ -70,12 +73,17 @@
if(C.buckled ||C.has_buckled_mobs())
to_chat(user, "[C] is attached to something!")
return
- if(C.abiotic(1) && !ignore_clothing)
- to_chat(user, "Subject may not have abiotic items on.")
- return
+
+ if(!ignore_clothing)
+ for(var/obj/item/I in C.held_items + C.get_equipped_items())
+ if(!(I.flags_1 & NODROP_1))
+ to_chat(user, "Subject may not have abiotic items on.")
+ return
user.visible_message("[user] starts to put [C] into the gibber!")
- src.add_fingerprint(user)
+
+ add_fingerprint(user)
+
if(do_after(user, gibtime, target = src))
if(C && user.pulling == C && !C.buckled && !C.has_buckled_mobs() && !occupant)
user.visible_message("[user] stuffs [C] into the gibber!")
diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
index 1b00de1842..f2f288fe7a 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
@@ -14,7 +14,7 @@
anchored = FALSE
use_power = NO_POWER_USE
layer = BELOW_OBJ_LAYER
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
max_integrity = 300
var/list/product_types = list()
var/dispense_flavour = ICECREAM_VANILLA
@@ -112,7 +112,7 @@
else
to_chat(user, "[O] already has ice cream in it.")
return 1
- else if(O.is_open_container())
+ else if(O.is_drainable())
return
else
return ..()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 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/games/cards.dm b/code/modules/games/cards.dm
index 89f6316297..bceaf6d7dd 100644
--- a/code/modules/games/cards.dm
+++ b/code/modules/games/cards.dm
@@ -187,7 +187,7 @@
ASSERT(H)
usr.visible_message("\The [usr] plays \the [card.name].")
- H.loc = get_step(usr,usr.dir)
+ H.forceMove(get_step(usr,usr.dir))
src.update_icon()
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 cb3ca7d6be..a35748e13e 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -13,7 +13,7 @@ body {
background: #fff;
font-family: Verdana, sans-serif;
font-size: 9pt;
- line-height: 1.4;
+ line-height: 1.2;
overflow-x: hidden;
overflow-y: scroll;
word-wrap: break-word;
@@ -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/halloween.dm b/code/modules/holiday/halloween.dm
index f8716870e1..a27db8dd38 100644
--- a/code/modules/holiday/halloween.dm
+++ b/code/modules/holiday/halloween.dm
@@ -146,7 +146,7 @@
timer = rand(1,15)
/mob/living/simple_animal/shade/howling_ghost/proc/EtherealMove(direction)
- loc = get_step(src, direction)
+ forceMove(get_step(src, direction))
setDir(direction)
/mob/living/simple_animal/shade/howling_ghost/proc/roam()
@@ -220,7 +220,7 @@
timer = rand(5,15)
playsound(M.loc, pick('sound/spookoween/scary_horn.ogg','sound/spookoween/scary_horn2.ogg', 'sound/spookoween/scary_horn3.ogg'), 300, 1)
spawn(12)
- loc = M.loc
+ forceMove(M.loc)
/mob/living/simple_animal/hostile/retaliate/clown/insane/MoveToTarget()
stalk(target)
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/holodeck/items.dm b/code/modules/holodeck/items.dm
index 54384753d7..6a8a720366 100644
--- a/code/modules/holodeck/items.dm
+++ b/code/modules/holodeck/items.dm
@@ -113,7 +113,7 @@
if(user.grab_state < GRAB_AGGRESSIVE)
to_chat(user, "
You need a better grip to do that!")
return
- L.loc = src.loc
+ L.forceMove(loc)
L.Knockdown(100)
visible_message("
[user] dunks [L] into \the [src]!")
user.stop_pulling()
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index 482a48edfd..d4269013f7 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -178,7 +178,7 @@
bees -= B
B.beehome = null
if(B.loc == src)
- B.loc = get_turf(src)
+ B.forceMove(drop_location())
relocated++
if(relocated)
to_chat(user, "
This queen has a different reagent to some of the bees who live here, those bees will not return to this apiary!")
@@ -201,7 +201,7 @@
if(B.isqueen)
continue
if(B.loc == src)
- B.loc = get_turf(src)
+ B.forceMove(drop_location())
B.target = user
bees = TRUE
if(bees)
@@ -221,7 +221,7 @@
var/obj/item/honey_frame/HF = pick_n_take(honey_frames)
if(HF)
if(!user.put_in_active_hand(HF))
- HF.loc = get_turf(src)
+ HF.forceMove(drop_location())
visible_message("
[user] removes a frame from the apiary.")
var/amtH = HF.honeycomb_capacity
@@ -229,7 +229,7 @@
while(honeycombs.len && amtH) //let's pretend you always grab the frame with the most honeycomb on it
var/obj/item/reagent_containers/honeycomb/HC = pick_n_take(honeycombs)
if(HC)
- HC.loc = get_turf(user)
+ HC.forceMove(drop_location())
amtH--
fallen++
if(fallen)
@@ -241,12 +241,12 @@
to_chat(user, "
There is no queen bee to remove!")
return
var/obj/item/queen_bee/QB = new()
- queen_bee.loc = QB
+ queen_bee.forceMove(QB)
bees -= queen_bee
QB.queen = queen_bee
QB.name = queen_bee.name
if(!user.put_in_active_hand(QB))
- QB.loc = get_turf(src)
+ QB.forceMove(drop_location())
visible_message("
[user] removes the queen from the apiary.")
queen_bee = null
@@ -254,8 +254,8 @@
new /obj/item/stack/sheet/mineral/wood (loc, 20)
for(var/mob/living/simple_animal/hostile/poison/bees/B in bees)
if(B.loc == src)
- B.loc = get_turf(src)
+ B.forceMove(drop_location())
for(var/obj/item/honey_frame/HF in honey_frames)
if(HF.loc == src)
- HF.loc = get_turf(src)
- qdel(src)
\ No newline at end of file
+ HF.forceMove(drop_location())
+ qdel(src)
diff --git a/code/modules/hydroponics/beekeeping/honeycomb.dm b/code/modules/hydroponics/beekeeping/honeycomb.dm
index 737736efc5..8b9d641eac 100644
--- a/code/modules/hydroponics/beekeeping/honeycomb.dm
+++ b/code/modules/hydroponics/beekeeping/honeycomb.dm
@@ -10,6 +10,7 @@
volume = 10
amount_per_transfer_from_this = 0
list_reagents = list("honey" = 5)
+ grind_results = list()
var/honey_color = ""
/obj/item/reagent_containers/honeycomb/New()
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 324a94128d..8939b60138 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -78,7 +78,7 @@
if(default_deconstruction_screwdriver(user, "biogen-empty-o", "biogen-empty", O))
if(beaker)
var/obj/item/reagent_containers/glass/B = beaker
- B.loc = loc
+ B.forceMove(drop_location())
beaker = null
update_icon()
return
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index bd0215138a..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
@@ -260,7 +260,7 @@
if(href_list["eject_seed"] && !operation)
if (seed)
- seed.loc = src.loc
+ seed.forceMove(drop_location())
seed.verb_pickup()
seed = null
update_genes()
@@ -275,7 +275,7 @@
update_icon()
else if(href_list["eject_disk"] && !operation)
if (disk)
- disk.loc = src.loc
+ disk.forceMove(drop_location())
disk.verb_pickup()
disk = null
update_genes()
@@ -368,7 +368,7 @@
/obj/machinery/plantgenes/proc/insert_seed(obj/item/seeds/S)
if(!istype(S) || seed)
return
- S.loc = src
+ S.forceMove(src)
seed = S
update_genes()
update_icon()
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index d003f40d4a..dadf077c8a 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -15,6 +15,7 @@
// Saves us from having to define each stupid grown's dried_type as itself.
// If you don't want a plant to be driable (watermelons) set this to null in the time definition.
resistance_flags = FLAMMABLE
+ var/dry_grind = FALSE //If TRUE, this object needs to be dry to be ground up
/obj/item/reagent_containers/food/snacks/grown/Initialize(mapload, obj/item/seeds/new_seed)
. = ..()
@@ -36,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()
@@ -137,6 +138,28 @@
return
return ..()
+/obj/item/reagent_containers/food/snacks/grown/grind_requirements()
+ if(dry_grind && !dry)
+ to_chat(usr, "
[src] needs to be dry before it can be ground up!")
+ return
+ return TRUE
+
+/obj/item/reagent_containers/food/snacks/grown/on_grind()
+ var/nutriment = reagents.get_reagent_amount("nutriment")
+ 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")
+ reagents.del_reagent("vitamin")
+
+/obj/item/reagent_containers/food/snacks/grown/on_juice()
+ var/nutriment = reagents.get_reagent_amount("nutriment")
+ 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")
+ reagents.del_reagent("vitamin")
+
// For item-containing growns such as eggy or gatfruit
/obj/item/reagent_containers/food/snacks/grown/shell/attack_self(mob/user)
var/obj/item/T
diff --git a/code/modules/hydroponics/grown/apple.dm b/code/modules/hydroponics/grown/apple.dm
index 7ec9a730ed..8b35fee872 100644
--- a/code/modules/hydroponics/grown/apple.dm
+++ b/code/modules/hydroponics/grown/apple.dm
@@ -15,6 +15,7 @@
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/apple/gold)
reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ juice_results = list("applejuice" = 0)
/obj/item/reagent_containers/food/snacks/grown/apple
seed = /obj/item/seeds/apple
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index bf71856323..72517e87bc 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -13,6 +13,7 @@
genes = list(/datum/plant_gene/trait/slip, /datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/banana/mime, /obj/item/seeds/banana/bluespace)
reagents_add = list("banana" = 0.1, "potassium" = 0.1, "vitamin" = 0.04, "nutriment" = 0.02)
+ juice_results = list("banana" = 0)
/obj/item/reagent_containers/food/snacks/grown/banana
seed = /obj/item/seeds/banana
diff --git a/code/modules/hydroponics/grown/beans.dm b/code/modules/hydroponics/grown/beans.dm
index 8ca2a5961a..46a7e7979f 100644
--- a/code/modules/hydroponics/grown/beans.dm
+++ b/code/modules/hydroponics/grown/beans.dm
@@ -26,6 +26,7 @@
filling_color = "#F0E68C"
bitesize_mod = 2
foodtype = VEGETABLES
+ grind_results = list("soymilk" = 0)
// Koibean
/obj/item/seeds/soya/koi
diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm
index 0d8c5d5a9a..541fb1b2a5 100644
--- a/code/modules/hydroponics/grown/berries.dm
+++ b/code/modules/hydroponics/grown/berries.dm
@@ -26,6 +26,7 @@
filling_color = "#FF00FF"
bitesize_mod = 2
foodtype = FRUIT
+ juice_results = list("berryjuice" = 0)
// Poison Berries
/obj/item/seeds/berry/poison
@@ -46,6 +47,7 @@
icon_state = "poisonberrypile"
filling_color = "#C71585"
foodtype = FRUIT | TOXIC
+ juice_results = list("poisonberryjuice" = 0)
// Death Berries
/obj/item/seeds/berry/death
@@ -121,6 +123,7 @@
filling_color = "#FF0000"
bitesize_mod = 2
foodtype = FRUIT
+ grind_results = list("cherryjelly" = 0)
// Blue Cherries
/obj/item/seeds/cherry/blue
@@ -142,6 +145,7 @@
filling_color = "#6495ED"
bitesize_mod = 2
foodtype = FRUIT
+ grind_results = list("bluecherryjelly" = 0)
// Grapes
/obj/item/seeds/grape
@@ -173,6 +177,7 @@
filling_color = "#FF1493"
bitesize_mod = 2
foodtype = FRUIT
+ juice_results = list("grapejuice" = 0)
// Green Grapes
/obj/item/seeds/grape/green
diff --git a/code/modules/hydroponics/grown/cereals.dm b/code/modules/hydroponics/grown/cereals.dm
index 7834ed15e8..d9b724d052 100644
--- a/code/modules/hydroponics/grown/cereals.dm
+++ b/code/modules/hydroponics/grown/cereals.dm
@@ -22,6 +22,7 @@
filling_color = "#F0E68C"
bitesize_mod = 2
foodtype = GRAIN
+ grind_results = list("flour" = 0)
// Oat
/obj/item/seeds/wheat/oat
@@ -42,6 +43,7 @@
filling_color = "#556B2F"
bitesize_mod = 2
foodtype = GRAIN
+ grind_results = list("flour" = 0)
// Rice
/obj/item/seeds/wheat/rice
@@ -63,6 +65,7 @@
filling_color = "#FAFAD2"
bitesize_mod = 2
foodtype = GRAIN
+ grind_results = list("rice" = 0)
//Meatwheat - grows into synthetic meat
/obj/item/seeds/wheat/meat
@@ -83,6 +86,7 @@
bitesize_mod = 2
seed = /obj/item/seeds/wheat/meat
foodtype = MEAT | GRAIN
+ grind_results = list("flour" = 0, "blood" = 0)
/obj/item/reagent_containers/food/snacks/grown/meatwheat/attack_self(mob/living/user)
user.visible_message("
[user] crushes [src] into meat.", "
You crush [src] into something that resembles meat.")
diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm
index 1b0cdc00d2..38f8a40ec3 100644
--- a/code/modules/hydroponics/grown/citrus.dm
+++ b/code/modules/hydroponics/grown/citrus.dm
@@ -30,6 +30,7 @@
desc = "It's so sour, your face will twist."
icon_state = "lime"
filling_color = "#00FF00"
+ juice_results = list("limejuice" = 0)
// Orange
/obj/item/seeds/orange
@@ -56,6 +57,7 @@
desc = "It's a tangy fruit."
icon_state = "orange"
filling_color = "#FFA500"
+ juice_results = list("orangejuice" = 0)
// Lemon
/obj/item/seeds/lemon
@@ -81,6 +83,7 @@
desc = "When life gives you lemons, make lemonade."
icon_state = "lemon"
filling_color = "#FFD700"
+ juice_results = list("lemonjuice" = 0)
// Combustible lemon
/obj/item/seeds/firelemon //combustible lemon is too long so firelemon
diff --git a/code/modules/hydroponics/grown/corn.dm b/code/modules/hydroponics/grown/corn.dm
index 827deaea47..4454c3c52a 100644
--- a/code/modules/hydroponics/grown/corn.dm
+++ b/code/modules/hydroponics/grown/corn.dm
@@ -25,6 +25,7 @@
trash = /obj/item/grown/corncob
bitesize_mod = 2
foodtype = VEGETABLES
+ juice_results = list("corn_starch" = 0)
/obj/item/grown/corncob
name = "corn cob"
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index e0845ffb2a..18eae2f4fd 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -182,6 +182,7 @@
throw_speed = 1
throw_range = 3
attack_verb = list("roasted", "scorched", "burned")
+ grind_results = list("capsaicin" = 0, "condensedcapsaicin" = 0)
/obj/item/grown/novaflower/add_juice()
..()
diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm
index 5e64d716ec..a64fc4b156 100644
--- a/code/modules/hydroponics/grown/melon.dm
+++ b/code/modules/hydroponics/grown/melon.dm
@@ -33,6 +33,7 @@
filling_color = "#008000"
bitesize_mod = 3
foodtype = FRUIT
+ juice_results = list("watermelonjuice" = 0)
// Holymelon
/obj/item/seeds/watermelon/holy
diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm
index 284f962e45..9ec936c1f2 100644
--- a/code/modules/hydroponics/grown/nettle.dm
+++ b/code/modules/hydroponics/grown/nettle.dm
@@ -43,6 +43,7 @@
throw_speed = 1
throw_range = 3
attack_verb = list("stung")
+ grind_results = list("sacid" = 0)
/obj/item/grown/nettle/suicide_act(mob/user)
user.visible_message("
[user] is eating some of [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -91,6 +92,7 @@
icon_state = "deathnettle"
force = 30
throwforce = 15
+ grind_results = list("facid" = 1, "sacid" = 1)
/obj/item/grown/nettle/death/add_juice()
..()
diff --git a/code/modules/hydroponics/grown/potato.dm b/code/modules/hydroponics/grown/potato.dm
index 0a3cbc060c..e127b166ea 100644
--- a/code/modules/hydroponics/grown/potato.dm
+++ b/code/modules/hydroponics/grown/potato.dm
@@ -17,6 +17,7 @@
genes = list(/datum/plant_gene/trait/battery)
mutatelist = list(/obj/item/seeds/potato/sweet)
reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ juice_results = list("potato" = 0)
/obj/item/reagent_containers/food/snacks/grown/potato
seed = /obj/item/seeds/potato
diff --git a/code/modules/hydroponics/grown/pumpkin.dm b/code/modules/hydroponics/grown/pumpkin.dm
index d5257aeee7..7113a8feab 100644
--- a/code/modules/hydroponics/grown/pumpkin.dm
+++ b/code/modules/hydroponics/grown/pumpkin.dm
@@ -24,6 +24,7 @@
filling_color = "#FFA500"
bitesize_mod = 2
foodtype = VEGETABLES
+ juice_results = list("pumpkinjuice" = 0)
/obj/item/reagent_containers/food/snacks/grown/pumpkin/attackby(obj/item/W as obj, mob/user as mob, params)
if(W.is_sharp())
@@ -53,4 +54,5 @@
icon_state = "blumpkin"
filling_color = "#87CEFA"
bitesize_mod = 2
- foodtype = VEGETABLES
\ No newline at end of file
+ foodtype = VEGETABLES
+ juice_results = list("blumpkinjuice" = 0)
diff --git a/code/modules/hydroponics/grown/root.dm b/code/modules/hydroponics/grown/root.dm
index 8666db45a8..fd78fa6ffa 100644
--- a/code/modules/hydroponics/grown/root.dm
+++ b/code/modules/hydroponics/grown/root.dm
@@ -22,6 +22,7 @@
filling_color = "#FFA500"
bitesize_mod = 2
foodtype = VEGETABLES
+ juice_results = list("carrotjuice" = 0)
/obj/item/reagent_containers/food/snacks/grown/carrot/attackby(obj/item/I, mob/user, params)
if(I.is_sharp())
diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm
index bd3b182c13..fc2ed221c5 100644
--- a/code/modules/hydroponics/grown/tea_coffee.dm
+++ b/code/modules/hydroponics/grown/tea_coffee.dm
@@ -14,7 +14,6 @@
icon_dead = "tea-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/tea/astra)
- reagents_add = list("vitamin" = 0.04, "teapowder" = 0.1)
/obj/item/reagent_containers/food/snacks/grown/tea
seed = /obj/item/seeds/tea
@@ -22,6 +21,8 @@
desc = "These aromatic tips of the tea plant can be dried to make tea."
icon_state = "tea_aspera_leaves"
filling_color = "#008000"
+ grind_results = list("teapowder" = 0)
+ dry_grind = TRUE
// Tea Astra
/obj/item/seeds/tea/astra
@@ -39,6 +40,7 @@
name = "Tea Astra tips"
icon_state = "tea_astra_leaves"
filling_color = "#4582B4"
+ grind_results = list("teapowder" = 0, "salglu_solution" = 0)
// Coffee
@@ -67,6 +69,8 @@
icon_state = "coffee_arabica"
filling_color = "#DC143C"
bitesize_mod = 2
+ dry_grind = TRUE
+ grind_results = list("coffeepowder" = 0)
// Coffee Robusta
/obj/item/seeds/coffee/robusta
@@ -84,4 +88,5 @@
seed = /obj/item/seeds/coffee/robusta
name = "coffee robusta beans"
desc = "Increases robustness by 37 percent!"
- icon_state = "coffee_robusta"
\ No newline at end of file
+ icon_state = "coffee_robusta"
+ grind_results = list("coffeepowder" = 0, "morphine" = 0)
diff --git a/code/modules/hydroponics/grown/tomato.dm b/code/modules/hydroponics/grown/tomato.dm
index 1bc42b45c0..4d066e769e 100644
--- a/code/modules/hydroponics/grown/tomato.dm
+++ b/code/modules/hydroponics/grown/tomato.dm
@@ -23,6 +23,8 @@
filling_color = "#FF6347"
bitesize_mod = 2
foodtype = VEGETABLES
+ grind_results = list("ketchup" = 0)
+ juice_results = list("tomatojuice" = 0)
// Blood Tomato
/obj/item/seeds/tomato/blood
@@ -44,6 +46,7 @@
splat_type = /obj/effect/gibspawner/generic
filling_color = "#FF0000"
foodtype = VEGETABLES | GROSS
+ grind_results = list("ketchup" = 0, "blood" = 0)
// Blue Tomato
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 a77808f006..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()
@@ -62,3 +62,7 @@
/obj/item/grown/microwave_act(obj/machine/microwave/M)
return
+
+/obj/item/grown/on_grind()
+ for(var/i in 1 to grind_results.len)
+ grind_results[grind_results[i]] = round(seed.potency)
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 9eafcec71b..c46fb92feb 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -108,7 +108,7 @@
var/needs_update = 0 // Checks if the icon needs updating so we don't redraw empty trays every time
if(myseed && (myseed.loc != src))
- myseed.loc = src
+ myseed.forceMove(src)
if(self_sustaining)
adjustNutri(1)
@@ -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/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index 0899a21132..b79d0652aa 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -17,7 +17,7 @@
return
while(t_amount < t_max)
var/obj/item/seeds/t_prod = F.seed.Copy()
- t_prod.loc = seedloc
+ t_prod.forceMove(seedloc)
t_amount++
qdel(O)
return 1
@@ -29,7 +29,7 @@
return
while(t_amount < t_max)
var/obj/item/seeds/t_prod = F.seed.Copy()
- t_prod.loc = seedloc
+ t_prod.forceMove(seedloc)
t_amount++
qdel(O)
return 1
@@ -168,7 +168,7 @@
for (var/obj/T in contents)//Now we find the seed we need to vend
var/obj/item/seeds/O = T
if (O.plantname == href_list["name"] && O.lifespan == href_list["li"] && O.endurance == href_list["en"] && O.maturation == href_list["ma"] && O.production == href_list["pr"] && O.yield == href_list["yi"] && O.potency == href_list["pot"])
- O.loc = src.loc
+ O.forceMove(drop_location())
break
src.updateUsrDialog()
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 272dbef071..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()
@@ -320,3 +320,55 @@
push_data()
activate_pin(2)
+
+/obj/item/integrated_circuit/converter/hsv2hex
+ name = "hsv to hexadecimal"
+ desc = "This circuit can convert a HSV (Hue, Saturation, and Value) color to a Hexadecimal RGB color."
+ extended_desc = "The first pin controls tint (0-359), the second pin controls how intense the tint is (0-255), and the third controls how bright the tint is (0 for black, 127 for normal, 255 for white)."
+ icon_state = "hsv-hex"
+ inputs = list(
+ "hue" = IC_PINTYPE_NUMBER,
+ "saturation" = IC_PINTYPE_NUMBER,
+ "value" = IC_PINTYPE_NUMBER
+ )
+ outputs = list("hexadecimal rgb" = IC_PINTYPE_COLOR)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+
+/obj/item/integrated_circuit/converter/hsv2hex/do_work()
+ var/result = null
+ pull_data()
+ var/hue = get_pin_data(IC_INPUT, 1)
+ var/saturation = get_pin_data(IC_INPUT, 2)
+ var/value = get_pin_data(IC_INPUT, 3)
+ if(isnum(hue)&&isnum(saturation)&&isnum(value))
+ result = HSVtoRGB(hsv(AngleToHue(hue),saturation,value))
+
+ set_pin_data(IC_OUTPUT, 1, result)
+ push_data()
+ activate_pin(2)
+
+/obj/item/integrated_circuit/converter/rgb2hex
+ name = "rgb to hexadecimal"
+ desc = "This circuit can convert a RGB (Red, Green, Blue) color to a Hexadecimal RGB color."
+ extended_desc = "The first pin controls red amount, the second pin controls green amount, and the third controls blue amount. All go from 0-255."
+ icon_state = "rgb-hex"
+ inputs = list(
+ "red" = IC_PINTYPE_NUMBER,
+ "green" = IC_PINTYPE_NUMBER,
+ "blue" = IC_PINTYPE_NUMBER
+ )
+ outputs = list("hexadecimal rgb" = IC_PINTYPE_COLOR)
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+
+/obj/item/integrated_circuit/converter/rgb2hex/do_work()
+ var/result = null
+ pull_data()
+ var/red = get_pin_data(IC_INPUT, 1)
+ var/green = get_pin_data(IC_INPUT, 2)
+ var/blue = get_pin_data(IC_INPUT, 3)
+ if(isnum(red)&&isnum(green)&&isnum(blue))
+ result = rgb(red,green,blue)
+
+ set_pin_data(IC_OUTPUT, 1, result)
+ push_data()
+ activate_pin(2)
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/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm
new file mode 100644
index 0000000000..85aeba5f10
--- /dev/null
+++ b/code/modules/keybindings/bindings_human.dm
@@ -0,0 +1,69 @@
+/mob/living/carbon/human/key_down(_key, client/user)
+ if(client.keys_held["Shift"])
+ switch(_key)
+ if("E") // Put held thing in belt or take out most recent thing from belt
+ var/obj/item/thing = get_active_held_item()
+ var/obj/item/storage/equipped_belt = get_item_by_slot(slot_belt)
+ if(!equipped_belt) // We also let you equip a belt like this
+ if(!thing)
+ to_chat(user, "You have no belt to take something out of.")
+ return
+ equip_to_slot_if_possible(thing, slot_belt)
+ return
+ if(!istype(equipped_belt)) // not a storage item
+ if(!thing)
+ to_chat(user, "You have no belt to take something out of.")
+ else
+ to_chat(user, "You can't fit anything in.")
+ return
+ if(thing) // put thing in belt
+ if(equipped_belt.can_be_inserted(thing))
+ equipped_belt.handle_item_insertion(thing)
+ else
+ to_chat(user, "You can't fit anything in.")
+ return
+ if(!equipped_belt.contents.len) // nothing to take out
+ to_chat(user, "There's nothing in your belt to take out.")
+ return
+ var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
+ if(!stored || stored.on_found(src))
+ return
+ stored.attack_hand(src) // take out thing from belt
+ return
+
+ if("B") // Put held thing in backpack or take out most recent thing from backpack
+ var/obj/item/thing = get_active_held_item()
+ var/obj/item/storage/equipped_backpack = get_item_by_slot(slot_back)
+ if(!equipped_backpack) // We also let you equip a backpack like this
+ if(!thing)
+ to_chat(user, "You have no backpack to take something out of.")
+ return
+ equip_to_slot_if_possible(thing, slot_back)
+ return
+ if(!istype(equipped_backpack)) // not a storage item
+ if(!thing)
+ to_chat(user, "You have no backpack to take something out of.")
+ else
+ to_chat(user, "You can't fit anything in.")
+ return
+ if(thing) // put thing in backpack
+ if(equipped_backpack.can_be_inserted(thing))
+ equipped_backpack.handle_item_insertion(thing)
+ else
+ to_chat(user, "You can't fit anything in.")
+ return
+ if(!equipped_backpack.contents.len) // nothing to take out
+ to_chat(user, "There's nothing in your backpack to take out.")
+ return
+ var/obj/item/stored = equipped_backpack.contents[equipped_backpack.contents.len]
+ if(!stored || stored.on_found(src))
+ return
+ stored.attack_hand(src) // take out thing from backpack
+ return
+
+ switch(_key)
+ if("E")
+ quick_equip()
+ return
+
+ return ..()
\ 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_items.dm b/code/modules/library/lib_items.dm
index 711ac4f33a..9cbd04bf42 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -49,7 +49,7 @@
anchored = TRUE
for(var/obj/item/I in loc)
if(istype(I, /obj/item/book))
- I.loc = src
+ I.forceMove(src)
update_icon()
@@ -123,7 +123,7 @@
if(!user.get_active_held_item())
user.put_in_hands(choice)
else
- choice.loc = get_turf(src)
+ choice.forceMove(drop_location())
update_icon()
@@ -289,7 +289,7 @@
user.put_in_hands(B)
return
else
- B.loc = src.loc
+ B.forceMove(drop_location())
qdel(src)
return
return
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 52077d2367..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"])
@@ -541,7 +541,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
cache = null
if(href_list["eject"])
for(var/obj/item/book/B in contents)
- B.loc = src.loc
+ B.forceMove(drop_location())
src.add_fingerprint(usr)
src.updateUsrDialog()
return
@@ -589,4 +589,4 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
B.icon_state = "book[rand(1,7)]"
qdel(P)
else
- P.loc = loc
+ P.forceMove(drop_location())
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 7fdecaaeb6..d655ed6e94 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -172,7 +172,7 @@
to_chat(M, "Your vision returns to normal.")
wisp.stop_orbit()
- wisp.loc = src
+ wisp.forceMove(src)
icon_state = "lantern-blue"
SSblackbox.record_feedback("tally", "wisp_lantern", 1, "Returned")
@@ -412,7 +412,7 @@
/obj/item/device/shared_storage/attackby(obj/item/W, mob/user, params)
if(bag)
- bag.loc = user
+ bag.forceMove(user)
bag.attackby(W, user, params)
@@ -421,7 +421,7 @@
return
if(loc == user && user.back && user.back == src)
if(bag)
- bag.loc = user
+ bag.forceMove(user)
bag.attack_hand(user)
else
..()
@@ -656,7 +656,7 @@
playsound(user, 'sound/magic/clockwork/fellowship_armory.ogg', 35, TRUE, frequency = 90000 - (active * 30000))
/obj/item/melee/transforming/cleaving_saw/clumsy_transform_effect(mob/living/user)
- if(user.disabilities & CLUMSY && prob(50))
+ if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
user.take_bodypart_damage(10)
@@ -799,13 +799,13 @@
force = 0
var/ghost_counter = ghost_check()
- force = Clamp((ghost_counter * 4), 0, 75)
+ force = CLAMP((ghost_counter * 4), 0, 75)
user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!")
..()
/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
var/ghost_counter = ghost_check()
- final_block_chance += Clamp((ghost_counter * 5), 0, 75)
+ final_block_chance += CLAMP((ghost_counter * 5), 0, 75)
owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!")
return ..()
diff --git a/code/modules/mining/lavaland/ruins/gym.dm b/code/modules/mining/lavaland/ruins/gym.dm
index 2eb30dc711..efda0f9c8f 100644
--- a/code/modules/mining/lavaland/ruins/gym.dm
+++ b/code/modules/mining/lavaland/ruins/gym.dm
@@ -29,7 +29,7 @@
icon_state = "fitnesslifter2"
user.setDir(SOUTH)
user.Stun(80)
- user.loc = src.loc
+ user.forceMove(src.loc)
var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
user.visible_message("[user] is [bragmessage]!")
var/lifts = 0
@@ -67,7 +67,7 @@
icon_state = "fitnessweight-c"
user.setDir(SOUTH)
user.Stun(80)
- user.loc = src.loc
+ user.forceMove(src.loc)
var/mutable_appearance/swole_overlay = mutable_appearance(icon, "fitnessweight-w", WALL_OBJ_LAYER)
add_overlay(swole_overlay)
var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
@@ -93,4 +93,4 @@
var/finishmessage = pick("You feel stronger!","You feel like you can take on the world!","You feel robust!","You feel indestructible!")
icon_state = "fitnessweight"
cut_overlay(swole_overlay)
- to_chat(user, "[finishmessage]")
\ No newline at end of file
+ to_chat(user, "[finishmessage]")
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/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index 3c7e736105..44f13d0a4f 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -88,7 +88,7 @@
stack_list[inp.type] = s
var/obj/item/stack/sheet/storage = stack_list[inp.type]
storage.amount += inp.amount //Stack the sheets
- inp.loc = null //Let the old sheet garbage collect
+ qdel(inp) //Let the old sheet garbage collect
while(storage.amount > stack_amt) //Get rid of excessive stackage
var/obj/item/stack/sheet/out = new inp.type()
out.amount = stack_amt
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/camera/camera.dm b/code/modules/mob/camera/camera.dm
index e058782be1..9a95bc9a4a 100644
--- a/code/modules/mob/camera/camera.dm
+++ b/code/modules/mob/camera/camera.dm
@@ -1,15 +1,18 @@
-// Camera mob, used by AI camera and blob.
-
-/mob/camera
- name = "camera mob"
+// Camera mob, used by AI camera and blob.
+
+/mob/camera
+ name = "camera mob"
density = FALSE
anchored = TRUE
- status_flags = GODMODE // You can't damage it.
+ status_flags = GODMODE // You can't damage it.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- see_in_dark = 7
- invisibility = INVISIBILITY_ABSTRACT // No one can see us
- sight = SEE_SELF
- move_on_shuttle = 0
-
-/mob/camera/experience_pressure_difference()
- return
+ see_in_dark = 7
+ invisibility = INVISIBILITY_ABSTRACT // No one can see us
+ sight = SEE_SELF
+ move_on_shuttle = 0
+
+/mob/camera/experience_pressure_difference()
+ return
+
+/mob/camera/forceMove(atom/destination)
+ loc = destination
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index 689ef552d9..1142d2d6cb 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -24,6 +24,9 @@ INITIALIZE_IMMEDIATE(/mob/dead)
/mob/dead/ConveyorMove() //lol
return
+/mob/dead/forceMove(atom/destination)
+ loc = destination
+
/mob/dead/Stat()
..()
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 458a54aa48..573183df96 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -21,9 +21,9 @@
S.Fade(TRUE)
if(length(GLOB.newplayer_start))
- loc = pick(GLOB.newplayer_start)
+ forceMove(pick(GLOB.newplayer_start))
else
- loc = locate(1,1,1)
+ forceMove(locate(1,1,1))
ComponentInitialize()
@@ -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))
@@ -282,7 +282,7 @@
var/obj/effect/landmark/observer_start/O = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list
to_chat(src, "Now teleporting.")
if (O)
- observer.loc = O.loc
+ observer.forceMove(O.loc)
else
to_chat(src, "Teleporting failed. Ahelp an admin please")
stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index d19f3d4bf8..4481de1e36 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -109,7 +109,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
else
T = locate(round(world.maxx/2), round(world.maxy/2), ZLEVEL_STATION_PRIMARY) //middle of the station
- loc = T
+ forceMove(T)
if(!name) //To prevent nameless ghosts
name = random_unique_name(gender)
@@ -288,10 +288,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/oldloc = loc
if(NewLoc)
- loc = NewLoc
+ forceMove(NewLoc)
update_parallax_contents()
else
- loc = get_turf(src) //Get out of closets and such as a ghost
+ forceMove(get_turf(src)) //Get out of closets and such as a ghost
if((direct & NORTH) && y < world.maxy)
y++
else if((direct & SOUTH) && y > 1)
@@ -371,7 +371,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!L || !L.len)
to_chat(usr, "No area available.")
- usr.loc = pick(L)
+ usr.forceMove(pick(L))
update_parallax_contents()
/mob/dead/observer/verb/follow()
@@ -445,7 +445,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/turf/T = get_turf(M) //Turf of the destination mob
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
- A.loc = T
+ A.forceMove(T)
A.update_parallax_contents()
else
to_chat(A, "This mob is not located in the game world.")
@@ -462,7 +462,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
views |= i
var/new_view = input("Choose your new view", "Modify view range", 7) as null|anything in views
if(new_view)
- client.change_view(Clamp(new_view, 7, max_view))
+ client.change_view(CLAMP(new_view, 7, max_view))
else
client.change_view(CONFIG_GET(string/default_view))
@@ -471,7 +471,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set hidden = TRUE
var/max_view = client.prefs.unlock_content ? GHOST_MAX_VIEW_RANGE_MEMBER : GHOST_MAX_VIEW_RANGE_DEFAULT
if(input)
- client.change_view(Clamp(client.view + input, 7, max_view))
+ client.rescale_view(input, 7, max_view)
/mob/dead/observer/verb/boo()
set category = "Ghost"
diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm
index ad64c53fc7..d2224a5965 100644
--- a/code/modules/mob/dead/observer/say.dm
+++ b/code/modules/mob/dead/observer/say.dm
@@ -1,25 +1,27 @@
-/mob/dead/observer/say(message)
- message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
-
- if (!message)
- return
-
+/mob/dead/observer/say(message)
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ if (!message)
+ return
+
log_talk(src,"Ghost/[src.key] : [message]", LOGSAY)
-
- . = src.say_dead(message)
-
-/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
- var/atom/movable/to_follow = speaker
- if(radio_freq)
- var/atom/movable/virtualspeaker/V = speaker
-
- if(isAI(V.source))
- var/mob/living/silicon/ai/S = V.source
- to_follow = S.eyeobj
- else
- to_follow = V.source
- var/link = FOLLOW_LINK(src, to_follow)
- // Recompose the message, because it's scrambled by default
- message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
- to_chat(src, "[link] [message]")
-
+
+ if(check_emote(message))
+ return
+
+ . = say_dead(message)
+
+/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+ var/atom/movable/to_follow = speaker
+ if(radio_freq)
+ var/atom/movable/virtualspeaker/V = speaker
+
+ if(isAI(V.source))
+ var/mob/living/silicon/ai/S = V.source
+ to_follow = S.eyeobj
+ else
+ to_follow = V.source
+ var/link = FOLLOW_LINK(src, to_follow)
+ // Recompose the message, because it's scrambled by default
+ message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ to_chat(src, "[link] [message]")
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
new file mode 100644
index 0000000000..5487b5b284
--- /dev/null
+++ b/code/modules/mob/emote.dm
@@ -0,0 +1,48 @@
+//The code execution of the emote datum is located at code/datums/emotes.dm
+/mob/emote(act, m_type = null, message = null)
+ act = lowertext(act)
+ var/param = message
+ var/custom_param = findchar(act, " ")
+ if(custom_param)
+ param = copytext(act, custom_param + 1, length(act) + 1)
+ act = copytext(act, 1, custom_param)
+
+ var/datum/emote/E
+ E = E.emote_list[act]
+ if(!E)
+ to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
+ return
+ E.run_emote(src, param, m_type)
+
+/datum/emote/flip
+ key = "flip"
+ key_third_person = "flips"
+ restraint_check = TRUE
+ mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
+ mob_type_ignore_stat_typecache = list(/mob/dead/observer)
+
+/datum/emote/flip/run_emote(mob/user, params)
+ . = ..()
+ if(.)
+ user.SpinAnimation(7,1)
+
+/datum/emote/spin
+ key = "spin"
+ key_third_person = "spins"
+ restraint_check = TRUE
+ mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
+ mob_type_ignore_stat_typecache = list(/mob/dead/observer)
+
+/datum/emote/spin/run_emote(mob/user)
+ . = ..()
+ if(.)
+ user.spin(20, 1)
+
+ if(iscyborg(user) && user.has_buckled_mobs())
+ var/mob/living/silicon/robot/R = user
+ GET_COMPONENT_FROM(riding_datum, /datum/component/riding, R)
+ if(riding_datum)
+ for(var/mob/M in R.buckled_mobs)
+ riding_datum.force_dismount(M)
+ else
+ R.unbuckle_all_mobs()
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 45f26d55c3..c1ea547b34 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -16,7 +16,7 @@
/mob/living/carbon/monkey/handle_blood()
- if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
+ if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
@@ -28,7 +28,7 @@
bleed_rate = 0
return
- if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
+ if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL && !(NOHUNGER in dna.species.species_traits))
@@ -201,13 +201,13 @@
return "blood"
/mob/living/carbon/monkey/get_blood_id()
- if(!(disabilities & NOCLONE))
+ if(!(has_disability(NOCLONE)))
return "blood"
/mob/living/carbon/human/get_blood_id()
if(dna.species.exotic_blood)
return dna.species.exotic_blood
- else if((NOBLOOD in dna.species.species_traits) || (disabilities & NOCLONE))
+ else if((NOBLOOD in dna.species.species_traits) || (has_disability(NOCLONE)))
return
return "blood"
diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm
index e4d49d7b70..e090592ba3 100644
--- a/code/modules/mob/living/brain/MMI.dm
+++ b/code/modules/mob/living/brain/MMI.dm
@@ -57,7 +57,7 @@
brainmob = newbrain.brainmob
newbrain.brainmob = null
- brainmob.loc = src
+ brainmob.forceMove(src)
brainmob.container = src
if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death.
brainmob.stat = CONSCIOUS //we manually revive the brain mob
@@ -90,7 +90,7 @@
/obj/item/device/mmi/proc/eject_brain(mob/user)
brainmob.container = null //Reset brainmob mmi var.
- brainmob.loc = brain //Throw mob into brain.
+ brainmob.forceMove(brain) //Throw mob into brain.
brainmob.stat = DEAD
brainmob.emp_damage = 0
brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision
@@ -120,7 +120,7 @@
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain)
- newbrain.loc = src
+ newbrain.forceMove(src)
brain = newbrain
else if(!brain)
brain = new(src)
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index db48302f49..b01c7c09ac 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -79,8 +79,8 @@
if(!brainmob.stored_dna)
brainmob.stored_dna = new /datum/dna/stored(brainmob)
C.dna.copy_dna(brainmob.stored_dna)
- if(L.disabilities & NOCLONE)
- brainmob.disabilities |= NOCLONE //This is so you can't just decapitate a husked guy and clone them without needing to get a new body
+ if(L.has_disability(NOCLONE))
+ brainmob.disabilities[NOCLONE] = L.disabilities[NOCLONE]
var/obj/item/organ/zombie_infection/ZI = L.getorganslot(ORGAN_SLOT_ZOMBIE)
if(ZI)
brainmob.set_species(ZI.old_species) //For if the brain is cloned
@@ -154,7 +154,7 @@
var/adjusted_amount
if(amount >= 0 && maximum)
var/brainloss = get_brain_damage()
- var/new_brainloss = Clamp(brainloss + amount, 0, maximum)
+ var/new_brainloss = CLAMP(brainloss + amount, 0, maximum)
if(brainloss > new_brainloss) //brainloss is over the cap already
return 0
adjusted_amount = new_brainloss - brainloss
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index ef704ef136..33a274c762 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -157,7 +157,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
new_name = pick(possible_names)
brainmob.name = "[new_name]-[rand(100, 999)]"
brainmob.real_name = brainmob.name
- brainmob.loc = src
+ brainmob.forceMove(src)
brainmob.container = src
if(autoping)
ping_ghosts("created", TRUE)
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 eb17ecc40a..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"
@@ -277,7 +289,7 @@ Doesn't work on other aliens/AI.*/
if(user.stomach_contents.len)
for(var/atom/movable/A in user.stomach_contents)
user.stomach_contents.Remove(A)
- A.loc = user.loc
+ A.forceMove(user.drop_location())
if(isliving(A))
var/mob/M = A
M.reset_perspective()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index fdca497bc3..fc759ec827 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -106,7 +106,7 @@
for(var/atom/movable/A in stomach_contents)
stomach_contents.Remove(A)
new_xeno.stomach_contents.Add(A)
- A.loc = new_xeno
+ A.forceMove(new_xeno)
..()
//For alien evolution/promotion/queen finder procs. Checks for an active alien of that type
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.dm b/code/modules/mob/living/carbon/carbon.dm
index e2ae973d43..23decdd59f 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -38,7 +38,7 @@
if(prob(src.getBruteLoss() - 50))
for(var/atom/movable/A in stomach_contents)
- A.loc = loc
+ A.forceMove(drop_location())
stomach_contents.Remove(A)
src.gib()
@@ -157,6 +157,8 @@
if(!throwable_mob.buckled)
thrown_thing = throwable_mob
stop_pulling()
+ if(has_disability(PACIFISM))
+ to_chat(src, "You gently let go of [throwable_mob].")
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
if(start_T && end_T)
@@ -168,6 +170,10 @@
thrown_thing = I
dropItemToGround(I)
+ if(has_disability(PACIFISM) && I.throwforce)
+ to_chat(src, "You set [I] down gently on the ground.")
+ return
+
if(thrown_thing)
visible_message("[src] has thrown [thrown_thing].")
add_logs(src, thrown_thing, "has thrown")
@@ -332,7 +338,7 @@
if (client)
client.screen -= W
if (W)
- W.loc = loc
+ W.forceMove(drop_location())
W.dropped(src)
if (W)
W.layer = initial(W.layer)
@@ -345,7 +351,7 @@
if (client)
client.screen -= W
if (W)
- W.loc = loc
+ W.forceMove(drop_location())
W.dropped(src)
if (W)
W.layer = initial(W.layer)
@@ -372,7 +378,7 @@
else
if(I == handcuffed)
- handcuffed.loc = loc
+ handcuffed.forceMove(drop_location())
handcuffed.dropped(src)
handcuffed = null
if(buckled && buckled.buckle_requires_restraints)
@@ -380,7 +386,7 @@
update_handcuffed()
return
if(I == legcuffed)
- legcuffed.loc = loc
+ legcuffed.forceMove(drop_location())
legcuffed.dropped()
legcuffed = null
update_inv_legcuffed()
@@ -403,7 +409,7 @@
dropItemToGround(I)
var/modifier = 0
- if(disabilities & CLUMSY)
+ if(has_disability(CLUMSY))
modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
switch(rand(1,100)+modifier) //91-100=Nothing special happens
@@ -512,7 +518,7 @@
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
update_stat()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
- become_husk()
+ become_husk("burn")
med_hud_set_health()
/mob/living/carbon/update_sight()
@@ -786,7 +792,7 @@
if(prob(50))
organs_amt++
O.Remove(src)
- O.loc = get_turf(src)
+ O.forceMove(drop_location())
if(organs_amt)
to_chat(user, "You retrieve some of [src]\'s internal organs!")
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 0bfa287a09..a6d4f3536b 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -306,11 +306,15 @@
if(eyes.eye_damage > 20)
if(prob(eyes.eye_damage - 20))
- if(become_nearsighted())
+ if(!has_disability(NEARSIGHT))
to_chat(src, "Your eyes start to burn badly!")
+ become_nearsighted(EYE_DAMAGE)
+
else if(prob(eyes.eye_damage - 25))
- if(become_blind())
+ if(!has_disability(BLIND))
to_chat(src, "You can't see anything!")
+ become_blind(EYE_DAMAGE)
+
else
to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!")
if(has_bane(BANE_LIGHT))
diff --git a/code/modules/mob/living/carbon/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/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 4b1afe0780..4453c33436 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -48,7 +48,7 @@
/mob/living/carbon/proc/Drain()
- become_husk()
- disabilities |= NOCLONE
+ become_husk(CHANGELING_DRAIN)
+ add_disability(NOCLONE, CHANGELING_DRAIN)
blood_volume = 0
return 1
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 6ed9291b83..39caec803b 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -187,31 +187,32 @@
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
msg += "[t_He] [p_do()]n't seem all there.\n"
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor bruising.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate bruising!\n"
- else
- msg += "[t_He] [t_has] severe bruising!\n"
+ if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor bruising.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate bruising!\n"
+ else
+ msg += "[t_He] [t_has] severe bruising!\n"
- temp = getFireLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor burns.\n"
- else if (temp < 50)
- msg += "[t_He] [t_has] moderate burns!\n"
- else
- msg += "[t_He] [t_has] severe burns!\n"
+ temp = getFireLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor burns.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_has] moderate burns!\n"
+ else
+ msg += "[t_He] [t_has] severe burns!\n"
- temp = getCloneLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor cellular damage.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate cellular damage!\n"
- else
- msg += "[t_He] [t_has] severe cellular damage!\n"
+ temp = getCloneLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor cellular damage.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate cellular damage!\n"
+ else
+ msg += "[t_He] [t_has] severe cellular damage!\n"
if(fire_stacks > 0)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index e8d4baba63..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
@@ -131,7 +134,7 @@
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
- I.loc = src
+ I.forceMove(src)
L.receive_damage(I.w_class*I.embedded_impact_pain_multiplier)
visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
hitpush = FALSE
@@ -140,8 +143,8 @@
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
- if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
- vore_attack(user, pulling)
+ if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (has_disability(FAT)) && ismonkey(pulling))
+ devour_mob(pulling)
else
..()
diff --git a/code/modules/mob/living/carbon/human/human_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..84da846bfd 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -91,19 +91,8 @@
return wear_id.GetID()
-/mob/living/carbon/human/abiotic(full_body = 0)
- var/abiotic_hands = FALSE
- for(var/obj/item/I in held_items)
- if(!(I.flags_1 & NODROP_1))
- abiotic_hands = TRUE
- break
- if(full_body && abiotic_hands && ((back && !(back.flags_1&NODROP_1)) || (wear_mask && !(wear_mask.flags_1&NODROP_1)) || (head && !(head.flags_1&NODROP_1)) || (shoes && !(shoes.flags_1&NODROP_1)) || (w_uniform && !(w_uniform.flags_1&NODROP_1)) || (wear_suit && !(wear_suit.flags_1&NODROP_1)) || (glasses && !(glasses.flags_1&NODROP_1)) || (ears && !(ears.flags_1&NODROP_1)) || (gloves && !(gloves.flags_1&NODROP_1)) ) )
- return TRUE
- return abiotic_hands
-
-
/mob/living/carbon/human/IsAdvancedToolUser()
- if(disabilities & MONKEYLIKE)
+ if(has_disability(MONKEYLIKE))
return FALSE
return TRUE//Humans can use guns and such
diff --git a/code/modules/mob/living/carbon/human/interactive.dm b/code/modules/mob/living/carbon/human/interactive.dm
index 9fd2cbf8de..8c913349c5 100644
--- a/code/modules/mob/living/carbon/human/interactive.dm
+++ b/code/modules/mob/living/carbon/human/interactive.dm
@@ -219,7 +219,7 @@
if(prob(25))
var/cType = pick(list(SNPC_BRUTE,SNPC_STEALTH,SNPC_MARTYR,SNPC_PSYCHO))
T.makeTraitor(cType)
- T.loc = pick(get_area_turfs(T.job2area(T.myjob)))
+ T.forceMove(pick(get_area_turfs(T.job2area(T.myjob))))
if(choice == "Custom")
var/cjob = input("Choose Job") as null|anything in SSjob.occupations
if(cjob)
@@ -256,7 +256,7 @@
var/doTele = input("Place the SNPC in their department?") as null|anything in list("Yes","No")
if(doTele)
if(doTele == "Yes")
- T.loc = pick(get_area_turfs(T.job2area(T.myjob)))
+ T.forceMove(pick(get_area_turfs(T.job2area(T.myjob))))
/mob/living/carbon/human/interactive/proc/doSetup()
Path_ID = new /obj/item/card/id(src)
@@ -339,7 +339,7 @@
if(TRAITS & TRAIT_SMART)
smartness = 75
else if(TRAITS & TRAIT_DUMB)
- disabilities |= CLUMSY
+ add_disability(CLUMSY, GENETIC_MUTATION)
smartness = 25
if(TRAITS & TRAIT_MEAN)
@@ -506,7 +506,7 @@
var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_hands,"right hand" = slot_hands)
if(hands)
slots = list ("left hand" = slot_hands,"right hand" = slot_hands)
- G.loc = src
+ G.forceMove(src)
if(G.force && G.force > best_force)
best_force = G.force
equip_in_one_of_slots(G, slots)
@@ -931,7 +931,7 @@
/mob/living/carbon/human/interactive/proc/npcDrop(var/obj/item/A,var/blacklist = 0)
if(blacklist)
blacklistItems += A
- A.loc = get_turf(src) // drop item works inconsistently
+ A.forceMove(drop_location()) // drop item works inconsistently
enforce_hands()
update_icons()
@@ -956,7 +956,7 @@
retal_target = traitorTarget
else
var/obj/item/I = traitorTarget
- I.loc = get_turf(traitorTarget) // pull it outta them
+ I.forceMove(get_turf(I)) // pull it outta them
else
take_to_slot(traitorTarget)
if(SNPC_MARTYR)
@@ -1315,7 +1315,7 @@
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")], grabbing various foodstuffs from [SF] and sticking them in it's mouth!")
for(var/obj/item/A in SF.contents)
if(prob(smartness/2))
- A.loc = src
+ A.forceMove(src)
if(foundCustom)
@@ -1398,7 +1398,7 @@
if(!Adjacent(toGrab))
tryWalk(toGrab)
else
- toGrab.loc = src
+ toGrab.forceMove(src)
if(finishedList.len > 0)
var/obj/structure/table/reinforced/RT
@@ -1563,7 +1563,7 @@
var/obj/item/W = main_hand
W.attack(TARGET,src)
else
- G.loc = get_turf(src) // drop item works inconsistently
+ G.forceMove(drop_location()) // drop item works inconsistently
enforce_hands()
update_icons()
else
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 4f41c2d40c..640447fc4d 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -187,7 +187,7 @@
if(G.tint)
update_tint()
if(G.vision_correction)
- if(disabilities & NEARSIGHT)
+ if(has_disability(NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
adjust_eye_damage(0)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 8363b64c9d..80db28b99d 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -313,7 +313,7 @@
if(prob(I.embedded_fall_chance))
BP.receive_damage(I.w_class*I.embedded_fall_pain_multiplier)
BP.embedded_objects -= I
- I.loc = get_turf(src)
+ I.forceMove(drop_location())
visible_message("[I] falls out of [name]'s [BP.name]!","[I] falls out of your [BP.name]!")
if(!has_embedded_objects())
clear_alert("embeddedobject")
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 0b02a2c711..451fadab62 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -312,7 +312,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!HD) //Decapitated
return
- if(H.disabilities & HUSK)
+ if(H.has_disability(HUSK))
return
var/datum/sprite_accessory/S
var/list/standing = list()
@@ -453,7 +453,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/obj/item/bodypart/head/HD = H.get_bodypart("head")
- if(HD && !(H.disabilities & HUSK))
+ if(HD && !(H.has_disability(HUSK)))
// lipstick
if(H.lip_style && (LIPS in species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
@@ -724,7 +724,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
- if(!(H.disabilities & HUSK))
+ if(!(H.has_disability(HUSK)))
if(!forced_colour)
switch(S.color_src)
if(MUTCOLORS)
@@ -1103,16 +1103,16 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
//The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
- if(H.disabilities & FAT)//I share your pain, past coder.
+ if(H.has_disability(FAT))//I share your pain, past coder.
if(H.overeatduration < 100)
to_chat(H, "You feel fit again!")
- H.disabilities &= ~FAT
+ H.remove_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration > 500)
to_chat(H, "You suddenly feel blubbery!")
- H.disabilities |= FAT
+ H.add_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
@@ -1269,7 +1269,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
. += (health_deficiency / 25)
if((hungry >= 70) && !flight) //Being hungry won't stop you from using flightpack controls/flapping your wings although it probably will in the wing case but who cares.
. += hungry / 50
- if(H.disabilities & FAT)
+ if(H.has_disability(FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
@@ -1315,11 +1315,14 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(user.has_disability(PACIFISM))
+ to_chat(user, "You don't want to harm [target]!")
+ return FALSE
if(target.check_block())
target.visible_message("[target] blocks [user]'s attack!")
- return 0
+ return FALSE
if(attacker_style && attacker_style.harm_act(user,target))
- return 1
+ return TRUE
else
var/atk_verb = user.dna.species.attack_verb
@@ -1344,7 +1347,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
playsound(target.loc, user.dna.species.miss_sound, 25, 1, -1)
target.visible_message("[user] has attempted to [atk_verb] [target]!",\
"[user] has attempted to [atk_verb] [target]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
var/armor_block = target.run_armor_check(affecting, "melee")
@@ -1366,8 +1369,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else if(target.lying)
target.forcesay(GLOB.hit_appends)
-
-
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
var/aim_for_mouth = user.zone_selected == "mouth"
var/target_on_help_and_unarmed = target.a_intent == INTENT_HELP && !target.get_active_held_item()
@@ -1387,10 +1388,12 @@ GLOBAL_LIST_EMPTY(roundstart_races)
return 1
else
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
-
+
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
- var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
+ var/randomized_zone = ran_zone(user.zone_selected)
+ target.SendSignal(COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
+ var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone)
var/randn = rand(1, 100)
if(randn <= 25)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
@@ -1511,8 +1514,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.confused = max(H.confused, 20)
H.adjustBrainLoss(20)
H.adjust_blurriness(10)
- if(prob(20))
+ if(prob(10))
H.gain_trauma(/datum/brain_trauma/mild/concussion)
+ else
+ if(!I.is_sharp())
+ H.adjustBrainLoss(I.force / 5)
if(prob(I.force + ((100 - H.health)/2)) && H != user)
var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
diff --git a/code/modules/mob/living/carbon/human/species_types/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 d2c83fa39f..34859a257f 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -369,7 +369,7 @@
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/target = get_turf(P.starting)
// redirect the projectile
- P.preparePixelProjectile(locate(Clamp(target.x + new_x, 1, world.maxx), Clamp(target.y + new_y, 1, world.maxy), H.z), H)
+ P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
return -1
return 0
@@ -725,7 +725,7 @@
/obj/structure/cloth_pile/proc/revive()
if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
return
- if(cloth_golem.suiciding || cloth_golem.disabilities & NOCLONE)
+ if(cloth_golem.suiciding || cloth_golem.has_disability(NOCLONE))
QDEL_NULL(cloth_golem)
return
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index fe0acc4feb..31883b4dcd 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -19,6 +19,11 @@
if(H)
H.endTailWag()
+/datum/species/human/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ H.endTailWag()
+ . = ..()
+
/datum/species/human/space_move(mob/living/carbon/human/H)
var/obj/item/device/flightpack/F = H.get_flightpack()
if(istype(F) && (F.flight) && F.allow_thrust(0.01, src))
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 257abf63d0..0d006196aa 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -42,6 +42,11 @@
if(H)
H.endTailWag()
+/datum/species/lizard/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ H.endTailWag()
+ . = ..()
+
/*
Lizard subspecies: ASHWALKERS
*/
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 6d1384f12f..aff8440930 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -94,8 +94,8 @@
to_chat(victim, "[H] is draining your blood!")
to_chat(H, "You drain some blood!")
playsound(H, 'sound/items/drink.ogg', 30, 1, -2)
- victim.blood_volume = Clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
- H.blood_volume = Clamp(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ victim.blood_volume = CLAMP(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ H.blood_volume = CLAMP(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
if(!victim.blood_volume)
to_chat(H, "You finish off [victim]'s blood supply!")
diff --git a/code/modules/mob/living/carbon/human/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/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index aca6973355..cf3d676e90 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -11,12 +11,12 @@
amount = dna.species.spec_stun(src,amount)
return ..()
-/mob/living/carbon/human/cure_husk()
+/mob/living/carbon/human/cure_husk(list/sources)
. = ..()
if(.)
update_hair()
-/mob/living/carbon/human/become_husk()
+/mob/living/carbon/human/become_husk(source)
if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks.
cure_husk()
return
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 7264e9ad95..14f294fd90 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -609,7 +609,7 @@ generate/load female uniform sprites matching all previously decided variables
if(BP.dmg_overlay_type)
. += "-[BP.dmg_overlay_type]"
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
. += "-husk"
/mob/living/carbon/human/load_limb_from_cache()
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 5eb09a8d83..4399607984 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -182,7 +182,7 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
var/ratio = (breath_gases[/datum/gas/plasma][MOLES]/safe_tox_max) * 10
- adjustToxLoss(Clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
+ adjustToxLoss(CLAMP(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
clear_alert("too_much_tox")
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index d6afdbdbc2..3e6b7f3ddd 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -120,16 +120,17 @@
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
if(L == src)
- return 0
-
+ return FALSE
+ if(has_disability(PACIFISM))
+ return FALSE
if(enemies[L])
- return 1
+ return TRUE
// target non-monkey mobs when aggressive, with a small probability of monkey v monkey
if(aggressive && (!istype(L, /mob/living/carbon/monkey/) || prob(MONKEY_AGGRESSIVE_MVM_PROB)))
- return 1
+ return TRUE
- return 0
+ return FALSE
/mob/living/carbon/monkey/proc/handle_combat()
// Don't do any AI if inside another mob (devoured)
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index 5a4ba686b2..87058ce76d 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -19,7 +19,7 @@
if(!HD) //Decapitated
return
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
return
var/hair_hidden = 0
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index e46ae2f8e6..1d5525edd9 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -59,48 +59,13 @@
clear_alert("high")
/mob/living/carbon/adjust_disgust(amount)
- disgust = Clamp(disgust+amount, 0, DISGUST_LEVEL_MAXEDOUT)
+ disgust = CLAMP(disgust+amount, 0, DISGUST_LEVEL_MAXEDOUT)
/mob/living/carbon/set_disgust(amount)
- disgust = Clamp(amount, 0, DISGUST_LEVEL_MAXEDOUT)
+ disgust = CLAMP(amount, 0, DISGUST_LEVEL_MAXEDOUT)
-/mob/living/carbon/cure_blind()
- if(disabilities & BLIND)
- disabilities &= ~BLIND
- adjust_blindness(-1)
- return 1
-/mob/living/carbon/become_blind()
- if(!(disabilities & BLIND))
- disabilities |= BLIND
- blind_eyes(1)
- return 1
-/mob/living/carbon/cure_nearsighted()
- if(disabilities & NEARSIGHT)
- disabilities &= ~NEARSIGHT
- clear_fullscreen("nearsighted")
- return 1
-
-/mob/living/carbon/become_nearsighted()
- if(!(disabilities & NEARSIGHT))
- disabilities |= NEARSIGHT
- overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
- return 1
-
-/mob/living/carbon/cure_husk()
- if(disabilities & HUSK)
- disabilities &= ~HUSK
- status_flags &= ~DISFIGURED
- update_body()
- return 1
-
-/mob/living/carbon/become_husk()
- if(disabilities & HUSK)
- return
- disabilities |= HUSK
- status_flags |= DISFIGURED //makes them unknown
- update_body()
- return 1
+////////////////////////////////////////TRAUMAS/////////////////////////////////////////
/mob/living/carbon/proc/get_traumas()
. = list()
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index 701fa0c7bc..5034abfbbe 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -290,7 +290,7 @@
else
. += "-robotic"
- if(disabilities & HUSK)
+ if(has_disability(HUSK))
. += "-husk"
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index dbc8da5a05..9517e1b705 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -157,7 +157,7 @@
/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- bruteloss = Clamp((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ bruteloss = CLAMP((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -168,7 +168,7 @@
/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- oxyloss = Clamp((oxyloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ oxyloss = CLAMP((oxyloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -187,7 +187,7 @@
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- toxloss = Clamp((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ toxloss = CLAMP((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -206,7 +206,7 @@
/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- fireloss = Clamp((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ fireloss = CLAMP((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
@@ -217,7 +217,7 @@
/mob/living/proc/adjustCloneLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
- cloneloss = Clamp((cloneloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
+ cloneloss = CLAMP((cloneloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 9f541aaf67..fd3c521cd1 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -1,18 +1,3 @@
-//The code execution of the emote datum is located at code/datums/emotes.dm
-/mob/living/emote(act, m_type = null, message = null)
- act = lowertext(act)
- var/param = message
- var/custom_param = findchar(act, " ")
- if(custom_param)
- param = copytext(act, custom_param + 1, length(act) + 1)
- act = copytext(act, 1, custom_param)
-
- var/datum/emote/E
- E = E.emote_list[act]
- if(!E)
- to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
- return
- E.run_emote(src, param, m_type)
/* EMOTE DATUMS */
/datum/emote/living
@@ -143,16 +128,6 @@
restraint_check = TRUE
wing_time = 10
-/datum/emote/living/flip
- key = "flip"
- key_third_person = "flips"
- restraint_check = TRUE
-
-/datum/emote/living/flip/run_emote(mob/user, params)
- . = ..()
- if(.)
- user.SpinAnimation(7,1)
-
/datum/emote/living/frown
key = "frown"
key_third_person = "frowns"
@@ -482,25 +457,6 @@
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
-/datum/emote/living/spin
- key = "spin"
- key_third_person = "spins"
- restraint_check = TRUE
-
-/datum/emote/living/spin/run_emote(mob/user)
- . = ..()
- if(.)
- user.spin(20, 1)
- if(iscyborg(user) && user.has_buckled_mobs())
- var/mob/living/silicon/robot/R = user
- GET_COMPONENT_FROM(riding_datum, /datum/component/riding, R)
- if(riding_datum)
- for(var/mob/M in R.buckled_mobs)
- riding_datum.force_dismount(M)
- else
- R.unbuckle_all_mobs()
-
-
/datum/emote/living/circle
key = "circle"
key_third_person = "circles"
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 0aafef753f..41c4572103 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -126,7 +126,7 @@
/mob/living/proc/handle_disabilities()
//Eyes
if(eye_blind) //blindness, heals slowly over time
- if(!stat && !(disabilities & BLIND))
+ if(!stat && !(has_disability(BLIND)))
eye_blind = max(eye_blind-1,0)
if(client && !eye_blind)
clear_alert("blind")
@@ -137,6 +137,9 @@
eye_blurry = max(eye_blurry-1, 0)
if(client && !eye_blurry)
clear_fullscreen("blurry")
+ if(has_disability(PACIFISM) && a_intent == INTENT_HARM)
+ to_chat(src, "You don't feel like harming anybody.")
+ a_intent_change(INTENT_HELP)
/mob/living/proc/update_damage_hud()
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index f589ecbb20..9b47a8c66b 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -343,8 +343,15 @@
return 1
return 0
+// Living mobs use can_inject() to make sure that the mob is not syringe-proof in general.
/mob/living/proc/can_inject()
- return 1
+ return TRUE
+
+/mob/living/is_injectable(allowmobs = TRUE)
+ return (allowmobs && reagents && can_inject())
+
+/mob/living/is_drawable(allowmobs = TRUE)
+ return (allowmobs && reagents && can_inject())
/mob/living/proc/get_organ_target()
var/mob/shooter = src
@@ -406,7 +413,6 @@
cure_nearsighted()
cure_blind()
cure_husk()
- disabilities = 0
hallucination = 0
heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
@@ -809,9 +815,12 @@
to_chat(src, "You don't have the dexterity to do this!")
return
/mob/living/proc/can_use_guns(obj/item/G)
- if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
+ if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, "You don't have the dexterity to do this!")
return FALSE
+ if(has_disability(PACIFISM))
+ to_chat(src, "You don't want to risk harming anyone!")
+ return FALSE
return TRUE
/mob/living/carbon/proc/update_stamina()
@@ -918,7 +927,7 @@
update_fire()
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
- fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
+ fire_stacks = CLAMP(fire_stacks + add_fire_stacks, -20, 20)
if(on_fire && fire_stacks <= 0)
ExtinguishMob()
@@ -1054,4 +1063,4 @@
/mob/living/onTransitZ(old_z,new_z)
..()
- update_z(new_z)
\ No newline at end of file
+ update_z(new_z)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f77c65225f..4800d9fb26 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -55,9 +55,9 @@
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
if(throwforce && w_class)
- return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
+ return CLAMP((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
else if(w_class)
- return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
+ return CLAMP(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
else
return 0
@@ -127,14 +127,17 @@
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src || anchored || !isturf(user.loc))
- return 0
+ return FALSE
if(!user.pulling || user.pulling != src)
user.start_pulling(src, supress_message)
return
if(!(status_flags & CANPUSH))
to_chat(user, "[src] can't be grabbed more aggressively!")
- return 0
+ return FALSE
+ if(user.has_disability(PACIFISM))
+ to_chat(user, "You don't want to risk hurting [src]!")
+ return FALSE
grippedby(user)
//proc to upgrade a simple pull into a more aggressive grab.
@@ -188,83 +191,97 @@
M.Feedstop()
return // can't attack while eating!
+ if(has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if (stat != DEAD)
add_logs(M, src, "attacked")
M.do_attack_animation(src)
visible_message("The [M.name] glomps [src]!", \
"The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE)
- return 1
+ return TRUE
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
if(M.melee_damage_upper == 0)
M.visible_message("\The [M] [M.friendly] [src]!")
- return 0
+ return FALSE
else
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
visible_message("\The [M] [M.attacktext] [src]!", \
"\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE)
add_logs(M, src, "attacked")
- return 1
+ return TRUE
/mob/living/attack_paw(mob/living/carbon/monkey/M)
if(isturf(loc) && istype(loc.loc, /area/start))
to_chat(M, "No attacking people at spawn, you jackass.")
- return 0
+ return FALSE
if (M.a_intent == INTENT_HARM)
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
to_chat(M, "You can't bite with your mouth covered!")
- return 0
+ return FALSE
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
if (prob(75))
add_logs(M, src, "attacked")
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
visible_message("[M.name] bites [src]!", \
"[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
- return 1
+ return TRUE
else
visible_message("[M.name] has attempted to bite [src]!", \
"[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
switch(L.a_intent)
if("help")
visible_message("[L.name] rubs its head against [src].")
- return 0
+ return FALSE
else
+ if(L.has_disability(PACIFISM))
+ to_chat(L, "You don't want to hurt anyone!")
+ return
L.do_attack_animation(src)
if(prob(90))
add_logs(L, src, "attacked")
visible_message("[L.name] bites [src]!", \
"[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
- return 1
+ return TRUE
else
visible_message("[L.name] has attempted to bite [src]!", \
"[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return 0
+ return FALSE
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
switch(M.a_intent)
if ("help")
visible_message("[M] caresses [src] with its scythe like arm.")
- return 0
-
+ return FALSE
if ("grab")
grabbedby(M)
- return 0
+ return FALSE
if("harm")
+ if(M.has_disability(PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
M.do_attack_animation(src)
- return 1
+ return TRUE
if("disarm")
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- return 1
+ return TRUE
/mob/living/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
@@ -347,7 +364,7 @@
//called when the mob receives a bright flash
/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
- if(get_eye_protection() < intensity && (override_blindness_check || !(disabilities & BLIND)))
+ if(get_eye_protection() < intensity && (override_blindness_check || !(has_disability(BLIND))))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
return 1
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 50f2ce4db0..6990262409 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -26,6 +26,8 @@
var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas
//and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt
+ var/list/disabilities = list()
+
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
var/now_pushing = null //used by living/Collide() and living/PushAM() to prevent potential infinite loop.
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index ffdd37bdca..611d9dbc4c 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -13,8 +13,8 @@
update_damage_hud()
update_health_hud()
- if (loc)
- var/turf/T = get_turf(src)
+ var/turf/T = get_turf(src)
+ if (isturf(T))
update_z(T.z)
//Vents
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index b1d0484086..4e731567f1 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -285,7 +285,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
- if(disabilities & MUTE)
+ if(has_disability(MUTE))
return 0
if(is_muzzled())
@@ -296,11 +296,6 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
-/mob/living/proc/check_emote(message)
- if(copytext(message, 1, 2) == "*")
- emote(copytext(message, 2))
- return 1
-
/mob/living/proc/get_message_mode(message)
var/key = copytext(message, 1, 2)
if(key == "#")
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 47d5a0ffd8..86314e33d7 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -117,7 +117,7 @@
job = "AI"
eyeobj.ai = src
- eyeobj.loc = src.loc
+ eyeobj.forceMove(src.loc)
rename_self("ai")
holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"default"))
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index b12430d26d..924ab615b8 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -138,7 +138,7 @@
/mob/living/silicon/pai/proc/process_hack()
if(cable && cable.machine && istype(cable.machine, /obj/machinery/door) && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
- hackprogress = Clamp(hackprogress + 4, 0, 100)
+ hackprogress = CLAMP(hackprogress + 4, 0, 100)
else
temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
@@ -283,8 +283,8 @@
/mob/living/silicon/pai/process()
- emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
- hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
+ emitterhealth = CLAMP((emitterhealth + emitterregen), -50, emittermaxhealth)
+ hit_slowdown = CLAMP((hit_slowdown - 1), 0, 100)
/mob/living/silicon/pai/generateStaticOverlay()
return
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index 83da7d9087..2c6c42e3bb 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -57,7 +57,7 @@
return FALSE //No we're not flammable
/mob/living/silicon/pai/proc/take_holo_damage(amount)
- emitterhealth = Clamp((emitterhealth - amount), -50, emittermaxhealth)
+ emitterhealth = CLAMP((emitterhealth - amount), -50, emittermaxhealth)
if(emitterhealth < 0)
fold_in(force = TRUE)
to_chat(src, "The impact degrades your holochassis!")
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index aab1f204f6..5445941ed3 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -23,7 +23,7 @@
if(cell && cell.charge)
if(cell.charge <= 100)
uneq_all()
- var/amt = Clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
+ var/amt = CLAMP((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
else
uneq_all()
@@ -50,6 +50,7 @@
if(!mind.special_role)
mind.special_role = "traitor"
SSticker.mode.traitors += mind
+ mind.add_antag_datum(/datum/antagonist/auto_custom) // ????
/mob/living/silicon/robot/update_health_hud()
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index db10f4a81c..9b44c7cff3 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -827,6 +827,9 @@
/mob/living/silicon/robot/modules/security
set_module = /obj/item/robot_module/security
+/mob/living/silicon/robot/modules/clown
+ set_module = /obj/item/robot_module/clown
+
/mob/living/silicon/robot/modules/peacekeeper
set_module = /obj/item/robot_module/peacekeeper
@@ -1029,9 +1032,9 @@
status_flags &= ~CANPUSH
if(module.clean_on_move)
- flags_1 |= CLEAN_ON_MOVE_1
+ AddComponent(/datum/component/cleaning)
else
- flags_1 &= ~CLEAN_ON_MOVE_1
+ qdel(GetComponent(/datum/component/cleaning))
hat_offset = module.hat_offset
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index b1be1c3076..2f1eb7d378 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -352,7 +352,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "k9"
- moduleselect_icon = "k9"
+ moduleselect_icon = "security"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -387,7 +387,7 @@
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical,
/obj/item/clockwork/weapon/ratvarian_spear)
cyborg_base_icon = "medihound"
- moduleselect_icon = "medihound"
+ moduleselect_icon = "medical"
can_be_pushed = FALSE
hat_offset = INFINITY
@@ -409,7 +409,7 @@
/obj/item/clockwork/slab/cyborg/janitor,
/obj/item/clockwork/replica_fabricator/cyborg)
cyborg_base_icon = "scrubpup"
- moduleselect_icon = "scrubpup"
+ moduleselect_icon = "janitor"
hat_offset = INFINITY
clean_on_move = TRUE
@@ -513,6 +513,37 @@
if(CL)
CL.reagents.add_reagent("lube", 2 * coeff)
+/obj/item/robot_module/clown
+ name = "Clown"
+ basic_modules = list(
+ /obj/item/device/assembly/flash/cyborg,
+ /obj/item/toy/crayon/rainbow,
+ /obj/item/device/instrument/bikehorn,
+ /obj/item/stamp/clown,
+ /obj/item/bikehorn,
+ /obj/item/bikehorn/airhorn,
+ /obj/item/paint/anycolor,
+ /obj/item/soap/nanotrasen,
+ /obj/item/pneumatic_cannon/pie/selfcharge/cyborg,
+ /obj/item/razor, //killbait material
+ /obj/item/lipstick/purple,
+ /obj/item/reagent_containers/spray/waterflower/cyborg,
+ /obj/item/borg/cyborghug/peacekeeper,
+ /obj/item/borg/lollipop/clown,
+ /obj/item/picket_sign/cyborg,
+ /obj/item/reagent_containers/borghypo/clown,
+ /obj/item/extinguisher/mini)
+ emag_modules = list(
+ /obj/item/reagent_containers/borghypo/clown/hacked,
+ /obj/item/reagent_containers/spray/waterflower/cyborg/hacked)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg,
+ /obj/item/clockwork/weapon/ratvarian_spear,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ moduleselect_icon = "service"
+ cyborg_base_icon = "clown"
+ hat_offset = -2
+
/obj/item/robot_module/butler
name = "Service"
basic_modules = list(
diff --git a/code/modules/mob/living/simple_animal/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/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 6ea4d2ef94..adc88c5633 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -135,7 +135,7 @@
switch(remove_from)
if("head")
if(inventory_head)
- inventory_head.loc = src.loc
+ inventory_head.forceMove(drop_location())
inventory_head = null
update_corgi_fluff()
regenerate_icons()
@@ -144,7 +144,7 @@
return
if("back")
if(inventory_back)
- inventory_back.loc = src.loc
+ inventory_back.forceMove(drop_location())
inventory_back = null
update_corgi_fluff()
regenerate_icons()
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index e4de4387be..ea159a5749 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -48,6 +48,7 @@
faction = list("neutral","silicon","turret")
dextrous = TRUE
dextrous_hud_type = /datum/hud/dextrous/drone
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/staticChoice = "static"
var/list/staticChoices = list("static", "blank", "letter", "animal")
var/picked = FALSE //Have we picked our visual appearence (+ colour if applicable)
@@ -57,7 +58,6 @@
"1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\
"2. You may not harm any being, regardless of intent or circumstance.\n"+\
"3. Your goals are to build, maintain, repair, improve, and provide power to the best of your abilities, You must never actively work against these goals."
- var/light_on = 0
var/heavy_emp_damage = 25 //Amount of damage sustained if hit by a heavy EMP pulse
var/alarms = list("Atmosphere" = list(), "Fire" = list(), "Power" = list())
var/obj/item/internal_storage //Drones can store one item, of any size/type in their body
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 7a2c9e6b39..c0a57e3739 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -67,7 +67,7 @@
L.dropItemToGround(src)
contents -= drone
- drone.loc = get_turf(src)
+ drone.forceMove(drop_location())
drone.reset_perspective()
drone.setDir(SOUTH )//Looks better
drone.visible_message("[drone] uncurls!")
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 3aa1153133..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
@@ -148,12 +148,11 @@
qdel(access_card) //we don't have free access
access_card = null
verbs -= /mob/living/simple_animal/drone/verb/check_laws
- verbs -= /mob/living/simple_animal/drone/verb/toggle_light
verbs -= /mob/living/simple_animal/drone/verb/drone_ping
/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/friendly/drone/verbs.dm b/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm
index 49faea14b3..86bc3b69e5 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm
@@ -11,23 +11,7 @@
to_chat(src, "Drone Laws")
to_chat(src, laws)
-
-/mob/living/simple_animal/drone/verb/toggle_light()
- set category = "Drone"
- set name = "Toggle drone light"
- if(stat == DEAD)
- to_chat(src, "There's no light in your life... by that I mean you're dead.")
- return
- if(light_on)
- set_light(0)
- else
- set_light(8)
-
- light_on = !light_on
-
- to_chat(src, "Your light is now [light_on ? "on" : "off"].")
-
/mob/living/simple_animal/drone/verb/drone_ping()
set category = "Drone"
set name = "Drone ping"
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 85ec19bfb9..809681ed6b 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -110,3 +110,7 @@
eatverb = "devours"
list_reagents = list("nutriment" = 3, "vitamin" = 2)
foodtype = GROSS | MEAT | RAW
+ grind_results = list("blood" = 20, "liquidgibs" = 5)
+
+/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
+ reagents.clear_reagents()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index a977338008..c6f0f6a91c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -79,10 +79,10 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
- move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
+ move_to_delay = CLAMP((health/maxHealth) * 10, 5, 10)
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/60),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/60),0,20)
if(charging)
return
ranged_cooldown = world.time + ranged_cooldown_time
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 58e3e0837b..79bedbe264 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -57,7 +57,7 @@ Difficulty: Very Hard
L.dust()
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
if(enrage(target))
@@ -558,7 +558,7 @@ Difficulty: Very Hard
H.regenerate_limbs()
H.regenerate_organs()
H.revive(1,0)
- H.disabilities |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal
+ H.add_disability(NOCLONE, MAGIC_DISABILITY) //Free revives, but significantly limits your options for reviving except via the crystal
H.grab_ghost(force = TRUE)
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
@@ -719,7 +719,7 @@ Difficulty: Very Hard
if(isliving(A) && holder_animal)
var/mob/living/L = A
L.notransform = 1
- L.disabilities |= MUTE
+ L.add_disability(MUTE, STASIS_MUTE)
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession
@@ -729,7 +729,7 @@ Difficulty: Very Hard
/obj/structure/closet/stasis/dump_contents(var/kill = 1)
STOP_PROCESSING(SSobj, src)
for(var/mob/living/L in src)
- L.disabilities &= ~MUTE
+ L.remove_disability(MUTE, STASIS_MUTE)
L.status_flags &= ~GODMODE
L.notransform = 0
if(holder_animal)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
index 7f12e684e8..724e4fc5c7 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
@@ -101,7 +101,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
if(swooping)
return
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + ranged_cooldown_time
if(prob(15 + anger_modifier) && !client)
@@ -227,10 +227,10 @@ Difficulty: Medium
//ensure swoop direction continuity.
if(negative)
- if(IsInRange(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
+ if(ISINRANGE(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
negative = FALSE
else
- if(IsInRange(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
+ if(ISINRANGE(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
negative = TRUE
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
new /obj/effect/temp_visual/dragon_swoop(loc)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 02fb81a1ed..8dc1780e5e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -187,7 +187,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
- anger_modifier = Clamp(((maxHealth - health) / 42),0,50)
+ anger_modifier = CLAMP(((maxHealth - health) / 42),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
new file mode 100644
index 0000000000..67a565f945
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -0,0 +1,103 @@
+/mob/living/simple_animal/hostile/netherworld
+ name = "creature"
+ desc = "A sanity-destroying otherthing from the netherworld."
+ icon_state = "otherthing"
+ icon_living = "otherthing"
+ icon_dead = "otherthing-dead"
+ health = 80
+ maxHealth = 80
+ obj_damage = 100
+ melee_damage_lower = 25
+ melee_damage_upper = 50
+ attacktext = "slashes"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ faction = list("creature")
+ speak_emote = list("screams")
+ gold_core_spawnable = HOSTILE_SPAWN
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ faction = list("nether")
+
+/mob/living/simple_animal/hostile/netherworld/migo
+ name = "mi-go"
+ desc = "A pinkish, fungoid crustacean-like creature with numerous pairs of clawed appendages and a head covered with waving antennae."
+ speak_emote = list("screams", "clicks", "chitters", "barks", "moans", "growls", "meows", "reverberates", "roars", "squeaks", "rattles", "exclaims", "yells", "remarks", "mumbles", "jabbers", "stutters", "seethes")
+ icon_state = "mi-go"
+ icon_living = "mi-go"
+ icon_dead = "mi-go-dead"
+ attacktext = "lacerates"
+ speed = -0.5
+ var/static/list/migo_sounds
+ deathmessage = "wails as its form turns into a pulpy mush."
+ death_sound = 'sound/voice/hiss6.ogg'
+
+/mob/living/simple_animal/hostile/netherworld/migo/Initialize()
+ . = ..()
+ migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/carhorn.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/megaphone.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/items/geiger/high1.ogg', 'sound/items/geiger/high2.ogg', 'sound/voice/bcreep.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/mpatchedup.ogg', 'sound/voice/mfeelbetter.ogg', 'sound/voice/human/manlaugh1.ogg', 'sound/voice/human/womanlaugh.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/clockcultalr.ogg', 'sound/ambience/antag/ling_aler.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/ambience/antag/monkey.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clockcult_gateway_disrupted.ogg', 'sound/effects/clownstep2.ogg', 'sound/effects/curse1.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosion_distant.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heart_beat.ogg', 'sound/effects/hyperspace_begin.ogg', 'sound/effects/hyperspace_end.ogg', 'sound/effects/his_grace_awaken.ogg', 'sound/effects/pai_boot.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/ratvar_reveal.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/misc/airraid.ogg', 'sound/misc/bang.ogg', 'sound/misc/disco.ogg', 'sound/misc/highlander.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/misc/splort.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/beam_sniper.ogg', 'sound/weapons/chainsawhit.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gunshot_silenced.ogg', 'sound/weapons/gunshot2.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kenetic_accel.ogg', 'sound/machines/clockcult/steam_whoosh.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlockclose.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlockopen.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/cryo_warning.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/machines/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/triple_beep.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/outbreak5.ogg', 'sound/ai/outbreak7.ogg', 'sound/ai/poweroff.ogg', 'sound/ai/radiation.ogg', 'sound/ai/shuttlecalled.ogg', 'sound/ai/shuttledock.ogg', 'sound/ai/shuttlerecalled.ogg', 'sound/ai/aimalf.ogg') //hahahaha fuck you code divers
+
+/mob/living/simple_animal/hostile/netherworld/migo/say(message)
+ ..()
+ if(stat)
+ return
+ var/chosen_sound = pick(migo_sounds)
+ playsound(src, chosen_sound, 100, TRUE)
+
+/mob/living/simple_animal/hostile/netherworld/migo/Life()
+ ..()
+ if(stat)
+ return
+ if(prob(10))
+ var/chosen_sound = pick(migo_sounds)
+ playsound(src, chosen_sound, 100, TRUE)
+
+/mob/living/simple_animal/hostile/netherworld/blankbody
+ name = "blank body"
+ desc = "This looks human enough, but its flesh has an ashy texture, and it's face is featureless save an eerie smile."
+ icon_state = "blank-body"
+ icon_living = "blank-body"
+ icon_dead = "blank-dead"
+ gold_core_spawnable = NO_SPAWN
+ health = 100
+ maxHealth = 100
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ attacktext = "punches"
+ deathmessage = "falls apart into a fine dust."
+
+/mob/living/simple_animal/hostile/spawner/nether
+ name = "netherworld link"
+ desc = "A direct link to another dimension full of creatures not very happy to see you. Entering the link would be a very bad idea."
+ icon_state = "nether"
+ icon_living = "nether"
+ health = 50
+ maxHealth = 50
+ spawn_time = 50 //5 seconds
+ max_mobs = 15
+ icon = 'icons/mob/nest.dmi'
+ spawn_text = "crawls through"
+ mob_type = /mob/living/simple_animal/hostile/netherworld/migo
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ faction = list("nether")
+ deathmessage = "shatters into oblivion."
+ del_on_death = TRUE
+
+/mob/living/simple_animal/hostile/spawner/nether/attack_hand(mob/user)
+ user.visible_message("[user] is violently pulled into the link!", \
+ "Touching the portal, you are quickly pulled through into a world of unimaginable horror!")
+ contents.Add(user)
+
+/mob/living/simple_animal/hostile/spawner/nether/Life()
+ ..()
+ var/list/C = src.get_contents()
+ for(var/mob/living/M in C)
+ if(M)
+ playsound(src, 'sound/magic/demon_consume.ogg', 50, 1)
+ M.adjustBruteLoss(60)
+ new /obj/effect/gibspawner/human(get_turf(M))
+ if(M.stat == DEAD)
+ var/mob/living/simple_animal/hostile/netherworld/blankbody/blank
+ blank = new(loc)
+ blank.name = "[M]"
+ blank.desc = "It's [M], but their flesh has an ashy texture, and their face is featureless save an eerie smile."
+ src.visible_message("[M] reemerges from the link!")
+ qdel(M)
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 681f36e6d9..e4de22b2a7 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -127,7 +127,7 @@
/mob/living/simple_animal/parrot/death(gibbed)
if(held_item)
- held_item.loc = src.loc
+ held_item.forceMove(drop_location())
held_item = null
walk(src,0)
@@ -702,7 +702,7 @@
continue
held_item = I
- I.loc = src
+ I.forceMove(src)
visible_message("[src] grabs [held_item]!", "You grab [held_item]!", "You hear the sounds of wings flapping furiously.")
return held_item
@@ -777,7 +777,7 @@
if(!drop_gently)
if(istype(held_item, /obj/item/grenade))
var/obj/item/grenade/G = held_item
- G.loc = src.loc
+ G.forceMove(drop_location())
G.prime()
to_chat(src, "You let go of [held_item]!")
held_item = null
@@ -785,7 +785,7 @@
to_chat(src, "You drop [held_item].")
- held_item.loc = src.loc
+ held_item.forceMove(drop_location())
held_item = null
return 1
@@ -801,7 +801,7 @@
for(var/atom/movable/AM in view(src,1))
for(var/perch_path in desired_perches)
if(istype(AM, perch_path))
- src.loc = AM.loc
+ src.forceMove(AM.loc)
icon_state = icon_sit
return
to_chat(src, "There is no perch nearby to sit on!")
@@ -838,7 +838,7 @@
/mob/living/simple_animal/parrot/proc/perch_on_human(mob/living/carbon/human/H)
if(!H)
return
- loc = get_turf(H)
+ forceMove(get_turf(H))
H.buckle_mob(src, force=1)
pixel_y = 9
pixel_x = pick(-8,8) //pick left or right shoulder
@@ -996,7 +996,7 @@
return
var/datum/disease/parrot_possession/P = new
P.parrot = src
- loc = H
+ forceMove(H)
H.ForceContractDisease(P)
parrot_interest = null
H.visible_message("[src] dive bombs into [H]'s chest and vanishes!", "[src] dive bombs into your chest, vanishing! This can't be good!")
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index a4851bb432..4c5b94f2e3 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -111,7 +111,7 @@
/mob/living/simple_animal/updatehealth()
..()
- health = Clamp(health, 0, maxHealth)
+ health = CLAMP(health, 0, maxHealth)
/mob/living/simple_animal/update_stat()
if(status_flags & GODMODE)
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index e7e71bf091..9654f91b6c 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -166,7 +166,7 @@
step_away(M,src)
M.Friends = Friends.Copy()
babies += M
- M.mutation_chance = Clamp(mutation_chance+(rand(5,-5)),0,100)
+ M.mutation_chance = CLAMP(mutation_chance+(rand(5,-5)),0,100)
SSblackbox.record_feedback("tally", "slime_babies_born", 1, M.colour)
var/mob/living/simple_animal/slime/new_slime = pick(babies)
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 3d50f03e17..0149c98a3e 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -137,3 +137,76 @@
to_chat(src, "[priority_absorb_key["self_message"]]")
priority_absorb_key["stuns_absorbed"] += amount
return TRUE
+
+/////////////////////////////////// DISABILITIES ////////////////////////////////////
+
+/mob/living/proc/add_disability(disability, source)
+ if(!disabilities[disability])
+ disabilities[disability] = list(source)
+ else
+ disabilities[disability] |= list(source)
+
+/mob/living/proc/remove_disability(disability, list/sources)
+ if(!disabilities[disability])
+ return
+
+ if(LAZYLEN(sources))
+ for(var/S in sources)
+ if(S in disabilities[disability])
+ disabilities[disability] -= S
+ else
+ disabilities[disability] = list()
+
+ if(!LAZYLEN(disabilities[disability]))
+ disabilities -= disability
+
+/mob/living/proc/has_disability(disability, list/sources)
+ if(!disabilities[disability])
+ return FALSE
+
+ . = FALSE
+
+ if(LAZYLEN(sources))
+ for(var/S in sources)
+ if(S in disabilities[disability])
+ return TRUE
+ else
+ if(LAZYLEN(disabilities[disability]))
+ return TRUE
+
+/mob/living/proc/remove_all_disabilities()
+ disabilities = list()
+
+/////////////////////////////////// DISABILITY PROCS ////////////////////////////////////
+
+/mob/living/proc/cure_blind(list/sources)
+ remove_disability(BLIND, sources)
+ if(!has_disability(BLIND))
+ adjust_blindness(-1)
+
+/mob/living/proc/become_blind(source)
+ if(!has_disability(BLIND))
+ blind_eyes(1)
+ add_disability(BLIND, source)
+
+/mob/living/proc/cure_nearsighted(list/sources)
+ remove_disability(NEARSIGHT, sources)
+ if(!has_disability(NEARSIGHT))
+ clear_fullscreen("nearsighted")
+
+/mob/living/proc/become_nearsighted(source)
+ if(!has_disability(NEARSIGHT))
+ overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
+ add_disability(NEARSIGHT, source)
+
+/mob/living/proc/cure_husk(list/sources)
+ remove_disability(HUSK, sources)
+ if(!has_disability(HUSK))
+ status_flags &= ~DISFIGURED
+ update_body()
+
+/mob/living/proc/become_husk(source)
+ if(!has_disability(HUSK))
+ status_flags |= DISFIGURED //makes them unknown
+ update_body()
+ add_disability(HUSK, source)
\ No newline at end of file
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 9ffbff5619..a91db7f177 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -45,6 +45,10 @@
client.change_view(CONFIG_GET(string/default_view)) // Resets the client.view in case it was changed.
+ if(client.player_details.player_actions.len)
+ for(var/datum/action/A in client.player_details.player_actions)
+ A.Grant(src)
+
if(!GLOB.individual_log_list[ckey])
GLOB.individual_log_list[ckey] = logging
else
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index edbf11654b..ecbaea015f 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -32,7 +32,6 @@
var/obj/machinery/machine = null
var/other_mobs = null
- var/disabilities = 0 //Carbon
var/atom/movable/pulling = null
var/grab_state = 0
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 3dc56c936b..10c9a04a6e 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -285,11 +285,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
firstname.Find(real_name)
return firstname.match
-/mob/proc/abiotic(full_body = 0)
- for(var/obj/item/I in held_items)
- if(!(I.flags_1 & NODROP_1))
- return 1
- return 0
//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left
/mob/verb/a_intent_change(input as text)
@@ -363,7 +358,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if(M.mind in SSticker.mode.cult)
return 2
if("nuclear")
- if(M.mind in SSticker.mode.syndicates)
+ if(M.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
return 2
if("changeling")
if(M.mind.has_antag_datum(/datum/antagonist/changeling,TRUE))
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 9885d1c4d6..94431a9a7c 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -107,7 +107,7 @@
return
mob.control_object.setDir(direct)
else
- mob.control_object.loc = get_step(mob.control_object,direct)
+ mob.control_object.forceMove(get_step(mob.control_object,direct))
return
#define MOVEMENT_DELAY_BUFFER 0.75
@@ -186,7 +186,7 @@
if(LAZYLEN(mob.user_movement_hooks))
for(var/obj/O in mob.user_movement_hooks)
O.intercept_user_move(direct, mob, n, oldloc)
-
+
var/atom/movable/P = mob.pulling
if(P && !ismob(P) && P.density)
mob.dir = turn(mob.dir, 180)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 1ee7f27452..f9ee14b638 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -1,82 +1,88 @@
-//Speech verbs.
-/mob/verb/say_verb(message as text)
- set name = "Say"
- set category = "IC"
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
- usr.say(message)
-
-
-/mob/verb/whisper_verb(message as text)
- set name = "Whisper"
- set category = "IC"
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
- whisper(message)
-
-/mob/proc/whisper(message, datum/language/language=null)
- say(message, language) //only living mobs actually whisper, everything else just talks
-
-/mob/verb/me_verb(message as text)
- set name = "Me"
- set category = "IC"
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
-
- message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
-
- usr.emote("me",1,message)
-
-/mob/proc/say_dead(var/message)
- var/name = real_name
- var/alt_name = ""
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled.")
- return
-
- if(jobban_isbanned(src, "OOC"))
- to_chat(src, "You have been banned from deadchat.")
- return
-
- if (src.client)
- if(src.client.prefs.muted & MUTE_DEADCHAT)
- to_chat(src, "You cannot talk in deadchat (muted).")
- return
-
- if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
- return
-
- var/mob/dead/observer/O = src
- if(isobserver(src) && O.deadchat_name)
- name = "[O.deadchat_name]"
- else
- if(mind && mind.name)
- name = "[mind.name]"
- else
- name = real_name
- if(name != real_name)
- alt_name = " (died as [real_name])"
-
- var/K
-
- if(key)
- K = src.key
-
- message = src.say_quote(message, get_spans())
- var/rendered = "DEAD: [name][alt_name] [message]"
-
- deadchat_broadcast(rendered, follow_target = src, speaker_key = K)
-
-/mob/proc/emote(var/act)
- return
-
-/mob/proc/hivecheck()
- return 0
-
-/mob/proc/lingcheck()
- return LINGHIVE_NONE
+//Speech verbs.
+/mob/verb/say_verb(message as text)
+ set name = "Say"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ if(message)
+ say(message)
+
+
+/mob/verb/whisper_verb(message as text)
+ set name = "Whisper"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ whisper(message)
+
+/mob/proc/whisper(message, datum/language/language=null)
+ say(message, language) //only living mobs actually whisper, everything else just talks
+
+/mob/verb/me_verb(message as text)
+ set name = "Me"
+ set category = "IC"
+
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+
+ usr.emote("me",1,message)
+
+/mob/proc/say_dead(var/message)
+ var/name = real_name
+ var/alt_name = ""
+
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+
+ if(jobban_isbanned(src, "OOC"))
+ to_chat(src, "You have been banned from deadchat.")
+ return
+
+ if (src.client)
+ if(src.client.prefs.muted & MUTE_DEADCHAT)
+ to_chat(src, "You cannot talk in deadchat (muted).")
+ return
+
+ if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
+ return
+
+ var/mob/dead/observer/O = src
+ if(isobserver(src) && O.deadchat_name)
+ name = "[O.deadchat_name]"
+ else
+ if(mind && mind.name)
+ name = "[mind.name]"
+ else
+ name = real_name
+ if(name != real_name)
+ alt_name = " (died as [real_name])"
+
+ var/K
+
+ if(key)
+ K = src.key
+
+ message = src.say_quote(message, get_spans())
+ var/rendered = "DEAD: [name][alt_name] [message]"
+
+ deadchat_broadcast(rendered, follow_target = src, speaker_key = K)
+
+/mob/proc/check_emote(message)
+ if(copytext(message, 1, 2) == "*")
+ emote(copytext(message, 2))
+ return 1
+
+/mob/proc/emote(var/act)
+ return
+
+/mob/proc/hivecheck()
+ return 0
+
+/mob/proc/lingcheck()
+ return LINGHIVE_NONE
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 80ab6929d5..8dfadf70f5 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -160,8 +160,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
- if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
+ if((stat != CONSCIOUS && stat != SOFT_CRIT))
blind_minimum = 1
+ if(isliving(src))
+ var/mob/living/L = src
+ if(L.has_disability(BLIND))
+ blind_minimum = 1
eye_blind = max(eye_blind+amount, blind_minimum)
if(!eye_blind)
clear_alert("blind")
@@ -177,8 +181,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
- if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
+ if(stat != CONSCIOUS && stat != SOFT_CRIT)
blind_minimum = 1
+ if(isliving(src))
+ var/mob/living/L = src
+ if(L.has_disability(BLIND))
+ blind_minimum = 1
eye_blind = blind_minimum
if(!eye_blind)
clear_alert("blind")
@@ -227,31 +235,6 @@
/mob/proc/set_disgust(amount)
return
-/////////////////////////////////// BLIND DISABILITY ////////////////////////////////////
-
-/mob/proc/cure_blind() //when we want to cure the BLIND disability only.
- return
-
-/mob/proc/become_blind()
- return
-
-/////////////////////////////////// NEARSIGHT DISABILITY ////////////////////////////////////
-
-/mob/proc/cure_nearsighted()
- return
-
-/mob/proc/become_nearsighted()
- return
-
-
-//////////////////////////////// HUSK DISABILITY ///////////////////////////:
-
-/mob/proc/cure_husk()
- return
-
-/mob/proc/become_husk()
- return
-
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 534307f727..42a1ce725f 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -58,7 +58,6 @@
O.suiciding = suiciding
if(hellbound)
O.hellbound = hellbound
- O.loc = loc
O.a_intent = INTENT_HARM
//keep viruses?
@@ -113,7 +112,7 @@
var/obj/item/bodypart/chest/torso = O.get_bodypart("chest")
if(cavity_object)
torso.cavity_item = cavity_object //cavity item is given to the new chest
- cavity_object.loc = O
+ cavity_object.forceMove(O)
for(var/missing_zone in missing_bodyparts_zones)
var/obj/item/bodypart/BP = O.get_bodypart(missing_zone)
@@ -220,8 +219,6 @@
if(hellbound)
O.hellbound = hellbound
- O.loc = loc
-
//keep viruses?
if (tr_flags & TR_KEEPVIRUS)
O.viruses = viruses
@@ -276,7 +273,7 @@
var/obj/item/bodypart/chest/torso = get_bodypart("chest")
if(cavity_object)
torso.cavity_item = cavity_object //cavity item is given to the new chest
- cavity_object.loc = O
+ cavity_object.forceMove(O)
for(var/missing_zone in missing_bodyparts_zones)
var/obj/item/bodypart/BP = O.get_bodypart(missing_zone)
@@ -401,7 +398,6 @@
R.mmi.brainmob.real_name = real_name //the name of the brain inside the cyborg is the robotized human's name.
R.mmi.brainmob.name = real_name
- R.loc = loc
R.job = "Cyborg"
R.notify_ai(NEW_BORG)
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/clipboard.dm b/code/modules/paperwork/clipboard.dm
index d9d220b0ef..e8487b3344 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -73,7 +73,7 @@
if(href_list["pen"])
if(haspen)
- haspen.loc = usr.loc
+ haspen.forceMove(usr.loc)
usr.put_in_hands(haspen)
haspen = null
@@ -96,7 +96,7 @@
if(href_list["remove"])
var/obj/item/P = locate(href_list["remove"])
if(istype(P) && P.loc == src)
- P.loc = usr.loc
+ P.forceMove(usr.loc)
usr.put_in_hands(P)
if(P == toppaper)
toppaper = null
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 3221a2c8db..c81ab37591 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -62,7 +62,7 @@
if(href_list["remove"])
var/obj/item/I = locate(href_list["remove"])
if(istype(I) && I.loc == src)
- I.loc = usr.loc
+ I.forceMove(usr.loc)
usr.put_in_hands(I)
if(href_list["read"])
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 1fb1846f4c..00fbcdc6f7 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -93,7 +93,7 @@
return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
- if(H.disabilities & CLUMSY && prob(25))
+ if(H.has_disability(CLUMSY) && prob(25))
to_chat(H, "You cut yourself on the paper! Ahhhh! Ahhhhh!")
H.damageoverlaytemp = 9001
H.update_damage_hud()
@@ -317,7 +317,7 @@
to_chat(user, "You stamp the paper with your rubber stamp.")
if(P.is_hot())
- if(user.disabilities & CLUMSY && prob(10))
+ if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("[user] accidentally ignites themselves!", \
"You miss the paper and accidentally light yourself on fire!")
user.dropItemToGround(P)
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 2d5fcc6e3a..17e2fe2a00 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -65,7 +65,7 @@
update_icon()
else if(P.is_hot())
- if(user.disabilities & CLUMSY && prob(10))
+ if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("[user] accidentally ignites themselves!", \
"You miss [src] and accidentally light yourself on fire!")
user.dropItemToGround(P)
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 0826a49c7c..cde600186f 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -23,6 +23,7 @@
throw_range = 7
materials = list(MAT_METAL=10)
pressure_resistance = 2
+ grind_results = list("iron" = 2, "iodine" = 1)
var/colour = "black" //what colour the ink is!
var/traitor_unlock_degrees = 0
var/degrees = 0
@@ -161,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)
@@ -174,7 +175,8 @@
reagents.trans_to(M, reagents.total_volume)
-/obj/item/pen/sleepy/New()
+/obj/item/pen/sleepy/Initialize()
+ . = ..()
create_reagents(45)
reagents.add_reagent("chloralhydrate2", 20)
reagents.add_reagent("mutetoxin", 15)
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 20038f5745..e065fd8c03 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -247,10 +247,10 @@
/obj/machinery/photocopier/proc/remove_photocopy(obj/item/O, mob/user)
if(!issilicon(user)) //surprised this check didn't exist before, putting stuff in AI's hand is bad
- O.loc = user.loc
+ O.forceMove(user.loc)
user.put_in_hands(O)
else
- O.loc = src.loc
+ O.forceMove(drop_location())
to_chat(user, "You take [O] out of [src].")
/obj/machinery/photocopier/attackby(obj/item/O, mob/user, params)
@@ -338,16 +338,16 @@
else
user.visible_message("[user] puts [target] onto the photocopier!", "You put [target] onto the photocopier.")
- target.loc = get_turf(src)
+ target.forceMove(drop_location())
ass = target
if(photocopy)
- photocopy.loc = src.loc
+ photocopy.forceMove(drop_location())
visible_message("[photocopy] is shoved out of the way by [ass]!")
photocopy = null
else if(copy)
- copy.loc = src.loc
+ copy.forceMove(drop_location())
visible_message("[copy] is shoved out of the way by [ass]!")
copy = null
updateUsrDialog()
@@ -391,5 +391,6 @@
/obj/item/device/toner
name = "toner cartridge"
icon_state = "tonercartridge"
+ grind_results = list("iodine" = 40, "iron" = 10)
var/charges = 5
var/max_charges = 5
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 48b045f680..6e908c0f6a 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -33,6 +33,7 @@
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
max_integrity = 50
+ grind_results = list("iodine" = 4)
var/icon/img //Big photo image
var/scribble //Scribble on the back.
var/blueprints = 0 //Does it include the blueprints?
diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm
index a37344d635..f8b8cae22a 100644
--- a/code/modules/power/antimatter/control.dm
+++ b/code/modules/power/antimatter/control.dm
@@ -339,7 +339,7 @@
if(href_list["ejectjar"])
if(fueljar)
- fueljar.loc = src.loc
+ fueljar.forceMove(drop_location())
fueljar = null
//fueljar.control_unit = null currently it does not care where it is
//update_icon() when we have the icon for it
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 7f3b428978..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
@@ -972,7 +972,7 @@
else
to_chat(occupier, "Primary core damaged, unable to return core processes.")
if(forced)
- occupier.loc = src.loc
+ occupier.forceMove(drop_location())
occupier.death()
occupier.gib()
for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
@@ -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/cable.dm b/code/modules/power/cable.dm
index 9e4e29ceb5..ca424cb80d 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -427,7 +427,7 @@ By design, d1 is the smallest direction and d2 is the highest
var/obj/O = P_list[1]
// remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist
if(remove)
- loc = null
+ moveToNullspace()
powernet.remove_cable(src) //remove the cut cable from its powernet
addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables
@@ -472,6 +472,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
singular_name = "cable piece"
full_w_class = WEIGHT_CLASS_SMALL
+ grind_results = list("copper" = 2) //2 copper per cable in the coil
/obj/item/stack/cable_coil/cyborg
is_cyborg = 1
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 1e1407e852..cd24dbb928 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -14,6 +14,7 @@
var/charge = 0 // note %age conveted to actual charge in New
var/maxcharge = 1000
materials = list(MAT_METAL=700, MAT_GLASS=50)
+ grind_results = list("lithium" = 15, "iron" = 5, "silicon" = 5)
var/rigged = 0 // true if rigged to explode
var/chargerate = 100 //how much power is given every tick in a recharger
var/self_recharge = 0 //does it self recharge, over time, or not?
@@ -107,6 +108,7 @@
to_chat(user, "You inject the solution into the power cell.")
if(S.reagents.has_reagent("plasma", 5))
rigged = 1
+ grind_results["plasma"] = 5
S.reagents.clear_reagents()
@@ -155,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
@@ -334,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/lighting.dm b/code/modules/power/lighting.dm
index 3acac6cee5..749dcb463e 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -680,6 +680,7 @@
var/base_state
var/switchcount = 0 // number of times switched
materials = list(MAT_GLASS=100)
+ grind_results = list("silicon" = 5, "nitrogen" = 10) //Nitrogen is used as a cheaper alternative to argon in incandescent lighbulbs
var/rigged = 0 // true if rigged to explode
var/brightness = 2 //how much light it gives off
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 0ede336ef6..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()
@@ -132,7 +132,7 @@
var/obj/item/tank/internals/plasma/Z = src.loaded_tank
if (!Z)
return
- Z.loc = get_turf(src)
+ Z.forceMove(drop_location())
Z.layer = initial(Z.layer)
Z.plane = initial(Z.plane)
src.loaded_tank = null
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 74aa140721..cdfbb35b34 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -285,9 +285,8 @@ field_generator power level display
var/field_dir = get_dir(T,get_step(G.loc, NSEW))
T = get_step(T, NSEW)
if(!locate(/obj/machinery/field/containment) in T)
- var/obj/machinery/field/containment/CF = new/obj/machinery/field/containment()
+ var/obj/machinery/field/containment/CF = new(T)
CF.set_master(src,G)
- CF.loc = T
CF.setDir(field_dir)
fields += CF
G.fields += CF
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 fb530f128f..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
@@ -419,7 +419,7 @@
new /obj/item/shard( src.loc )
var/obj/item/circuitboard/computer/solar_control/M = new /obj/item/circuitboard/computer/solar_control( A )
for (var/obj/C in src)
- C.loc = src.loc
+ C.forceMove(drop_location())
A.circuit = M
A.state = 3
A.icon_state = "3"
@@ -430,7 +430,7 @@
var/obj/structure/frame/computer/A = new /obj/structure/frame/computer( src.loc )
var/obj/item/circuitboard/computer/solar_control/M = new /obj/item/circuitboard/computer/solar_control( A )
for (var/obj/C in src)
- C.loc = src.loc
+ C.forceMove(drop_location())
A.circuit = M
A.state = 4
A.icon_state = "4"
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/power/tracker.dm b/code/modules/power/tracker.dm
index 5e129acf8f..a46627b7ca 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -47,7 +47,7 @@
S.glass_type = /obj/item/stack/sheet/glass
S.tracker = 1
S.anchored = TRUE
- S.loc = src
+ S.forceMove(src)
update_icon()
//updates the tracker icon and the facing angle for the control computer
@@ -94,4 +94,4 @@
// Tracker Electronic
/obj/item/electronics/tracker
- name = "tracker electronics"
\ No newline at end of file
+ name = "tracker electronics"
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 e5b905019d..b3439c86b2 100644
--- a/code/modules/projectiles/ammunition/caseless.dm
+++ b/code/modules/projectiles/ammunition/caseless.dm
@@ -4,10 +4,11 @@
/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
- loc = null
+ moveToNullspace()
return 1
else
return 0
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/boxes_magazines/internal_mag.dm b/code/modules/projectiles/boxes_magazines/internal_mag.dm
index 3a8b4e6f2f..f486be732d 100644
--- a/code/modules/projectiles/boxes_magazines/internal_mag.dm
+++ b/code/modules/projectiles/boxes_magazines/internal_mag.dm
@@ -51,10 +51,10 @@
var/obj/item/ammo_casing/bullet = stored_ammo[i]
if(!bullet || !bullet.BB) // found a spent ammo
stored_ammo[i] = R
- R.loc = src
+ R.forceMove(src)
if(bullet)
- bullet.loc = get_turf(src.loc)
+ bullet.forceMove(drop_location())
return 1
return 0
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 37e868462e..97a907031c 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -77,9 +77,8 @@
..()
var/obj/item/gun/G = locate(/obj/item/gun) in contents
if(G)
- G.loc = loc
- qdel(G.pin)
- G.pin = null
+ G.forceMove(loc)
+ QDEL_NULL(G.pin)
visible_message("[G] can now fit a new pin, but the old one was destroyed in the process.", null, null, 3)
qdel(src)
@@ -108,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)
@@ -159,7 +158,7 @@
//Exclude lasertag guns from the CLUMSY check.
if(clumsy_check)
if(istype(user))
- if (user.disabilities & CLUMSY && prob(40))
+ if (user.has_disability(CLUMSY) && prob(40))
to_chat(user, "You shoot yourself in the foot with [src]!")
var/shot_leg = pick("l_leg", "r_leg")
process_fire(user,user,0,params, zone_override = shot_leg)
@@ -401,7 +400,8 @@
/obj/item/gun/dropped(mob/user)
..()
- zoom(user,FALSE)
+ if(zoomed)
+ zoom(user,FALSE)
if(azoom)
azoom.Remove(user)
if(alight)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index bfc9ceac64..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
@@ -107,16 +113,21 @@
/obj/item/gun/ballistic/attack_self(mob/living/user)
var/obj/item/ammo_casing/AC = chambered //Find chambered round
if(magazine)
- magazine.loc = get_turf(src.loc)
+ 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.loc = get_turf(src)
- AC.SpinAnimation(10, 1)
+ AC.forceMove(drop_location())
+ 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
@@ -216,4 +227,3 @@
desc = "A foreign knock-off suppressor, it feels flimsy, cheap, and brittle. Still fits all weapons."
icon = 'icons/obj/guns/projectile.dmi'
icon_state = "suppressor"
-
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index eb36608e77..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"]"
@@ -325,7 +325,7 @@
else if(cover_open && magazine)
//drop the mag
magazine.update_icon()
- magazine.loc = get_turf(src.loc)
+ magazine.forceMove(drop_location())
user.put_in_hands(magazine)
magazine = null
update_icon()
@@ -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 42f4fb8a05..b98bdaf957 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -39,13 +39,11 @@
var/obj/item/ammo_casing/CB
CB = magazine.get_round(0)
if(CB)
- CB.loc = get_turf(src.loc)
- CB.SpinAnimation(10, 1)
- CB.update_icon()
+ CB.forceMove(drop_location())
+ 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)
@@ -289,7 +287,7 @@
var/obj/item/ammo_casing/CB
CB = magazine.get_round(0)
chambered = null
- CB.loc = get_turf(src.loc)
+ CB.forceMove(drop_location())
CB.update_icon()
num_unloaded++
if (num_unloaded)
@@ -351,7 +349,7 @@
clumsy_check = 0
/obj/item/gun/ballistic/revolver/reverse/can_trigger_gun(mob/living/user)
- if((user.disabilities & CLUMSY) || (user.mind && user.mind.assigned_role == "Clown"))
+ if((user.has_disability(CLUMSY)) || (user.mind && user.mind.assigned_role == "Clown"))
return ..()
if(process_fire(user, user, 0, zone_override = "head"))
user.visible_message("[user] somehow manages to shoot [user.p_them()]self in the face!", "You somehow shoot yourself in the face! How the hell?!")
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 650e5ec81f..e702013233 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -56,8 +56,8 @@
/obj/item/gun/ballistic/shotgun/proc/pump_unload(mob/M)
if(chambered)//We have a shell in the chamber
- chambered.loc = get_turf(src)//Eject casing
- chambered.SpinAnimation(5, 1)
+ chambered.forceMove(drop_location())//Eject casing
+ 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 e1069a6bce..a2ea7dfb59 100644
--- a/code/modules/projectiles/guns/beam_rifle.dm
+++ b/code/modules/projectiles/guns/beam_rifle.dm
@@ -4,9 +4,6 @@
#define ZOOM_LOCK_CENTER_VIEW 2
#define ZOOM_LOCK_OFF 3
-#define ZOOM_SPEED_STEP 0
-#define ZOOM_SPEED_INSTANT 1
-
#define AUTOZOOM_PIXEL_STEP_FACTOR 48
#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1
@@ -45,7 +42,7 @@
var/lastangle = 0
var/aiming_lastangle = 0
var/mob/current_user = null
- var/obj/effect/projectile_beam/current_tracer
+ var/list/obj/effect/projectile_beam/current_tracers
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
var/structure_bleed_coeff = 0.7
@@ -69,9 +66,8 @@
//ZOOMING
var/zoom_current_view_increase = 0
var/zoom_target_view_increase = 10
- var/zoom_speed = ZOOM_SPEED_STEP
var/zooming = FALSE
- var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE
+ var/zoom_lock = ZOOM_LOCK_OFF
var/zooming_angle
var/current_zoom_x = 0
var/current_zoom_y = 0
@@ -80,7 +76,6 @@
var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged")
var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty")
- var/datum/action/item_action/zoom_speed_action/zoom_speed_action
var/datum/action/item_action/zoom_lock_action/zoom_lock_action
/obj/item/gun/energy/beam_rifle/debug
@@ -103,15 +98,6 @@
. = ..()
/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action)
- if(istype(action, /datum/action/item_action/zoom_speed_action))
- zoom_speed++
- if(zoom_speed > 1)
- zoom_speed = ZOOM_SPEED_STEP
- switch(zoom_speed)
- if(ZOOM_SPEED_STEP)
- to_chat(owner, "You switch [src]'s digital zoom to stepper mode.")
- if(ZOOM_SPEED_INSTANT)
- to_chat(owner, "You switch [src]'s digital zoom to instant mode.")
if(istype(action, /datum/action/item_action/zoom_lock_action))
zoom_lock++
if(zoom_lock > 3)
@@ -135,8 +121,6 @@
var/total_time = SSfastprocess.wait
if(delay_override)
total_time = delay_override
- if(zoom_speed == ZOOM_SPEED_INSTANT)
- total_time = 0
zoom_animating = total_time
animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL)
zoom_animating = 0
@@ -150,18 +134,10 @@
/obj/item/gun/energy/beam_rifle/proc/handle_zooming()
if(!zooming || !check_user())
return
- if(zoom_speed == ZOOM_SPEED_INSTANT)
- current_user.client.change_view(world.view + zoom_target_view_increase)
- zoom_current_view_increase = zoom_target_view_increase
- set_autozoom_pixel_offsets_immediate(zooming_angle)
- smooth_zooming()
- return
- if(zoom_current_view_increase > zoom_target_view_increase)
- return
- zoom_current_view_increase++
- current_user.client.change_view(zoom_current_view_increase + world.view)
+ current_user.client.change_view(world.view + zoom_target_view_increase)
+ zoom_current_view_increase = zoom_target_view_increase
set_autozoom_pixel_offsets_immediate(zooming_angle)
- smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed)
+ smooth_zooming()
/obj/item/gun/energy/beam_rifle/proc/start_zooming()
if(zoom_lock == ZOOM_LOCK_OFF)
@@ -169,8 +145,9 @@
zooming = TRUE
/obj/item/gun/energy/beam_rifle/proc/stop_zooming()
- zooming = FALSE
- reset_zooming()
+ if(zooming)
+ zooming = FALSE
+ reset_zooming()
/obj/item/gun/energy/beam_rifle/proc/reset_zooming()
if(!check_user(FALSE))
@@ -204,14 +181,14 @@
/obj/item/gun/energy/beam_rifle/Initialize()
. = ..()
+ current_tracers = list()
START_PROCESSING(SSprojectiles, src)
- zoom_speed_action = new(src)
zoom_lock_action = new(src)
/obj/item/gun/energy/beam_rifle/Destroy()
STOP_PROCESSING(SSfastprocess, src)
set_user(null)
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/emp_act(severity)
@@ -245,6 +222,7 @@
/obj/item/gun/energy/beam_rifle/process()
if(!aiming)
+ last_process = world.time
return
check_user()
handle_zooming()
@@ -299,7 +277,7 @@
set waitfor = FALSE
aiming_time_left = aiming_time
aiming = FALSE
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
stop_zooming()
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
@@ -341,7 +319,7 @@
sync_ammo()
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
stop_aiming()
- QDEL_NULL(current_tracer)
+ QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
@@ -365,7 +343,7 @@
AC.sync_stats()
/obj/item/gun/energy/beam_rifle/proc/delay_penalty(amount)
- aiming_time_left = Clamp(aiming_time_left + amount, 0, aiming_time)
+ aiming_time_left = CLAMP(aiming_time_left + amount, 0, aiming_time)
/obj/item/ammo_casing/energy/beam_rifle
name = "particle acceleration lens"
@@ -416,11 +394,11 @@
HS_BB.stun = projectile_stun
HS_BB.impact_structure_damage = impact_structure_damage
HS_BB.aoe_mob_damage = aoe_mob_damage
- HS_BB.aoe_mob_range = Clamp(aoe_mob_range, 0, 15) //Badmin safety lock
+ HS_BB.aoe_mob_range = CLAMP(aoe_mob_range, 0, 15) //Badmin safety lock
HS_BB.aoe_fire_chance = aoe_fire_chance
HS_BB.aoe_fire_range = aoe_fire_range
HS_BB.aoe_structure_damage = aoe_structure_damage
- HS_BB.aoe_structure_range = Clamp(aoe_structure_range, 0, 15) //Badmin safety lock
+ HS_BB.aoe_structure_range = CLAMP(aoe_structure_range, 0, 15) //Badmin safety lock
HS_BB.wall_devastate = wall_devastate
HS_BB.wall_pierce_amount = wall_pierce_amount
HS_BB.structure_pierce_amount = structure_piercing
@@ -502,11 +480,11 @@
if(!do_pierce)
return FALSE
if(pierced[target]) //we already pierced them go away
- loc = get_turf(target)
+ forceMove(get_turf(target))
return TRUE
if(isclosedturf(target))
if(wall_pierce++ < wall_pierce_amount)
- loc = target
+ forceMove(target)
if(prob(wall_devastate))
if(iswallturf(target))
var/turf/closed/wall/W = target
@@ -522,7 +500,7 @@
var/obj/O = AM
O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE)
pierced[AM] = TRUE
- loc = get_turf(AM)
+ forceMove(AM.drop_location())
structure_pierce++
return TRUE
return FALSE
@@ -555,136 +533,103 @@
handle_impact(target)
/obj/item/projectile/beam/beam_rifle/Collide(atom/target)
- paused = TRUE
if(check_pierce(target))
permutated += target
return FALSE
if(!QDELETED(target))
cached = get_turf(target)
- paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
- paused = TRUE
if(!QDELETED(target))
cached = get_turf(target)
handle_hit(target)
- paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/hitscan
icon_state = ""
var/tracer_type = /obj/effect/projectile_beam/tracer
- var/starting_z
- var/starting_p_x
- var/starting_p_y
+ var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
var/constant_tracer = FALSE
- var/travelled_p_x = 0
- var/travelled_p_y = 0
- var/tracer_spawned = FALSE
+ var/beam_index
/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
- paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED!
- spawn_tracer(constant_tracer)
+ if(loc)
+ var/datum/point/pcache = trajectory.copy_to()
+ beam_segments[beam_index] = pcache
+ generate_tracers(constant_tracer)
return ..()
-/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE)
- if(tracer_spawned)
- return
- tracer_spawned = TRUE
- //Remind me to port baystation trajectories so this shit isn't needed...
- var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1)
- var/scaling = pixels_travelled/world.icon_size
- var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2))
- var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2))
- var/tracer_px = midpoint_p_x % world.icon_size
- var/tracer_py = midpoint_p_y % world.icon_size
- var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size
- var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size
- var/obj/effect/projectile_beam/PB = new tracer_type(src)
- PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z))
- if(put_in_rifle && istype(gun))
- if(gun.current_tracer)
- QDEL_NULL(gun.current_tracer)
- gun.current_tracer = PB
- else
- QDEL_IN(PB, 5)
+/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
+ var/datum/point/pcache = trajectory.copy_to()
+ . = ..()
+ if(. && !QDELETED(src)) //successful touch and not destroyed.
+ beam_segments[beam_index] = pcache
+ beam_index = pcache
+ beam_segments[beam_index] = null
-/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T)
- if(!istype(T))
- return TRUE
- var/tx = T.x
- var/ty = T.y
- if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10))
- return TRUE
- return FALSE
+/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
+ var/datum/point/pcache = trajectory.copy_to()
+ beam_segments[beam_index] = pcache
+ beam_index = RETURN_PRECISE_POINT(newloc)
+ beam_segments[beam_index] = null
+ return ..()
+
+/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
+ set waitfor = FALSE
+ if(highlander && istype(gun))
+ QDEL_LIST(gun.current_tracers)
+ for(var/datum/point/p in beam_segments)
+ gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
+ else
+ for(var/datum/point/p in beam_segments)
+ generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
+ if(cleanup)
+ QDEL_LIST(beam_segments)
+ beam_segments = null
+ QDEL_NULL(beam_index)
/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
- set waitfor = 0
+ set waitfor = FALSE
+ var/turf/starting = get_turf(src)
+ trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
if(!log_override && firer && original)
add_logs(firer, original, "fired at", src, " [get_area(src)]")
+ fired = TRUE
if(setAngle)
Angle = setAngle
- var/next_run = world.time
- var/old_pixel_x = pixel_x
- var/old_pixel_y = pixel_y
var/safety = 0 //The code works fine, but... just in case...
var/turf/c2
- var/starting_x = loc.x
- var/starting_y = loc.y
- starting_z = loc.z
- starting_p_x = starting_x * world.icon_size + pixel_x
- starting_p_y = starting_y * world.icon_size + pixel_y
+ beam_segments = list() //initialize segment list with the list for the first segment
+ beam_index = RETURN_PRECISE_POINT(src)
+ beam_segments[beam_index] = null //record start.
+ if(spread)
+ Angle += (rand() - 0.5) * spread
while(loc)
+ if(paused || QDELETED(src))
+ return
if(++safety > (range * 3)) //If it's looping for way, way too long...
+ qdel(src)
+ stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
return //Kill!
- if(spread)
- Angle += (rand() - 0.5) * spread
var/matrix/M = new
M.Turn(Angle)
transform = M
- var/Pixel_x=sin(Angle)+16*sin(Angle)*2
- var/Pixel_y=cos(Angle)+16*cos(Angle)*2
- travelled_p_x += Pixel_x
- travelled_p_y += Pixel_y
- var/pixel_x_offset = old_pixel_x + Pixel_x
- var/pixel_y_offset = old_pixel_y + Pixel_y
- var/new_x = x
- var/new_y = y
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- old_pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- old_pixel_x += 32
- new_x--
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- old_pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- old_pixel_y += 32
- new_y--
- pixel_x = old_pixel_x
- pixel_y = old_pixel_y
- step_towards(src, locate(new_x, new_y, z))
- next_run += max(world.tick_lag, speed)
- var/delay = next_run - world.time
- if(delay <= world.tick_lag*2)
- pixel_x = pixel_x_offset
- pixel_y = pixel_y_offset
+ trajectory.increment()
+ var/turf/T = trajectory.return_turf()
+ if(T.z != loc.z)
+ before_z_change(loc, T)
+ trajectory_ignore_forcemove = TRUE
+ forceMove(T)
+ trajectory_ignore_forcemove = FALSE
else
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
- old_pixel_x = pixel_x_offset
- old_pixel_y = pixel_y_offset
+ step_towards(src, T)
+ animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
+
if(can_hit_target(original, permutated))
Collide(original)
- c2 = loc
Range()
- if(check_for_turf_edge(loc))
- spawn_tracer(constant_tracer)
+ c2 = get_turf(src)
if(istype(c2))
cached = c2
@@ -704,76 +649,3 @@
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
qdel(src)
return FALSE
-
-/obj/effect/projectile_beam
- icon = 'icons/obj/projectiles.dmi'
- layer = ABOVE_MOB_LAYER
- anchored = TRUE
- light_power = 1
- light_range = 2
- light_color = "#00ffff"
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- flags_1 = ABSTRACT_1
- appearance_flags = 0
-
-/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
- var/matrix/M
- if(!override)
- M = transform
- else
- M = new
- M.Scale(nx,ny)
- transform = M
-
-/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
- var/matrix/M
- if(!override)
- M = transform
- else
- M = new
- M.Turn(angle)
- transform = M
-
-/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
- if(angle_override && p_x && p_y && color_override && scaling)
- apply_vars(angle_override, p_x, p_y, color_override, scaling)
- return ..()
-
-/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0)
- var/mutable_appearance/look = new(src)
- look.pixel_x = p_x
- look.pixel_y = p_y
- if(color_override)
- look.color = color_override
- appearance = look
- scale_to(1,scaling, FALSE)
- turn_to(angle_override, FALSE)
- if(!isnull(new_loc)) //If you want to null it just delete it...
- forceMove(new_loc)
- for(var/i in 1 to increment)
- pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
- pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
-
-/obj/effect/projectile_beam/tracer
- icon_state = "tracer_beam"
-
-/obj/effect/projectile_beam/tracer/aiming
- icon_state = "gbeam"
-
-/datum/action/item_action/zoom_speed_action
- name = "Toggle Zooming Speed"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
- button_icon_state = "projectile"
- background_icon_state = "bg_tech"
-
-/datum/action/item_action/zoom_lock_action
- name = "Switch Zoom Mode"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
- button_icon_state = "zoom_mode"
- background_icon_state = "bg_tech"
-
-/obj/effect/projectile_beam/singularity_pull()
- return
-
-/obj/effect/projectile_beam/singularity_act()
- return
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 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/guns/syringe_gun.dm b/code/modules/projectiles/guns/syringe_gun.dm
index b8e3c97e81..ac9f7daedf 100644
--- a/code/modules/projectiles/guns/syringe_gun.dm
+++ b/code/modules/projectiles/guns/syringe_gun.dm
@@ -42,7 +42,7 @@
if(!S)
return 0
- S.loc = user.loc
+ S.forceMove(user.loc)
syringes.Remove(S)
to_chat(user, "You unload [S] from \the [src].")
@@ -101,4 +101,4 @@
return TRUE
else
to_chat(user, "[src] cannot hold more syringes!")
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index faf7de9010..6cbe2de450 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -129,7 +129,7 @@
// A gun with ultra-honk pin is useful for clown and useless for everyone else.
/obj/item/device/firing_pin/clown/ultra/pin_auth(mob/living/user)
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
- if(!(user.disabilities & CLUMSY) && !(user.mind && user.mind.assigned_role == "Clown"))
+ if(!(user.has_disability(CLUMSY)) && !(user.mind && user.mind.assigned_role == "Clown"))
return 0
return 1
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 0e3bd98c68..08142f1e8d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -31,16 +31,11 @@
var/last_projectile_move = 0
var/last_process = 0
var/time_offset = 0
- var/old_pixel_x = 0
- var/old_pixel_y = 0
- var/pixel_x_increment = 0
- var/pixel_y_increment = 0
- var/pixel_x_offset = 0
- var/pixel_y_offset = 0
- var/new_x = 0
- var/new_y = 0
+ var/datum/point/vector/trajectory
+ var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
+ var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
var/Angle = 0
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
var/spread = 0 //amount (in degrees) of projectile spread
@@ -48,6 +43,9 @@
var/ricochets = 0
var/ricochets_max = 2
var/ricochet_chance = 30
+
+ var/colliding = FALSE //pause processing..
+
var/ignore_source_check = FALSE
var/damage = 10
@@ -168,27 +166,35 @@
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
- return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
+ return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
+/obj/item/projectile/proc/on_ricochet(atom/A)
+ return
+
/obj/item/projectile/Collide(atom/A)
+ colliding = TRUE
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
ricochets++
if(A.handle_ricochet(src))
+ on_ricochet(A)
ignore_source_check = TRUE
range = initial(range)
- return FALSE
+ return TRUE
if(firer && !ignore_source_check)
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
- loc = A.loc
+ trajectory_ignore_forcemove = TRUE
+ forceMove(get_turf(A))
+ trajectory_ignore_forcemove = FALSE
+ colliding = FALSE
return FALSE
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
- var/volume = Clamp(vol_by_damage() + 20, 0, 100)
+ var/volume = CLAMP(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
@@ -197,25 +203,32 @@
if(!prehit(A))
if(forcedodge)
- loc = target_turf
+ trajectory_ignore_forcemove = TRUE
+ forceMove(target_turf)
+ trajectory_ignore_forcemove = FALSE
+ colliding = FALSE
return FALSE
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
- loc = target_turf
+ trajectory_ignore_forcemove = TRUE
+ forceMove(target_turf)
+ trajectory_ignore_forcemove = FALSE
if(A)
permutated.Add(A)
+ colliding = FALSE
return FALSE
else
var/atom/alt = select_target(A)
if(alt)
if(!prehit(alt))
+ colliding = FALSE
return FALSE
alt.bullet_act(src, def_zone)
qdel(src)
+ colliding = FALSE
return TRUE
-
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
return
@@ -246,12 +259,30 @@
return TRUE
return FALSE
+/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
+ if(!trajectory && isnull(forced_angle) && isnull(Angle))
+ return FALSE
+ var/datum/point/vector/current = trajectory
+ if(!current)
+ var/turf/T = get_turf(src)
+ current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed)
+ var/datum/point/vector/v = current.return_vector_after_increments(moves)
+ return v.return_turf()
+
+/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
+ var/turf/current = get_turf(src)
+ var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
+ return getline(current, ending)
+
+/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
+ return
+
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return TRUE //Bullets don't drift in space
/obj/item/projectile/process()
last_process = world.time
- if(!loc || !fired)
+ if(!loc || !fired || !trajectory)
fired = FALSE
return PROCESS_KILL
if(paused || !isturf(loc))
@@ -259,7 +290,7 @@
return
var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset
time_offset = 0
- var/required_moves = speed > 0? Floor(elapsed_time_deciseconds / speed) : MOVES_HITSCAN //Would be better if a 0 speed made hitscan but everyone hates those so I can't make it a universal system :<
+ var/required_moves = speed > 0? FLOOR(elapsed_time_deciseconds / speed, 1) : MOVES_HITSCAN //Would be better if a 0 speed made hitscan but everyone hates those so I can't make it a universal system :<
if(required_moves == MOVES_HITSCAN)
required_moves = SSprojectiles.global_max_tick_moves
else
@@ -267,7 +298,7 @@
var/overrun = required_moves - SSprojectiles.global_max_tick_moves
required_moves = SSprojectiles.global_max_tick_moves
time_offset += overrun * speed
- time_offset += Modulus(elapsed_time_deciseconds, speed)
+ time_offset += MODULUS(elapsed_time_deciseconds, speed)
for(var/i in 1 to required_moves)
pixel_move(required_moves)
@@ -285,73 +316,70 @@
setAngle(angle)
if(spread)
setAngle(Angle + ((rand() - 0.5) * spread))
+ var/turf/starting = get_turf(src)
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
- var/turf/starting = get_turf(src)
- var/turf/target = locate(Clamp(starting + xo, 1, world.maxx), Clamp(starting + yo, 1, world.maxy), starting.z)
+ if(isnull(xo) || isnull(yo))
+ stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
+ qdel(src)
+ return
+ var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
setAngle(Get_Angle(src, target))
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
- old_pixel_x = pixel_x
- old_pixel_y = pixel_y
+ trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
last_projectile_move = world.time
fired = TRUE
if(!isprocessing)
START_PROCESSING(SSprojectiles, src)
+ pixel_move(1) //move it now!
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
Angle = new_angle
- return TRUE
-
-/obj/item/projectile/proc/pixel_move(moves)
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
+ if(trajectory)
+ trajectory.set_angle(new_angle)
+ return TRUE
- pixel_x_increment=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
- pixel_y_increment=round((cos(Angle)+16*cos(Angle)*2), 1)
- pixel_x_offset = old_pixel_x + pixel_x_increment
- pixel_y_offset = old_pixel_y + pixel_y_increment
- new_x = x
- new_y = y
+/obj/item/projectile/forceMove(atom/target)
+ . = ..()
+ if(trajectory && !trajectory_ignore_forcemove && isturf(target))
+ trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- old_pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- old_pixel_x += 32
- new_x--
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- old_pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- old_pixel_y += 32
- new_y--
+/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
+ if(!loc || !trajectory)
+ return
+ last_projectile_move = world.time
+ if(!nondirectional_sprite)
+ var/matrix/M = new
+ M.Turn(Angle)
+ transform = M
+ trajectory.increment(trajectory_multiplier)
+ var/turf/T = trajectory.return_turf()
+ if(T.z != loc.z)
+ before_z_change(loc, T)
+ trajectory_ignore_forcemove = TRUE
+ forceMove(T)
+ trajectory_ignore_forcemove = FALSE
+ pixel_x = trajectory.return_px()
+ pixel_y = trajectory.return_py()
+ else
+ step_towards(src, T)
+ pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
+ pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
+ animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
- step_towards(src, locate(new_x, new_y, z))
- pixel_x = old_pixel_x
- pixel_y = old_pixel_y
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = 1, flags = ANIMATION_END_NOW)
- old_pixel_x = pixel_x_offset
- old_pixel_y = pixel_y_offset
if(can_hit_target(original, permutated))
Collide(original)
Range()
- last_projectile_move = world.time
//Returns true if the target atom is on our current turf and above the right layer
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
- if(target && (target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target))
- if(loc == get_turf(target))
- if(!(target in passthrough))
- return TRUE
- return FALSE
+ return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
var/turf/curloc = get_turf(source)
@@ -362,7 +390,8 @@
if(targloc || !params)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
-
+ setAngle(Get_Angle(src, targloc))
+
if(isliving(source) && params)
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
p_x = calculated[2]
@@ -372,8 +401,13 @@
setAngle(calculated[1] + spread)
else
setAngle(calculated[1])
- else
+ else if(targloc)
+ yo = targloc.y - curloc.y
+ xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc))
+ else
+ stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
+ qdel(src)
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
var/list/mouse_control = params2list(params)
@@ -403,7 +437,7 @@
var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
- angle = Atan2(y - oy, x - ox)
+ angle = ATAN2(y - oy, x - ox)
return list(angle, p_x, p_y)
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index 5a650ff2c3..152cff6c74 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -100,7 +100,7 @@
/obj/item/projectile/meteor/Collide(atom/A)
if(A == firer)
- loc = A.loc
+ forceMove(A.loc)
return
A.ex_act(EXPLODE_HEAVY)
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1)
@@ -612,4 +612,3 @@
knockdown = 0
nodamage = TRUE
return ..()
-
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 77fcd50306..48dd5c2dc0 100644
--- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
@@ -2,7 +2,7 @@
#define MILK_TO_BUTTER_COEFF 15
/obj/machinery/reagentgrinder
- name = "All-In-One Grinder"
+ name = "\improper All-In-One Grinder"
desc = "From BlenderTech. Will It Blend? Let's test it out!"
icon = 'icons/obj/kitchen.dmi'
icon_state = "juicer1"
@@ -16,97 +16,6 @@
var/operating = FALSE
var/obj/item/reagent_containers/beaker = null
var/limit = 10
-
- var/static/list/blend_items = list(
- //Sheets
- /obj/item/stack/sheet/mineral/plasma = list("plasma" = 20),
- /obj/item/stack/sheet/metal = list("iron" = 20),
- /obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma" = 20),
- /obj/item/stack/sheet/mineral/wood = list("carbon" = 20),
- /obj/item/stack/sheet/glass = list("silicon" = 20),
- /obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20),
- /obj/item/stack/sheet/mineral/uranium = list("uranium" = 20),
- /obj/item/stack/sheet/mineral/bananium = list("banana" = 20),
- /obj/item/stack/sheet/mineral/silver = list("silver" = 20),
- /obj/item/stack/sheet/mineral/gold = list("gold" = 20),
- /obj/item/stack/sheet/bluespace_crystal = list("bluespace" = 20),
- /obj/item/stack/cable_coil = list ("copper" = 5),
- /obj/item/ore/bluespace_crystal = list("bluespace" = 20),
- /obj/item/grown/nettle/basic = list("sacid" = 0),
- /obj/item/grown/nettle/death = list("facid" = 0, "sacid" = 0),
- /obj/item/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0),
- //Blender Stuff
- /obj/item/reagent_containers/food/snacks/donkpocket/warm = list("omnizine" = 3),
- /obj/item/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0),
- /obj/item/reagent_containers/food/snacks/grown/wheat = list("flour" = -5),
- /obj/item/reagent_containers/food/snacks/grown/oat = list("flour" = -5),
- /obj/item/reagent_containers/food/snacks/grown/rice = list("rice" = -5),
- /obj/item/reagent_containers/food/snacks/donut = list("sprinkles" = -2, "sugar" = 1),
- /obj/item/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0),
- /obj/item/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0),
- /obj/item/reagent_containers/food/snacks/egg = list("eggyolk" = -5),
- /obj/item/reagent_containers/food/snacks/deadmouse = list ("blood" = 20, "gibs" = 5), // You monster
- //Grinder stuff, but only if dry
- /obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
- /obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0),
- //Stuff that doesn't quite fit in the other categories
- /obj/item/electronics = list ("iron" = 10, "silicon" = 10),
- /obj/item/circuitboard = list ("silicon" = 20, "sacid" = 0.5), // Retrieving acid this way is extremely inefficient
- /obj/item/match = list ("phosphorus" = 2),
- /obj/item/device/toner = list ("iodine" = 40, "iron" = 10),
- /obj/item/photo = list ("iodine" = 4),
- /obj/item/pen = list ("iodine" = 2, "iron" = 1),
- /obj/item/reagent_containers/food/drinks/soda_cans = list ("aluminium" = 10),
- /obj/item/trash/can = list ("aluminium" = 10),
- /obj/item/device/flashlight/flare = list ("sulfur" = 15),
- /obj/item/device/flashlight/glowstick = list ("phenol" = 15, "hydrodgen" = 10, "oxygen" = 5),
- /obj/item/stock_parts/cell = list ("lithium" = 15, "iron" = 5, "silicon" = 5),
- /obj/item/soap = list ("lye" = 10),
- /obj/item/device/analyzer = list ("mercury" = 5, "iron" = 5, "silicon" = 5),
- /obj/item/lighter = list ("iron" = 1, "weldingfuel" = 5, "oil" = 5),
- /obj/item/light = list ("silicon" = 5, "nitrogen" = 10), //Nitrogen is used as a cheaper alternative to argon in incandescent lighbulbs
- /obj/item/cigbutt/ = list ("carbon" = 2),
- /obj/item/trash/coal = list ("carbon" = 20),
- /obj/item/stack/medical/bruise_pack = list ("styptic_powder" = 5),
- /obj/item/stack/medical/ointment = list ("silver_sulfadiazine" = 5),
- //All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.!
- /obj/item/slime_extract = list(),
- /obj/item/reagent_containers/pill = list(),
- /obj/item/reagent_containers/food = list(),
- /obj/item/reagent_containers/honeycomb = list(),
- /obj/item/toy/crayon = list(),
- /obj/item/clothing/mask/cigarette = list())
-
- var/static/list/juice_items = list(
- //Juicer Stuff
- /obj/item/reagent_containers/food/snacks/grown/corn = list("corn_starch" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/banana = list("banana" = 0),
- /obj/item/reagent_containers/food/snacks/grown/potato = list("potato" = 0),
- /obj/item/reagent_containers/food/snacks/grown/citrus/lemon = list("lemonjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/citrus/orange = list("orangejuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/citrus/lime = list("limejuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/watermelon = list("watermelonjuice" = 0),
- /obj/item/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/berries/poison = list("poisonberryjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/pumpkin = list("pumpkinjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/blumpkin = list("blumpkinjuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/apple = list("applejuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/grapes = list("grapejuice" = 0),
- /obj/item/reagent_containers/food/snacks/grown/grapes/green = list("grapejuice" = 0))
-
- var/static/list/dried_items = list(
- //Grinder stuff, but only if dry,
- /obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
- /obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
- /obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0))
-
var/list/holdingitems
/obj/machinery/reagentgrinder/Initialize()
@@ -153,11 +62,12 @@
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!")
return TRUE
+ to_chat(user, "You slide [I] into [src].")
beaker = I
update_icon()
updateUsrDialog()
@@ -165,15 +75,8 @@
to_chat(user, "There's already a container inside [src].")
return TRUE //no afterattack
- if(is_type_in_list(I, dried_items))
- if(istype(I, /obj/item/reagent_containers/food/snacks/grown))
- var/obj/item/reagent_containers/food/snacks/grown/G = I
- if(!G.dry)
- to_chat(user, "You must dry [G] first!")
- return TRUE
-
- if(length(holdingitems) >= limit)
- to_chat(user, "The machine cannot hold anymore items.")
+ if(holdingitems.len >= limit)
+ to_chat(user, "[src] is filled to capacity!")
return TRUE
//Fill machine with a bag!
@@ -192,14 +95,18 @@
updateUsrDialog()
return TRUE
- if (!is_type_in_list(I, blend_items) && !is_type_in_list(I, juice_items))
+ if(!I.grind_results && !I.juice_results)
if(user.a_intent == INTENT_HARM)
return ..()
else
- to_chat(user, "Cannot refine into a reagent!")
+ to_chat(user, "You cannot grind [I] into reagents!")
return TRUE
+ if(!I.grind_requirements(src)) //Error messages should be in the objects' definitions
+ return
+
if(user.transferItemToLoc(I, src))
+ to_chat(user, "You add [I] to [src].")
holdingitems[I] = TRUE
updateUsrDialog()
return FALSE
@@ -214,7 +121,7 @@
user.set_machine(src)
interact(user)
-/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu
+/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave
var/is_chamber_empty = FALSE
var/is_beaker_ready = FALSE
var/processing_chamber = ""
@@ -307,60 +214,10 @@
holdingitems -= O
updateUsrDialog()
-/obj/machinery/reagentgrinder/proc/get_allowed_by_obj(obj/item/O)
- for (var/i in blend_items)
- if (istype(O, i))
- return blend_items[i]
-
-/obj/machinery/reagentgrinder/proc/get_allowed_juice_by_obj(obj/item/reagent_containers/food/snacks/O)
- for(var/i in juice_items)
- if(istype(O, i))
- return juice_items[i]
-
-/obj/machinery/reagentgrinder/proc/get_grownweapon_amount(obj/item/grown/O)
- if (!istype(O) || !O.seed)
- return 5
- else if (O.seed.potency == -1)
- return 5
- else
- return round(O.seed.potency)
-
-/obj/machinery/reagentgrinder/proc/get_juice_amount(obj/item/reagent_containers/food/snacks/grown/O)
- if (!istype(O) || !O.seed)
- return 5
- else if (O.seed.potency == -1)
- return 5
- else
- return round(5*sqrt(O.seed.potency))
-
/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O)
holdingitems -= O
qdel(O)
-/obj/machinery/reagentgrinder/proc/juice()
- power_change()
- if(!beaker || (beaker && (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)))
- return
- operate_for(50, juicing = TRUE)
-
- //Snacks
- for(var/obj/item/i in holdingitems)
- var/obj/item/I = i
- if(istype(I, /obj/item/reagent_containers/food/snacks))
- var/obj/item/reagent_containers/food/snacks/O = I
- if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
- break
- var/list/allowed = get_allowed_juice_by_obj(O)
- if(isnull(allowed))
- break
- for(var/r_id in allowed)
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- var/amount = get_juice_amount(O)
- beaker.reagents.add_reagent(r_id, min(amount, space))
- if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
- break
- remove_object(O)
-
/obj/machinery/reagentgrinder/proc/shake_for(duration)
var/offset = prob(50) ? -2 : 2
var/old_pixel_x = pixel_x
@@ -386,8 +243,26 @@
operating = FALSE
updateUsrDialog()
-/obj/machinery/reagentgrinder/proc/grind()
+/obj/machinery/reagentgrinder/proc/juice()
+ power_change()
+ if(!beaker || (beaker && (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)))
+ return
+ operate_for(50, juicing = TRUE)
+ for(var/obj/item/i in holdingitems)
+ if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
+ break
+ var/obj/item/I = i
+ if(I.juice_results)
+ juice_item(I)
+/obj/machinery/reagentgrinder/proc/juice_item(obj/item/I) //Juicing results can be found in respective object definitions
+ if(I.on_juice(src) == -1)
+ to_chat(usr, "[src] shorts out as it tries to juice up [I], and transfers it back to storage.")
+ return
+ beaker.reagents.add_reagent_list(I.juice_results)
+ remove_object(I)
+
+/obj/machinery/reagentgrinder/proc/grind()
power_change()
if(!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
return
@@ -396,82 +271,17 @@
if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
break
var/obj/item/I = i
- //Snacks
- if(istype(I, /obj/item/reagent_containers/food/snacks))
- var/obj/item/reagent_containers/food/snacks/O = I
- var/list/allowed = get_allowed_by_obj(O)
- if(isnull(allowed))
- continue
- for(var/r_id in allowed)
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- var/amount = allowed[r_id]
- if(amount <= 0)
- if(amount == 0)
- if (O.reagents != null && O.reagents.has_reagent("nutriment"))
- beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment"), space))
- O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
- else
- if (O.reagents != null && O.reagents.has_reagent("nutriment"))
- beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment")*abs(amount)), space))
- O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
- else
- O.reagents.trans_id_to(beaker, r_id, min(amount, space))
- if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
- break
- if(O.reagents.reagent_list.len == 0)
- remove_object(O)
- //Sheets
- else if(istype(I, /obj/item/stack/sheet))
- var/obj/item/stack/sheet/O = I
- var/list/allowed = get_allowed_by_obj(O)
- for(var/t in 1 to round(O.amount, 1))
- for(var/r_id in allowed)
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- var/amount = allowed[r_id]
- beaker.reagents.add_reagent(r_id,min(amount, space))
- if (space < amount)
- break
- if(t == round(O.amount, 1))
- remove_object(O)
- break
- //Plants
- else if(istype(I, /obj/item/grown))
- var/obj/item/grown/O = I
- var/list/allowed = get_allowed_by_obj(O)
- for (var/r_id in allowed)
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- var/amount = allowed[r_id]
- if (amount == 0)
- if (O.reagents != null && O.reagents.has_reagent(r_id))
- beaker.reagents.add_reagent(r_id,min(O.reagents.get_reagent_amount(r_id), space))
- else
- beaker.reagents.add_reagent(r_id,min(amount, space))
- if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
- break
- remove_object(O)
- else if(istype(I, /obj/item/slime_extract))
- var/obj/item/slime_extract/O = I
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- if (O.reagents != null)
- var/amount = O.reagents.total_volume
- O.reagents.trans_to(beaker, min(amount, space))
- if (O.Uses > 0)
- beaker.reagents.add_reagent("slimejelly",min(20, space))
- remove_object(O)
- if(istype(I, /obj/item/reagent_containers))
- var/obj/item/reagent_containers/O = I
- var/amount = O.reagents.total_volume
- O.reagents.trans_to(beaker, amount)
- if(!O.reagents.total_volume)
- remove_object(O)
- else if(istype(I, /obj/item/toy/crayon))
- var/obj/item/toy/crayon/O = I
- for (var/r_id in O.reagent_contents)
- var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
- if(!space)
- break
- beaker.reagents.add_reagent(r_id, min(O.reagent_contents[r_id], space))
- remove_object(O)
+ if(I.grind_results)
+ grind_item(i)
+
+/obj/machinery/reagentgrinder/proc/grind_item(obj/item/I) //Grind results can be found in respective object definitions
+ if(I.on_grind(src) == -1) //Call on_grind() to change amount as needed, and stop grinding the item if it returns -1
+ to_chat(usr, "[src] shorts out as it tries to grind up [I], and transfers it back to storage.")
+ return
+ beaker.reagents.add_reagent_list(I.grind_results)
+ if(I.reagents)
+ I.reagents.trans_to(beaker, I.reagents.total_volume)
+ remove_object(I)
/obj/machinery/reagentgrinder/proc/mix(mob/user)
//For butter and other things that would change upon shaking or mixing
@@ -484,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/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index b62afb80c0..0bb00f5b49 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -70,7 +70,7 @@
//nothing
if(21 to INFINITY)
if(prob(current_cycle-10))
- M.cure_nearsighted()
+ M.cure_nearsighted(list(EYE_DAMAGE))
..()
return
@@ -172,6 +172,22 @@
M.emote("laugh")
..()
+/datum/reagent/consumable/superlaughter
+ name = "Super Laughter"
+ id = "superlaughter"
+ description = "Funny until you're the one laughing."
+ metabolization_rate = 1.5 * REAGENTS_METABOLISM
+ color = "#FF4DD2"
+ taste_description = "laughter"
+
+/datum/reagent/consumable/superlaughter/on_mob_life(mob/living/carbon/M)
+ if(!iscarbon(M))
+ return
+ if(prob(30))
+ M.visible_message("[M] bursts out into a fit of uncontrollable laughter!", "You burst out in a fit of uncontrollable laughter!")
+ M.Stun(5)
+ ..()
+
/datum/reagent/consumable/potato_juice
name = "Potato Juice"
id = "potato"
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index a3c0d2c034..a9f9145972 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -97,10 +97,10 @@
/datum/reagent/consumable/cooking_oil/reaction_obj(obj/O, reac_volume)
if(holder && holder.chem_temp >= fry_temperature)
- if(isitem(O))
+ if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder))
O.loc.visible_message("[O] rapidly fries as it's splashed with hot oil! Somehow.")
- var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location())
- F.fry(O, volume)
+ var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location(), O)
+ F.fry(volume)
/datum/reagent/consumable/cooking_oil/reaction_mob(mob/living/M, method = TOUCH, reac_volume, show_message = 1, touch_protection = 0)
if(!istype(M))
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index ddb08db032..03134784a4 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -44,7 +44,7 @@
M.adjustToxLoss(-5, 0)
M.hallucination = 0
M.setBrainLoss(0)
- M.disabilities = 0
+ M.remove_all_disabilities()
M.set_blurriness(0)
M.set_blindness(0)
M.SetKnockdown(0, 0)
@@ -667,16 +667,16 @@
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
return
- if(M.disabilities & BLIND)
+ if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "Your vision slowly returns...")
- M.cure_blind()
- M.cure_nearsighted()
+ M.cure_blind(EYE_DAMAGE)
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
- else if(M.disabilities & NEARSIGHT)
+ else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "The blackness in your peripheral vision fades.")
- M.cure_nearsighted()
+ M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
@@ -765,7 +765,7 @@
M.visible_message("[M]'s body convulses a bit, and then falls still once more.")
return
M.visible_message("[M]'s body convulses a bit.")
- if(!M.suiciding && !(M.disabilities & NOCLONE) && !M.hellbound)
+ if(!M.suiciding && !(M.has_disability(NOCLONE)) && !M.hellbound)
if(!M)
return
if(M.notify_ghost_cloning(source = M))
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 711c333896..0a6288896a 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -141,7 +141,7 @@
taste_description = "mint"
/datum/reagent/toxin/minttoxin/on_mob_life(mob/living/M)
- if(M.disabilities & FAT)
+ if(M.has_disability(FAT))
M.gib()
return ..()
@@ -850,9 +850,9 @@
/datum/reagent/toxin/peaceborg/confuse/on_mob_life(mob/living/M)
if(M.confused < 6)
- M.confused = Clamp(M.confused + 3, 0, 5)
+ M.confused = CLAMP(M.confused + 3, 0, 5)
if(M.dizziness < 6)
- M.dizziness = Clamp(M.dizziness + 3, 0, 5)
+ M.dizziness = CLAMP(M.dizziness + 3, 0, 5)
if(prob(20))
to_chat(M, "You feel confused and disorientated.")
..()
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 0e645e3798..b77dcc435a 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -168,7 +168,7 @@
return
holder.remove_reagent("sorium", created_volume*4)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume*4), 1, 6)
+ var/range = CLAMP(sqrt(created_volume*4), 1, 6)
goonchem_vortex(T, 1, range)
/datum/chemical_reaction/sorium_vortex
@@ -179,7 +179,7 @@
/datum/chemical_reaction/sorium_vortex/on_reaction(datum/reagents/holder, created_volume)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume), 1, 6)
+ var/range = CLAMP(sqrt(created_volume), 1, 6)
goonchem_vortex(T, 1, range)
/datum/chemical_reaction/liquid_dark_matter
@@ -193,7 +193,7 @@
return
holder.remove_reagent("liquid_dark_matter", created_volume*3)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume*3), 1, 6)
+ var/range = CLAMP(sqrt(created_volume*3), 1, 6)
goonchem_vortex(T, 0, range)
/datum/chemical_reaction/ldm_vortex
@@ -204,7 +204,7 @@
/datum/chemical_reaction/ldm_vortex/on_reaction(datum/reagents/holder, created_volume)
var/turf/T = get_turf(holder.my_atom)
- var/range = Clamp(sqrt(created_volume/2), 1, 6)
+ var/range = CLAMP(sqrt(created_volume/2), 1, 6)
goonchem_vortex(T, 0, range)
/datum/chemical_reaction/flash_powder
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 8698c10b05..6fb21e847b 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -48,15 +48,6 @@
/obj/item/reagent_containers/afterattack(obj/target, mob/user , flag)
return
-/obj/item/reagent_containers/proc/reagentlist(obj/item/reagent_containers/snack) //Attack logs for regents in pills
- var/data
- if(snack.reagents.reagent_list && snack.reagents.reagent_list.len) //find a reagent list if there is and check if it has entries
- for (var/datum/reagent/R in snack.reagents.reagent_list) //no reagents will be left behind
- data += "[R.id]([R.volume] units); " //Using IDs because SOME chemicals(I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
- return data
- else
- return "No reagents"
-
/obj/item/reagent_containers/proc/canconsume(mob/eater, mob/user)
if(!iscarbon(eater))
return 0
@@ -80,8 +71,7 @@
..()
/obj/item/reagent_containers/fire_act(exposed_temperature, exposed_volume)
- reagents.chem_temp += 30
- reagents.handle_reactions()
+ reagents.expose_temperature(exposed_temperature)
..()
/obj/item/reagent_containers/throw_impact(atom/target)
@@ -127,7 +117,8 @@
reagents.clear_reagents()
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
- if(is_open_container())
- reagents.chem_temp = max(reagents.chem_temp, 1000)
- reagents.handle_reactions()
+ reagents.expose_temperature(1000)
..()
+
+/obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ reagents.expose_temperature(exposed_temperature)
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 28a07d5862..e736c344db 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -130,6 +130,18 @@ Borg Hypospray
reagent_ids = list ("facid", "mutetoxin", "cyanide", "sodium_thiopental", "heparin", "lexorin")
accepts_reagent_upgrades = FALSE
+/obj/item/reagent_containers/borghypo/clown
+ name = "laughter injector"
+ desc = "Keeps the crew happy and productive!"
+ reagent_ids = list("laughter")
+ accepts_reagent_upgrades = FALSE
+
+/obj/item/reagent_containers/borghypo/clown/hacked
+ name = "laughter injector"
+ desc = "Keeps the crew so happy they don't work!"
+ reagent_ids = list("superlaughter")
+ accepts_reagent_upgrades = FALSE
+
/obj/item/reagent_containers/borghypo/syndicate
name = "syndicate cyborg hypospray"
desc = "An experimental piece of Syndicate technology used to produce powerful restorative nanites used to very quickly restore injuries of all types. Also metabolizes potassium iodide, for radiation poisoning, and morphine, for offense."
@@ -173,7 +185,7 @@ Borg Shaker
if(!proximity)
return
- else if(target.is_open_container() && target.reagents)
+ else if(target.is_refillable())
var/datum/reagents/R = reagent_list[mode]
if(!R.total_volume)
to_chat(user, "[src] is currently out of this ingredient! Please allow some time for the synthesizer to produce more.")
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 30aa67e91a..144db32a6c 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -6,7 +6,7 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(1, 2, 3, 4, 5)
volume = 5
- container_type = TRANSPARENT_1
+ container_type = TRANSPARENT
/obj/item/reagent_containers/dropper/afterattack(obj/target, mob/user , proximity)
if(!proximity)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index df2df7c171..06a242cca9 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -3,7 +3,7 @@
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50)
volume = 50
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
spillable = TRUE
resistance_flags = ACID_PROOF
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.")
- add_logs(user, M, "fed", reagentlist(src))
+ add_logs(user, M, "fed", reagents.log_list())
else
to_chat(user, "You swallow a gulp of [src].")
var/fraction = min(5/reagents.total_volume, 1)
@@ -56,32 +56,30 @@
if((!proximity) || !check_allowed_items(target,target_self=1))
return
- else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
-
- if(target.reagents && !target.reagents.total_volume)
- to_chat(user, "[target] is empty and can't be refilled!")
- return
-
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "[src] is full.")
- return
-
- var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
- to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
-
- else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "[src] is empty!")
return
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "[target] is full.")
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
return
-
var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "You transfer [trans] unit\s of the solution to [target].")
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty and can't be refilled!")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
+
else if(reagents.total_volume)
if(user.a_intent == INTENT_HARM)
user.visible_message("[user] splashes the contents of [src] onto [target]!", \
@@ -91,15 +89,9 @@
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
var/hotness = I.is_hot()
- if(hotness)
- var/added_heat = (hotness / 100) //ishot returns a temperature
- if(reagents)
- if(reagents.chem_temp < hotness) //can't be heated to be hotter than the source
- reagents.chem_temp += added_heat
- to_chat(user, "You heat [src] with [I].")
- reagents.handle_reactions()
- else
- to_chat(user, "[src] is already hotter than [I]!")
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
if(istype(I, /obj/item/reagent_containers/food/snacks/egg)) //breaking eggs
var/obj/item/reagent_containers/food/snacks/egg/E = I
@@ -169,7 +161,6 @@
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact
name = "cryostasis beaker"
@@ -179,7 +170,6 @@
materials = list(MAT_METAL=3000)
volume = 50
amount_per_transfer_from_this = 10
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/noreact/Initialize()
. = ..()
@@ -195,7 +185,6 @@
volume = 300
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300)
- flags_1 = OPENCONTAINER_1
/obj/item/reagent_containers/glass/beaker/cryoxadone
list_reagents = list("cryoxadone" = 30)
@@ -238,7 +227,6 @@
amount_per_transfer_from_this = 20
possible_transfer_amounts = list(10,15,20,25,30,50,70)
volume = 70
- flags_1 = OPENCONTAINER_1
flags_inv = HIDEHAIR
slot_flags = SLOT_HEAD
resistance_flags = NONE
@@ -409,4 +397,4 @@
/obj/item/reagent_containers/glass/beaker/large/bromine
name = "bromine beaker"
- list_reagents = list("bromine" = 50)
\ No newline at end of file
+ list_reagents = list("bromine" = 50)
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index dff0869322..53e0c9bfb6 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -10,7 +10,7 @@
volume = 30
possible_transfer_amounts = list()
resistance_flags = ACID_PROOF
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
var/ignore_flags = 0
var/infinite = FALSE
@@ -88,7 +88,7 @@
amount_per_transfer_from_this = 10
volume = 10
ignore_flags = 1 //so you can medipen through hardsuits
- container_type = DRAWABLE_1
+ container_type = DRAWABLE
flags_1 = null
list_reagents = list("epinephrine" = 10)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 324623edbd..4908a55911 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -1,154 +1,160 @@
-/obj/item/reagent_containers/pill
- name = "pill"
- desc = "A tablet or capsule."
- icon = 'icons/obj/chemical.dmi'
- icon_state = "pill"
- item_state = "pill"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- possible_transfer_amounts = list()
- volume = 50
- var/apply_type = INGEST
- var/apply_method = "swallow"
- var/roundstart = 0
- var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
-
-/obj/item/reagent_containers/pill/Initialize()
- . = ..()
- if(!icon_state)
- icon_state = "pill[rand(1,20)]"
- if(reagents.total_volume && roundstart)
- name += " ([reagents.total_volume]u)"
-
-
-/obj/item/reagent_containers/pill/attack_self(mob/user)
- return
-
-
-/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
- if(!canconsume(M, user))
- return 0
-
- if(M == user)
- M.visible_message("[user] attempts to [apply_method] [src].")
- if(self_delay)
- if(!do_mob(user, M, self_delay))
- return 0
- to_chat(M, "You [apply_method] [src].")
-
- else
- M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \
- "[user] attempts to force [M] to [apply_method] [src].")
- if(!do_mob(user, M))
- return 0
- M.visible_message("[user] forces [M] to [apply_method] [src].", \
- "[user] forces [M] to [apply_method] [src].")
-
-
- add_logs(user, M, "fed", reagentlist(src))
- if(reagents.total_volume)
- reagents.reaction(M, apply_type)
- reagents.trans_to(M, reagents.total_volume)
- qdel(src)
- return 1
-
-
-/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)
- to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.")
- 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]!")
- reagents.trans_to(target, reagents.total_volume)
- qdel(src)
-
-/obj/item/reagent_containers/pill/tox
- name = "toxins pill"
- desc = "Highly toxic."
- icon_state = "pill5"
- list_reagents = list("toxin" = 50)
- roundstart = 1
-/obj/item/reagent_containers/pill/cyanide
- name = "cyanide pill"
- desc = "Don't swallow this."
- icon_state = "pill5"
- list_reagents = list("cyanide" = 50)
- roundstart = 1
-/obj/item/reagent_containers/pill/adminordrazine
- name = "adminordrazine pill"
- desc = "It's magic. We don't have to explain it."
- icon_state = "pill16"
- list_reagents = list("adminordrazine" = 50)
- roundstart = 1
-/obj/item/reagent_containers/pill/morphine
- name = "morphine pill"
- desc = "Commonly used to treat insomnia."
- icon_state = "pill8"
- list_reagents = list("morphine" = 30)
- roundstart = 1
-/obj/item/reagent_containers/pill/stimulant
- name = "stimulant pill"
- desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
- icon_state = "pill19"
- list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
- roundstart = 1
-/obj/item/reagent_containers/pill/salbutamol
- name = "salbutamol pill"
- desc = "Used to treat oxygen deprivation."
- icon_state = "pill16"
- list_reagents = list("salbutamol" = 30)
- roundstart = 1
-/obj/item/reagent_containers/pill/charcoal
- name = "charcoal pill"
- desc = "Neutralizes many common toxins."
- icon_state = "pill17"
- list_reagents = list("charcoal" = 10)
- roundstart = 1
-/obj/item/reagent_containers/pill/epinephrine
- name = "epinephrine pill"
- desc = "Used to stabilize patients."
- icon_state = "pill5"
- list_reagents = list("epinephrine" = 15)
- roundstart = 1
-/obj/item/reagent_containers/pill/mannitol
- name = "mannitol pill"
- desc = "Used to treat brain damage."
- icon_state = "pill17"
- list_reagents = list("mannitol" = 50)
- roundstart = 1
-/obj/item/reagent_containers/pill/mutadone
- name = "mutadone pill"
- desc = "Used to treat genetic damage."
- icon_state = "pill20"
- list_reagents = list("mutadone" = 50)
- roundstart = 1
-/obj/item/reagent_containers/pill/salicyclic
- name = "salicylic acid pill"
- desc = "Used to dull pain."
- icon_state = "pill9"
- list_reagents = list("sal_acid" = 24)
- roundstart = 1
-/obj/item/reagent_containers/pill/oxandrolone
- name = "oxandrolone pill"
- desc = "Used to stimulate burn healing."
- icon_state = "pill11"
- list_reagents = list("oxandrolone" = 24)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/insulin
- name = "insulin pill"
- desc = "Handles hyperglycaemic coma."
- icon_state = "pill18"
- list_reagents = list("insulin" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/shadowtoxin
- name = "black pill"
- desc = "I wouldn't eat this if I were you."
- icon_state = "pill9"
- color = "#454545"
- list_reagents = list("shadowmutationtoxin" = 1)
+/obj/item/reagent_containers/pill
+ name = "pill"
+ desc = "A tablet or capsule."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "pill"
+ item_state = "pill"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ possible_transfer_amounts = list()
+ volume = 50
+ grind_results = list()
+ var/apply_type = INGEST
+ var/apply_method = "swallow"
+ var/roundstart = 0
+ var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
+
+/obj/item/reagent_containers/pill/Initialize()
+ . = ..()
+ if(!icon_state)
+ icon_state = "pill[rand(1,20)]"
+ if(reagents.total_volume && roundstart)
+ name += " ([reagents.total_volume]u)"
+
+
+/obj/item/reagent_containers/pill/attack_self(mob/user)
+ return
+
+
+/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
+ if(!canconsume(M, user))
+ return 0
+
+ if(M == user)
+ M.visible_message("[user] attempts to [apply_method] [src].")
+ if(self_delay)
+ if(!do_mob(user, M, self_delay))
+ return 0
+ to_chat(M, "You [apply_method] [src].")
+
+ else
+ M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \
+ "[user] attempts to force [M] to [apply_method] [src].")
+ if(!do_mob(user, M))
+ return 0
+ M.visible_message("[user] forces [M] to [apply_method] [src].", \
+ "[user] forces [M] to [apply_method] [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)
+ qdel(src)
+ return 1
+
+
+/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
+ if(!proximity)
+ return
+ 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]!")
+ reagents.trans_to(target, reagents.total_volume)
+ qdel(src)
+
+/obj/item/reagent_containers/pill/tox
+ name = "toxins pill"
+ desc = "Highly toxic."
+ icon_state = "pill5"
+ list_reagents = list("toxin" = 50)
+ roundstart = 1
+/obj/item/reagent_containers/pill/cyanide
+ name = "cyanide pill"
+ desc = "Don't swallow this."
+ icon_state = "pill5"
+ list_reagents = list("cyanide" = 50)
+ roundstart = 1
+/obj/item/reagent_containers/pill/adminordrazine
+ name = "adminordrazine pill"
+ desc = "It's magic. We don't have to explain it."
+ icon_state = "pill16"
+ list_reagents = list("adminordrazine" = 50)
+ roundstart = 1
+/obj/item/reagent_containers/pill/morphine
+ name = "morphine pill"
+ desc = "Commonly used to treat insomnia."
+ icon_state = "pill8"
+ list_reagents = list("morphine" = 30)
+ roundstart = 1
+/obj/item/reagent_containers/pill/stimulant
+ name = "stimulant pill"
+ desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
+ icon_state = "pill19"
+ list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
+ roundstart = 1
+/obj/item/reagent_containers/pill/salbutamol
+ name = "salbutamol pill"
+ desc = "Used to treat oxygen deprivation."
+ icon_state = "pill16"
+ list_reagents = list("salbutamol" = 30)
+ roundstart = 1
+/obj/item/reagent_containers/pill/charcoal
+ name = "charcoal pill"
+ desc = "Neutralizes many common toxins."
+ icon_state = "pill17"
+ list_reagents = list("charcoal" = 10)
+ roundstart = 1
+/obj/item/reagent_containers/pill/epinephrine
+ name = "epinephrine pill"
+ desc = "Used to stabilize patients."
+ icon_state = "pill5"
+ list_reagents = list("epinephrine" = 15)
+ roundstart = 1
+/obj/item/reagent_containers/pill/mannitol
+ name = "mannitol pill"
+ desc = "Used to treat brain damage."
+ icon_state = "pill17"
+ list_reagents = list("mannitol" = 50)
+ roundstart = 1
+/obj/item/reagent_containers/pill/mutadone
+ name = "mutadone pill"
+ desc = "Used to treat genetic damage."
+ icon_state = "pill20"
+ list_reagents = list("mutadone" = 50)
+ roundstart = 1
+/obj/item/reagent_containers/pill/salicyclic
+ name = "salicylic acid pill"
+ desc = "Used to dull pain."
+ icon_state = "pill9"
+ list_reagents = list("sal_acid" = 24)
+ roundstart = 1
+/obj/item/reagent_containers/pill/oxandrolone
+ name = "oxandrolone pill"
+ desc = "Used to stimulate burn healing."
+ icon_state = "pill11"
+ list_reagents = list("oxandrolone" = 24)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/insulin
+ name = "insulin pill"
+ desc = "Handles hyperglycaemic coma."
+ icon_state = "pill18"
+ list_reagents = list("insulin" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/shadowtoxin
+ name = "black pill"
+ desc = "I wouldn't eat this if I were you."
+ icon_state = "pill9"
+ color = "#454545"
+ list_reagents = list("shadowmutationtoxin" = 1)
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 789345ca77..f79418eee5 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -7,7 +7,7 @@
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
flags_1 = NOBLUDGEON_1
- container_type = OPENCONTAINER_1
+ container_type = OPENCONTAINER
slot_flags = SLOT_BELT
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
@@ -18,22 +18,22 @@
var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode.
var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode.
var/stream_amount = 10 //the amount of reagents transfered when in stream mode.
+ var/can_fill_from_container = TRUE
amount_per_transfer_from_this = 5
volume = 250
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
-
-/obj/item/reagent_containers/spray/afterattack(atom/A as mob|obj, mob/user)
+/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
return
- if(istype(A, /obj/structure/reagent_dispensers) && get_dist(src,A) <= 1) //this block copypasted from reagent_containers/glass, for lack of a better solution
- if(!A.reagents.total_volume && A.reagents)
- to_chat(user, "\The [A] is empty.")
+ if((A.is_drainable() && !A.is_refillable()) && get_dist(src,A) <= 1 && can_fill_from_container)
+ if(!A.reagents.total_volume)
+ to_chat(user, "[A] is empty.")
return
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "\The [src] is full.")
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
return
var/trans = A.reagents.trans_to(src, 50) //transfer 50u , using the spray's transfer amount would take too long to refill
@@ -41,7 +41,7 @@
return
if(reagents.total_volume < amount_per_transfer_from_this)
- to_chat(user, "\The [src] is empty!")
+ to_chat(user, "[src] is empty!")
return
spray(A)
@@ -123,6 +123,14 @@
current_range = spray_range
to_chat(user, "You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""]. You'll now use [amount_per_transfer_from_this] units per use.")
+/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, params)
+ var/hotness = I.is_hot()
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
+ return ..()
+
+
/obj/item/reagent_containers/spray/verb/empty()
set name = "Empty Spray Bottle"
set category = "Object"
@@ -197,6 +205,46 @@
/obj/item/reagent_containers/spray/waterflower/attack_self(mob/user) //Don't allow changing how much the flower sprays
return
+/obj/item/reagent_containers/spray/waterflower/cyborg
+ container_type = NONE
+ volume = 100
+ list_reagents = list("water" = 100)
+ var/generate_amount = 5
+ var/generate_type = "water"
+ var/last_generate = 0
+ var/generate_delay = 10 //deciseconds
+ can_fill_from_container = FALSE
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/hacked
+ name = "nova flower"
+ desc = "This doesn't look safe at all..."
+ list_reagents = list("clf3" = 3)
+ volume = 3
+ generate_type = "clf3"
+ generate_amount = 1
+ generate_delay = 40 //deciseconds
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Initialize()
+ . = ..()
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/process()
+ if(world.time > last_generate + generate_delay)
+ return
+ last_generate = world.time
+ generate_reagents()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/empty()
+ to_chat(usr, "You can not empty this!")
+ return
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/proc/generate_reagents()
+ reagents.add_reagent(generate_type, generate_amount)
+
//chemsprayer
/obj/item/reagent_containers/spray/chemsprayer
name = "chem sprayer"
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 87fb2b8a9e..3f38be95c9 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -13,7 +13,7 @@
var/busy = FALSE // needed for delayed drawing of blood
var/proj_piercing = 0 //does it pierce through thick clothes when shot with syringe gun
materials = list(MAT_METAL=10, MAT_GLASS=20)
- container_type = TRANSPARENT_1
+ container_type = TRANSPARENT
/obj/item/reagent_containers/syringe/Initialize()
. = ..()
@@ -107,11 +107,8 @@
update_icon()
if(SYRINGE_INJECT)
- //Always log attemped injections for admins
- var/list/rinject = list()
- for(var/datum/reagent/R in reagents.reagent_list)
- rinject += R.name
- var/contained = english_list(rinject)
+ // Always log attemped injections for admins
+ var/contained = reagents.log_list()
add_logs(user, L, "attemped to inject", src, addition="which had [contained]")
if(!reagents.total_volume)
@@ -157,7 +154,7 @@
/obj/item/reagent_containers/syringe/update_icon()
- var/rounded_vol = Clamp(round((reagents.total_volume / volume * 15),5), 0, 15)
+ var/rounded_vol = CLAMP(round((reagents.total_volume / volume * 15),5), 0, 15)
cut_overlays()
if(ismob(loc))
var/injoverlay
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index ea80f4c508..f0c0ecfb68 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -5,7 +5,7 @@
icon_state = "water"
density = TRUE
anchored = FALSE
- container_type = DRAWABLE_1
+ container_type = DRAINABLE | AMOUNT_VISIBLE
pressure_resistance = 2*ONE_ATMOSPHERE
max_integrity = 300
var/tank_volume = 1000 //In units, how much the dispenser can hold
@@ -18,7 +18,7 @@
boom()
/obj/structure/reagent_dispensers/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/reagent_containers))
+ if(W.is_refillable())
return 0 //so we can refill them via their afterattack.
else
return ..()
@@ -28,14 +28,6 @@
reagents.add_reagent(reagent_id, tank_volume)
. = ..()
-/obj/structure/reagent_dispensers/examine(mob/user)
- ..()
- if(reagents.total_volume)
- to_chat(user, "It has [reagents.total_volume] unit\s left.")
- else
- to_chat(user, "It's empty.")
-
-
/obj/structure/reagent_dispensers/proc/boom()
visible_message("\The [src] ruptures!")
chem_splash(loc, 5, list(reagents))
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index ed14ae63c1..62965f7ca1 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -29,7 +29,7 @@
if(make_from)
setDir(make_from.dir)
- make_from.loc = null
+ make_from.moveToNullspace()
stored = make_from
pressure_charging = FALSE // newly built disposal bins start with pump off
else
@@ -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
@@ -471,7 +471,7 @@
if(isobj(AM))
var/obj/O = AM
- O.loc = src
+ O.forceMove(src)
else if(ismob(AM))
var/mob/M = AM
if(prob(2)) // to prevent mobs being stuck in infinite loops
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/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 2343bd8814..059d9c982c 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -111,6 +111,7 @@
desc = "The circuit board for a sleeper."
id = "sleeper"
build_path = /obj/item/circuitboard/machine/sleeper
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/cryotube
@@ -118,6 +119,7 @@
desc = "The circuit board for a cryotube."
id = "cryotube"
build_path = /obj/item/circuitboard/machine/cryo_tube
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/chem_dispenser
@@ -125,12 +127,14 @@
desc = "The circuit board for a portable chem dispenser."
id = "chem_dispenser"
build_path = /obj/item/circuitboard/machine/chem_dispenser
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/chem_master
name = "Machine Design (Chem Master Board)"
desc = "The circuit board for a Chem Master 3000."
id = "chem_master"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/chem_master
category = list ("Medical Machinery")
@@ -138,6 +142,7 @@
name = "Machine Design (Chemical Heater Board)"
desc = "The circuit board for a chemical heater."
id = "chem_heater"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/chem_heater
category = list ("Medical Machinery")
@@ -153,12 +158,14 @@
desc = "Allows for the construction of circuit boards used to build a new Cloning Machine console."
id = "clonecontrol"
build_path = /obj/item/circuitboard/computer/cloning
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
category = list("Medical Machinery")
/datum/design/board/clonepod
name = "Machine Design (Clone Pod)"
desc = "Allows for the construction of circuit boards used to build a Cloning Pod."
id = "clonepod"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/clonepod
category = list("Medical Machinery")
@@ -166,6 +173,7 @@
name = "Machine Design (Cloning Scanner)"
desc = "Allows for the construction of circuit boards used to build a Cloning Scanner."
id = "clonescanner"
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
build_path = /obj/item/circuitboard/machine/clonescanner
category = list("Medical Machinery")
diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm
index e3caef247c..05acb20f0e 100644
--- a/code/modules/research/destructive_analyzer.dm
+++ b/code/modules/research/destructive_analyzer.dm
@@ -44,6 +44,8 @@ Note: Must be placed within 3 tiles of the R&D Console
to_chat(user, "
You add the [O.name] to the [src.name]!")
flick("d_analyzer_la", src)
addtimer(CALLBACK(src, .proc/finish_loading), 10)
+ if (linked_console)
+ linked_console.updateUsrDialog()
/obj/machinery/rnd/destructive_analyzer/proc/finish_loading()
update_icon()
@@ -93,30 +95,35 @@ Note: Must be placed within 3 tiles of the R&D Console
/obj/machinery/rnd/destructive_analyzer/proc/user_try_decon_id(id, mob/user)
if(!istype(loaded_item) || !istype(linked_console))
return FALSE
- if(id && !(id == RESEARCH_MATERIAL_RECLAMATION_ID))
+
+ if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID)
var/datum/techweb_node/TN = get_techweb_node_by_id(id)
if(!istype(TN))
return FALSE
- var/list/pos1 = techweb_item_boost_check(loaded_item)
- if(isnull(pos1[id]))
+ var/list/can_boost = techweb_item_boost_check(loaded_item)
+ if(isnull(can_boost[id]))
return FALSE
var/dpath = loaded_item.type
- if(isnull(TN.boost_item_paths[dpath]))
+ var/worth = TN.boost_item_paths[dpath]
+ if(isnull(worth))
return FALSE
- var/dboost = TN.boost_item_paths[dpath]
- var/choice = input("Are you sure you want to destroy [loaded_item.name] for a boost of [dboost? 0 : dboost] in node [TN.display_name]") in list("Proceed", "Cancel")
+ var/difference = min(worth, TN.research_cost) - linked_console.stored_research.boosted_nodes[TN.id]
+ if(worth && difference <= 0)
+ return FALSE
+ var/choice = input("Are you sure you want to destroy [loaded_item] to [!worth ? "reveal [TN.display_name]" : "boost [TN.display_name] by [difference] point\s"]?") in list("Proceed", "Cancel")
if(choice == "Cancel")
return FALSE
if(QDELETED(loaded_item) || QDELETED(linked_console) || !user.Adjacent(linked_console) || QDELETED(src))
return FALSE
- SSblackbox.record_feedback("nested_tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]"))
+ SSblackbox.record_feedback("nested tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]"))
if(destroy_item(loaded_item))
linked_console.stored_research.boost_with_path(SSresearch.techweb_nodes[TN.id], dpath)
+
else
var/point_value = techweb_item_point_check(loaded_item)
if(linked_console.stored_research.deconstructed_items[loaded_item.type])
point_value = 0
- var/choice = input("Are you sure you want to destroy [loaded_item.name] for [point_value? "[point_value] points" : "material reclaimation"]?") in list("Proceed", "Cancel")
+ var/choice = input("Are you sure you want to destroy [loaded_item] for [point_value ? "[point_value] research points" : "material reclamation"]?") in list("Proceed", "Cancel")
if(choice == "Cancel")
return FALSE
if(QDELETED(loaded_item) || QDELETED(linked_console) || !user.Adjacent(linked_console) || QDELETED(src))
@@ -133,4 +140,5 @@ Note: Must be placed within 3 tiles of the R&D Console
return FALSE
loaded_item.forceMove(get_turf(src))
loaded_item = null
+ update_icon()
return TRUE
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 56848c6394..bad8f1e5aa 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -219,8 +219,8 @@
return
var/turf/dropturf = get_turf(pick(view(1,src)))
if(!dropturf) //Failsafe to prevent the object being lost in the void forever.
- dropturf = get_turf(src)
- loaded_item.loc = dropturf
+ dropturf = drop_location()
+ loaded_item.forceMove(dropturf)
if(delete)
qdel(loaded_item)
loaded_item = null
@@ -510,7 +510,7 @@
throwSmoke(loc)
if(trackedRuntime)
throwSmoke(trackedRuntime.loc)
- trackedRuntime.loc = loc
+ trackedRuntime.forceMove(drop_location())
investigate_log("Experimentor has stolen Runtime!", INVESTIGATE_EXPERIMENTOR)
else
new /mob/living/simple_animal/pet/cat(loc)
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 cf250f50f1..8e2ce4b7a0 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -11,7 +11,8 @@
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
@@ -29,6 +30,10 @@
. = ..()
create_reagents(100)
+/obj/item/slime_extract/on_grind()
+ if(Uses)
+ grind_results["slimejelly"] = 20
+
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
@@ -290,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
@@ -314,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)
@@ -467,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/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
index 7f301bf8b9..f98162266a 100644
--- a/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
+++ b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
@@ -9,7 +9,7 @@
faction = list("ashwalker")
health = 200
maxHealth = 200
- loot = list(/obj/effect/collapse)
+ loot = null
var/meat_counter = 6
/mob/living/simple_animal/hostile/spawner/lavaland/ash_walker/death()
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/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 65636aa528..de1b0022f6 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -119,7 +119,7 @@
return
if(!my_port)
- my_port = new /obj/docking_port/stationary()
+ my_port = new(locate(eyeobj.x - x_offset, eyeobj.y - y_offset, eyeobj.z))
my_port.name = shuttlePortName
my_port.id = shuttlePortId
my_port.height = shuttle_port.height
@@ -128,7 +128,6 @@
my_port.dwidth = shuttle_port.dwidth
my_port.hidden = shuttle_port.hidden
my_port.dir = the_eye.dir
- my_port.loc = locate(eyeobj.x - x_offset, eyeobj.y - y_offset, eyeobj.z)
if(current_user.client)
current_user.client.images -= the_eye.placed_images
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 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/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm
index 283ac0f35c..ee5a435a86 100644
--- a/code/modules/shuttle/syndicate.dm
+++ b/code/modules/shuttle/syndicate.dm
@@ -56,8 +56,8 @@
shuttlePortName = "custom location"
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
view_range = 13
- x_offset = -4
- y_offset = -2
+ x_offset = -7
+ y_offset = -1
see_hidden = TRUE
#undef SYNDICATE_CHALLENGE_TIMER
\ No newline at end of file
diff --git a/code/modules/space_transition/space_transition.dm b/code/modules/space_transition/space_transition.dm
index 2a8be8a761..edcad9b620 100644
--- a/code/modules/space_transition/space_transition.dm
+++ b/code/modules/space_transition/space_transition.dm
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[A] = src
/datum/space_level/proc/set_neigbours(list/L)
- for(var/datum/point/P in L)
+ for(var/datum/space_transition_point/P in L)
if(P.x == xi)
if(P.y == yi+1)
neigbours[TEXT_NORTH] = P.spl
@@ -35,13 +35,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[TEXT_WEST] = P.spl
P.spl.neigbours[TEXT_EAST] = src
-/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
+/datum/space_transition_point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
var/list/neigbours = list()
var/x
var/y
var/datum/space_level/spl
-/datum/point/New(nx, ny, list/point_grid)
+/datum/space_transition_point/New(nx, ny, list/point_grid)
if(!point_grid)
qdel(src)
return
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
return
point_grid[x][y] = src
-/datum/point/proc/set_neigbours(list/grid)
+/datum/space_transition_point/proc/set_neigbours(list/grid)
var/max_X = grid.len
var/list/max_Y = grid[1]
max_Y = max_Y.len
@@ -86,13 +86,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
k++
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
var/list/grid = list()
- var/datum/point/P
+ var/datum/space_transition_point/P
for(var/i = 1, i<=conf_set_len*2+1, i++)
for(var/j = 1, j<=conf_set_len*2+1, j++)
- P = new/datum/point(i,j, point_grid)
+ P = new/datum/space_transition_point(i,j, point_grid)
point_grid[i][j] = P
grid.Add(P)
- for(var/datum/point/pnt in grid)
+ for(var/datum/space_transition_point/pnt in grid)
pnt.set_neigbours(point_grid)
P = point_grid[conf_set_len+1][conf_set_len+1]
var/list/possible_points = list()
diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm
index 87c1b8de44..306c3fcef6 100644
--- a/code/modules/spells/spell_types/conjure.dm
+++ b/code/modules/spells/spell_types/conjure.dm
@@ -56,6 +56,18 @@
range = 3
newVars = list("emagged" = 2, "remote_disabled" = 1,"shoot_sound" = 'sound/weapons/laser.ogg',"projectile" = /obj/item/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot")
+/obj/effect/proc_holder/spell/aoe_turf/conjure/linkWorlds
+ name = "Link Worlds"
+ desc = "A whole new dimension for you to play with! They won't be happy about it, though."
+ invocation = "WTF"
+ clothes_req = FALSE
+ charge_max = 600
+ cooldown_min = 200
+ summon_type = list(/mob/living/simple_animal/hostile/spawner/nether)
+ summon_amt = 1
+ range = 1
+ cast_sound = 'sound/weapons/marauder.ogg'
+
/obj/effect/proc_holder/spell/targeted/conjure_item
name = "Summon weapon"
desc = "A generic spell that should not exist. This summons an instance of a specific type of item, or if one already exists, un-summons it. Summons into hand if possible."
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index ca6a534ee0..8e9b4fb1e4 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -209,12 +209,14 @@
to_chat(target, "
A freezing darkness surrounds you...")
target.playsound_local(get_turf(target), 'sound/hallucinations/i_see_you1.ogg', 50, 1)
user.playsound_local(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
- target.adjust_blindness(5)
+ target.become_blind("abyssal_gaze")
addtimer(CALLBACK(src, .proc/cure_blindness, target), 40)
target.bodytemperature -= 200
/obj/effect/proc_holder/spell/targeted/abyssal_gaze/proc/cure_blindness(mob/target)
- target.adjust_blindness(-5)
+ if(isliving(target))
+ var/mob/living/L = target
+ L.cure_blind(BLIND, "abyssal_gaze")
/obj/effect/proc_holder/spell/targeted/dominate
name = "Dominate"
diff --git a/code/modules/spells/spell_types/genetic.dm b/code/modules/spells/spell_types/genetic.dm
index c6945dab50..1b60800458 100644
--- a/code/modules/spells/spell_types/genetic.dm
+++ b/code/modules/spells/spell_types/genetic.dm
@@ -1,32 +1,34 @@
-/obj/effect/proc_holder/spell/targeted/genetic
- name = "Genetic"
- desc = "This spell inflicts a set of mutations and disabilities upon the target."
-
- var/disabilities = 0 //bits
- var/list/mutations = list() //mutation strings
- var/duration = 100 //deciseconds
- /*
- Disabilities
- 1st bit - ?
- 2nd bit - ?
- 3rd bit - ?
- 4th bit - ?
- 5th bit - ?
- 6th bit - ?
- */
-
-/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
- playMagSound()
- for(var/mob/living/carbon/target in targets)
- if(!target.dna)
- continue
- for(var/A in mutations)
- target.dna.add_mutation(A)
- target.disabilities |= disabilities
+/obj/effect/proc_holder/spell/targeted/genetic
+ name = "Genetic"
+ desc = "This spell inflicts a set of mutations and disabilities upon the target."
+
+ var/list/disabilities = list() //disabilities
+ var/list/mutations = list() //mutation strings
+ var/duration = 100 //deciseconds
+ /*
+ Disabilities
+ 1st bit - ?
+ 2nd bit - ?
+ 3rd bit - ?
+ 4th bit - ?
+ 5th bit - ?
+ 6th bit - ?
+ */
+
+/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
+ playMagSound()
+ for(var/mob/living/carbon/target in targets)
+ if(!target.dna)
+ continue
+ for(var/A in mutations)
+ target.dna.add_mutation(A)
+ for(var/A in disabilities)
+ target.add_disability(A, GENETICS_SPELL)
addtimer(CALLBACK(src, .proc/remove, target), duration)
/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target)
if(!QDELETED(target))
for(var/A in mutations)
target.dna.remove_mutation(A)
- target.disabilities &= ~disabilities
+ for(var/A in disabilities)
+ target.remove_disability(A, GENETICS_SPELL)
diff --git a/code/modules/spells/spell_types/rightandwrong.dm b/code/modules/spells/spell_types/rightandwrong.dm
index b992871004..7ab3121a3a 100644
--- a/code/modules/spells/spell_types/rightandwrong.dm
+++ b/code/modules/spells/spell_types/rightandwrong.dm
@@ -22,12 +22,14 @@
guns.owner = H.mind
H.mind.objectives += guns
H.mind.special_role = "survivalist"
+ H.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(H, "
You are the survivalist! Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way.")
else
var/datum/objective/steal_five_of_type/summon_magic/magic = new
magic.owner = H.mind
H.mind.objectives += magic
H.mind.special_role = "amateur magician"
+ H.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(H, "
You are the amateur magician! Grow your newfound talent! Grab as many magical artefacts as possible, by any means necessary. Kill anyone who gets in your way.")
var/datum/objective/survive/survive = new
survive.owner = H.mind
diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm
index 9b120c2e7f..b36dfc885d 100644
--- a/code/modules/spells/spell_types/wizard.dm
+++ b/code/modules/spells/spell_types/wizard.dm
@@ -209,7 +209,7 @@
summon_amt = 10
range = 3
- summon_type = list(/mob/living/simple_animal/hostile/creature)
+ summon_type = list(/mob/living/simple_animal/hostile/netherworld)
cast_sound = 'sound/magic/summonitems_generic.ogg'
/obj/effect/proc_holder/spell/targeted/trigger/blind
@@ -289,7 +289,7 @@
var/mob/living/M = AM
M.Knockdown(stun_amt)
to_chat(M, "
You're thrown back by [user]!")
- AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time.
+ AM.throw_at(throwtarget, ((CLAMP((maxthrow - (CLAMP(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time.
/obj/effect/proc_holder/spell/aoe_turf/repulse/xeno //i fixed conflicts only to find out that this is in the WIZARD file instead of the xeno file?!
name = "Tail Sweep"
diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm
index 98ec01f641..88377455c6 100644
--- a/code/modules/station_goals/station_goal.dm
+++ b/code/modules/station_goals/station_goal.dm
@@ -26,11 +26,11 @@
/datum/station_goal/proc/check_completion()
return completed
-/datum/station_goal/proc/print_result()
+/datum/station_goal/proc/get_result()
if(check_completion())
- to_chat(world, "
Station Goal : [name] :
Completed!")
+ return "
[name] : Completed!"
else
- to_chat(world, "
Station Goal : [name] :
Failed!")
+ return "
[name] : Failed!"
/datum/station_goal/Destroy()
SSticker.mode.station_goals -= src
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 790942d897..474075591f 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -217,7 +217,7 @@
C = owner
no_update = 0
- if(C.disabilities & HUSK)
+ if(C.has_disability(HUSK))
species_id = "husk" //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index e99455c833..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()
@@ -142,11 +142,11 @@
//when a limb is dropped, the internal organs are removed from the mob and put into the limb
/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/C)
Remove(C)
- loc = LB
+ forceMove(LB)
/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/C)
Remove(C) //Changeling brain concerns are now handled in Remove
- loc = LB
+ forceMove(LB)
LB.brain = src
if(brainmob)
LB.brainmob = brainmob
@@ -270,7 +270,7 @@
attach_limb(C, special)
/obj/item/bodypart/proc/attach_limb(mob/living/carbon/C, special)
- loc = null
+ moveToNullspace()
owner = C
C.bodyparts += src
if(held_index)
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index f631400bee..464da21e44 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -61,7 +61,7 @@
C = owner
real_name = C.real_name
- if(C.disabilities & HUSK)
+ if(C.has_disability(HUSK))
real_name = "Unknown"
hair_style = "Bald"
facial_hair_style = "Shaved"
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index c8a47d2096..00a9a99bb0 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -23,9 +23,9 @@
/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] successfully fixes [target]'s eyes!", "
You succeed in fixing [target]'s eyes.")
- target.cure_blind()
+ target.cure_blind(list(EYE_DAMAGE))
target.set_blindness(0)
- target.cure_nearsighted()
+ target.cure_nearsighted(list(EYE_DAMAGE))
target.blur_eyes(35) //this will fix itself slowly.
target.set_eye_damage(0)
return TRUE
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index 488f2e81b1..ba43a5cc3b 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -4,7 +4,7 @@
possible_locs = list("chest")
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
- if(target.disabilities & FAT)
+ if(target.has_disability(FAT))
return 1
return 0
diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index e23e7ff7d3..a90923e58f 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -61,7 +61,7 @@
/obj/item/organ/cyberimp/arm/emag_act()
return 0
-/obj/item/organ/cyberimp/arm/gun/emp_act(severity)
+/obj/item/organ/cyberimp/arm/emp_act(severity)
if(prob(15/severity) && owner)
to_chat(owner, "
[src] is hit by EMP!")
// give the owner an idea about why his implant is glitching
diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm
index 98b2a84ac0..905f9c2e1f 100644
--- a/code/modules/surgery/organs/ears.dm
+++ b/code/modules/surgery/organs/ears.dm
@@ -25,7 +25,7 @@
return
var/mob/living/carbon/C = owner
// genetic deafness prevents the body from using the ears, even if healthy
- if(C.disabilities & DEAF)
+ if(C.has_disability(DEAF))
deaf = max(deaf, 1)
else
if(C.ears && (C.ears.flags_2 & HEALS_EARS_2))
@@ -42,7 +42,7 @@
var/mob/living/carbon/C = owner
- if(iscarbon(owner) && C.disabilities & DEAF)
+ if(iscarbon(owner) && C.has_disability(DEAF))
deaf = 1
/obj/item/organ/ears/proc/adjustEarDamage(ddmg, ddeaf)
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 51e39605c4..f8f57c650f 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -199,7 +199,7 @@
return
var/range = input(user, "Enter range (0 - [max_light_beam_distance])", "Range Select", 0) as null|num
- set_distance(Clamp(range, 0, max_light_beam_distance))
+ set_distance(CLAMP(range, 0, max_light_beam_distance))
assume_rgb(C)
/obj/item/organ/eyes/robotic/glow/proc/assume_rgb(newcolor)
diff --git a/code/modules/surgery/organs/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 @@